void CharCreationManager::HandleLifeEvents(MsgEntry* me,Client* client)
{
    psLifeEventMsg message(me);

    if(!message.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psLifeEventMsg from client id %u.\n",me->clientnum);
        return;
    }

    psLifeEventMsg response(me->clientnum);

    for(size_t x = 0; x < lifeEvents.GetSize(); x++)
    {
        response.AddEvent(lifeEvents[x]);
    }

    response.ConstructMessage();
    if(response.valid)
        response.SendMessage();
    else
    {
        Bug2("Failed to construct a valid psLifeEventMsg for client id %u.\n",me->clientnum);
    }

}
void CharCreationManager::HandleParents(MsgEntry* me,Client* client)
{
    psCreationChoiceMsg message(me);
    if(!message.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psCreationChoiceMsg from client id %u.\n",me->clientnum);
        return;
    }

    psCreationChoiceMsg response(me->clientnum, (int) parentData.GetSize(), MSGTYPE_CHAR_CREATE_PARENTS);
    for(size_t x = 0; x < parentData.GetSize(); x++)
    {
        response.AddChoice(parentData[x]->id,
                           parentData[x]->name,
                           parentData[x]->description,
                           parentData[x]->choiceArea,
                           parentData[x]->cpCost);
    }

    response.ConstructMessage();
    if(response.valid)
        response.SendMessage();
    else
    {
        Bug2("Failed to construct a valid psCreationChoiceMsg for client id %u.\n",me->clientnum);
    }
}
void CharCreationManager::HandleChildhood(MsgEntry* me,Client* client)
{
    psCreationChoiceMsg message(me);

    if(!message.valid)
    {
        Debug2(LOG_NET, me->clientnum,"Received unparsable Childhood request from client: %u\n", me->clientnum);
        return;
    }

    psCreationChoiceMsg response(me->clientnum, (int) childhoodData.GetSize(), MSGTYPE_CHAR_CREATE_CHILDHOOD);

    for(size_t x = 0; x < childhoodData.GetSize(); x++)
    {
        response.AddChoice(childhoodData[x]->id,
                           childhoodData[x]->name,
                           childhoodData[x]->description,
                           childhoodData[x]->choiceArea,
                           childhoodData[x]->cpCost);
    }

    response.ConstructMessage();
    if(response.valid)
    {
        response.SendMessage();
    }
    else
    {
        Bug2("Failed to construct a valid psCreationChoiceMsg for client id %u.\n",me->clientnum);
    }

}
void ClientConnectionSet::MarkDelete(Client* client)
{
    CS::Threading::RecursiveMutexScopedLock lock(mutex);

    uint32_t clientid = client->GetClientNum();
    if(!addrHash.DeleteAll(client->GetAddress()))
        Bug2("Couldn't delete client %d, it was never added!", clientid);

    hash.DeleteAll(clientid);
    toDelete.Push(client);
}
Exemple #5
0
void AuthenticationServer::SendDisconnect(Client* client, const char *reason)
{
    if (client->GetActor())
    {
        psDisconnectMessage msg(client->GetClientNum(), client->GetActor()->GetEID(), reason);
        if (msg.valid)
        {
            msg.msg->priority = PRIORITY_LOW;
            psserver->GetEventManager()->Broadcast(msg.msg, NetBase::BC_FINALPACKET);
        }
        else
        {
            Bug2("Could not create a valid psDisconnectMessage for client %u.\n",client->GetClientNum());
        }
    }
    else
    {
        psDisconnectMessage msg(client->GetClientNum(), 0, reason);
        if (msg.valid)
        {
            psserver->GetEventManager()->Broadcast(msg.msg, NetBase::BC_FINALPACKET);
        }
    }
}
Exemple #6
0
void AuthenticationServer::HandleAuthent(MsgEntry *me, Client *notused)
{
    csTicks start = csGetTicks();

    psAuthenticationMessage msg(me); // This cracks message into members.

    if (!msg.valid)
    {
        Debug1(LOG_NET,me->clientnum,"Mangled psAuthenticationMessage received.\n");
        return;
    }

    if (!CheckAuthenticationPreCondition(me->clientnum, msg.NetVersionOk(),msg.sUser))
        return;

    csString status;
    status.Format("%s, %u, Received Authentication Message", (const char *) msg.sUser, me->clientnum);
    psserver->GetLogCSV()->Write(CSV_AUTHENT, status);

    if ( msg.sUser.Length() == 0 || msg.sPassword.Length() == 0)
    {
        psserver->RemovePlayer(me->clientnum,"No username or password entered");

        Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: No username or password.\n",
                (const char *)msg.sUser);            
        return;                
    }
    
    // Check if login was correct
    Notify2(LOG_CONNECTIONS,"Check Login for: '%s'\n", (const char*)msg.sUser);
    psAccountInfo *acctinfo=CacheManager::GetSingleton().GetAccountInfoByUsername((const char *)msg.sUser);

    if ( !acctinfo )
    {
        // invalid
        psserver->RemovePlayer(me->clientnum,"Incorrect password or username.");

        Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: No account found with that name.\n",
                (const char *)msg.sUser);            
        return;                
    }

    // Add account to cache to optimize repeated login attempts
    CacheManager::GetSingleton().AddToCache(acctinfo,msg.sUser,120);
    
    // Check if password was correct
    csString passwordhashandclientnum (acctinfo->password);
    passwordhashandclientnum.Append(":");
    passwordhashandclientnum.Append(me->clientnum);
    
    csString encoded_hash = csMD5::Encode(passwordhashandclientnum).HexString();
    if (strcmp( encoded_hash.GetData() , msg.sPassword.GetData())) // authentication error
    {
        psserver->RemovePlayer(me->clientnum, "Incorrect password or username.");
        Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected (Bad password).",(const char *)msg.sUser);
        // No delete necessary because AddToCache will auto-delete
        // delete acctinfo;
        return;
    }
    
    /**
     * Check if the client is already logged in
     */
    Client* existingClient = clients->FindAccount(acctinfo->accountid, me->clientnum);
    if (existingClient)  // account already logged in
    {
        // invalid authent message from a different client
        csString reason;
        if(existingClient->IsZombie())
        {
            reason.Format("Your character(%s) was still in combat or casting a spell when you disconnected. "
                          "This connection is being overridden by a new login.", existingClient->GetName());
        }
        else
        {
            reason.Format("You are already logged on to this server as %s. "
                          "This connection is being overridden by a new login..", existingClient->GetName());
        }

        psserver->RemovePlayer(existingClient->GetClientNum(), reason);
        Notify2(LOG_CONNECTIONS,"User '%s' authentication request overrides an existing logged in user.\n",
            (const char *)msg.sUser);

        // No delete necessary because AddToCache will auto-delete
        // delete acctinfo;
    }


    if(csGetTicks() - start > 500)
    {
        csString status;
        status.Format("Warning: Spent %u time authenticating account ID %u, After password check", 
            csGetTicks() - start, acctinfo->accountid);
        psserver->GetLogCSV()->Write(CSV_STATUS, status);
    }


    Client *client = clients->FindAny(me->clientnum);
    if (!client)
    {
        Bug2("Couldn't find client %d?!?",me->clientnum);
        // No delete necessary because AddToCache will auto-delete
        // delete acctinfo;
        return;
    }

    client->SetName(msg.sUser);
    client->SetAccountID( acctinfo->accountid );
    

    // Check to see if the client is banned
    time_t now = time(0);
    BanEntry* ban = banmanager.GetBanByAccount(acctinfo->accountid);
    if (ban == NULL)
    {
        // Account not banned; try IP range
        ban = banmanager.GetBanByIPRange(client->GetIPRange());
        // 2 day IP ban limit removed
        //if (ban && ban->end && now > ban->start + IP_RANGE_BAN_TIME)
        //{  
        //    // Only ban by IP range for the first 2 days
        //    ban = NULL;
        //}
    }
    if (ban)
    {
        if (now > ban->end)  // Time served
        {
            banmanager.RemoveBan(acctinfo->accountid);
        }
        else  // Notify and block
        {
            tm* timeinfo = gmtime(&(ban->end));
            csString banmsg;
            banmsg.Format("You are banned until %d-%d-%d %d:%d GMT.  Reason: %s",
                          timeinfo->tm_year+1900,
                          timeinfo->tm_mon+1,
                          timeinfo->tm_mday,
                          timeinfo->tm_hour,
                          timeinfo->tm_min,
                          ban->reason.GetData() );
    
            psserver->RemovePlayer(me->clientnum, banmsg);
    
            Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected (Banned).",(const char *)msg.sUser);
            // No delete necessary because AddToCache will auto-delete
            // delete acctinfo;
            return;
        }
    }

    if(csGetTicks() - start > 500)
    {
        csString status;
        status.Format("Warning: Spent %u time authenticating account ID %u, After ban check", 
            csGetTicks() - start, acctinfo->accountid);
        psserver->GetLogCSV()->Write(CSV_STATUS, status);
    }

    /** Check to see if there are any players on that account.  All accounts should have
    *    at least one player in this function.
    */
    psCharacterList *charlist = psserver->CharacterLoader.LoadCharacterList(acctinfo->accountid);

    if (!charlist)
    {
        Error2("Could not load Character List for account! Rejecting client %s!\n",(const char *)msg.sUser);
        psserver->RemovePlayer( me->clientnum, "Could not load the list of characters for your account.  Please contact a PS Admin for help.");
        delete acctinfo;
        return;
    }

    // cache will auto-delete this ptr if it times out
    CacheManager::GetSingleton().AddToCache(charlist, CacheManager::GetSingleton().MakeCacheName("list", client->GetAccountID().Unbox()),120);

    
     /**
     * CHECK 6: Connection limit
     * 
     * We check against number of concurrent connections, but players with
     * security rank of GameMaster or higher are not subject to this limit.
     */
    if (psserver->IsFull(clients->Count(),client)) 
    {
        // invalid
        psserver->RemovePlayer(me->clientnum, "The server is full right now.  Please try again in a few minutes.");

        Notify2(LOG_CONNECTIONS, "User '%s' authentication request rejected: Too many connections.\n", (const char *)msg.sUser );
        // No delete necessary because AddToCache will auto-delete
        // delete acctinfo;
        status = "User limit hit!";
        psserver->GetLogCSV()->Write(CSV_STATUS, status);
        return;
    }

    Notify3(LOG_CONNECTIONS,"User '%s' (%d) added to active client list\n",(const char*) msg.sUser, me->clientnum);

    // Get the struct to refresh
    // Update last login ip and time
    char addr[20];
    client->GetIPAddress(addr);
    acctinfo->lastloginip = addr;

    tm* gmtm = gmtime(&now);
    csString timeStr;
    timeStr.Format("%d-%02d-%02d %02d:%02d:%02d",
        gmtm->tm_year+1900,
        gmtm->tm_mon+1,
        gmtm->tm_mday,
        gmtm->tm_hour,
        gmtm->tm_min,
        gmtm->tm_sec);

    acctinfo->lastlogintime = timeStr;
    acctinfo->os = msg.os_;
    acctinfo->gfxcard = msg.gfxcard_;
    acctinfo->gfxversion = msg.gfxversion_;
    CacheManager::GetSingleton().UpdateAccountInfo(acctinfo);

    iCachedObject *obj = CacheManager::GetSingleton().RemoveFromCache(CacheManager::GetSingleton().MakeCacheName("auth",acctinfo->accountid));
    CachedAuthMessage *cam;

    if (!obj)
    {
        // Send approval message
        psAuthApprovedMessage *message = new psAuthApprovedMessage(me->clientnum,client->GetPID(), charlist->GetValidCount() );    

        if(csGetTicks() - start > 500)
        {
            csString status;
            status.Format("Warning: Spent %u time authenticating account ID %u, After approval", 
                csGetTicks() - start, acctinfo->accountid);
            psserver->GetLogCSV()->Write(CSV_STATUS, status);
        }

        // Send out the character list to the auth'd player    
        for (int i=0; i<MAX_CHARACTERS_IN_LIST; i++)
        {
            if (charlist->GetEntryValid(i))
            {
                // Quick load the characters to get enough info to send to the client
                psCharacter* character = psserver->CharacterLoader.QuickLoadCharacterData( charlist->GetCharacterID(i), false );
                if (character == NULL)
                {
                    Error2("QuickLoadCharacterData failed for character '%s'", charlist->GetCharacterName(i));
                    continue;
                }

                Notify3(LOG_CHARACTER, "Sending %s to client %d\n", character->name.GetData(), me->clientnum );
                character->AppendCharacterSelectData(*message);

                delete character;
            }
        }
        message->ConstructMsg();
        cam = new CachedAuthMessage(message);
    }
    else
    {
        // recover underlying object
        cam = (CachedAuthMessage *)obj->RecoverObject();
        // update client id since new connection here
        cam->msg->msg->clientnum = me->clientnum;
    }
    // Send auth approved and char list in one message now
    cam->msg->SendMessage();
    CacheManager::GetSingleton().AddToCache(cam, CacheManager::GetSingleton().MakeCacheName("auth",acctinfo->accountid), 10);

    SendMsgStrings(me->clientnum, true); 
    
    client->SetSpamPoints(acctinfo->spamPoints);
    client->SetAdvisorPoints(acctinfo->advisorPoints);
    client->SetSecurityLevel(acctinfo->securitylevel);

    if (acctinfo->securitylevel >= GM_TESTER)
    {
        psserver->GetAdminManager()->Admin(me->clientnum, client);
    }
    
    if (CacheManager::GetSingletonPtr()->GetCommandManager()->Validate(client->GetSecurityLevel(), "default advisor"))
        psserver->GetAdviceManager()->AddAdvisor(client);

    if (CacheManager::GetSingletonPtr()->GetCommandManager()->Validate(client->GetSecurityLevel(), "default buddylisthide"))
        client->SetBuddyListHide(true);

    psserver->GetWeatherManager()->SendClientGameTime(me->clientnum);

    if(csGetTicks() - start > 500)
    {
        csString status;
        status.Format("Warning: Spent %u time authenticating account ID %u, After load", 
            csGetTicks() - start, acctinfo->accountid);
        psserver->GetLogCSV()->Write(CSV_STATUS, status);
    }

    status.Format("%s - %s, %u, Logged in", addr, (const char*) msg.sUser, me->clientnum);
    psserver->GetLogCSV()->Write(CSV_AUTHENT, status);
}
void CharCreationManager::HandleUploadMessage(MsgEntry* me, Client* client)
{
    Debug1(LOG_NEWCHAR, me->clientnum,"New Character is being created");

    psCharUploadMessage upload(me);

    if(!upload.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psUploadMessage from client %u.",me->clientnum);
        return;
    }

    AccountID acctID = client->GetAccountID();
    if(!acctID.IsValid())
    {
        Error2("Player tried to upload a character to unknown account %s.", ShowID(acctID));

        psCharRejectedMessage reject(me->clientnum);

        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"Could not find your account.");
        return;
    }

    // Check to see if the player already has 4 accounts;
    csString query;
    query.Format("SELECT id FROM characters WHERE account_id=%d", acctID.Unbox());
    Result result(db->Select(query));
    if(result.IsValid() && result.Count() >= CHARACTERS_ALLOWED)
    {
        psserver->RemovePlayer(me->clientnum,"At your character limit.");
        return;
    }

    csString playerName =  upload.name;
    csString lastName =  upload.lastname;

    playerName = NormalizeCharacterName(playerName);
    lastName = NormalizeCharacterName(lastName);

    // Check banned names
    if(psserver->GetCharManager()->IsBanned(playerName))
    {
        csString error;
        error.Format("The name %s is banned", playerName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());
        reject.SendMessage();
        return;
    }

    if(psserver->GetCharManager()->IsBanned(lastName))
    {
        csString error;
        error.Format("The lastname %s is banned", lastName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());
        reject.SendMessage();
        return;
    }

    Debug3(LOG_NEWCHAR, me->clientnum,"Got player firstname (%s) and lastname (%s)\n",playerName.GetData(), lastName.GetData());

    ///////////////////////////////////////////////////////////////
    //  Check to see if the player name is valid
    ///////////////////////////////////////////////////////////////
    if(playerName.Length() == 0 || !FilterName(playerName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_LEGAL_NAME,
                                     "The name you specifed is not a legal player name.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    if(lastName.Length() != 0 && !FilterName(lastName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_LEGAL_NAME,
                                     "The name you specifed is not a legal lastname.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    Debug2(LOG_NEWCHAR, me->clientnum,"Checking player firstname '%s'..\n",playerName.GetData());
    ///////////////////////////////////////////////////////////////
    //  Check to see if the character name is unique in 'characters'.
    ///////////////////////////////////////////////////////////////
    if(!IsUnique(playerName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_UNIQUE_NAME,
                                     "The firstname you specifed is not unique.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    if(lastName.Length())
    {
        Debug2(LOG_NEWCHAR, me->clientnum,"Checking player lastname '%s'..\n",lastName.GetData());
        if(!IsLastNameAvailable(lastName, acctID))
        {
            psCharRejectedMessage reject(me->clientnum,
                                         psCharRejectedMessage::NON_UNIQUE_NAME,
                                         "The lastname you specifed is not unique.");

            psserver->GetEventManager()->SendMessage(reject.msg);
            return;
        }
    }
    ///////////////////////////////////////////////////////////////
    //  Check to see if the character name is on the reserve list.
    ///////////////////////////////////////////////////////////////
    int reservedName = IsReserved(playerName, acctID);
    if(reservedName == NAME_RESERVED)
    {
        csString error;
        error.Format("The name %s is reserved", playerName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }


    csString error;
    if(!psserver->charCreationManager->Validate(upload, error))
    {
        error.Append(", your creation choices are invalid.");
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::INVALID_CREATION,
                                     (char*)error.GetData());

        reject.SendMessage();
        return;
    }

    ///////////////////////////////////////////////////////////////
    //  Create the psCharacter structure for the player.
    ///////////////////////////////////////////////////////////////
    psCharacter* chardata=new psCharacter();
    chardata->SetCharType(PSCHARACTER_TYPE_PLAYER);
    chardata->SetFullName(playerName,lastName);
    chardata->SetCreationInfo(upload.bio);

    psRaceInfo* raceinfo=psserver->GetCacheManager()->GetRaceInfoByNameGender(upload.race, (PSCHARACTER_GENDER)upload.gender);
    if(raceinfo==NULL)
    {
        Error3("Invalid race/gender combination on character creation:  Race='%d' Gender='%d'", upload.race, upload.gender);
        psCharRejectedMessage reject(me->clientnum);
        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"Player tried to create an invalid race/gender.");
        delete chardata;
        return;
    }
    chardata->SetRaceInfo(raceinfo);
    chardata->SetHitPoints(50.0);
    chardata->GetMaxHP().SetBase(0.0);
    chardata->GetMaxMana().SetBase(0.0);

    //range is unused here
    float x,y,z,yrot,range;
    const char* sectorname;
    InstanceID newinstance = DEFAULT_INSTANCE;

    //get the option entries for tutorial from the server options. Note it's tutorial:variousdata
    optionEntry* tutorialEntry = psserver->GetCacheManager()->getOptionSafe("tutorial","");
    sectorname = tutorialEntry->getOptionSafe("sectorname", "tutorial")->getValue();

    psSectorInfo* sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname);

    if(!sectorinfo || PlayerHasFinishedTutorial(acctID, sectorinfo->uid))
    {
        raceinfo->GetStartingLocation(x,y,z,yrot,range,sectorname);
        sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname);

        //As we aren't going in the tutorial disable the tutorial help messages disable them
        for(int i = 0; i < TutorialManager::TUTOREVENTTYPE_COUNT; i++)
            chardata->CompleteHelpEvent(i);
    }
    else
    {
        // Try tutorial level first.
        x = tutorialEntry->getOptionSafe("sectorx", "-225.37")->getValueAsDouble();
        y = tutorialEntry->getOptionSafe("sectory", "-21.32")->getValueAsDouble();
        z = tutorialEntry->getOptionSafe("sectorz", "26.79")->getValueAsDouble();
        yrot = tutorialEntry->getOptionSafe("sectoryrot", "-2.04")->getValueAsDouble();
    }

    bool sectorFound = true;

    if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL)
    {
        Error2("Sector='%s' found but no map file was detected for it. Using NPCroom1", sectorname);
        sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName("NPCroom1");
        if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL)
        {
            Error1("NPCroom1 failed - Critical");
            sectorFound = false;
        }
        else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name))
        {
            sectorFound = true;
        }
        else
        {
            sectorFound = false;
        }
    }
    else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name))
    {
        sectorFound = true;
    }
    else
    {
        sectorFound = false;
    }


    if(!sectorFound)
    {
        Error2("Unresolvable starting sector='%s'", sectorname);
        psCharRejectedMessage reject(me->clientnum);
        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"No starting Sector.");
        delete chardata;
        return;
    }

    chardata->SetLocationInWorld(newinstance, sectorinfo, x, y, z, yrot);

    psTrait* trait;
