bool psCharAppearance::Detach(const char* socketName, bool removeItem ) { if (!socketName || !state.IsValid()) { return false; } CS_ASSERT(state.IsValid()); csRef<iSpriteCal3DSocket> socket = state->FindSocket( socketName ); if ( !socket ) { Notify2(LOG_CHARACTER, "Socket %s not found.", socketName ); return false; } csRef<iMeshWrapper> meshWrap = socket->GetMeshWrapper(); if ( !meshWrap ) { Notify2(LOG_CHARACTER, "No mesh in socket: %s.", socketName ); } else { meshWrap->QuerySceneNode()->SetParent (0); socket->SetMeshWrapper( NULL ); if(removeItem) engine->RemoveObject( meshWrap ); } usedSlots.Delete(socketName); return true; }
bool psCharAppearance::Attach(const char* socketName, const char* meshFactName, const char* materialName) { if (!socketName || !meshFactName || !state.IsValid()) { return false; } CS_ASSERT(state.IsValid()); csRef<iSpriteCal3DSocket> socket = state->FindSocket( socketName ); if ( !socket ) { Notify2(LOG_CHARACTER, "Socket %s not found.", socketName); return false; } bool failed = false; csRef<iMeshFactoryWrapper> factory = psengine->GetLoader()->LoadFactory(meshFactName, &failed); if(failed) { Notify2(LOG_CHARACTER, "Mesh factory %s not found.", meshFactName ); return false; } csRef<iMaterialWrapper> material; if(materialName != NULL) { psengine->GetLoader()->LoadMaterial(materialName, &failed); if(failed) { Notify2(LOG_CHARACTER, "Material %s not found.", materialName); return false; } } if(!factory.IsValid() || (materialName != NULL && !material.IsValid())) { Attachment attach(true); attach.factName = meshFactName; attach.materialName = materialName; attach.socket = socket; if(delayedAttach.IsEmpty()) { psengine->RegisterDelayedLoader(this); } delayedAttach.PushBack(attach); } else { ProcessAttach(factory, material, meshFactName, socket); } return true; }
void SpawnManager::RemoveNPC(gemObject *obj) { Debug2(LOG_SPAWN,0,"RemoveNPC:%s\n",obj->GetName() ); ServerStatus::mob_deathcount++; PID pid = obj->GetPID(); Notify3(LOG_SPAWN, "Sending NPC %s disconnect msg to %zu clients.\n", ShowID(obj->GetEID()), obj->GetMulticastClients().GetSize()); if (obj->GetCharacterData()==NULL) { Error2("Character data for npc character %s was not found! Entity stays dead.\n", ShowID(pid)); return; } SpawnRule *respawn = NULL; int spawnruleid = obj->GetCharacterData()->NPC_GetSpawnRuleID(); if (spawnruleid) { // Queue for respawn according to rules respawn = rules.Get(spawnruleid, NULL); } if (!respawn) { if (spawnruleid == 0) // spawnruleid 0 is for non-respawning NPCs { Notify2(LOG_SPAWN,"Temporary NPC based on player ID %s has died. Entity stays dead.\n", ShowID(pid)); } else { Error3("Respawn rule for player %s, rule %d was not found! Entity stays dead.\n", ShowID(pid), spawnruleid); } // Remove mesh, etc from engine entityManager->RemoveActor(obj); return; } // Remove mesh, etc from engine entityManager->RemoveActor(obj); int delay = respawn->GetRespawnDelay(); PID newplayer = respawn->CheckSubstitution(pid); psRespawnGameEvent *newevent = new psRespawnGameEvent(this, delay, newplayer, respawn); psserver->GetEventManager()->Push(newevent); Notify3(LOG_SPAWN, "Scheduled NPC %s to be respawned in %.1f seconds", ShowID(newplayer), (float)delay/1000.0); }
NetBase::~NetBase() { if (ready) Close(); Notify2(LOG_ANY,"Total bytes sent out was %li.\n",totaltransferout); Notify2(LOG_ANY,"Total bytes received was %li.\n", totaltransferin); socklibrefcount--; if (socklibrefcount==0) { exitSocket(); } if (randomgen) delete randomgen; delete profs; if (input_buffer) cs_free(input_buffer); }
bool AuthenticationServer::CheckAuthenticationPreCondition(int clientnum, bool netversionok, const char * sUser) { /** * CHECK 1: Is Network protokol compatible? */ if (!netversionok) { psserver->RemovePlayer (clientnum, "You are not running the correct version of PlaneShift. Please launch the updater."); return false; } /** * CHECK 2: Server has loaded a map */ // check if server is already ready (ie level loaded) if (!psserver->IsReady()) { if (psserver->HasBeenReady()) { // Locked psserver->RemovePlayer(clientnum,"The server is up but about to shutdown. Please try again in 2 minutes."); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: Server does not accept connections anymore.", sUser ); } else { // Not ready yet psserver->RemovePlayer(clientnum,"The server is up but not fully ready to go yet. Please try again in a few minutes."); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: Server has not loaded a world map.\n", sUser ); } return false; } return true; }
void WeatherManager::QueueNextEvent(int delayticks, int eventtype, int eventvalue, int duration, int fade, const char* sector, psSectorInfo* si, uint clientnum, int r,int g,int b) { psWeatherGameEvent* event; // There are no notify for 7 pars so we create a string first. csString note; note.Format("QueueNextEvent Delay: %d Type: %d Value: %d " "Duration: %d Fade: %d Sector: %s ...", delayticks,eventtype,eventvalue,duration, fade,sector); Notify2(LOG_WEATHER, "%s", note.GetDataSafe()); event = new psWeatherGameEvent(this, delayticks, eventtype, eventvalue, duration, fade, sector, si, clientnum, r,g,b); { CS::Threading::MutexScopedLock lock(eventsMutex); events.Push(event); } psserver->GetEventManager()->Push(event); }
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 WeatherManager::HandleWeatherEvent(psWeatherGameEvent* event) { { CS::Threading::MutexScopedLock lock(eventsMutex); events.Delete(event); // Delete this from our "db" } // See if we want to ignore this event for(size_t i = 0; i < ignored.GetSize(); i++) { if(event == ignored[i]) { ignored.DeleteIndex(i); return; } } switch(event->type) { case psWeatherMessage::SNOW: case psWeatherMessage::RAIN: { event->si->current_rain_drops = event->value; Notify4(LOG_WEATHER,"New %s in sector '%s': %d",event->type == psWeatherMessage::SNOW ? "snow" : "rain", event->si->name.GetData(),event->value); psWeatherMessage::NetWeatherInfo info; info.has_downfall = true; info.downfall_is_snow = (event->type == psWeatherMessage::SNOW); info.has_fog = true; info.has_lightning = false; info.downfall_drops = event->value; // Save current fog and calculate new. if(event->value) { // Only save the fog 'history' once. After that we just override. if(!event->si->densitySaved) { event->si->fog_density_old = event->si->fog_density; event->si->densitySaved = true; } // Set fog colour if there's not already fog. if(!event->si->fog_density) { event->si->r = 255; event->si->g = 255; event->si->b = 255; } if(info.downfall_drops < 8000) { // Calculate fog to be linear in range 0 to 200 event->si->fog_density = (int)(200.0f*(info.downfall_drops-1000.0f)/8000.0f); } else { event->si->fog_density = 200; } } else if(event->si->fog_density) { // Restore fog, if the fog wasn't turned off. event->si->fog_density = event->si->fog_density_old; event->si->densitySaved = false; } info.fog_density = event->si->fog_density; info.r = event->si->r; info.g = event->si->g; info.b = event->si->b; info.sector = event->sector; if(event->fade) { info.downfall_fade = event->fade; info.fog_fade = event->fade; } else { if(event->value) { info.downfall_fade = event->si->GetRandomWeatherFadeIn((unsigned int)event->type); info.fog_fade = info.downfall_fade; } else { info.downfall_fade = event->si->GetRandomWeatherFadeOut((unsigned int)event->type); info.fog_fade = info.downfall_fade; } } Notify4(LOG_WEATHER,"Drops: %d Density: %d Sector: %s\n", info.downfall_drops,info.fog_density,info.sector.GetDataSafe()); psWeatherMessage rain(0,info); if(rain.valid) psserver->GetEventManager()->Broadcast(rain.msg,NetBase::BC_EVERYONE); else { Bug1("Could not create valid psWeatherMessage (rain) for broadcast.\n"); } // Make sure we don't have any other events in this sector that will disturb // Simple case is when event types are equal. In addition we have to test // for the mutal exclusive case where we are changing from snow to rain or // rain to snow. { CS::Threading::MutexScopedLock lock(eventsMutex); for(size_t i = 0; i < events.GetSize(); i++) { psWeatherGameEvent* evt = events[i]; if(evt->sector == event->sector && (evt->type == event->type || ((evt->type == psWeatherMessage::RAIN || evt->type == psWeatherMessage::SNOW) && (event->type == psWeatherMessage::RAIN || event->type == psWeatherMessage::SNOW)))) { ignored.Push(evt); // Ignore when the eventmanager handles the event events.DeleteIndex(i); i--; Notify4(LOG_WEATHER,"Removed disturbing event for sector '%s' (%d,%d)", evt->sector.GetData(),evt->value,evt->duration); } } } if(event->value) // Queue event to turn off rain/snow. { if(event->type != psWeatherMessage::SNOW) event->si->is_raining = true; else event->si->is_snowing = true; if(event->si->GetWeatherEnabled((unsigned int) psWeatherMessage::LIGHTNING) && event->value > 2000 && event->si->is_raining) { // Queue lightning during rain storm here first QueueNextEvent(event->si->GetRandomWeatherGap((unsigned int) psWeatherMessage::LIGHTNING), psWeatherMessage::LIGHTNING, 0, 0, 0, event->si->name, event->si, event->clientnum); } // Queue event to stop rain/snow int duration; if(event->duration != -1) { if(event->duration) { duration = event->duration; } else { duration = event->si->GetRandomWeatherDuration((unsigned int) event->type); } QueueNextEvent(duration, event->type, 0, 0, event->fade, event->si->name, event->si); } } else // Stop rain/snow. { if(event->type== psWeatherMessage::SNOW) event->si->is_snowing = false; else event->si->is_raining = false; // Queue event to turn on again later if enabled StartWeather(event->si); } break; } case psWeatherMessage::FOG: { // Update sector weather info event->si->fog_density = event->value; event->si->r = event->cr; event->si->g = event->cg; event->si->b = event->cb; // Update the clients psWeatherMessage::NetWeatherInfo info; info.has_downfall = false; info.downfall_is_snow = false; info.has_fog = true; info.has_lightning = false; info.sector = event->si->name; info.fog_density = event->si->fog_density; info.r = event->cr; info.g = event->cg; info.b = event->cb; info.downfall_drops = 0; info.downfall_fade = 0; Notify3(LOG_WEATHER,"New Fog in sector '%s': %d", event->si->name.GetData(), event->value); // Save the fade in so we can reverse it when fading out. if(event->fade) { event->si->fogFade = event->fade; } else { // We're removing fog, so removed the 'saved' flag. event->si->densitySaved = false; } info.fog_fade = event->si->fogFade; psWeatherMessage fog(0,info); if(fog.valid) psserver->GetEventManager()->Broadcast(fog.msg,NetBase::BC_EVERYONE); else { Bug1("Could not create valid psWeatherMessage (fog) for broadcast.\n"); } if(event->value) // Queue event to turn off fog. { // Queue event to stop rain/snow int duration; if(event->duration != -1) { if(event->duration) { duration = event->duration; } else { duration = event->si->GetRandomWeatherDuration((unsigned int) event->type); } QueueNextEvent(duration, event->type, 0, 0, event->si->GetRandomWeatherFadeOut((unsigned int)psWeatherMessage::FOG), event->si->name, event->si); } } else // Stop fog. { // Queue event to turn on again later if enabled StartWeather(event->si, psWeatherMessage::FOG); } break; } case psWeatherMessage::LIGHTNING: { if(event->si->is_raining) { Notify2(LOG_WEATHER,"Lightning in sector '%s'",event->sector.GetData()); psWeatherMessage::NetWeatherInfo info; info.has_downfall = false; info.downfall_is_snow = false; info.has_fog = false; info.has_lightning = true; info.sector = event->sector; info.fog_fade = info.downfall_fade = 0; info.r = info.g = info.b = 0; info.downfall_drops = info.fog_density = 0; psWeatherMessage lightning(0,info, event->clientnum); if(lightning.valid) { psserver->GetEventManager()->Broadcast(lightning.msg); } else { Bug1("Could not create valid psWeatherMessage (lightning) for broadcast.\n"); } if(event->si->is_raining && event->si->GetWeatherEnabled((unsigned int) psWeatherMessage::LIGHTNING)) { QueueNextEvent(event->si->GetRandomWeatherGap((unsigned int) psWeatherMessage::LIGHTNING), psWeatherMessage::LIGHTNING, 0, 0, 0, event->si->name, event->si, event->clientnum); } } break; } case psWeatherMessage::DAYNIGHT: { QueueNextEvent(GAME_MINUTE_IN_TICKS, psWeatherMessage::DAYNIGHT, 0, 0, 0, NULL, NULL); gameTimeMinute++; if(gameTimeMinute >= 60) { gameTimeMinute = 0; gameTimeHour++; if(gameTimeHour >= 24) { gameTimeHour = 0; gameTimeDay++; if(gameTimeDay >= monthLengths[gameTimeMonth-1]+1) { gameTimeDay = 1; gameTimeMonth++; if(gameTimeMonth >= MONTH_COUNT+1) { gameTimeMonth = 1; gameTimeYear++; } } } // Only save and broadcast every game hour. SaveGameTime(); BroadcastGameTime(); } else { // Super clients should get the time every minute BroadcastGameTimeSuperclients(); } break; } default: { break; } } }