diff --git a/pswgcommon b/pswgcommon index 4fcb6279b..fb34e52e3 160000 --- a/pswgcommon +++ b/pswgcommon @@ -1 +1 @@ -Subproject commit 4fcb6279b46c9f90d50289e80e837dfeb0e466d3 +Subproject commit fb34e52e38da4380cb19b8cf82291ab08c3a2306 diff --git a/src/main/java/com/projectswg/holocore/services/gameplay/player/quest/QuestService.kt b/src/main/java/com/projectswg/holocore/services/gameplay/player/quest/QuestService.kt index 05285fa28..0fdb2de8b 100644 --- a/src/main/java/com/projectswg/holocore/services/gameplay/player/quest/QuestService.kt +++ b/src/main/java/com/projectswg/holocore/services/gameplay/player/quest/QuestService.kt @@ -36,6 +36,7 @@ import com.projectswg.common.network.packets.swg.zone.PlayMusicMessage import com.projectswg.common.network.packets.swg.zone.chat.ChatSystemMessage import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestCompletedMessage import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestTaskCounterMessage +import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestTaskTimerData import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent import com.projectswg.holocore.intents.gameplay.player.experience.ExperienceIntent import com.projectswg.holocore.intents.gameplay.player.quest.AbandonQuestIntent @@ -277,9 +278,24 @@ class QuestService(private val destroyMultiAndLootDie: Die = RandomDie()) : Serv val minTime = currentTask.minTime val maxTime = currentTask.maxTime val random = ThreadLocalRandom.current() - val delay = random.nextInt(minTime, maxTime) * 1000 - executor.execute(delay.toLong()) { - advanceQuest(questName, player, currentTask) + val delaySeconds = random.nextInt(minTime, maxTime + 1) + val delayMilliseconds = delaySeconds * 1000 + executor.execute(delayMilliseconds.toLong()) { // TODO if the server is restarted, the timer will be lost and the quest will be stuck + if (player.playerObject.isQuestInJournal(questName)) { + StandardLog.onPlayerTrace(this, player, "timer for task %d of quest %s expired", currentTask.index, questName) + advanceQuest(questName, player, currentTask) + } + } + + if (currentTask.isVisible) { + player.playerObject.updatePlayTime() // So the client can calculate the correct time remaining after we send QuestTaskTimerData + val task = currentTask.index + val timerPacket = QuestTaskTimerData(player.creatureObject.objectId) + timerPacket.questName = questName + timerPacket.taskId = task + timerPacket.counterText = "@quest/groundquests:timer_timertext" + timerPacket.duration = player.playerObject.playTime + delaySeconds + player.sendPacket(timerPacket) } } diff --git a/src/test/java/com/projectswg/holocore/services/gameplay/player/quest/QuestTaskTypeTest.kt b/src/test/java/com/projectswg/holocore/services/gameplay/player/quest/QuestTaskTypeTest.kt index e2ee62513..f16158967 100644 --- a/src/test/java/com/projectswg/holocore/services/gameplay/player/quest/QuestTaskTypeTest.kt +++ b/src/test/java/com/projectswg/holocore/services/gameplay/player/quest/QuestTaskTypeTest.kt @@ -31,6 +31,7 @@ import com.projectswg.common.network.packets.swg.login.creation.ClientCreateChar import com.projectswg.common.network.packets.swg.zone.CommPlayerMessage import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestCompletedMessage import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestTaskCounterMessage +import com.projectswg.common.network.packets.swg.zone.object_controller.quest.QuestTaskTimerData import com.projectswg.common.network.packets.swg.zone.server_ui.SuiCreatePageMessage import com.projectswg.holocore.intents.gameplay.combat.RequestCreatureDeathIntent import com.projectswg.holocore.intents.gameplay.player.quest.GrantQuestIntent @@ -194,6 +195,17 @@ class QuestTaskTypeTest : TestRunnerSynchronousIntents() { assertNotNull(questCompletedMessage, "Quest not completed in time") } + @Test + @DisplayName("quest.task.ground.timer") + fun timer() { + val player = createPlayer() + + GrantQuestIntent.broadcast(player, "quest/test_timer") + val questTaskTimerData = player.waitForNextPacket(QuestTaskTimerData::class.java) + + assertNotNull(questTaskTimerData, "Quest task time should have been sent") + } + private class CharacterSnapshot(private val player: GenericPlayer) { // Helper class to snapshot a character's state val xp = player.playerObject.getExperiencePoints("dance") val rebelFactionPoints = player.playerObject.getFactionPoints()["rebel"] ?: 0