//    CPrintf(CON_DEBUG, "Trait: %d\n", upload.selectedFace );
    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedFace);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairStyle);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedBeardStyle);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairColour);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedSkinColour);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    gemActor* actor = new gemActor(gemSupervisor, cacheManager, entityManager, chardata,
                                   raceinfo->mesh_name,
                                   newinstance,
                                   EntityManager::GetSingleton().FindSector(sectorinfo->name),
                                   csVector3(x,y,z),yrot,
                                   client->GetClientNum());

    actor->SetupCharData();

    if(!upload.verify)
    {
        if(!psServer::CharacterLoader.NewCharacterData(acctID,chardata))
        {
            Error1("Character could not be created.");
            psCharRejectedMessage reject(me->clientnum);
            psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
            psserver->RemovePlayer(me->clientnum,"Your character could not be created in the database.");
            delete chardata;
            return;
        }
    }

    // Check to see if a path name was set. If so we will use that to generate
    // the character starting stats and skills.
    if(upload.path != "None")
    {
        // Progression Event name is PATH_PathName
        csString name("PATH_");
        name.Append(upload.path);
        ProgressionScript* script = psserver->GetProgressionManager()->FindScript(name.GetData());
        if(script)
        {
            // The script uses the race base character points to calculate starting stats.
            MathEnvironment env;
            env.Define("CharPoints", raceinfo->initialCP);
            env.Define("Actor", actor);
            script->Run(&env);
        }
    }
    else
    {
        //int cpUsage = psserver->charCreationManager->CalculateCPChoice( upload.choices ) +
        //              psserver->charCreationManager->CalculateCPLife(upload.lifeEvents );
        for(size_t ci = 0; ci < upload.choices.GetSize(); ci++)
        {
            CharCreationManager::CreationChoice* choice = psserver->charCreationManager->FindChoice(upload.choices[ci]);
            if(choice)
            {
                csString name(psserver->charCreationManager->FindChoice(upload.choices[ci])->name.GetData());
                Debug3(LOG_NEWCHAR, me->clientnum,"Choice: %s Creation Script: %s", name.GetData(), choice->eventScript.GetData());

                MathEnvironment env;
                env.Define("Actor", actor);
                if(choice->choiceArea == FATHER_JOB || choice->choiceArea == MOTHER_JOB)
                {
                    int modifier = (choice->choiceArea == FATHER_JOB) ? upload.fatherMod : upload.motherMod;
                    if(modifier > 3 || modifier < 1)
                        modifier = 1;

                    env.Define("ParentStatus", modifier);
                }
                ProgressionScript* script = psserver->GetProgressionManager()->FindScript(choice->eventScript);
                if(script)
                    script->Run(&env);
            }
            else
            {
                Debug2(LOG_NEWCHAR, me->clientnum,"Character Choice %d not found\n", upload.choices[ci]);
            }
        }
        for(size_t li = 0; li < upload.lifeEvents.GetSize(); li++)
        {
            MathEnvironment env;
            env.Define("Actor", actor);
            LifeEventChoiceServer* lifeEvent = psserver->charCreationManager->FindLifeEvent(upload.lifeEvents[li]);
            if(!lifeEvent)
            {
                Error2("No LifeEvent Script found: %d", upload.lifeEvents[li]);
                continue;
            }

            csString scriptName(lifeEvent->eventScript.GetData());
            Debug2(LOG_NEWCHAR, me->clientnum, "LifeEvent Script: %s", scriptName.GetDataSafe());

            ProgressionScript* script = psserver->GetProgressionManager()->FindScript(scriptName);
            if(script)
                script->Run(&env);
        }
    }

    if(!upload.verify)
    {

        if(reservedName == NAME_RESERVED_FOR_YOU)
        {
            AssignScript(chardata);
        }
        // This function recalculates the Max HP, Mana and Stamina of the new character
        chardata->RecalculateStats();

        // Make sure the new player have HP, Mana and Samina that was calculated
        chardata->SetHitPoints(chardata->GetMaxHP().Base());
        chardata->SetMana(chardata->GetMaxMana().Base());
        chardata->SetStamina(chardata->GetMaxPStamina().Base(),true);
        chardata->SetStamina(chardata->GetMaxMStamina().Base(),false);


        psServer::CharacterLoader.SaveCharacterData(chardata, actor);
        Debug1(LOG_NEWCHAR,me->clientnum,"Player Creation Complete");

        // Remove cached objects to make sure that the client gets a fresh character
        // list from the database if it logs out and in within 2 minutes.
        iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("list",client->GetAccountID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }
        obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("auth",client->GetAccountID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }

        // Here everything is ok
        client->SetPID(chardata->GetPID());
        client->SetName(playerName);

        psCharApprovedMessage app(me->clientnum);
        if(app.valid)
            psserver->GetEventManager()->SendMessage(app.msg);
        else
            Bug2("Could not create valid psCharApprovedMessage for client %u.\n",me->clientnum);
    }
    else
    {
        psCharVerificationMesg mesg(me->clientnum);
        size_t z;
        //unfortunately count goes out of valid area so we need to check on charisma

        for(z = 0; z < psserver->GetCacheManager()->GetSkillAmount(); z++)
        {
            unsigned int rank = chardata->Skills().GetSkillRank((PSSKILL) z).Base();

            psSkillInfo* info = psserver->GetCacheManager()->GetSkillByID(z);
            csString name("Not found");
            if(info)
                name.Replace(info->name);

            if(rank > 0)
            {
                if(z >= PSSKILL_AGI && z <= PSSKILL_WILL)
                {
                    mesg.AddStat(rank, name);
                }
                else
                {
                    mesg.AddSkill(rank, name);
                }
            }
        }
        mesg.Construct();
        mesg.SendMessage();
    }

    delete actor;

    if(!upload.verify)
    {
        // Remove char data from the cache
        iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("char", chardata->GetPID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }
    }
}
Exemple #8
0
// This function is called from the network thread, no acces to server
// internal data should be made
void NetManager::CheckLinkDead()
{
    csTicks currenttime = csGetTicks();

    csArray<uint32_t> checkedClients;
    Client *pClient = NULL;

    // Delete all clients marked for deletion already
    clients.SweepDelete();

    while(true)
    {
        pClient = NULL;

        // Put the iterator in a limited scope so we don't hold on to the lock which may cause deadlock
        {
            ClientIterator i(clients);

            while(i.HasNext())
            {
                Client *candidate = i.Next();

                // Skip if already seen
                if(checkedClients.FindSortedKey(csArrayCmp<uint32_t, uint32_t> (candidate->GetClientNum())) != csArrayItemNotFound)
                    continue;

                checkedClients.InsertSorted(candidate->GetClientNum());
                pClient = candidate;
                break;
            }
        }

        // No more clients to check so break
        if(!pClient)
            break;

        // Shortcut here so zombies may immediately disconnect
        if(pClient->IsZombie() && pClient->ZombieAllowDisconnect())
        {
            /* This simulates receipt of this message from the client
             ** without any network access, so that disconnection logic
             ** is all in one place.
             */
            psDisconnectMessage discon(pClient->GetClientNum(), 0, "You should not see this.");
            if (discon.valid)
            {
                Connection* connection = pClient->GetConnection();
                HandleCompletedMessage(discon.msg, connection, NULL,NULL);
            }
            else
            {
                Bug2("Failed to create valid psDisconnectMessage for client id %u.\n", pClient->GetClientNum());
            }
        }
        else if (pClient->GetConnection()->lastRecvPacketTime+timeout < currenttime)
        {
            if (pClient->GetConnection()->heartbeat < 10 && pClient->GetConnection()->lastRecvPacketTime+timeout * 10 > currenttime)
            {
                psHeartBeatMsg ping(pClient->GetClientNum());
                Broadcast(ping.msg, NetBase::BC_FINALPACKET);
                pClient->GetConnection()->heartbeat++;
            }
            else
            {
                if(!pClient->AllowDisconnect())
                    continue;

                char ipaddr[20];
                pClient->GetIPAddress(ipaddr);

                csString status;
                status.Format("%s, %u, Client (%s) went linkdead.", ipaddr, pClient->GetClientNum(), pClient->GetName());
                psserver->GetLogCSV()->Write(CSV_AUTHENT, status);

                /* This simulates receipt of this message from the client
                 ** without any network access, so that disconnection logic
                 ** is all in one place.
                 */
                psDisconnectMessage discon(pClient->GetClientNum(), 0, "You are linkdead.");
                if (discon.valid)
                {
                    Connection* connection = pClient->GetConnection();
                    HandleCompletedMessage(discon.msg, connection, NULL,NULL);
                }
                else
                {
                    Bug2("Failed to create valid psDisconnectMessage for client id %u.\n", pClient->GetClientNum());
                }
            }
        }
    }
}