예제 #1
0
// ----------------------------------------------------------------------------
void GetPeerAddress::asynchronousUpdate()
{
    if (m_request->isDone())
    {
        const XMLNode * result = m_request->getXMLData();

        std::string success;
        if(result->get("success", &success) && success == "yes")
        {
            uint32_t ip;
            result->get("ip", &ip);
            m_address.setIP(ip);

            uint16_t port;
            uint32_t my_ip = NetworkConfig::get()->getMyAddress().getIP();
            if (m_address.getIP() == my_ip && !NetworkConfig::m_disable_lan)
                result->get("private_port", &port);
            else
                result->get("port", &port);
            m_address.setPort(port);

            Log::debug("GetPeerAddress", "Peer address retrieved.");
        }
        else
        {
            Log::error("GetPeerAddress", "Failed to get peer address.");
        }
        requestTerminate();

        delete m_request;
        m_request = NULL;
    }
}   // asynchronousUpdate
예제 #2
0
/** Detects public IP-address and port by first sending a request to a randomly
 * selected STUN server and then parsing and validating the response */
void GetPublicAddress::asynchronousUpdate()
{
    // If the user has specified an address, use it instead of the stun protocol.
    if (m_my_address.getIP() != 0 && m_my_address.getPort() != 0)
    {
        NetworkConfig::get()->setMyAddress(m_my_address);
        m_state = EXITING;
        requestTerminate();
    }
//#define LAN_TEST
#ifdef LAN_TEST
    TransportAddress address(0x7f000001, 4);
    NetworkConfig::get()->setMyAddress(address);
    m_state = EXITING;
    requestTerminate();
    return;
#endif

    if (m_state == NOTHING_DONE)
    {
        createStunRequest();
    }
    if (m_state == STUN_REQUEST_SENT)
    {
        std::string message = parseStunResponse();
        delete m_transaction_host;
        if (message != "")
        {
            Log::warn("GetPublicAddress", "%s", message.c_str());
            m_state = NOTHING_DONE;  // try again
        }
        else
        {
            // The address and the port are known, so the connection can be closed
            m_state = EXITING;
            requestTerminate();
        }
    }
}   // asynchronousUpdate
/** Simple finite state machine. First get the public ip address. Once this
 *  is known, register the server and its address with the stk server so that
 *  client can find it.
 */
void ServerLobbyRoomProtocol::update()
{
    switch (m_state)
    {
    case NONE:
        // Start the protocol to find the public ip address.
        m_current_protocol = new GetPublicAddress(this);
        m_current_protocol->requestStart();
        m_state = GETTING_PUBLIC_ADDRESS;
        // The callback from GetPublicAddress will wake this protocol up
        requestPause();
        break;
    case GETTING_PUBLIC_ADDRESS:
        {
            Log::debug("ServerLobbyRoomProtocol", "Public address known.");
            // Free GetPublicAddress protocol
            delete m_current_protocol;

            // Register this server with the STK server. This will block
            // this thread, but there is no need for the protocol manager
            // to react to any requests before the server is registered.
            registerServer();
            Log::info("ServerLobbyRoomProtocol", "Server registered.");
            m_state = ACCEPTING_CLIENTS;
        }
        break;
    case ACCEPTING_CLIENTS:
    {
        // Only poll the STK server if this is a WAN server.
        if(NetworkConfig::get()->isWAN())
            checkIncomingConnectionRequests();
        if (m_in_race && World::getWorld() &&
            RaceEventManager::getInstance<RaceEventManager>()->isRunning())
        {
            checkRaceFinished();
        }

        break;
    }
    case SELECTING_KARTS:
        break;   // Nothing to do, this is event based
    case DONE:
        m_state = EXITING;
        requestTerminate();
        break;
    case EXITING:
        break;
    }
}   // update
예제 #4
0
// ----------------------------------------------------------------------------
void ConnectToServer::update(int ticks)
{
    switch(m_state.load())
    {
        case GOT_SERVER_ADDRESS:
        {
            // Make sure lobby display the quick play server name
            assert(m_server);
            NetworkingLobby::getInstance()->setJoinedServer(m_server);
            break;
        }
        case DONE:
        {
            // lobby room protocol if we're connected only
            if (STKHost::get()->getPeerCount() > 0 &&
                STKHost::get()->getServerPeerForClient()->isConnected() &&
                !m_server_address.isUnset())
            {
                // Let main thread create ClientLobby for better
                // synchronization with GUI
                NetworkConfig::get()->clearActivePlayersForClient();
                auto cl = LobbyProtocol::create<ClientLobby>(m_server_address,
                    m_server);
                STKHost::get()->startListening();
                cl->requestStart();
            }
            if (STKHost::get()->getPeerCount() == 0)
            {
                // Shutdown STKHost (go back to online menu too)
                STKHost::get()->setErrorMessage(
                    _("Cannot connect to server %s.", m_server->getName()));
                STKHost::get()->requestShutdown();
            }
            requestTerminate();
            m_state = EXITING;
            break;
        }
        default:
            break;
    }
}   // update
예제 #5
0
// ----------------------------------------------------------------------------
void StartGameProtocol::update()
{
    switch(m_state)
    {
        case SYNCHRONIZATION_WAIT:
        {
            // Wait till the synchronisation protocol is running
            Protocol *p = ProtocolManager::getInstance()
                        ->getProtocol(PROTOCOL_SYNCHRONIZATION);
            SynchronizationProtocol* protocol =
                              static_cast<SynchronizationProtocol*>(p);
            if (protocol)
            {
                // Now the synchronization protocol exists.
                Log::info("StartGameProtocol", "Starting the race loading.");
                // This will create the world instance,
                // i.e. load track and karts
                m_game_setup->getRaceConfig()->setRaceData();
                World::getWorld()->setNetworkWorld(true);
                m_state = LOADING;
            }
            break;
        }
        case LOADING:
        {
            if (m_ready) m_state = READY;
            break;
        }
        case READY:
        {
            // set karts into the network game setup
            STKHost::get()->getGameSetup()->bindKartsToProfiles();
            m_state = EXITING;
            requestTerminate();
            break;
        }
    }   // switch
}   // update
/** Detects public IP-address and port by first sending a request to a randomly
 * selected STUN server and then parsing and validating the response */
