// The spawnDelay mechansim is complex and interacts with other weird things like levelUp messages and server suspension TEST(SpawnDelayTest, SpawnDelayTests) { GamePair gamePair; // An empty level should work fine here ClientGame *clientGame = gamePair.getClient(0); ServerGame *serverGame = gamePair.server; ASSERT_TRUE(serverGame->getGameType()) << "Expect a GameType by now!"; // Idle for a while, let things settle gamePair.idle(10, 5); ASSERT_TRUE(clientGame->getGameType()) << "Expect a GameType by now!"; Vector<DatabaseObject *> fillVector; // Ship should have spawned by now... check for it on the client and server fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Ship should have spawned by now Ship *ship = static_cast<Ship *>(fillVector[0]); // Server's copy of the ship fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // And it should be on the client, too ASSERT_FALSE(clientGame->isSpawnDelayed()); // Should not be spawn-delayed at this point killShip(ship); gamePair.idle(10, 5); // 5 cycles // Ship should have spawned by now... check for it on the client and server fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Ship should have respawned and be available on the server... fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // ...and also on the client // Scenario 1: Player is idle and gets spawn delayed -- no other players in game // TODO: Also need a scenario where palyer goes idle and gets spawn delayed, but game does not get suspended due to other players doScenario1(gamePair); // Scenario 2: Player enters idle command, other players, so server does not suspend itself. Since // player used idle command, a 5 second penalty will be levied against them. doScenario2(gamePair); // Scenarios 3 & 4 -- Player enters /idle command, no other players, so server suspends itself partially (3) or fully (4) // See https://code.google.com/p/googletest/wiki/AdvancedGuide#Using_Assertions_in_Sub-routines for details on this technique { SCOPED_TRACE("Scenario 3, letGameSlipIntoFullSuspendMode is false"); doScenario34(gamePair, false); } { SCOPED_TRACE("Scenario 4, letGameSlipIntoFullSuspendMode is true"); doScenario34(gamePair, true); } // Scenario 5 -- Player enters idle when in punishment delay period for pervious /idle command doScenario5(gamePair); // Not complete // Scenario 6 -- Player is shown a new levelup screen doScenario6(gamePair); // Not complete // Scenario 7 -- Player is shown a levelup screen they have already seen doScenario7(gamePair); // Not complete // Scenario 8 -- Player is shown (new) levelup screen while they are idle due to inaction // Scenario 9 -- Player is shown (new) levelup screen while they are idle due to idle command // Scenario 10 -- Player is shown (new) levelup screen while they are in penalty phase of idle command // Scenario 11 -- Player is changing their loadout when the level changes. This triggers a delayed spawn. doScenario11(gamePair); }
TEST(GameUserInterfaceTest, Engineer) { InputCodeManager::initializeKeyNames(); GamePair gamePair(getLevelCodeForTestingEngineer1(), 3); // See def for description of level ServerGame *serverGame = GameManager::getServerGame(); const Vector<ClientGame *> *clientGames = GameManager::getClientGames(); GameSettings *clientSettings = clientGames->first()->getSettings(); GameUserInterface *gameUI = clientGames->first()->getUIManager()->getUI<GameUserInterface>(); DEFINE_KEYS_AND_EVENTS(clientSettings); // Idle for a while, let things settle GamePair::idle(10, 5); // Verify that engineer is enabled ASSERT_TRUE(serverGame->getGameType()->isEngineerEnabled()) << "Engineer should be enabled on server!"; for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_TRUE(clientGames->get(i)->getGameType()) << "Clients should have a GameType by now!"; ASSERT_TRUE(clientGames->get(i)->getGameType()->isEngineerEnabled()) << "Engineer mode not propagating to clients!"; } ASSERT_TRUE(serverGame->getClientInfo(0)->getShip()->isInZone(LoadoutZoneTypeNumber)); // Check level is as we expected // Add engineer to current loadout ASSERT_FALSE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gameUI->activateHelper(HelperMenu::LoadoutHelperType); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gameUI->onKeyDown(LOADOUT_KEY_ENGR); gameUI->onKeyDown(LOADOUT_KEY_REPAIR); // First 2 modules... gameUI->onKeyDown(LOADOUT_KEY_PHASER); gameUI->onKeyDown(LOADOUT_KEY_BOUNCE); gameUI->onKeyDown(LOADOUT_KEY_TRIPLE); // ...then 3 weapons // On this level, the ship spawn is inside a loadout zone, so loadout should take effect immediately GamePair::idle(10, 5); ASSERT_EQ("Engineer,Repair,Phaser,Bouncer,Triple", serverGame->getClientInfo(0)->getShip()->getLoadoutString()); for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_EQ("Engineer,Repair,Phaser,Bouncer,Triple", clientGames->get(0)->getLocalPlayerShip()->getLoadoutString()); } // Fly down to pick up resource item -- to get flying to work, need to create events at a very basic level ClientGame *clientGame = clientGames->get(0); Point startPos = clientGame->getLocalPlayerShip()->getActualPos(); Event::onEvent(clientGame, &EventDownPressed); GamePair::idle(100, 5); Event::onEvent(clientGame, &EventDownReleased); Point endPos = clientGame->getLocalPlayerShip()->getActualPos(); ASSERT_TRUE(startPos.distSquared(endPos) > 0) << "Ship did not move!!"; for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_TRUE(clientGames->get(0)->getLocalPlayerShip()->isCarryingItem(ResourceItemTypeNumber)); } // Time to engineer! gameUI->onKeyDown(KEY_MOD1); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::EngineerHelperType)) << "Expect engineer helper menu to be active!"; InputCode key = EngineerHelper::getInputCodeForOption(EngineeredTeleporterEntrance, true); gameUI->onKeyDown(key); ASSERT_FALSE(static_cast<const EngineerHelper *>(gameUI->getActiveHelper())->isMenuBeingDisplayed()); gameUI->onKeyDown(KEY_MOD1); // Place entrance gameUI->onKeyDown(KEY_MOD1); // Place exit GamePair::idle(100, 5); // Let things mellow for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); Vector<DatabaseObject *> fillVector; clientGames->get(i)->getLevel()->findObjects(TeleporterTypeNumber, fillVector); EXPECT_EQ(1, fillVector.size()) << "Expected a teleporter!"; } }
// Scenario 3, 4 -- Player enters /idle command, no other players, so server suspends itself // In this case, no returnToGame penalty should be levied // In this scenario 3, player un-idles during the suspend game timer countdown (there is a 2 second delay after all players are idle) // In scenario 4, player enters full suspend mode before unidling static void doScenario34(GamePair &gamePair, bool letGameSlipIntoFullSuspendMode) { ClientGame *clientGame = gamePair.getClient(0); ServerGame *serverGame = gamePair.server; // Make sure we start off in a "normal" state ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_FALSE(clientGame->isSpawnDelayed()); gamePair.idle(Ship::KillDeleteDelay / 15, 20); // Idle; give things time to propagate fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Now that player 2 has left, should only be one ship fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); Vector<string> words; ChatCommands::idleHandler(clientGame, words); gamePair.idle(10, 10); // Idle; give things time to propagate, timers to time out, etc. ASSERT_TRUE(serverGame->getClientInfo(0)->isSpawnDelayed()); ASSERT_TRUE(serverGame->isOrIsAboutToBeSuspended()); EXPECT_FALSE(serverGame->isSuspended()); ASSERT_TRUE(clientGame->isSpawnDelayed()); // Status should have propagated to client by now EXPECT_FALSE(clientGame->isSuspended()); fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(0, fillVector.size()); // No ships remaining in game -- don't check client as it may have exploding ship there fillVector.clear(); // ReturnToGame penalty has been set, but won't start to count down until ship attempts to spawn ASSERT_FALSE(clientGame->inReturnToGameCountdown()); ASSERT_TRUE(static_cast<FullClientInfo *>(serverGame->getClientInfo(0))->hasReturnToGamePenalty()); // Penalty has been primed ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); if(letGameSlipIntoFullSuspendMode) gamePair.idle(ServerGame::PreSuspendSettlingPeriod / 20, 25); // Player presses a key to rejoin the game; since game was suspended, player can resume without penalty ASSERT_TRUE(serverGame->isOrIsAboutToBeSuspended()) << "Game should be suspended"; if(letGameSlipIntoFullSuspendMode) { // In here, game is suspended EXPECT_TRUE(serverGame->isSuspended()); EXPECT_TRUE(clientGame->isSuspended()); // Check if server clocks are still counting down... should be stopped S32 snow = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 cnow = clientGame->getGameType()->getRemainingGameTimeInMs(); gamePair.idle(10, 10); S32 slater = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 clater = clientGame->getGameType()->getRemainingGameTimeInMs(); EXPECT_EQ(snow, slater) << "Looks like server clock is still running (should be stopped)!"; EXPECT_EQ(cnow, clater) << "Looks like client clock is still running (should be stopped)!"; } else { // In here, game is not (yet) suspended, but is in the 2 second cooldown period that comes after // all players have left or are idle, but before full suspension EXPECT_FALSE(serverGame->isSuspended()); EXPECT_FALSE(clientGame->isSuspended()); // Check if clocks are still counting down... should be still running S32 snow = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 cnow = clientGame->getGameType()->getRemainingGameTimeInMs(); gamePair.idle(10, 10); S32 slater = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 clater = clientGame->getGameType()->getRemainingGameTimeInMs(); EXPECT_NE(snow, slater) << "Looks like server clock is stopped (should be running)!"; EXPECT_NE(cnow, clater) << "Looks like client clock is stopped (should be running)!"; } clientGame->undelaySpawn(); // Simulate effects of key press gamePair.idle(10, 5); // Idle; give things time to propagate ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); // No returnToGame penalty ASSERT_FALSE(clientGame->inReturnToGameCountdown()); gamePair.idle(Ship::KillDeleteDelay / 15, 20); // Idle; give dead ships time to be cleaned up // Check to ensure ship spawned fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_FALSE(clientGame->isSpawnDelayed()); }