void GetPublicAddress::asynchronousUpdate()
{
    if (m_state == NOTHING_DONE)
    {
        createStunRequest();
    }
    if (m_state == STUN_REQUEST_SENT)
    {
        std::string message = parseStunResponse();
        delete m_transaction_host;
        if (message != "")
        {
            Log::warn("GetPublicAddress", "%s", message.c_str());
            m_state = NOTHING_DONE;  // try again
        }
        else
        {
            // The address and the port are known, so the connection can be closed
            m_state = EXITING;
            requestTerminate();
        }
    }
}   // asynchronousUpdate
/** Simple finite state machine. First get the public ip address. Once this
 *  is known, register the server and its address with the stk server so that
 *  client can find it.
 */
void ServerLobbyRoomProtocol::update(float dt)
{
    switch (m_state)
    {
    case NONE:
        // Start the protocol to find the public ip address.
        m_current_protocol = new GetPublicAddress(this);
        m_current_protocol->requestStart();
        m_state = GETTING_PUBLIC_ADDRESS;
        // The callback from GetPublicAddress will wake this protocol up
        requestPause();
        break;
    case GETTING_PUBLIC_ADDRESS:
        {
            Log::debug("ServerLobbyRoomProtocol", "Public address known.");
            // Free GetPublicAddress protocol
            delete m_current_protocol;

            // Register this server with the STK server. This will block
            // this thread, but there is no need for the protocol manager
            // to react to any requests before the server is registered.
            registerServer();
            Log::info("ServerLobbyRoomProtocol", "Server registered.");
            m_state = ACCEPTING_CLIENTS;
        }
        break;
    case ACCEPTING_CLIENTS:
    {
        // Only poll the STK server if this is a WAN server.
        if(NetworkConfig::get()->isWAN())
            checkIncomingConnectionRequests();
        break;
    }
    case SELECTING:
        break;   // Nothing to do, this is event based
    case RACING:
        if (World::getWorld() &&
            RaceEventManager::getInstance<RaceEventManager>()->isRunning())
        {
            checkRaceFinished();
        }
        break;
    case RESULT_DISPLAY:
        if(StkTime::getRealTime() > m_timeout)
        {
            // Send a notification to all clients to exit 
            // the race result screen
            NetworkString *exit_result_screen = getNetworkString(1);
            exit_result_screen->setSynchronous(true);
            exit_result_screen->addUInt8(LE_EXIT_RESULT);
            sendMessageToPeersChangingToken(exit_result_screen,
                                            /*reliable*/true);
            delete exit_result_screen;
            m_state = ACCEPTING_CLIENTS;
            RaceResultGUI::getInstance()->backToLobby();
            // notify the network world that it is stopped
            RaceEventManager::getInstance()->stop();
            // stop race protocols
            findAndTerminateProtocol(PROTOCOL_CONTROLLER_EVENTS);
            findAndTerminateProtocol(PROTOCOL_KART_UPDATE);
            findAndTerminateProtocol(PROTOCOL_GAME_EVENTS);
        }
        break;
    case DONE:
        m_state = EXITING;
        requestTerminate();
        break;
    case EXITING:
        break;
    }
}   // update
예제 #8
0
// ----------------------------------------------------------------------------
void ConnectToServer::asynchronousUpdate()
{
    switch(m_state)
    {
        case NONE:
        {
            Log::info("ConnectToServer", "Protocol starting");
            // This protocol will write the public address of this
            // instance to STKHost.
            m_current_protocol = new GetPublicAddress(this);
            m_current_protocol->requestStart();
            // This protocol will be unpaused in the callback from 
            // GetPublicAddress
            requestPause();
            m_state = GETTING_SELF_ADDRESS;
            break;
        }
        case GETTING_SELF_ADDRESS:
        {
            delete m_current_protocol;   // delete GetPublicAddress
            m_current_protocol = NULL;

            registerWithSTKServer();  // Register us with STK server

            if (m_quick_join)
            {
                handleQuickConnect();
                // Quick connect will give us the server details,
                // so we can immediately try to connect to the server
                m_state = REQUESTING_CONNECTION;
            }
            else
            {
                m_state = GOT_SERVER_ADDRESS;
            }
        }
        break;
        case GOT_SERVER_ADDRESS:
        {
            assert(!m_quick_join);
            delete m_current_protocol;
            m_current_protocol = NULL;
            Log::info("ConnectToServer", "Server's address known");

            // we're in the same lan (same public ip address) !!
            if (m_server_address.getIP() ==
                NetworkConfig::get()->getMyAddress().getIP())
            {
                Log::info("ConnectToServer",
                    "Server appears to be in the same LAN.");
            }
            m_state = REQUESTING_CONNECTION;
            m_current_protocol = new RequestConnection(m_server_id);
            m_current_protocol->requestStart();
            break;
        }
        case REQUESTING_CONNECTION:
            // In case of a LAN server, m_crrent_protocol is NULL
            if (!m_current_protocol ||
                m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
            {
                delete m_current_protocol;
                m_current_protocol = NULL;
                // Server knows we want to connect
                Log::info("ConnectToServer", "Connection request made");
                if (m_server_address.getIP() == 0 ||
                    m_server_address.getPort() == 0  )
                { 
                    // server data not correct, hide address and stop
                    m_state = HIDING_ADDRESS;
                    Log::error("ConnectToServer", "Server address is %s",
                               m_server_address.toString().c_str());
                    m_current_protocol = new HidePublicAddress();
                    m_current_protocol->requestStart();
                    return;
                }
                if (m_server_address.getIP() 
                      == NetworkConfig::get()->getMyAddress().getIP() ||
                      NetworkConfig::get()->isLAN())
                {
                    // We're in the same lan (same public ip address).
                    // The state will change to CONNECTING
                    handleSameLAN();
                }
                else
                {
                    m_state = CONNECTING;
                    m_current_protocol = new PingProtocol(m_server_address, 2.0);
                    m_current_protocol->requestStart();
                }
            }
            break;
        case CONNECTING: // waiting the server to answer our connection
            {
                static double timer = 0;
                if (StkTime::getRealTime() > timer+5.0) // every 5 seconds
                {
                    STKHost::get()->connect(m_server_address);
                    timer = StkTime::getRealTime();
                    Log::info("ConnectToServer", "Trying to connect to %s",
                              m_server_address.toString().c_str());
                }
                break;
            }
        case CONNECTED:
        {
            Log::info("ConnectToServer", "Connected");
            if(m_current_protocol)
            {
                // Kill the ping protocol because we're connected
                m_current_protocol->requestTerminate();
            }
            delete m_current_protocol;
            m_current_protocol = NULL;
            // LAN networking does not use the stk server tables.
            if(NetworkConfig::get()->isWAN())
            {
                m_current_protocol = new HidePublicAddress();
                m_current_protocol->requestStart();
            }
            m_state = HIDING_ADDRESS;
            break;
        }
        case HIDING_ADDRESS:
            // Wait till we have hidden our address
            if (!m_current_protocol ||
                m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
            {
                if(m_current_protocol)
                {
                    delete m_current_protocol;
                    m_current_protocol = NULL;
                    Log::info("ConnectToServer", "Address hidden");
                }
                m_state = DONE;
                // lobby room protocol if we're connected only
                if(STKHost::get()->getPeers()[0]->isConnected())
                {
                    Protocol *p = new ClientLobbyRoomProtocol(m_server_address);
                    p->requestStart();
                }
            }
            break;
        case DONE:
            requestTerminate();
            m_state = EXITING;
            break;
        case EXITING:
            break;
    }
}   // asynchronousUpdate
예제 #9
0
void Enchantment::applyEnchantment(std::shared_ptr<Object> target)
{
    //Invalid target?
    if( target->isTerminated() || (!target->isAlive() && !_enchantProfile->_target._stay) ) {
		Log::get().warn("%s:%d: invalid target\n", __FILE__, __LINE__);
        requestTerminate();
        return;
    }

    //Already added to a target?
    if(_target.lock()) {
        throw std::logic_error("Enchantment::applyEnchantment() - Already applied\n");
    }

    // do retargeting, if necessary
    // Should it choose an inhand item?
    if (_enchantProfile->retarget) {
        // Left, right, or both are valid
        if (target->getRightHandItem()) {
            // Only right hand is valid
            target = target->getRightHandItem();
        }
        else if (target->getLeftHandItem()) {
            // Pick left hand
            target = target->getLeftHandItem();
        }
        else {
            // No weapons to pick, make it fail
			Log::get().debug("Enchantment::applyEnchantment() - failed because target has no valid items in hand\n");
            requestTerminate();
            return;
        }
    }

    //Set our target, stored as a weak_ptr
    _target = target;

    // Check damage type, 90% damage resistance is enough to resist the enchant
    if (_enchantProfile->required_damagetype < DAMAGE_COUNT) {
        if (target->getDamageReduction(_enchantProfile->required_damagetype) >= 0.90f) {
			Log::get().debug("Enchantment::applyEnchantment() - failed because the target is immune to the enchant.\n");
            requestTerminate();
            return;
        }
    }

    // Check if target has the required damage type we need
    if (_enchantProfile->require_damagetarget_damagetype < DAMAGE_COUNT) {
        if (target->damagetarget_damagetype != _enchantProfile->require_damagetarget_damagetype) {
			Log::get().warn("%s:%d: application of enchantment failed because the target not have the right damagetarget_damagetype.\n", __FILE__, __LINE__);
            requestTerminate();
            return;
        }
    }

    //modify enchant duration with damage resistance (bad resistance actually *increases* duration!)
    if ( _lifeTime > 0 && _enchantProfile->required_damagetype < DAMAGE_COUNT && target ) {
        _lifeTime -= std::ceil(target->getDamageReduction(_enchantProfile->required_damagetype) * _enchantProfile->lifetime);
    }

    // Create an overlay character?
    if (_enchantProfile->spawn_overlay)
    {
        std::shared_ptr<Object> overlay = _currentModule->spawnObject(target->getPosition(), _spawnerProfileID, target->team, 0, target->ori.facing_z, "", ObjectRef::Invalid );
        if (overlay)
        {
            _overlay = overlay;                             //Kill this character on end...
            overlay->ai.setTarget(target->getObjRef());
            overlay->is_overlay  = true;
            overlay->ai.state = _enchantProfile->spawn_overlay; // ??? WHY DO THIS ???

            // Start out with ActionMJ...  Object activated
            int action = overlay->getProfile()->getModel()->getAction(ACTION_MJ);
            if ( !ACTION_IS_TYPE( action, D ) )
            {
                chr_start_anim( overlay.get(), action, false, true );
            }

            // Assume it's transparent...
            overlay->setLight(254);
            overlay->setAlpha(128);
        }
    }

    //Check if this enchant has any set modifiers that conflicts with another enchant
    _modifiers.remove_if([this, &target](const EnchantModifier &modifier) {

        //Only set types can conflict
        if(!Ego::Attribute::isOverrideSetAttribute(modifier._type)) {
            return false;
        }

        //Is there no conflict?
        if(target->getTempAttributes().find(modifier._type) == target->getTempAttributes().end()) {
            return false;
        }

        //Ok there exist a conflict, so now we have to resolve it somehow
        //Does this enchant override other enchants?
        if(getProfile()->_override) {
            bool conflictResolved = false;

            //Find the active enchant that conflicts with us
            for(const std::shared_ptr<Ego::Enchantment> &conflictingEnchant : target->getActiveEnchants()) {
                conflictingEnchant->_modifiers.remove_if([this, &conflictingEnchant, &modifier, &conflictResolved](const EnchantModifier &otherModifier)
                    {
                        //Is this the one?
                        if(modifier._type == otherModifier._type) {
                            conflictResolved = true;

                            //Remove Enchants that conflict with this one?
                            if(getProfile()->remove_overridden) {
                                conflictingEnchant->requestTerminate();
                            }

                            return true;
                        }

                        //Nope, keep looking
                        return false;
                    });

                //Has it been resolved?
                if(conflictResolved) {
                    break;
                }
            }

            //We have higher priority than exiting enchants
            return false;
        }
        else {
            //The existing enchant has higher priority than ours
            return true;
        }
    });

    //Now actually apply the values to the target
    for(const EnchantModifier &modifier : _modifiers)
    {
        //These should never occur
        if(modifier._type == Ego::Attribute::NR_OF_PRIMARY_ATTRIBUTES ||
           modifier._type == Ego::Attribute::NR_OF_ATTRIBUTES) 
        {
            throw std::logic_error("Enchant.cpp - Invalid enchant type: meta-type as modifier");
        }

        //Morph is special and handled differently than others
        if(modifier._type == Ego::Attribute::MORPH) {
            //Store target's original armor
            target->getTempAttributes()[Ego::Attribute::MORPH] = target->skin;

            //Transform the object
            target->polymorphObject(_spawnerProfileID, 0);
        }

        //Is it a set type?
        else if(Ego::Attribute::isOverrideSetAttribute(modifier._type)) {
            target->getTempAttributes()[modifier._type] = modifier._value;
        }

        //It's a cumulative addition
        else {
            target->getTempAttributes()[modifier._type] += modifier._value;            
        }
    }

    //Finally apply boost values to owner as well
    std::shared_ptr<Object> owner = _owner.lock();
    if(owner != nullptr && !owner->isTerminated()) {
        owner->getTempAttributes()[Ego::Attribute::MANA_REGEN] += _ownerManaSustain;
        owner->getTempAttributes()[Ego::Attribute::LIFE_REGEN] += _ownerLifeSustain;
    }

    //Insert this enchantment into the Objects list of active enchants
    target->getActiveEnchants().push_front(shared_from_this());    
}
예제 #10
0
void Enchantment::update()
{
    if(isTerminated()) return;

    //Have we lost our target?
    std::shared_ptr<Object> target = _target.lock();
    std::shared_ptr<Object> owner = _owner.lock();
    if(target == nullptr || target->isTerminated()) {
        requestTerminate();
        return;
    }

    //End enchant if owner of the Enchant has died?
    if(!_enchantProfile->_owner._stay) {
        if(!owner || !owner->isAlive()) {
            requestTerminate();
            return;
        }
    }

    //End enchant if target of the enchant has died?
    if(!_enchantProfile->_target._stay && !target->isAlive()) {
        requestTerminate();
        return;
    }

    //Spawn particles?
    if(_spawnParticlesTimer > 0) {
        _spawnParticlesTimer--;
        if(_spawnParticlesTimer == 0) {
            _spawnParticlesTimer = _enchantProfile->contspawn._delay;

            FACING_T facing = target->ori.facing_z;
            for (uint8_t i = 0; i < _enchantProfile->contspawn._amount; ++i)
            {
                ParticleHandler::get().spawnLocalParticle(target->getPosition(), facing, _spawnerProfileID, _enchantProfile->contspawn._lpip,
                                                          ObjectRef::Invalid, GRIP_LAST, 
                                                          owner != nullptr ? owner->getTeam().toRef() : static_cast<TEAM_REF>(Team::TEAM_DAMAGE), 
                                                          owner != nullptr ? owner->getObjRef() : ObjectRef::Invalid,
                                                          ParticleRef::Invalid, i, ObjectRef::Invalid);

                facing += _enchantProfile->contspawn._facingAdd;
            }
        }
    }

    //Can we kill the target by draining life?
    if(target->isAlive()) {
        if (target->getLife() + _targetLifeDrain < 0.0f) {
            target->kill(owner, false);
        }
    }

    //Can the owner still sustain us?
    if (owner && owner->isAlive()) {

        //Killed by draining life?
        if(owner->getLife() + _ownerLifeSustain < 0.0f) {
            owner->kill(target, false);

            if(_enchantProfile->endIfCannotPay || !_enchantProfile->_target._stay) {
                requestTerminate();
                return;
            }
        }

        //Owner has no longer enough mana to sustain the enchant?
        if(_enchantProfile->endIfCannotPay) {
            if(owner->getMana() + _ownerManaSustain < 0.0f) {
                requestTerminate();
                return;
            }
        }
    }

    //Decrement the lifetimer
    if(_lifeTime > 0) {
        if(_lifeTime == 0) {
            requestTerminate();
        }        
    }
}