Support for changing the game's timescale
Context-specific (like per-world) timescales can also be added later
This commit is contained in:
parent
607be74945
commit
4b0bc220e4
@ -172,6 +172,8 @@ Mixer::Mixer(unsigned sampleRate, unsigned channels) {
|
||||
m_groupVolumes[MixerGroup::Effects] = {1.0f, 1.0f, 0};
|
||||
m_groupVolumes[MixerGroup::Music] = {1.0f, 1.0f, 0};
|
||||
m_groupVolumes[MixerGroup::Cinematic] = {1.0f, 1.0f, 0};
|
||||
|
||||
m_speed = 1.0f;
|
||||
}
|
||||
|
||||
unsigned Mixer::sampleRate() const {
|
||||
@ -203,6 +205,10 @@ bool Mixer::hasEffect(String const& effectName) {
|
||||
return m_effects.contains(effectName);
|
||||
}
|
||||
|
||||
void Mixer::setSpeed(float speed) {
|
||||
m_speed = speed;
|
||||
}
|
||||
|
||||
void Mixer::setVolume(float volume, float rampTime) {
|
||||
MutexLocker locker(m_mutex);
|
||||
m_volume.target = volume;
|
||||
@ -259,6 +265,8 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount, ExtraMixFunction extraMi
|
||||
for (size_t i = 0; i < bufferSize; ++i)
|
||||
outBuffer[i] = 0;
|
||||
|
||||
float speed = m_speed;
|
||||
|
||||
{
|
||||
MutexLocker locker(m_queueMutex);
|
||||
// Mix all active sounds
|
||||
@ -288,6 +296,9 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount, ExtraMixFunction extraMi
|
||||
? approach(audioInstance->m_pitchMultiplierTarget, audioInstance->m_pitchMultiplier, audioInstance->m_pitchMultiplierVelocity * time)
|
||||
: audioInstance->m_pitchMultiplier;
|
||||
|
||||
if (audioInstance->m_mixerGroup == MixerGroup::Effects)
|
||||
pitchMultiplier *= speed;
|
||||
|
||||
if (audioStopVolEnd == 0.0f && audioInstance->m_stopping)
|
||||
finished = true;
|
||||
|
||||
@ -461,7 +472,7 @@ void Mixer::setGroupVolume(MixerGroup group, float targetValue, float rampTime)
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::update(PositionalAttenuationFunction positionalAttenuationFunction) {
|
||||
void Mixer::update(float dt, PositionalAttenuationFunction positionalAttenuationFunction) {
|
||||
{
|
||||
MutexLocker locker(m_queueMutex);
|
||||
eraseWhere(m_audios, [&](auto& p) {
|
||||
|
@ -115,6 +115,9 @@ public:
|
||||
StringList currentEffects();
|
||||
bool hasEffect(String const& effectName);
|
||||
|
||||
// Global speed
|
||||
void setSpeed(float speed);
|
||||
|
||||
// Global volume
|
||||
void setVolume(float volume, float rampTime);
|
||||
|
||||
@ -131,7 +134,7 @@ public:
|
||||
|
||||
// Call within the main loop of the program using Mixer, calculates
|
||||
// positional attenuation of audio and does cleanup.
|
||||
void update(PositionalAttenuationFunction positionalAttenuationFunction = {});
|
||||
void update(float dt, PositionalAttenuationFunction positionalAttenuationFunction = {});
|
||||
|
||||
private:
|
||||
struct EffectInfo {
|
||||
@ -161,6 +164,7 @@ private:
|
||||
List<int16_t> m_mixBuffer;
|
||||
|
||||
Map<MixerGroup, RampedValue> m_groupVolumes;
|
||||
atomic<float> m_speed;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -346,6 +346,7 @@ void ClientApplication::processInput(InputEvent const& event) {
|
||||
}
|
||||
|
||||
void ClientApplication::update() {
|
||||
float dt = WorldTimestep * GlobalTimescale;
|
||||
if (m_state >= MainAppState::Title) {
|
||||
if (auto p2pNetworkingService = appController()->p2pNetworkingService()) {
|
||||
if (auto join = p2pNetworkingService->pullPendingJoin()) {
|
||||
@ -361,21 +362,21 @@ void ClientApplication::update() {
|
||||
}
|
||||
|
||||
if (!m_errorScreen->accepted())
|
||||
m_errorScreen->update();
|
||||
m_errorScreen->update(dt);
|
||||
|
||||
if (m_state == MainAppState::Mods)
|
||||
updateMods();
|
||||
updateMods(dt);
|
||||
else if (m_state == MainAppState::ModsWarning)
|
||||
updateModsWarning();
|
||||
updateModsWarning(dt);
|
||||
|
||||
if (m_state == MainAppState::Splash)
|
||||
updateSplash();
|
||||
updateSplash(dt);
|
||||
else if (m_state == MainAppState::Error)
|
||||
updateError();
|
||||
updateError(dt);
|
||||
else if (m_state == MainAppState::Title)
|
||||
updateTitle();
|
||||
updateTitle(dt);
|
||||
else if (m_state > MainAppState::Title)
|
||||
updateRunning();
|
||||
updateRunning(dt);
|
||||
|
||||
// Swallow leftover encoded voice data if we aren't in-game to allow mic read to continue for settings.
|
||||
if (m_state <= MainAppState::Title) {
|
||||
@ -647,8 +648,8 @@ void ClientApplication::setError(String const& error, std::exception const& e) {
|
||||
changeState(MainAppState::Title);
|
||||
}
|
||||
|
||||
void ClientApplication::updateMods() {
|
||||
m_cinematicOverlay->update();
|
||||
void ClientApplication::updateMods(float dt) {
|
||||
m_cinematicOverlay->update(dt);
|
||||
auto ugcService = appController()->userGeneratedContentService();
|
||||
if (ugcService) {
|
||||
if (ugcService->triggerContentDownload()) {
|
||||
@ -686,27 +687,28 @@ void ClientApplication::updateMods() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientApplication::updateModsWarning() {
|
||||
void ClientApplication::updateModsWarning(float dt) {
|
||||
if (m_errorScreen->accepted())
|
||||
changeState(MainAppState::Splash);
|
||||
}
|
||||
|
||||
void ClientApplication::updateSplash() {
|
||||
m_cinematicOverlay->update();
|
||||
void ClientApplication::updateSplash(float dt) {
|
||||
m_cinematicOverlay->update(dt);
|
||||
if (!m_rootLoader.isRunning() && (m_cinematicOverlay->completable() || m_cinematicOverlay->completed()))
|
||||
changeState(MainAppState::Title);
|
||||
}
|
||||
|
||||
void ClientApplication::updateError() {
|
||||
void ClientApplication::updateError(float dt) {
|
||||
if (m_errorScreen->accepted())
|
||||
changeState(MainAppState::Title);
|
||||
}
|
||||
|
||||
void ClientApplication::updateTitle() {
|
||||
m_cinematicOverlay->update();
|
||||
void ClientApplication::updateTitle(float dt) {
|
||||
m_cinematicOverlay->update(dt);
|
||||
|
||||
m_titleScreen->update();
|
||||
m_mainMixer->update();
|
||||
m_titleScreen->update(dt);
|
||||
m_mainMixer->update(dt);
|
||||
m_mainMixer->setSpeed(GlobalTimescale);
|
||||
|
||||
appController()->setAcceptingTextInput(m_titleScreen->textInputActive());
|
||||
|
||||
@ -752,7 +754,7 @@ void ClientApplication::updateTitle() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientApplication::updateRunning() {
|
||||
void ClientApplication::updateRunning(float dt) {
|
||||
try {
|
||||
auto p2pNetworkingService = appController()->p2pNetworkingService();
|
||||
bool clientIPJoinable = m_root->configuration()->get("clientIPJoinable").toBool();
|
||||
@ -869,12 +871,13 @@ void ClientApplication::updateRunning() {
|
||||
voiceData.setByteOrder(ByteOrder::LittleEndian);
|
||||
//voiceData.writeBytes(VoiceBroadcastPrefix.utf8Bytes()); transmitting with SE compat for now
|
||||
bool needstoSendVoice = m_voice->send(voiceData, 5000);
|
||||
m_universeClient->update();
|
||||
m_universeClient->update(dt);
|
||||
|
||||
if (checkDisconnection())
|
||||
return;
|
||||
|
||||
if (auto worldClient = m_universeClient->worldClient()) {
|
||||
m_worldPainter->update(dt);
|
||||
auto& broadcastCallback = worldClient->broadcastCallback();
|
||||
if (!broadcastCallback) {
|
||||
broadcastCallback = [&](PlayerPtr player, StringView broadcast) -> bool {
|
||||
@ -909,12 +912,12 @@ void ClientApplication::updateRunning() {
|
||||
}
|
||||
worldClient->setInteractiveHighlightMode(isActionTaken(InterfaceAction::ShowLabels));
|
||||
}
|
||||
updateCamera(dt);
|
||||
|
||||
updateCamera();
|
||||
|
||||
m_cinematicOverlay->update();
|
||||
m_mainInterface->update();
|
||||
m_mainMixer->update(m_cinematicOverlay->muteSfx(), m_cinematicOverlay->muteMusic());
|
||||
m_cinematicOverlay->update(dt);
|
||||
m_mainInterface->update(dt);
|
||||
m_mainMixer->update(dt, m_cinematicOverlay->muteSfx(), m_cinematicOverlay->muteMusic());
|
||||
m_mainMixer->setSpeed(GlobalTimescale);
|
||||
|
||||
bool inputActive = m_mainInterface->textInputActive();
|
||||
appController()->setAcceptingTextInput(inputActive);
|
||||
@ -970,12 +973,12 @@ bool ClientApplication::isActionTakenEdge(InterfaceAction action) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientApplication::updateCamera() {
|
||||
void ClientApplication::updateCamera(float dt) {
|
||||
if (!m_universeClient->worldClient())
|
||||
return;
|
||||
|
||||
WorldCamera& camera = m_worldPainter->camera();
|
||||
camera.update(WorldTimestep);
|
||||
camera.update(dt);
|
||||
|
||||
if (m_mainInterface->fixedCamera())
|
||||
return;
|
||||
|
@ -58,17 +58,17 @@ private:
|
||||
void setError(String const& error);
|
||||
void setError(String const& error, std::exception const& e);
|
||||
|
||||
void updateMods();
|
||||
void updateModsWarning();
|
||||
void updateSplash();
|
||||
void updateError();
|
||||
void updateTitle();
|
||||
void updateRunning();
|
||||
void updateMods(float dt);
|
||||
void updateModsWarning(float dt);
|
||||
void updateSplash(float dt);
|
||||
void updateError(float dt);
|
||||
void updateTitle(float dt);
|
||||
void updateRunning(float dt);
|
||||
|
||||
bool isActionTaken(InterfaceAction action) const;
|
||||
bool isActionTakenEdge(InterfaceAction action) const;
|
||||
|
||||
void updateCamera();
|
||||
void updateCamera(float dt);
|
||||
|
||||
RootUPtr m_root;
|
||||
ThreadFunction<void> m_rootLoader;
|
||||
|
@ -173,7 +173,7 @@ bool ActionBar::sendEvent(InputEvent const& event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActionBar::update() {
|
||||
void ActionBar::update(float dt) {
|
||||
auto inventory = m_player->inventory();
|
||||
auto abl = inventory->selectedActionBarLocation();
|
||||
if (abl.is<CustomBarIndex>()) {
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
PanePtr createTooltip(Vec2I const& screenPosition) override;
|
||||
bool sendEvent(InputEvent const& event) override;
|
||||
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
Maybe<String> cursorOverride(Vec2I const& screenPosition) override;
|
||||
|
||||
|
@ -98,21 +98,21 @@ AiInterface::AiInterface(UniverseClientPtr client, CinematicPtr cinematic, MainI
|
||||
m_defaultRecruitDescription = assets->json("/interface/ai/ai.config:defaultRecruitDescription").toString();
|
||||
}
|
||||
|
||||
void AiInterface::update() {
|
||||
void AiInterface::update(float dt) {
|
||||
if (!m_client->playerOnOwnShip())
|
||||
dismiss();
|
||||
|
||||
Pane::update();
|
||||
Pane::update(dt);
|
||||
|
||||
m_showCrewButton->setVisibility(m_currentPage == AiPages::StatusPage);
|
||||
m_showMissionsButton->setVisibility(m_currentPage == AiPages::StatusPage);
|
||||
m_backButton->setVisibility(m_currentPage != AiPages::StatusPage);
|
||||
|
||||
m_staticAnimation.update(WorldTimestep);
|
||||
m_scanlineAnimation.update(WorldTimestep);
|
||||
m_staticAnimation.update(dt);
|
||||
m_scanlineAnimation.update(dt);
|
||||
|
||||
if (m_currentSpeech) {
|
||||
m_textLength += m_currentSpeech->speedModifier * m_aiDatabase->charactersPerSecond() * WorldTimestep;
|
||||
m_textLength += m_currentSpeech->speedModifier * m_aiDatabase->charactersPerSecond() * dt;
|
||||
m_currentTextWidget->setText(m_currentSpeech->text);
|
||||
m_currentTextWidget->setTextCharLimit(min(m_textMaxLength, floor(m_textLength)));
|
||||
|
||||
@ -129,10 +129,10 @@ void AiInterface::update() {
|
||||
if (m_chatterSound)
|
||||
m_chatterSound->stop();
|
||||
}
|
||||
m_faceAnimation.second.update(WorldTimestep * m_currentSpeech->speedModifier);
|
||||
m_faceAnimation.second.update(dt * m_currentSpeech->speedModifier);
|
||||
} else {
|
||||
setFaceAnimation("idle");
|
||||
m_faceAnimation.second.update(WorldTimestep);
|
||||
m_faceAnimation.second.update(dt);
|
||||
if (m_chatterSound)
|
||||
m_chatterSound->stop();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class AiInterface : public Pane {
|
||||
public:
|
||||
AiInterface(UniverseClientPtr client, CinematicPtr cinematic, MainInterfacePaneManager* paneManager);
|
||||
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
void displayed() override;
|
||||
void dismissed() override;
|
||||
|
@ -71,8 +71,8 @@ void BaseScriptPane::dismissed() {
|
||||
m_script.uninit();
|
||||
}
|
||||
|
||||
void BaseScriptPane::tick() {
|
||||
Pane::tick();
|
||||
void BaseScriptPane::tick(float dt) {
|
||||
Pane::tick(dt);
|
||||
|
||||
for (auto p : m_canvasClickCallbacks) {
|
||||
for (auto const& clickEvent : p.first->pullClickEvents())
|
||||
@ -83,7 +83,7 @@ void BaseScriptPane::tick() {
|
||||
m_script.invoke(p.second, (int)keyEvent.key, keyEvent.keyDown);
|
||||
}
|
||||
|
||||
m_script.update(m_script.updateDt());
|
||||
m_script.update(m_script.updateDt(dt));
|
||||
}
|
||||
|
||||
bool BaseScriptPane::sendEvent(InputEvent const& event) {
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
void displayed() override;
|
||||
void dismissed() override;
|
||||
|
||||
void tick() override;
|
||||
void tick(float dt) override;
|
||||
|
||||
bool sendEvent(InputEvent const& event) override;
|
||||
|
||||
|
@ -183,13 +183,13 @@ void CharCreationPane::randomize() {
|
||||
changed();
|
||||
}
|
||||
|
||||
void CharCreationPane::tick() {
|
||||
Pane::tick();
|
||||
void CharCreationPane::tick(float dt) {
|
||||
Pane::tick(dt);
|
||||
if (!active())
|
||||
return;
|
||||
if (!m_previewPlayer)
|
||||
return;
|
||||
m_previewPlayer->animatePortrait();
|
||||
m_previewPlayer->animatePortrait(dt);
|
||||
}
|
||||
|
||||
bool CharCreationPane::sendEvent(InputEvent const& event) {
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
void randomize();
|
||||
void randomizeName();
|
||||
|
||||
virtual void tick() override;
|
||||
virtual void tick(float dt) override;
|
||||
virtual bool sendEvent(InputEvent const& event) override;
|
||||
|
||||
virtual PanePtr createTooltip(Vec2I const&) override;
|
||||
|
@ -95,8 +95,8 @@ Chat::Chat(UniverseClientPtr client) : m_client(client) {
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void Chat::update() {
|
||||
Pane::update();
|
||||
void Chat::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
auto team = m_client->teamClient()->currentTeam();
|
||||
for (auto button : fetchChild<ButtonGroup>("filterGroup")->buttons()) {
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
virtual void renderImpl() override;
|
||||
virtual void hide() override;
|
||||
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
|
||||
void addLine(String const& text, bool showPane = true);
|
||||
void addMessages(List<ChatReceivedMessage> const& messages, bool showPane = true);
|
||||
|
@ -86,9 +86,9 @@ void ChatBubbleManager::setCamera(WorldCamera const& camera) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBubbleManager::update(WorldClientPtr world) {
|
||||
m_bubbles.forEach([this, &world](BubbleState<Bubble>& bubbleState, Bubble& bubble) {
|
||||
bubble.age += WorldTimestep;
|
||||
void ChatBubbleManager::update(float dt, WorldClientPtr world) {
|
||||
m_bubbles.forEach([this, dt, &world](BubbleState<Bubble>& bubbleState, Bubble& bubble) {
|
||||
bubble.age += dt;
|
||||
if (auto entity = world->get<ChattyEntity>(bubble.entity)) {
|
||||
bubble.onscreen = m_camera.worldGeometry().rectIntersectsRect(
|
||||
m_camera.worldScreenRect(), entity->metaBoundBox().translated(entity->position()));
|
||||
@ -97,7 +97,7 @@ void ChatBubbleManager::update(WorldClientPtr world) {
|
||||
});
|
||||
|
||||
for (auto& portraitBubble : m_portraitBubbles) {
|
||||
portraitBubble.age += WorldTimestep;
|
||||
portraitBubble.age += dt;
|
||||
if (auto entity = world->entity(portraitBubble.entity)) {
|
||||
portraitBubble.onscreen = m_camera.worldGeometry().rectIntersectsRect(m_camera.worldScreenRect(), entity->metaBoundBox().translated(entity->position()));
|
||||
if (auto chatter = as<ChattyEntity>(entity))
|
||||
@ -125,7 +125,7 @@ void ChatBubbleManager::update(WorldClientPtr world) {
|
||||
return false;
|
||||
});
|
||||
|
||||
m_bubbles.update();
|
||||
m_bubbles.update(dt);
|
||||
}
|
||||
|
||||
uint8_t ChatBubbleManager::calcDistanceFadeAlpha(Vec2F bubbleScreenPosition, StoredFunctionPtr fadeFunction) const {
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
|
||||
void addChatActions(List<ChatAction> chatActions, bool silent = false);
|
||||
|
||||
void update(WorldClientPtr world);
|
||||
void update(float dt, WorldClientPtr world);
|
||||
void render();
|
||||
|
||||
private:
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
List<Bubble> filtered(function<bool(Bubble const&, T const&)> func);
|
||||
void forEach(function<void(Bubble&, T&)> func);
|
||||
|
||||
void update();
|
||||
void update(float dt);
|
||||
void clear();
|
||||
bool empty() const;
|
||||
|
||||
@ -170,7 +170,7 @@ void BubbleSeparator<T>::forEach(function<void(Bubble&, T&)> func) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BubbleSeparator<T>::update() {
|
||||
void BubbleSeparator<T>::update(float dt) {
|
||||
m_bubbles.exec([this](Bubble& bubble) {
|
||||
Vec2F delta = bubble.seperatedOffset - bubble.currentOffset;
|
||||
bubble.currentOffset += m_tweenFactor * delta;
|
||||
|
@ -103,7 +103,7 @@ void Cinematic::setPlayer(PlayerPtr player) {
|
||||
m_player = player;
|
||||
}
|
||||
|
||||
void Cinematic::update() {
|
||||
void Cinematic::update(float dt) {
|
||||
m_currentTimeSkip = {};
|
||||
for (auto timeSkip : m_timeSkips) {
|
||||
if (currentTimecode() >= timeSkip.availableTime && currentTimecode() < timeSkip.skipToTime)
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
|
||||
void setPlayer(PlayerPtr player);
|
||||
|
||||
void update();
|
||||
void update(float dt);
|
||||
void render();
|
||||
|
||||
bool completed() const;
|
||||
|
@ -50,7 +50,7 @@ void CodexInterface::show() {
|
||||
updateCodexList();
|
||||
}
|
||||
|
||||
void CodexInterface::tick() {
|
||||
void CodexInterface::tick(float dt) {
|
||||
updateCodexList();
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
CodexInterface(PlayerPtr player);
|
||||
|
||||
virtual void show() override;
|
||||
virtual void tick() override;
|
||||
virtual void tick(float dt) override;
|
||||
|
||||
void showTitles();
|
||||
void showSelectedContents();
|
||||
|
@ -258,11 +258,11 @@ void ContainerPane::burn() {
|
||||
m_containerInteractor->burnContainer();
|
||||
}
|
||||
|
||||
void ContainerPane::update() {
|
||||
Pane::update();
|
||||
void ContainerPane::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
if (m_script)
|
||||
m_script->update(m_script->updateDt());
|
||||
m_script->update(m_script->updateDt(dt));
|
||||
|
||||
m_itemBag->clearItems();
|
||||
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
bool giveContainerResult(ContainerResult result);
|
||||
|
||||
protected:
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
private:
|
||||
enum class ExpectingSwap {
|
||||
|
@ -226,7 +226,7 @@ size_t CraftingPane::itemCount(List<ItemPtr> const& store, ItemDescriptor const&
|
||||
return itemDb->getCountOfItem(store, item);
|
||||
}
|
||||
|
||||
void CraftingPane::update() {
|
||||
void CraftingPane::update(float dt) {
|
||||
// shut down if we can't reach the table anymore.
|
||||
if (m_sourceEntityId != NullEntityId) {
|
||||
auto sourceEntity = as<TileEntity>(m_worldClient->entity(m_sourceEntityId));
|
||||
@ -296,7 +296,7 @@ void CraftingPane::update() {
|
||||
|
||||
setLabel("lblPlayerMoney", toString((int)m_player->currency("money")));
|
||||
|
||||
Pane::update();
|
||||
Pane::update(dt);
|
||||
}
|
||||
|
||||
void CraftingPane::updateCraftButtons() {
|
||||
|
@ -34,7 +34,7 @@ private:
|
||||
|
||||
List<ItemRecipe> determineRecipes();
|
||||
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
void updateCraftButtons();
|
||||
void updateAvailableRecipes();
|
||||
bool consumeIngredients(ItemRecipe& recipe, int count);
|
||||
|
@ -70,12 +70,12 @@ bool ErrorScreen::handleInputEvent(InputEvent const& event) {
|
||||
return m_paneManager->sendInputEvent(event);
|
||||
}
|
||||
|
||||
void ErrorScreen::update() {
|
||||
m_paneManager->update();
|
||||
void ErrorScreen::update(float dt) {
|
||||
m_paneManager->update(dt);
|
||||
m_cursor.update(dt);
|
||||
}
|
||||
|
||||
void ErrorScreen::renderCursor() {
|
||||
m_cursor.update(WorldTimestep);
|
||||
Vec2I cursorPos = m_cursorScreenPos;
|
||||
Vec2I cursorSize = m_cursor.size();
|
||||
Vec2I cursorOffset = m_cursor.offset();
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
void render(bool useBackdrop = false);
|
||||
|
||||
bool handleInputEvent(InputEvent const& event);
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
void renderCursor();
|
||||
|
@ -236,7 +236,7 @@ bool InventoryPane::containsNewItems() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void InventoryPane::update() {
|
||||
void InventoryPane::update(float dt) {
|
||||
auto inventory = m_player->inventory();
|
||||
auto context = Widget::context();
|
||||
|
||||
@ -255,7 +255,7 @@ void InventoryPane::update() {
|
||||
m_trashSlot->setItem(inventory->itemsAt(TrashSlot()));
|
||||
m_trashSlot->showLinkIndicator(customBarItems.contains(m_trashSlot->item()));
|
||||
if (auto trashItem = m_trashSlot->item()) {
|
||||
if (m_trashBurn.tick() && trashItem->count() > 0) {
|
||||
if (m_trashBurn.tick(dt) && trashItem->count() > 0) {
|
||||
m_player->statistics()->recordEvent("trashItem", JsonObject{
|
||||
{"itemName", trashItem->name()},
|
||||
{"count", trashItem->count()},
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
bool containsNewItems() const;
|
||||
|
||||
protected:
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
void selectTab(String const& selected);
|
||||
|
||||
private:
|
||||
|
@ -520,8 +520,9 @@ void MainInterface::handleInteractAction(InteractAction interactAction) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainInterface::update() {
|
||||
m_paneManager.update();
|
||||
void MainInterface::update(float dt) {
|
||||
m_paneManager.update(dt);
|
||||
m_cursor.update(dt);
|
||||
|
||||
m_questLogInterface->pollDialog(&m_paneManager);
|
||||
|
||||
@ -544,7 +545,7 @@ void MainInterface::update() {
|
||||
|
||||
// update mouseover target
|
||||
EntityId newMouseOverTarget = NullEntityId;
|
||||
m_stickyTargetingTimer.tick();
|
||||
m_stickyTargetingTimer.tick(dt);
|
||||
auto mouseoverEntities = m_client->worldClient()->query<DamageBarEntity>(RectF::withCenter(cursorWorldPos, Vec2F(1, 1)), [=](shared_ptr<DamageBarEntity> const& entity) {
|
||||
return entity != player
|
||||
&& entity->damageBar() == DamageBarType::Default
|
||||
@ -578,10 +579,10 @@ void MainInterface::update() {
|
||||
if (damageBarEntity && damageBarEntity->damageBar() == DamageBarType::Special) {
|
||||
float targetHealth = damageBarEntity->health() / damageBarEntity->maxHealth();
|
||||
float fillSpeed = 1.0f / Root::singleton().assets()->json("/interface.config:specialDamageBar.fillTime").toFloat();
|
||||
if (abs(targetHealth - m_specialDamageBarValue) < fillSpeed * WorldTimestep)
|
||||
if (abs(targetHealth - m_specialDamageBarValue) < fillSpeed * dt)
|
||||
m_specialDamageBarValue = targetHealth;
|
||||
else
|
||||
m_specialDamageBarValue += copysign(1.0f, targetHealth - m_specialDamageBarValue) * fillSpeed * WorldTimestep;
|
||||
m_specialDamageBarValue += copysign(1.0f, targetHealth - m_specialDamageBarValue) * fillSpeed * dt;
|
||||
} else {
|
||||
m_specialDamageBarTarget = NullEntityId;
|
||||
}
|
||||
@ -696,7 +697,7 @@ void MainInterface::update() {
|
||||
|
||||
for (auto it = m_messages.begin(); it != m_messages.end();) {
|
||||
auto& message = *it;
|
||||
message->cooldown -= WorldTimestep;
|
||||
message->cooldown -= dt;
|
||||
if (message->cooldown < 0)
|
||||
it = m_messages.erase(it);
|
||||
else
|
||||
@ -713,7 +714,7 @@ void MainInterface::update() {
|
||||
|
||||
auto worldId = m_client->playerWorld();
|
||||
if (worldId.is<CelestialWorldId>()) {
|
||||
if (m_planetNameTimer.tick())
|
||||
if (m_planetNameTimer.tick(dt))
|
||||
m_paneManager.dismissRegisteredPane(MainInterfacePanes::PlanetText);
|
||||
else
|
||||
m_paneManager.displayRegisteredPane(MainInterfacePanes::PlanetText);
|
||||
@ -755,8 +756,8 @@ void MainInterface::update() {
|
||||
|
||||
updateCursor();
|
||||
|
||||
m_nameplatePainter->update(m_client->worldClient(), m_worldPainter->camera(), m_client->worldClient()->interactiveHighlightMode());
|
||||
m_questIndicatorPainter->update(m_client->worldClient(), m_worldPainter->camera());
|
||||
m_nameplatePainter->update(dt, m_client->worldClient(), m_worldPainter->camera(), m_client->worldClient()->interactiveHighlightMode());
|
||||
m_questIndicatorPainter->update(dt, m_client->worldClient(), m_worldPainter->camera());
|
||||
|
||||
m_chatBubbleManager->setCamera(m_worldPainter->camera());
|
||||
if (auto worldClient = m_client->worldClient()) {
|
||||
@ -781,7 +782,7 @@ void MainInterface::update() {
|
||||
}
|
||||
|
||||
m_chatBubbleManager->addChatActions(chatActions);
|
||||
m_chatBubbleManager->update(worldClient);
|
||||
m_chatBubbleManager->update(dt, worldClient);
|
||||
}
|
||||
|
||||
if (auto container = m_client->worldClient()->get<ContainerEntity>(m_containerInteractor->openContainerId())) {
|
||||
@ -803,7 +804,7 @@ void MainInterface::update() {
|
||||
pair.second->setSize(Vec2I(m_guiContext->windowSize()));
|
||||
else
|
||||
pair.second->setSize(Vec2I(m_guiContext->windowInterfaceSize()));
|
||||
pair.second->update();
|
||||
pair.second->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1427,8 +1428,6 @@ void MainInterface::renderCursor() {
|
||||
if (m_cinematicOverlay && !m_cinematicOverlay->completed())
|
||||
return m_guiContext->applicationController()->setCursorVisible(false);
|
||||
|
||||
m_cursor.update(WorldTimestep);
|
||||
|
||||
Vec2I cursorPos = m_cursorScreenPos;
|
||||
Vec2I cursorSize = m_cursor.size();
|
||||
Vec2I cursorOffset = m_cursor.offset();
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
void handleInteractAction(InteractAction interactAction);
|
||||
|
||||
// Handles incoming client messages, aims main player, etc.
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
// Render things e.g. quest indicators that should be drawn in the world
|
||||
// behind interface e.g. chat bubbles
|
||||
|
@ -23,7 +23,7 @@ void MainMixer::setWorldPainter(WorldPainterPtr worldPainter) {
|
||||
m_worldPainter = move(worldPainter);
|
||||
}
|
||||
|
||||
void MainMixer::update(bool muteSfx, bool muteMusic) {
|
||||
void MainMixer::update(float dt, bool muteSfx, bool muteMusic) {
|
||||
auto assets = Root::singleton().assets();
|
||||
|
||||
auto updateGroupVolume = [&](MixerGroup group, bool muted, String const& settingName) {
|
||||
@ -111,9 +111,9 @@ void MainMixer::update(bool muteSfx, bool muteMusic) {
|
||||
};
|
||||
|
||||
if (Voice* voice = Voice::singletonPtr())
|
||||
voice->update(attenuationFunction);
|
||||
voice->update(dt, attenuationFunction);
|
||||
|
||||
m_mixer->update(attenuationFunction);
|
||||
m_mixer->update(dt, attenuationFunction);
|
||||
|
||||
} else {
|
||||
if (m_mixer->hasEffect("lowpass"))
|
||||
@ -122,9 +122,9 @@ void MainMixer::update(bool muteSfx, bool muteMusic) {
|
||||
m_mixer->removeEffect("echo", 0);
|
||||
|
||||
if (Voice* voice = Voice::singletonPtr())
|
||||
voice->update();
|
||||
voice->update(dt);
|
||||
|
||||
m_mixer->update();
|
||||
m_mixer->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +132,10 @@ MixerPtr MainMixer::mixer() const {
|
||||
return m_mixer;
|
||||
}
|
||||
|
||||
void MainMixer::setSpeed(float speed) {
|
||||
m_mixer->setSpeed(max(speed, 0.0f));
|
||||
}
|
||||
|
||||
void MainMixer::setVolume(float volume, float rampTime) {
|
||||
m_mixer->setVolume(volume, rampTime);
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ public:
|
||||
void setUniverseClient(UniverseClientPtr universeClient);
|
||||
void setWorldPainter(WorldPainterPtr worldPainter);
|
||||
|
||||
void update(bool muteSfx = false, bool muteMusic = false);
|
||||
void update(float dt, bool muteSfx = false, bool muteMusic = false);
|
||||
|
||||
MixerPtr mixer() const;
|
||||
|
||||
void setSpeed(float speed);
|
||||
void setVolume(float volume, float rampTime = 0.0f);
|
||||
void read(int16_t* sampleData, size_t frameCount, Mixer::ExtraMixFunction = {});
|
||||
|
||||
|
@ -138,8 +138,8 @@ PanePtr MerchantPane::createTooltip(Vec2I const& screenPosition) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void MerchantPane::update() {
|
||||
Pane::update();
|
||||
void MerchantPane::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
if (!m_worldClient->playerCanReachEntity(m_sourceEntityId))
|
||||
dismiss();
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
ItemPtr addItems(ItemPtr const& items);
|
||||
|
||||
protected:
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
private:
|
||||
void swapSlot();
|
||||
|
@ -51,8 +51,8 @@ ModsMenu::ModsMenu() {
|
||||
copyLinkLabel->setVisibility(!hasDesktopService);
|
||||
}
|
||||
|
||||
void ModsMenu::update() {
|
||||
Pane::update();
|
||||
void ModsMenu::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
size_t selectedItem = m_modList->selectedItem();
|
||||
if (selectedItem == NPos) {
|
||||
|
@ -13,7 +13,7 @@ class ModsMenu : public Pane {
|
||||
public:
|
||||
ModsMenu();
|
||||
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
private:
|
||||
static String bestModName(JsonObject const& metadata, String const& sourcePath);
|
||||
|
@ -28,7 +28,7 @@ NameplatePainter::NameplatePainter() {
|
||||
m_nametags.setMovementThreshold(nametagConfig.getFloat("movementThreshold"));
|
||||
}
|
||||
|
||||
void NameplatePainter::update(WorldClientPtr const& world, WorldCamera const& camera, bool inspectionMode) {
|
||||
void NameplatePainter::update(float dt, WorldClientPtr const& world, WorldCamera const& camera, bool inspectionMode) {
|
||||
m_camera = camera;
|
||||
|
||||
Set<EntityId> foundEntities;
|
||||
@ -70,7 +70,7 @@ void NameplatePainter::update(WorldClientPtr const& world, WorldCamera const& ca
|
||||
});
|
||||
|
||||
m_entitiesWithNametags = move(foundEntities);
|
||||
m_nametags.update();
|
||||
m_nametags.update(dt);
|
||||
}
|
||||
|
||||
void NameplatePainter::render() {
|
||||
|
@ -15,7 +15,7 @@ class NameplatePainter {
|
||||
public:
|
||||
NameplatePainter();
|
||||
|
||||
void update(WorldClientPtr const& world, WorldCamera const& camera, bool inspectionMode);
|
||||
void update(float dt, WorldClientPtr const& world, WorldCamera const& camera, bool inspectionMode);
|
||||
void render();
|
||||
|
||||
private:
|
||||
|
@ -16,7 +16,7 @@ AnimationPtr indicatorAnimation(String indicatorPath) {
|
||||
return make_shared<Animation>(assets->json(indicatorPath), indicatorPath);
|
||||
}
|
||||
|
||||
void QuestIndicatorPainter::update(WorldClientPtr const& world, WorldCamera const& camera) {
|
||||
void QuestIndicatorPainter::update(float dt, WorldClientPtr const& world, WorldCamera const& camera) {
|
||||
m_camera = camera;
|
||||
|
||||
Set<EntityId> foundIndicators;
|
||||
@ -30,7 +30,7 @@ void QuestIndicatorPainter::update(WorldClientPtr const& world, WorldCamera cons
|
||||
if (auto currentIndicator = m_indicators.ptr(entity->entityId())) {
|
||||
currentIndicator->screenPos = screenPos;
|
||||
if (currentIndicator->indicatorName == indicator->indicatorImage) {
|
||||
currentIndicator->animation->update(WorldTimestep);
|
||||
currentIndicator->animation->update(dt);
|
||||
} else {
|
||||
currentIndicator->indicatorName = indicator->indicatorImage;
|
||||
currentIndicator->animation = indicatorAnimation(indicator->indicatorImage);
|
||||
|
@ -13,7 +13,7 @@ class QuestIndicatorPainter {
|
||||
public:
|
||||
QuestIndicatorPainter(UniverseClientPtr const& client);
|
||||
|
||||
void update(WorldClientPtr const& world, WorldCamera const& camera);
|
||||
void update(float dt, WorldClientPtr const& world, WorldCamera const& camera);
|
||||
void render();
|
||||
|
||||
private:
|
||||
|
@ -93,12 +93,12 @@ void QuestLogInterface::pollDialog(PaneManager* paneManager) {
|
||||
|
||||
void QuestLogInterface::displayed() {
|
||||
Pane::displayed();
|
||||
tick();
|
||||
tick(0);
|
||||
fetchData();
|
||||
}
|
||||
|
||||
void QuestLogInterface::tick() {
|
||||
Pane::tick();
|
||||
void QuestLogInterface::tick(float dt) {
|
||||
Pane::tick(dt);
|
||||
auto selected = getSelected();
|
||||
if (selected && m_manager->hasQuest(selected->data().toString())) {
|
||||
auto quest = m_manager->getQuest(selected->data().toString());
|
||||
@ -284,7 +284,7 @@ void QuestLogInterface::showQuests(List<QuestPtr> quests) {
|
||||
}
|
||||
|
||||
auto verticalLayout = fetchChild<VerticalLayout>("scrollArea.verticalLayout");
|
||||
verticalLayout->update();
|
||||
verticalLayout->update(0);
|
||||
}
|
||||
|
||||
QuestPane::QuestPane(QuestPtr const& quest, PlayerPtr player) : Pane(), m_quest(quest), m_player(move(player)) {}
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
virtual ~QuestLogInterface() {}
|
||||
|
||||
virtual void displayed() override;
|
||||
virtual void tick() override;
|
||||
virtual void tick(float dt) override;
|
||||
virtual PanePtr createTooltip(Vec2I const& screenPosition) override;
|
||||
|
||||
void fetchData();
|
||||
|
@ -71,7 +71,7 @@ bool QuestTrackerPane::sendEvent(InputEvent const& event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuestTrackerPane::update() {
|
||||
void QuestTrackerPane::update(float dt) {
|
||||
if (m_currentQuest) {
|
||||
if (auto objectiveList = m_currentQuest->objectiveList()) {
|
||||
if (objectiveList->size() == 0) {
|
||||
@ -172,7 +172,7 @@ void QuestTrackerPane::update() {
|
||||
}
|
||||
}
|
||||
|
||||
Pane::update();
|
||||
Pane::update(dt);
|
||||
}
|
||||
|
||||
void QuestTrackerPane::setQuest(QuestPtr const& quest) {
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
QuestTrackerPane();
|
||||
|
||||
bool sendEvent(InputEvent const& event) override;
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
|
||||
void setQuest(QuestPtr const& quest);
|
||||
|
||||
|
@ -44,9 +44,9 @@ RadioMessagePopup::RadioMessagePopup() {
|
||||
enterStage(PopupStage::Hidden);
|
||||
}
|
||||
|
||||
void RadioMessagePopup::update() {
|
||||
void RadioMessagePopup::update(float dt) {
|
||||
if (messageActive()) {
|
||||
if (m_stageTimer.tick())
|
||||
if (m_stageTimer.tick(dt))
|
||||
nextPopupStage();
|
||||
|
||||
if (m_popupStage == PopupStage::AnimateIn) {
|
||||
@ -65,11 +65,11 @@ void RadioMessagePopup::update() {
|
||||
setBG("", strf("{}:{}", m_animateOutImage, frame), "");
|
||||
}
|
||||
|
||||
m_slideTimer = min(m_slideTimer + WorldTimestep, m_slideTime);
|
||||
m_slideTimer = min(m_slideTimer + dt, m_slideTime);
|
||||
updateAnchorOffset();
|
||||
}
|
||||
|
||||
Pane::update();
|
||||
Pane::update(dt);
|
||||
}
|
||||
|
||||
void RadioMessagePopup::dismissed() {
|
||||
|
@ -16,7 +16,7 @@ class RadioMessagePopup : public Pane {
|
||||
public:
|
||||
RadioMessagePopup();
|
||||
|
||||
void update() override;
|
||||
void update(float dt) override;
|
||||
void dismissed() override;
|
||||
|
||||
bool messageActive();
|
||||
|
@ -47,11 +47,11 @@ void ScriptPane::dismissed() {
|
||||
m_script.removeCallbacks("world");
|
||||
}
|
||||
|
||||
void ScriptPane::tick() {
|
||||
void ScriptPane::tick(float dt) {
|
||||
if (m_sourceEntityId != NullEntityId && !m_client->worldClient()->playerCanReachEntity(m_sourceEntityId))
|
||||
dismiss();
|
||||
|
||||
BaseScriptPane::tick();
|
||||
BaseScriptPane::tick(dt);
|
||||
}
|
||||
|
||||
PanePtr ScriptPane::createTooltip(Vec2I const& screenPosition) {
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
void displayed() override;
|
||||
void dismissed() override;
|
||||
|
||||
void tick() override;
|
||||
void tick(float dt) override;
|
||||
|
||||
PanePtr createTooltip(Vec2I const& screenPosition) override;
|
||||
|
||||
|
@ -58,8 +58,8 @@ void StatusPane::renderImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
void StatusPane::update() {
|
||||
Pane::update();
|
||||
void StatusPane::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
auto assets = Root::singleton().assets();
|
||||
auto interfaceScale = m_guiContext->interfaceScale();
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void renderImpl() override;
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
|
||||
private:
|
||||
struct StatusEffectIndicator {
|
||||
|
@ -80,8 +80,8 @@ void TeamBar::acceptInvitation(Uuid const& inviterUuid) {
|
||||
m_client->teamClient()->acceptInvitation(inviterUuid);
|
||||
}
|
||||
|
||||
void TeamBar::update() {
|
||||
Pane::update();
|
||||
void TeamBar::update(float dt) {
|
||||
Pane::update(dt);
|
||||
|
||||
updatePlayerResources();
|
||||
|
||||
@ -338,7 +338,7 @@ void TeamMemberMenu::open(Uuid memberUuid, Vec2I position) {
|
||||
Pane::show();
|
||||
}
|
||||
|
||||
void TeamMemberMenu::update() {
|
||||
void TeamMemberMenu::update(float dt) {
|
||||
auto stillValid = false;
|
||||
auto members = m_owner->m_client->teamClient()->members();
|
||||
for (auto member : members) {
|
||||
@ -355,7 +355,7 @@ void TeamMemberMenu::update() {
|
||||
|
||||
updateWidgets();
|
||||
|
||||
Pane::update();
|
||||
Pane::update(dt);
|
||||
}
|
||||
|
||||
void TeamMemberMenu::updateWidgets() {
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
|
||||
void open(Uuid memberUuid, Vec2I position);
|
||||
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
|
||||
private:
|
||||
void updateWidgets();
|
||||
@ -77,7 +77,7 @@ public:
|
||||
void acceptInvitation(Uuid const& inviterUuid);
|
||||
|
||||
protected:
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
|
||||
private:
|
||||
void updatePlayerResources();
|
||||
|
@ -120,7 +120,7 @@ TeleportDialog::TeleportDialog(UniverseClientPtr client,
|
||||
fetchChild<ButtonWidget>("btnTeleport")->setEnabled(destList->selectedItem() != NPos);
|
||||
}
|
||||
|
||||
void TeleportDialog::tick() {
|
||||
void TeleportDialog::tick(float dt) {
|
||||
if (!m_client->worldClient()->playerCanReachEntity(m_sourceEntityId))
|
||||
dismiss();
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
EntityId sourceEntityId,
|
||||
TeleportBookmark currentLocation);
|
||||
|
||||
void tick() override;
|
||||
void tick(float dt) override;
|
||||
|
||||
void selectDestination();
|
||||
void teleport();
|
||||
|
@ -114,15 +114,17 @@ bool TitleScreen::handleInputEvent(InputEvent const& event) {
|
||||
return m_paneManager.sendInputEvent(event);
|
||||
}
|
||||
|
||||
void TitleScreen::update() {
|
||||
void TitleScreen::update(float dt) {
|
||||
m_cursor.update(dt);
|
||||
|
||||
for (auto p : m_rightAnchoredButtons)
|
||||
p.first->setPosition(Vec2I(m_guiContext->windowWidth() / m_guiContext->interfaceScale(), 0) + p.second);
|
||||
m_mainMenu->determineSizeFromChildren();
|
||||
|
||||
m_skyBackdrop->update();
|
||||
m_environmentPainter->update();
|
||||
m_skyBackdrop->update(dt);
|
||||
m_environmentPainter->update(dt);
|
||||
|
||||
m_paneManager.update();
|
||||
m_paneManager.update(dt);
|
||||
|
||||
if (!finishedState()) {
|
||||
if (auto audioSample = m_musicTrackManager.updateAmbient(m_musicTrack, m_skyBackdrop->isDayTime())) {
|
||||
@ -423,7 +425,6 @@ void TitleScreen::back() {
|
||||
void TitleScreen::renderCursor() {
|
||||
auto assets = Root::singleton().assets();
|
||||
|
||||
m_cursor.update(WorldTimestep);
|
||||
Vec2I cursorPos = m_cursorScreenPos;
|
||||
Vec2I cursorSize = m_cursor.size();
|
||||
Vec2I cursorOffset = m_cursor.offset();
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
void render();
|
||||
|
||||
bool handleInputEvent(InputEvent const& event);
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
bool textInputActive() const;
|
||||
|
||||
|
@ -420,7 +420,7 @@ void Voice::mix(int16_t* buffer, size_t frameCount, unsigned channels) {
|
||||
}
|
||||
}
|
||||
|
||||
void Voice::update(PositionalAttenuationFunction positionalAttenuationFunction) {
|
||||
void Voice::update(float dt, PositionalAttenuationFunction positionalAttenuationFunction) {
|
||||
for (auto& entry : m_speakers) {
|
||||
if (SpeakerPtr& speaker = entry.second) {
|
||||
if (positionalAttenuationFunction) {
|
||||
|
@ -136,7 +136,7 @@ public:
|
||||
void mix(int16_t* buffer, size_t frames, unsigned channels);
|
||||
|
||||
typedef function<float(unsigned, Vec2F, float)> PositionalAttenuationFunction;
|
||||
void update(PositionalAttenuationFunction positionalAttenuationFunction = {});
|
||||
void update(float dt, PositionalAttenuationFunction positionalAttenuationFunction = {});
|
||||
|
||||
void setDeviceName(Maybe<String> device);
|
||||
StringList availableDevices();
|
||||
|
@ -35,7 +35,7 @@ void WirePane::reset() {
|
||||
m_connecting = false;
|
||||
}
|
||||
|
||||
void WirePane::update() {
|
||||
void WirePane::update(float dt) {
|
||||
if (!active())
|
||||
return;
|
||||
if (!m_worldClient->inWorld()) {
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
WirePane(WorldClientPtr worldClient, PlayerPtr player, WorldPainterPtr worldPainter);
|
||||
virtual ~WirePane() {}
|
||||
|
||||
virtual void update() override;
|
||||
virtual void update(float dt) override;
|
||||
virtual bool sendEvent(InputEvent const& event) override;
|
||||
|
||||
virtual SwingResult swing(WorldGeometry const& geometry, Vec2F position, FireMode mode) override;
|
||||
|
@ -720,7 +720,7 @@ void ActorMovementController::clearControls() {
|
||||
m_controlModifiers = ActorMovementModifiers();
|
||||
}
|
||||
|
||||
void ActorMovementController::tickMaster() {
|
||||
void ActorMovementController::tickMaster(float dt) {
|
||||
EntityAnchorConstPtr newAnchor;
|
||||
if (auto anchorState = m_anchorState.get()) {
|
||||
if (auto anchorableEntity = as<AnchorableEntity>(world()->entity(anchorState->entityId)))
|
||||
@ -743,8 +743,8 @@ void ActorMovementController::tickMaster() {
|
||||
m_groundMovement.set(false);
|
||||
m_liquidMovement.set(false);
|
||||
|
||||
setVelocity((m_entityAnchor->position - MovementController::position()) / WorldTimestep);
|
||||
MovementController::tickMaster();
|
||||
setVelocity((m_entityAnchor->position - MovementController::position()) / dt);
|
||||
MovementController::tickMaster(dt);
|
||||
setPosition(m_entityAnchor->position);
|
||||
} else {
|
||||
auto activeParameters = m_baseParameters.merge(m_controlParameters);
|
||||
@ -775,7 +775,7 @@ void ActorMovementController::tickMaster() {
|
||||
if (appliedForceRegion()) {
|
||||
m_pathController->reset();
|
||||
} else if (!m_pathController->pathfinding()) {
|
||||
m_pathMoveResult = m_pathController->move(*this, activeParameters, activeModifiers, m_controlPathMove->second, WorldTimestep)
|
||||
m_pathMoveResult = m_pathController->move(*this, activeParameters, activeModifiers, m_controlPathMove->second, dt)
|
||||
.apply([this](bool result) { return pair<Vec2F, bool>(m_controlPathMove->first, result); });
|
||||
|
||||
auto action = m_pathController->curAction();
|
||||
@ -811,7 +811,7 @@ void ActorMovementController::tickMaster() {
|
||||
|
||||
// MovementController still handles updating liquid percentage and updating force regions
|
||||
updateLiquidPercentage();
|
||||
updateForceRegions();
|
||||
updateForceRegions(dt);
|
||||
// onGround flag needs to be manually set, won't be set by MovementController::tickMaster
|
||||
setOnGround(onGround);
|
||||
clearControls();
|
||||
@ -894,7 +894,7 @@ void ActorMovementController::tickMaster() {
|
||||
float minGroundSustain = *activeParameters.groundMovementMinimumSustain;
|
||||
float maxGroundSustain = *activeParameters.groundMovementMaximumSustain;
|
||||
float groundCheckDistance = *activeParameters.groundMovementCheckDistance;
|
||||
m_groundMovementSustainTimer.tick();
|
||||
m_groundMovementSustainTimer.tick(dt);
|
||||
if (onGround()) {
|
||||
m_groundMovementSustainTimer = GameTimer(maxGroundSustain);
|
||||
} else if (!m_groundMovementSustainTimer.ready() && groundCheckDistance > 0.0f && maxGroundSustain - m_groundMovementSustainTimer.timer > minGroundSustain) {
|
||||
@ -933,15 +933,15 @@ void ActorMovementController::tickMaster() {
|
||||
m_groundMovementSustainTimer = GameTimer(0);
|
||||
|
||||
} else if (holdJump) {
|
||||
m_reJumpTimer.tick();
|
||||
m_reJumpTimer.tick(dt);
|
||||
if (m_jumpHoldTimer)
|
||||
m_jumpHoldTimer->tick();
|
||||
m_jumpHoldTimer->tick(dt);
|
||||
|
||||
approachYVelocity(*jumpProfile.jumpSpeed * jumpModifier, *jumpProfile.jumpControlForce * jumpModifier);
|
||||
|
||||
} else {
|
||||
m_jumping.set(false);
|
||||
m_reJumpTimer.tick();
|
||||
m_reJumpTimer.tick(dt);
|
||||
}
|
||||
|
||||
if (m_controlMove == Direction::Left) {
|
||||
@ -1003,7 +1003,7 @@ void ActorMovementController::tickMaster() {
|
||||
bool falling = (yVelocity() < *activeParameters.fallStatusSpeedMin) && !m_groundMovement.get();
|
||||
m_falling.set(falling);
|
||||
|
||||
MovementController::tickMaster();
|
||||
MovementController::tickMaster(dt);
|
||||
|
||||
m_lastControlJump = m_controlJump;
|
||||
m_lastControlDown = m_controlDown;
|
||||
@ -1017,8 +1017,8 @@ void ActorMovementController::tickMaster() {
|
||||
clearControls();
|
||||
}
|
||||
|
||||
void ActorMovementController::tickSlave() {
|
||||
MovementController::tickSlave();
|
||||
void ActorMovementController::tickSlave(float dt) {
|
||||
MovementController::tickSlave(dt);
|
||||
|
||||
m_entityAnchor.reset();
|
||||
if (auto anchorState = m_anchorState.get()) {
|
||||
@ -1309,7 +1309,7 @@ Maybe<bool> PathController::move(ActorMovementController& movementController, Ac
|
||||
float angleFactor = movementController.velocity().normalized() * delta.normalized();
|
||||
float speedAlongAngle = angleFactor * movementController.velocity().magnitude();
|
||||
auto acc = parameters.airForce.value(0.0) / movementController.mass();
|
||||
sourceVelocity = delta.normalized() * fmin(parameters.flySpeed.value(0.0), speedAlongAngle + acc * WorldTimestep);
|
||||
sourceVelocity = delta.normalized() * fmin(parameters.flySpeed.value(0.0), speedAlongAngle + acc * dt);
|
||||
targetVelocity = sourceVelocity;
|
||||
}
|
||||
break;
|
||||
|
@ -245,11 +245,11 @@ public:
|
||||
// Clears all control data.
|
||||
void clearControls();
|
||||
|
||||
// Integrates the ActorMovementController one WorldTimestep and applies all
|
||||
// Integrates the ActorMovementController and applies all
|
||||
// the control data and clears it for the next step.
|
||||
void tickMaster();
|
||||
void tickMaster(float dt);
|
||||
|
||||
void tickSlave();
|
||||
void tickSlave(float dt);
|
||||
|
||||
|
||||
private:
|
||||
|
@ -58,7 +58,7 @@ DataStream& operator>>(DataStream& ds, RemoteDamageNotification& damageNotificat
|
||||
|
||||
DamageManager::DamageManager(World* world, ConnectionId connectionId) : m_world(world), m_connectionId(connectionId) {}
|
||||
|
||||
void DamageManager::update() {
|
||||
void DamageManager::update(float dt) {
|
||||
float const DefaultDamageTimeout = 1.0f;
|
||||
|
||||
auto damageIt = makeSMutableMapIterator(m_recentEntityDamages);
|
||||
@ -67,7 +67,7 @@ void DamageManager::update() {
|
||||
auto eventIt = makeSMutableIterator(events);
|
||||
while (eventIt.hasNext()) {
|
||||
auto& event = eventIt.next();
|
||||
event.timeout -= WorldTimestep;
|
||||
event.timeout -= dt;
|
||||
auto entityIdTimeoutGroup = event.timeoutGroup.maybe<EntityId>();
|
||||
if (event.timeout <= 0.0f || (entityIdTimeoutGroup && !m_world->entity(*entityIdTimeoutGroup)))
|
||||
eventIt.remove();
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
|
||||
// Notify entities that they have caused damage, apply damage to master
|
||||
// entities, produce damage notifications, and run down damage timeouts.
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
// Incoming RemoteHitRequest and RemoteDamageRequest must have the
|
||||
// destinationConnection equal to the DamageManager's connectionId
|
||||
|
@ -30,7 +30,7 @@ void EffectEmitter::setBaseVelocity(Vec2F const& velocity) {
|
||||
m_baseVelocity = velocity;
|
||||
}
|
||||
|
||||
void EffectEmitter::tick(EntityMode mode) {
|
||||
void EffectEmitter::tick(float dt, EntityMode mode) {
|
||||
if (mode == EntityMode::Master) {
|
||||
m_activeSources.set(move(m_newSources));
|
||||
m_newSources.clear();
|
||||
@ -42,7 +42,7 @@ void EffectEmitter::tick(EntityMode mode) {
|
||||
eraseWhere(m_sources, [](EffectSourcePtr const& source) { return source->expired(); });
|
||||
|
||||
for (auto& ps : m_sources)
|
||||
ps->tick();
|
||||
ps->tick(dt);
|
||||
|
||||
Set<pair<String, String>> current;
|
||||
for (auto& ps : m_sources) {
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
void setDirection(Direction direction);
|
||||
void setBaseVelocity(Vec2F const& velocity);
|
||||
|
||||
void tick(EntityMode mode);
|
||||
void tick(float dt, EntityMode mode);
|
||||
void reset();
|
||||
|
||||
void render(RenderCallback* renderCallback);
|
||||
|
@ -72,8 +72,8 @@ void EffectSource::stop() {
|
||||
m_stop = true;
|
||||
}
|
||||
|
||||
void EffectSource::tick() {
|
||||
m_timer -= WorldTimestep;
|
||||
void EffectSource::tick(float dt) {
|
||||
m_timer -= dt;
|
||||
if ((m_timer <= 0) && m_loops) {
|
||||
m_timer = m_loopDuration + m_durationVariance * Random::randf(-0.5f, 0.5f);
|
||||
m_loopTick = true;
|
||||
|
@ -17,7 +17,7 @@ class EffectSource {
|
||||
public:
|
||||
EffectSource(String const& kind, String suggestedSpawnLocation, Json const& definition);
|
||||
String const& kind() const;
|
||||
void tick();
|
||||
void tick(float dt);
|
||||
bool expired() const;
|
||||
void stop();
|
||||
List<String> particles();
|
||||
|
@ -2,9 +2,8 @@
|
||||
|
||||
namespace Star {
|
||||
|
||||
float GlobalTimescale = 1.0f;
|
||||
float WorldTimestep = 1.0f / 60.0f;
|
||||
|
||||
// This is used to correct interpolation. It must match the timestep of the server you are connected to.
|
||||
float ServerWorldTimestep = 1.0f / 60.0f;
|
||||
|
||||
EnumMap<Direction> const DirectionNames{
|
||||
|
@ -93,6 +93,7 @@ extern EnumMap<Rarity> const RarityNames;
|
||||
// distance (one tile).
|
||||
unsigned const TilePixels = 8;
|
||||
|
||||
extern float GlobalTimescale;
|
||||
extern float WorldTimestep;
|
||||
extern float ServerWorldTimestep;
|
||||
float const SystemWorldTimestep = 1.0f / 20.0f;
|
||||
|
@ -176,7 +176,7 @@ RectF ItemDrop::collisionArea() const {
|
||||
return m_boundBox;
|
||||
}
|
||||
|
||||
void ItemDrop::update(uint64_t) {
|
||||
void ItemDrop::update(float dt, uint64_t) {
|
||||
if (isMaster()) {
|
||||
if (m_owningEntity.get() != NullEntityId) {
|
||||
auto owningEntity = world()->entity(m_owningEntity.get());
|
||||
@ -228,9 +228,9 @@ void ItemDrop::update(uint64_t) {
|
||||
m_movementController.applyParameters(parameters);
|
||||
}
|
||||
|
||||
m_movementController.tickMaster();
|
||||
m_movementController.tickMaster(dt);
|
||||
|
||||
m_intangibleTimer.tick(WorldTimestep);
|
||||
m_intangibleTimer.tick(dt);
|
||||
m_dropAge.update(world()->epochTime());
|
||||
m_ageItemsTimer.update(world()->epochTime());
|
||||
|
||||
@ -252,7 +252,7 @@ void ItemDrop::update(uint64_t) {
|
||||
} else {
|
||||
m_netGroup.tickNetInterpolation(WorldTimestep);
|
||||
Root::singleton().itemDatabase()->loadItem(m_itemDescriptor.get(), m_item);
|
||||
m_movementController.tickSlave();
|
||||
m_movementController.tickSlave(dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
|
||||
RectF collisionArea() const override;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
bool shouldDestroy() const override;
|
||||
|
||||
|
@ -441,41 +441,43 @@ void Monster::damagedOther(DamageNotification const& damage) {
|
||||
m_statusController->damagedOther(damage);
|
||||
}
|
||||
|
||||
void Monster::update(uint64_t) {
|
||||
void Monster::update(float dt, uint64_t) {
|
||||
if (!inWorld())
|
||||
return;
|
||||
|
||||
m_movementController->setTimestep(dt);
|
||||
|
||||
if (isMaster()) {
|
||||
m_networkedAnimator.setFlipped((m_movementController->facingDirection() == Direction::Left) != m_monsterVariant.reversed);
|
||||
|
||||
if (m_knockedOut) {
|
||||
m_knockoutTimer -= WorldTimestep;
|
||||
m_knockoutTimer -= dt;
|
||||
} else {
|
||||
if (m_scriptComponent.updateReady())
|
||||
m_physicsForces.set({});
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
|
||||
if (shouldDie())
|
||||
knockout();
|
||||
}
|
||||
|
||||
m_movementController->tickMaster();
|
||||
m_movementController->tickMaster(dt);
|
||||
|
||||
m_statusController->tickMaster();
|
||||
updateStatus();
|
||||
m_statusController->tickMaster(dt);
|
||||
updateStatus(dt);
|
||||
} else {
|
||||
m_netGroup.tickNetInterpolation(WorldTimestep);
|
||||
|
||||
m_statusController->tickSlave();
|
||||
updateStatus();
|
||||
m_statusController->tickSlave(dt);
|
||||
updateStatus(dt);
|
||||
|
||||
m_movementController->tickSlave();
|
||||
m_movementController->tickSlave(dt);
|
||||
}
|
||||
|
||||
if (world()->isServer()) {
|
||||
m_networkedAnimator.update(WorldTimestep, nullptr);
|
||||
m_networkedAnimator.update(dt, nullptr);
|
||||
} else {
|
||||
m_networkedAnimator.update(WorldTimestep, &m_networkedAnimatorDynamicTarget);
|
||||
m_networkedAnimator.update(dt, &m_networkedAnimatorDynamicTarget);
|
||||
m_networkedAnimatorDynamicTarget.updatePosition(position());
|
||||
|
||||
m_scriptedAnimator.update();
|
||||
@ -543,12 +545,12 @@ Vec2F Monster::getAbsolutePosition(Vec2F relativePosition) const {
|
||||
return m_movementController->position() + relativePosition;
|
||||
}
|
||||
|
||||
void Monster::updateStatus() {
|
||||
void Monster::updateStatus(float dt) {
|
||||
m_effectEmitter.setSourcePosition("normal", position());
|
||||
m_effectEmitter.setSourcePosition("mouth", position() + mouthOffset());
|
||||
m_effectEmitter.setSourcePosition("feet", position() + feetOffset());
|
||||
m_effectEmitter.setDirection(m_movementController->facingDirection());
|
||||
m_effectEmitter.tick(*entityMode());
|
||||
m_effectEmitter.tick(dt, *entityMode());
|
||||
}
|
||||
|
||||
LuaCallbacks Monster::makeMonsterCallbacks() {
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
bool shouldDestroy() const override;
|
||||
void destroy(RenderCallback* renderCallback) override;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
|
||||
@ -137,7 +137,7 @@ public:
|
||||
private:
|
||||
Vec2F getAbsolutePosition(Vec2F relativePosition) const;
|
||||
|
||||
void updateStatus();
|
||||
void updateStatus(float dt);
|
||||
LuaCallbacks makeMonsterCallbacks();
|
||||
|
||||
void addChatMessage(String const& message, String const& portrait = "");
|
||||
|
@ -170,6 +170,8 @@ DataStream& operator<<(DataStream& ds, MovementParameters const& movementParamet
|
||||
MovementController::MovementController(MovementParameters const& parameters) {
|
||||
m_resting = false;
|
||||
|
||||
m_timeStep = WorldTimestep;
|
||||
|
||||
m_liquidPercentage = 0.0f;
|
||||
m_liquidId = EmptyLiquidId;
|
||||
|
||||
@ -392,15 +394,15 @@ void MovementController::rotate(float rotationRate) {
|
||||
return;
|
||||
|
||||
m_resting = false;
|
||||
m_rotation.set(fmod(rotation() + rotationRate * WorldTimestep, 2 * Constants::pi));
|
||||
m_rotation.set(fmod(rotation() + rotationRate * m_timeStep, 2 * Constants::pi));
|
||||
}
|
||||
|
||||
void MovementController::accelerate(Vec2F const& acceleration) {
|
||||
setVelocity(velocity() + acceleration * WorldTimestep);
|
||||
setVelocity(velocity() + acceleration * m_timeStep);
|
||||
}
|
||||
|
||||
void MovementController::force(Vec2F const& force) {
|
||||
setVelocity(velocity() + force / mass() * WorldTimestep);
|
||||
setVelocity(velocity() + force / mass() * m_timeStep);
|
||||
}
|
||||
|
||||
void MovementController::approachVelocity(Vec2F const& targetVelocity, float maxControlForce) {
|
||||
@ -414,7 +416,7 @@ void MovementController::approachVelocity(Vec2F const& targetVelocity, float max
|
||||
if (diffMagnitude == 0.0f)
|
||||
return;
|
||||
|
||||
float maximumAcceleration = maxControlForce / mass() * WorldTimestep;
|
||||
float maximumAcceleration = maxControlForce / mass() * m_timeStep;
|
||||
float clampedMagnitude = clamp(diffMagnitude, 0.0f, maximumAcceleration);
|
||||
|
||||
setVelocity(velocity() + diff * (clampedMagnitude / diffMagnitude));
|
||||
@ -437,7 +439,7 @@ void MovementController::approachVelocityAlongAngle(float angle, float targetVel
|
||||
if (positiveOnly && diff < 0)
|
||||
return;
|
||||
|
||||
float maximumAcceleration = maxControlForce / mass() * WorldTimestep;
|
||||
float maximumAcceleration = maxControlForce / mass() * m_timeStep;
|
||||
|
||||
float diffMagnitude = std::fabs(diff);
|
||||
float clampedMagnitude = clamp(diffMagnitude, 0.0f, maximumAcceleration);
|
||||
@ -464,7 +466,12 @@ void MovementController::uninit() {
|
||||
updatePositionInterpolators();
|
||||
}
|
||||
|
||||
void MovementController::tickMaster() {
|
||||
void MovementController::setTimestep(float dt) {
|
||||
m_timeStep = dt;
|
||||
}
|
||||
|
||||
void MovementController::tickMaster(float dt) {
|
||||
setTimestep(dt);
|
||||
auto geometry = world()->geometry();
|
||||
|
||||
m_zeroG.set(!*m_parameters.gravityEnabled || *m_parameters.gravityMultiplier == 0 || world()->gravity(position()) == 0);
|
||||
@ -478,7 +485,7 @@ void MovementController::tickMaster() {
|
||||
if (surfaceCollision) {
|
||||
Vec2F surfacePositionDelta = geometry.diff(surfaceCollision->position, m_surfaceMovingCollisionPosition);
|
||||
setPosition(position() + surfacePositionDelta);
|
||||
Vec2F newSurfaceVelocity = surfacePositionDelta / WorldTimestep;
|
||||
Vec2F newSurfaceVelocity = surfacePositionDelta / dt;
|
||||
setVelocity(velocity() - m_surfaceVelocity + newSurfaceVelocity);
|
||||
m_surfaceVelocity = newSurfaceVelocity;
|
||||
} else {
|
||||
@ -496,7 +503,7 @@ void MovementController::tickMaster() {
|
||||
|
||||
// don't integrate velocity when resting
|
||||
Vec2F relativeVelocity = m_resting ? Vec2F() : velocity();
|
||||
Vec2F originalMovement = relativeVelocity * WorldTimestep;
|
||||
Vec2F originalMovement = relativeVelocity * dt;
|
||||
if (surfaceCollision)
|
||||
relativeVelocity -= m_surfaceVelocity;
|
||||
|
||||
@ -507,7 +514,7 @@ void MovementController::tickMaster() {
|
||||
unsigned steps;
|
||||
float maxMovementPerStep = *m_parameters.maxMovementPerStep;
|
||||
if (maxMovementPerStep > 0.0f)
|
||||
steps = std::floor(vmag(relativeVelocity) * WorldTimestep / maxMovementPerStep) + 1;
|
||||
steps = std::floor(vmag(relativeVelocity) * dt / maxMovementPerStep) + 1;
|
||||
else
|
||||
steps = 1;
|
||||
|
||||
@ -516,8 +523,8 @@ void MovementController::tickMaster() {
|
||||
steps = 0;
|
||||
|
||||
for (unsigned i = 0; i < steps; ++i) {
|
||||
float dt = WorldTimestep / steps;
|
||||
Vec2F movement = relativeVelocity * dt;
|
||||
float dtSteps = dt / steps;
|
||||
Vec2F movement = relativeVelocity * dtSteps;
|
||||
|
||||
if (!*m_parameters.collisionEnabled || collisionPoly().isNull()) {
|
||||
setPosition(position() + movement);
|
||||
@ -546,7 +553,7 @@ void MovementController::tickMaster() {
|
||||
queryBounds.combine(queryBounds.translated(movement));
|
||||
queryCollisions(queryBounds);
|
||||
auto result = collisionMove(m_workingCollisions, body, movement, ignorePlatforms, *m_parameters.enableSurfaceSlopeCorrection && !zeroG(),
|
||||
maximumCorrection, maximumPlatformCorrection, bodyCenter);
|
||||
maximumCorrection, maximumPlatformCorrection, bodyCenter, dtSteps);
|
||||
|
||||
setPosition(position() + result.movement);
|
||||
|
||||
@ -572,7 +579,7 @@ void MovementController::tickMaster() {
|
||||
if (*m_parameters.stickyCollision && result.collisionKind != CollisionKind::Slippery) {
|
||||
// When sticking, cancel all velocity and apply stickyForce in the
|
||||
// opposite of the direction of collision correction.
|
||||
relativeVelocity = -normCorrection * *m_parameters.stickyForce / mass() * dt;
|
||||
relativeVelocity = -normCorrection * *m_parameters.stickyForce / mass() * dtSteps;
|
||||
m_stickingDirection.set(-normCorrection.angle());
|
||||
break;
|
||||
} else {
|
||||
@ -597,14 +604,14 @@ void MovementController::tickMaster() {
|
||||
// independently).
|
||||
|
||||
if (relativeVelocity[0] < 0 && correction[0] > 0)
|
||||
relativeVelocity[0] = min(0.0f, relativeVelocity[0] + correction[0] / WorldTimestep);
|
||||
relativeVelocity[0] = min(0.0f, relativeVelocity[0] + correction[0] / dt);
|
||||
else if (relativeVelocity[0] > 0 && correction[0] < 0)
|
||||
relativeVelocity[0] = max(0.0f, relativeVelocity[0] + correction[0] / WorldTimestep);
|
||||
relativeVelocity[0] = max(0.0f, relativeVelocity[0] + correction[0] / dt);
|
||||
|
||||
if (relativeVelocity[1] < 0 && correction[1] > 0)
|
||||
relativeVelocity[1] = min(0.0f, relativeVelocity[1] + correction[1] / WorldTimestep);
|
||||
relativeVelocity[1] = min(0.0f, relativeVelocity[1] + correction[1] / dt);
|
||||
else if (relativeVelocity[1] > 0 && correction[1] < 0)
|
||||
relativeVelocity[1] = max(0.0f, relativeVelocity[1] + correction[1] / WorldTimestep);
|
||||
relativeVelocity[1] = max(0.0f, relativeVelocity[1] + correction[1] / dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -641,7 +648,7 @@ void MovementController::tickMaster() {
|
||||
float buoyancy = *m_parameters.liquidBuoyancy * m_liquidPercentage + *m_parameters.airBuoyancy * (1.0f - liquidPercentage());
|
||||
float gravity = world()->gravity(position()) * *m_parameters.gravityMultiplier * (1.0f - buoyancy);
|
||||
Vec2F environmentVelocity;
|
||||
environmentVelocity[1] -= gravity * WorldTimestep;
|
||||
environmentVelocity[1] -= gravity * dt;
|
||||
|
||||
if (onGround() && *m_parameters.slopeSlidingFactor != 0 && m_surfaceSlope[1] != 0)
|
||||
environmentVelocity += -m_surfaceSlope * (m_surfaceSlope[0] * m_surfaceSlope[1]) * *m_parameters.slopeSlidingFactor;
|
||||
@ -673,16 +680,17 @@ void MovementController::tickMaster() {
|
||||
// but it is applied here as a multiplicitave factor from [0, 1] so it does
|
||||
// not induce oscillation at very high friction and so it cannot be
|
||||
// negative.
|
||||
float frictionFactor = clamp(friction / mass() * WorldTimestep, 0.0f, 1.0f);
|
||||
float frictionFactor = clamp(friction / mass() * dt, 0.0f, 1.0f);
|
||||
newVelocity = lerp(frictionFactor, newVelocity, refVel);
|
||||
}
|
||||
|
||||
setVelocity(newVelocity);
|
||||
|
||||
updateForceRegions();
|
||||
updateForceRegions(dt);
|
||||
}
|
||||
|
||||
void MovementController::tickSlave() {
|
||||
void MovementController::tickSlave(float dt) {
|
||||
setTimestep(dt);
|
||||
if (auto movingCollisionId = m_surfaceMovingCollision.get()) {
|
||||
if (auto physicsEntity = world()->get<PhysicsEntity>(movingCollisionId->physicsEntityId)) {
|
||||
if (auto collision = physicsEntity->movingCollision(movingCollisionId->collisionIndex)) {
|
||||
@ -724,7 +732,7 @@ void MovementController::forEachMovingCollision(RectF const& region, function<bo
|
||||
}
|
||||
}
|
||||
|
||||
void MovementController::updateForceRegions() {
|
||||
void MovementController::updateForceRegions(float dt) {
|
||||
auto geometry = world()->geometry();
|
||||
auto pos = position();
|
||||
auto body = collisionBody();
|
||||
@ -841,11 +849,12 @@ CollisionKind MovementController::maxOrNullCollision(CollisionKind a, CollisionK
|
||||
}
|
||||
|
||||
MovementController::CollisionResult MovementController::collisionMove(List<CollisionPoly>& collisionPolys, PolyF const& body, Vec2F const& movement,
|
||||
bool ignorePlatforms, bool enableSurfaceSlopeCorrection, float maximumCorrection, float maximumPlatformCorrection, Vec2F sortCenter) {
|
||||
bool ignorePlatforms, bool enableSurfaceSlopeCorrection, float maximumCorrection, float maximumPlatformCorrection, Vec2F sortCenter, float dt) {
|
||||
unsigned const MaximumSeparationLoops = 3;
|
||||
float const SlideAngle = Constants::pi / 3;
|
||||
float const SlideCorrectionLimit = 0.2f;
|
||||
float const SeparationTolerance = 0.001f;
|
||||
float separationTolerance = 0.001f * (dt * 60.f);
|
||||
maximumPlatformCorrection *= (dt * 60.f);
|
||||
|
||||
if (body.isNull())
|
||||
return {movement, Vec2F(), {}, false, false, Vec2F(1, 0), CollisionKind::None};
|
||||
@ -861,7 +870,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
|
||||
if (enableSurfaceSlopeCorrection) {
|
||||
// First try separating with our ground sliding cheat.
|
||||
separation = collisionSeparate(collisionPolys, checkBody, ignorePlatforms, maximumPlatformCorrection, sortCenter, true, SeparationTolerance);
|
||||
separation = collisionSeparate(collisionPolys, checkBody, ignorePlatforms, maximumPlatformCorrection, sortCenter, true, separationTolerance);
|
||||
totalCorrection += separation.correction;
|
||||
checkBody.translate(separation.correction);
|
||||
maxCollided = maxOrNullCollision(maxCollided, separation.collisionKind);
|
||||
@ -889,7 +898,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
totalCorrection = Vec2F();
|
||||
for (size_t i = 0; i < MaximumSeparationLoops; ++i) {
|
||||
separation = collisionSeparate(collisionPolys, checkBody, ignorePlatforms,
|
||||
maximumPlatformCorrection, sortCenter, false, SeparationTolerance);
|
||||
maximumPlatformCorrection, sortCenter, false, separationTolerance);
|
||||
totalCorrection += separation.correction;
|
||||
checkBody.translate(separation.correction);
|
||||
maxCollided = maxOrNullCollision(maxCollided, separation.collisionKind);
|
||||
@ -911,7 +920,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
checkBody = body;
|
||||
totalCorrection = -movement;
|
||||
for (size_t i = 0; i < MaximumSeparationLoops; ++i) {
|
||||
separation = collisionSeparate(collisionPolys, checkBody, true, maximumPlatformCorrection, sortCenter, false, SeparationTolerance);
|
||||
separation = collisionSeparate(collisionPolys, checkBody, true, maximumPlatformCorrection, sortCenter, false, separationTolerance);
|
||||
totalCorrection += separation.correction;
|
||||
checkBody.translate(separation.correction);
|
||||
maxCollided = maxOrNullCollision(maxCollided, separation.collisionKind);
|
||||
@ -931,7 +940,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
result.movement = movement + totalCorrection;
|
||||
result.correction = totalCorrection;
|
||||
result.isStuck = false;
|
||||
result.onGround = result.correction[1] > SeparationTolerance;
|
||||
result.onGround = result.correction[1] > separationTolerance;
|
||||
result.surfaceMovingCollisionId = surfaceMovingCollisionId;
|
||||
result.collisionKind = maxCollided;
|
||||
result.groundSlope = Vec2F(1, 0);
|
||||
@ -944,7 +953,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
// geometry, rather than off to the side.
|
||||
float maxSideHorizontalOverlap = 0.0f;
|
||||
RectF touchingBounds = checkBody.boundBox();
|
||||
touchingBounds.pad(SeparationTolerance);
|
||||
touchingBounds.pad(separationTolerance);
|
||||
for (auto const& cp : collisionPolys) {
|
||||
if (!cp.polyBounds.intersects(touchingBounds))
|
||||
continue;
|
||||
@ -959,7 +968,7 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
float t = clamp(side.lineProjection(bodyVertex), 0.0f, 1.0f);
|
||||
Vec2F nearPoint = side.eval(t);
|
||||
if (nearPoint[1] > cp.sortPosition[1]) {
|
||||
if (vmagSquared(bodyVertex - nearPoint) <= square(SeparationTolerance)) {
|
||||
if (vmagSquared(bodyVertex - nearPoint) <= square(separationTolerance)) {
|
||||
maxSideHorizontalOverlap = thisSideHorizontalOverlap;
|
||||
result.groundSlope = side.diff().normalized();
|
||||
if (result.groundSlope[0] < 0)
|
||||
@ -981,8 +990,6 @@ MovementController::CollisionResult MovementController::collisionMove(List<Colli
|
||||
MovementController::CollisionSeparation MovementController::collisionSeparate(List<CollisionPoly>& collisionPolys, PolyF const& poly,
|
||||
bool ignorePlatforms, float maximumPlatformCorrection, Vec2F const& sortCenter, bool upward, float separationTolerance) {
|
||||
|
||||
maximumPlatformCorrection *= WorldTimestep * 60.0f;
|
||||
|
||||
CollisionSeparation separation = {};
|
||||
separation.collisionKind = CollisionKind::None;
|
||||
bool intersects = false;
|
||||
|
@ -180,13 +180,16 @@ public:
|
||||
void init(World* world);
|
||||
void uninit();
|
||||
|
||||
// Stores dt value for Lua calls.
|
||||
void setTimestep(float dt);
|
||||
|
||||
// Integrates the ActorMovementController one WorldTimestep and applies all
|
||||
// forces.
|
||||
void tickMaster();
|
||||
void tickMaster(float dt);
|
||||
|
||||
// Does not integrate, only tracks master state and updates non-networked
|
||||
// fields based on local data
|
||||
void tickSlave();
|
||||
void tickSlave(float dt);
|
||||
|
||||
void setIgnorePhysicsEntities(Set<EntityId> ignorePhysicsEntities);
|
||||
// iterate over all physics entity collision polys in the region, iteration stops if the callback returns false
|
||||
@ -194,7 +197,7 @@ public:
|
||||
|
||||
protected:
|
||||
// forces the movement controller onGround status, used when manually controlling movement outside the movement controller
|
||||
void updateForceRegions();
|
||||
void updateForceRegions(float dt);
|
||||
void updateLiquidPercentage();
|
||||
void setOnGround(bool onGround);
|
||||
|
||||
@ -239,7 +242,7 @@ private:
|
||||
|
||||
static CollisionKind maxOrNullCollision(CollisionKind a, CollisionKind b);
|
||||
static CollisionResult collisionMove(List<CollisionPoly>& collisionPolys, PolyF const& body, Vec2F const& movement,
|
||||
bool ignorePlatforms, bool enableSurfaceSlopeCorrection, float maximumCorrection, float maximumPlatformCorrection, Vec2F sortCenter);
|
||||
bool ignorePlatforms, bool enableSurfaceSlopeCorrection, float maximumCorrection, float maximumPlatformCorrection, Vec2F sortCenter, float dt);
|
||||
static CollisionSeparation collisionSeparate(List<CollisionPoly>& collisionPolys, PolyF const& poly,
|
||||
bool ignorePlatforms, float maximumPlatformCorrection, Vec2F const& sortCenter, bool upward, float separationTolerance);
|
||||
|
||||
@ -287,6 +290,7 @@ private:
|
||||
|
||||
bool m_resting;
|
||||
int m_restTicks;
|
||||
float m_timeStep;
|
||||
|
||||
List<CollisionPoly> m_workingCollisions;
|
||||
List<PolyF> m_collisionBuffers;
|
||||
|
@ -345,12 +345,14 @@ void Npc::damagedOther(DamageNotification const& damage) {
|
||||
m_statusController->damagedOther(damage);
|
||||
}
|
||||
|
||||
void Npc::update(uint64_t) {
|
||||
void Npc::update(float dt, uint64_t) {
|
||||
if (!inWorld())
|
||||
return;
|
||||
|
||||
m_movementController->setTimestep(dt);
|
||||
|
||||
if (isMaster()) {
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
|
||||
if (inConflictingLoungeAnchor())
|
||||
m_movementController->resetAnchorState();
|
||||
@ -385,10 +387,10 @@ void Npc::update(uint64_t) {
|
||||
m_statusController->setPersistentEffects("armor", m_armor->statusEffects());
|
||||
m_statusController->setPersistentEffects("tools", m_tools->statusEffects());
|
||||
|
||||
m_movementController->tickMaster();
|
||||
m_statusController->tickMaster();
|
||||
m_movementController->tickMaster(dt);
|
||||
m_statusController->tickMaster(dt);
|
||||
|
||||
tickShared();
|
||||
tickShared(dt);
|
||||
|
||||
if (!is<LoungeAnchor>(m_movementController->entityAnchor())) {
|
||||
if (m_movementController->groundMovement()) {
|
||||
@ -413,9 +415,9 @@ void Npc::update(uint64_t) {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_emoteCooldownTimer.tick())
|
||||
if (m_emoteCooldownTimer.tick(dt))
|
||||
m_emoteState = HumanoidEmote::Idle;
|
||||
if (m_danceCooldownTimer.tick())
|
||||
if (m_danceCooldownTimer.tick(dt))
|
||||
m_dance = {};
|
||||
|
||||
if (m_chatMessageUpdated) {
|
||||
@ -425,7 +427,7 @@ void Npc::update(uint64_t) {
|
||||
m_chatMessageUpdated = false;
|
||||
}
|
||||
|
||||
if (m_blinkCooldownTimer.tick()) {
|
||||
if (m_blinkCooldownTimer.tick(dt)) {
|
||||
m_blinkCooldownTimer = GameTimer(Random::randf(m_blinkInterval[0], m_blinkInterval[1]));
|
||||
if (m_emoteState == HumanoidEmote::Idle)
|
||||
addEmote(HumanoidEmote::Blink);
|
||||
@ -436,10 +438,10 @@ void Npc::update(uint64_t) {
|
||||
|
||||
} else {
|
||||
m_netGroup.tickNetInterpolation(WorldTimestep);
|
||||
m_movementController->tickSlave();
|
||||
m_statusController->tickSlave();
|
||||
m_movementController->tickSlave(dt);
|
||||
m_statusController->tickSlave(dt);
|
||||
|
||||
tickShared();
|
||||
tickShared(dt);
|
||||
}
|
||||
|
||||
if (world()->isClient())
|
||||
@ -534,7 +536,7 @@ Vec2F Npc::getAbsolutePosition(Vec2F relativePosition) const {
|
||||
return m_movementController->position() + relativePosition;
|
||||
}
|
||||
|
||||
void Npc::tickShared() {
|
||||
void Npc::tickShared(float dt) {
|
||||
if (m_hitDamageNotificationLimiter)
|
||||
m_hitDamageNotificationLimiter--;
|
||||
|
||||
@ -547,7 +549,7 @@ void Npc::tickShared() {
|
||||
m_effectEmitter->setSourcePosition("backArmor", backArmorOffset() + position());
|
||||
|
||||
m_effectEmitter->setDirection(m_humanoid.facingDirection());
|
||||
m_effectEmitter->tick(*entityMode());
|
||||
m_effectEmitter->tick(dt, *entityMode());
|
||||
|
||||
m_humanoid.setMovingBackwards(m_movementController->movingDirection() != m_movementController->facingDirection());
|
||||
m_humanoid.setFacingDirection(m_movementController->facingDirection());
|
||||
@ -575,12 +577,12 @@ void Npc::tickShared() {
|
||||
m_armor->setupHumanoidClothingDrawables(m_humanoid, false);
|
||||
|
||||
m_tools->suppressItems(!canUseTool());
|
||||
m_tools->tick(m_shifting.get(), {});
|
||||
m_tools->tick(dt, m_shifting.get(), {});
|
||||
|
||||
if (auto overrideDirection = m_tools->setupHumanoidHandItems(m_humanoid, position(), aimPosition()))
|
||||
m_movementController->controlFace(*overrideDirection);
|
||||
|
||||
m_humanoid.animate(WorldTimestep);
|
||||
m_humanoid.animate(dt);
|
||||
}
|
||||
|
||||
LuaCallbacks Npc::makeNpcCallbacks() {
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
bool shouldDestroy() const override;
|
||||
void destroy(RenderCallback* renderCallback) override;
|
||||
|
||||
void update(uint64_t currentVersion) override;
|
||||
void update(float dt, uint64_t currentVersion) override;
|
||||
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
|
||||
@ -177,7 +177,7 @@ public:
|
||||
private:
|
||||
Vec2F getAbsolutePosition(Vec2F relativePosition) const;
|
||||
|
||||
void tickShared();
|
||||
void tickShared(float dt);
|
||||
LuaCallbacks makeNpcCallbacks();
|
||||
|
||||
void setupNetStates();
|
||||
|
@ -352,12 +352,12 @@ List<Vec2I> Object::roots() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Object::update(uint64_t) {
|
||||
void Object::update(float dt, uint64_t) {
|
||||
if (!inWorld())
|
||||
return;
|
||||
|
||||
if (isMaster()) {
|
||||
m_tileDamageStatus->recover(m_config->tileDamageParameters, WorldTimestep);
|
||||
m_tileDamageStatus->recover(m_config->tileDamageParameters, dt);
|
||||
|
||||
if (m_liquidCheckTimer.wrapTick())
|
||||
checkLiquidBroken();
|
||||
@ -369,24 +369,24 @@ void Object::update(uint64_t) {
|
||||
setImageKey("frame", toString(frame));
|
||||
}
|
||||
|
||||
m_animationTimer = std::fmod(m_animationTimer + WorldTimestep, orientation->animationCycle);
|
||||
m_animationTimer = std::fmod(m_animationTimer + dt, orientation->animationCycle);
|
||||
}
|
||||
|
||||
m_networkedAnimator->update(WorldTimestep, nullptr);
|
||||
m_networkedAnimator->update(dt, nullptr);
|
||||
m_networkedAnimator->setFlipped(direction() == Direction::Left, m_animationCenterLine);
|
||||
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
|
||||
} else {
|
||||
m_networkedAnimator->update(WorldTimestep, &m_networkedAnimatorDynamicTarget);
|
||||
m_networkedAnimator->update(dt, &m_networkedAnimatorDynamicTarget);
|
||||
m_networkedAnimatorDynamicTarget.updatePosition(position() + m_animationPosition);
|
||||
}
|
||||
|
||||
if (m_lightFlickering)
|
||||
m_lightFlickering->update(WorldTimestep);
|
||||
m_lightFlickering->update(dt);
|
||||
|
||||
for (auto& timer : m_emissionTimers)
|
||||
timer.tick();
|
||||
timer.tick(dt);
|
||||
|
||||
if (world()->isClient())
|
||||
m_scriptedAnimator.update();
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
virtual bool shouldDestroy() const override;
|
||||
virtual void destroy(RenderCallback* renderCallback) override;
|
||||
|
||||
virtual void update(uint64_t currentStep) override;
|
||||
virtual void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
virtual void render(RenderCallback* renderCallback) override;
|
||||
|
||||
|
@ -718,18 +718,18 @@ float Plant::branchRotation(float xPos, float rotoffset) const {
|
||||
return copysign(0.00117f, m_windLevel) * (std::sin(m_windTime + rotoffset + xPos / 10.0f) * intensity - intensity / 300.0f);
|
||||
}
|
||||
|
||||
void Plant::update(uint64_t) {
|
||||
m_windTime += WorldTimestep;
|
||||
void Plant::update(float dt, uint64_t) {
|
||||
m_windTime += dt;
|
||||
m_windTime = std::fmod(m_windTime, 628.32f);
|
||||
m_windLevel = world()->windLevel(Vec2F(m_tilePosition));
|
||||
|
||||
if (isMaster()) {
|
||||
if (m_tileDamageStatus.damaged())
|
||||
m_tileDamageStatus.recover(m_tileDamageParameters, WorldTimestep);
|
||||
m_tileDamageStatus.recover(m_tileDamageParameters, dt);
|
||||
} else {
|
||||
if (m_tileDamageStatus.damaged() && !m_tileDamageStatus.damageProtected()) {
|
||||
float damageEffectPercentage = m_tileDamageStatus.damageEffectPercentage();
|
||||
m_windTime += damageEffectPercentage * 10 * WorldTimestep;
|
||||
m_windTime += damageEffectPercentage * 10 * dt;
|
||||
m_windLevel += damageEffectPercentage * 20;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
// Root blocks for this plant.
|
||||
List<Vec2I> roots() const override;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
|
||||
|
@ -176,9 +176,10 @@ RectF PlantDrop::collisionRect() const {
|
||||
return shape.boundBox();
|
||||
}
|
||||
|
||||
void PlantDrop::update(uint64_t) {
|
||||
m_time -= WorldTimestep;
|
||||
void PlantDrop::update(float dt, uint64_t) {
|
||||
m_time -= dt;
|
||||
|
||||
m_movementController.setTimestep(dt);
|
||||
if (isMaster()) {
|
||||
if (m_spawnedDropEffects && !m_spawnedDrops.get())
|
||||
m_spawnedDropEffects = false; // false positive assumption over already having done the effect
|
||||
@ -187,7 +188,7 @@ void PlantDrop::update(uint64_t) {
|
||||
m_firstTick = false;
|
||||
|
||||
// think up a better curve then sin
|
||||
auto rotationAcceleration = 0.01f * world()->gravity(position()) * copysign(1.0f, m_rotationRate) * WorldTimestep;
|
||||
auto rotationAcceleration = 0.01f * world()->gravity(position()) * copysign(1.0f, m_rotationRate) * dt;
|
||||
if (abs(m_movementController.rotation()) > m_rotationCap)
|
||||
m_rotationRate -= rotationAcceleration;
|
||||
else if (std::fabs(m_movementController.rotation()) < m_rotationFallThreshold)
|
||||
@ -203,7 +204,7 @@ void PlantDrop::update(uint64_t) {
|
||||
parameters.gravityEnabled = std::fabs(m_movementController.rotation()) >= m_rotationFallThreshold;
|
||||
m_movementController.applyParameters(parameters);
|
||||
|
||||
m_movementController.tickMaster();
|
||||
m_movementController.tickMaster(dt);
|
||||
if (m_movementController.onGround())
|
||||
m_time = 0;
|
||||
}
|
||||
@ -243,7 +244,7 @@ void PlantDrop::update(uint64_t) {
|
||||
if (m_spawnedDrops.get())
|
||||
m_firstTick = false;
|
||||
|
||||
m_movementController.tickSlave();
|
||||
m_movementController.tickSlave(dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
RectF collisionRect() const;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
|
||||
|
@ -153,6 +153,7 @@ Player::Player(PlayerConfigPtr config, Uuid uuid) {
|
||||
m_statusController->resetAllResources();
|
||||
|
||||
m_landingNoisePending = false;
|
||||
m_footstepPending = false;
|
||||
|
||||
setKeepAlive(true);
|
||||
|
||||
@ -776,10 +777,12 @@ Maybe<Json> Player::receiveMessage(ConnectionId fromConnection, String const& me
|
||||
return {};
|
||||
}
|
||||
|
||||
void Player::update(uint64_t) {
|
||||
void Player::update(float dt, uint64_t) {
|
||||
m_movementController->setTimestep(dt);
|
||||
|
||||
if (isMaster()) {
|
||||
if (m_emoteCooldownTimer) {
|
||||
m_emoteCooldownTimer -= WorldTimestep;
|
||||
m_emoteCooldownTimer -= dt;
|
||||
if (m_emoteCooldownTimer <= 0) {
|
||||
m_emoteCooldownTimer = 0;
|
||||
m_emoteState = HumanoidEmote::Idle;
|
||||
@ -793,7 +796,7 @@ void Player::update(uint64_t) {
|
||||
m_chatMessageUpdated = false;
|
||||
}
|
||||
|
||||
m_blinkCooldownTimer -= WorldTimestep;
|
||||
m_blinkCooldownTimer -= dt;
|
||||
if (m_blinkCooldownTimer <= 0) {
|
||||
m_blinkCooldownTimer = Random::randf(m_blinkInterval[0], m_blinkInterval[1]);
|
||||
auto loungeAnchor = as<LoungeAnchor>(m_movementController->entityAnchor());
|
||||
@ -801,13 +804,13 @@ void Player::update(uint64_t) {
|
||||
addEmote(HumanoidEmote::Blink);
|
||||
}
|
||||
|
||||
m_lastDamagedOtherTimer += WorldTimestep;
|
||||
m_lastDamagedOtherTimer += dt;
|
||||
|
||||
if (m_movementController->zeroG())
|
||||
m_movementController->controlParameters(m_zeroGMovementParameters);
|
||||
|
||||
if (isTeleporting()) {
|
||||
m_teleportTimer -= WorldTimestep;
|
||||
m_teleportTimer -= dt;
|
||||
if (m_teleportTimer <= 0 && m_state == State::TeleportIn) {
|
||||
m_state = State::Idle;
|
||||
m_effectsAnimator->burstParticleEmitter(m_teleportAnimationType + "Burst");
|
||||
@ -817,9 +820,9 @@ void Player::update(uint64_t) {
|
||||
if (!isTeleporting()) {
|
||||
processControls();
|
||||
|
||||
m_questManager->update();
|
||||
m_companions->update();
|
||||
m_deployment->update();
|
||||
m_questManager->update(dt);
|
||||
m_companions->update(dt);
|
||||
m_deployment->update(dt);
|
||||
|
||||
bool edgeTriggeredUse = take(m_edgeTriggeredUse);
|
||||
|
||||
@ -871,12 +874,12 @@ void Player::update(uint64_t) {
|
||||
|
||||
m_tools->effects(*m_effectEmitter);
|
||||
|
||||
m_movementController->tickMaster();
|
||||
m_movementController->tickMaster(dt);
|
||||
|
||||
m_techController->tickMaster();
|
||||
m_techController->tickMaster(dt);
|
||||
|
||||
for (auto& p : m_genericScriptContexts)
|
||||
p.second->update(WorldTimestep * p.second->updateDelta());
|
||||
p.second->update(p.second->updateDt(dt));
|
||||
|
||||
if (edgeTriggeredUse) {
|
||||
auto anchor = as<LoungeAnchor>(m_movementController->entityAnchor());
|
||||
@ -896,7 +899,7 @@ void Player::update(uint64_t) {
|
||||
m_techController->setLoadedTech(m_techs->equippedTechs().values());
|
||||
|
||||
if (!isDead())
|
||||
m_statusController->tickMaster();
|
||||
m_statusController->tickMaster(dt);
|
||||
|
||||
if (!modeConfig().hunger)
|
||||
m_statusController->resetResource("food");
|
||||
@ -909,7 +912,7 @@ void Player::update(uint64_t) {
|
||||
m_statusController->setPersistentEffects("hunger", {});
|
||||
|
||||
for (auto& pair : m_delayedRadioMessages) {
|
||||
if (pair.first.tick())
|
||||
if (pair.first.tick(dt))
|
||||
queueRadioMessage(pair.second);
|
||||
}
|
||||
m_delayedRadioMessages.filter([](pair<GameTimer, RadioMessage>& pair) { return !pair.first.ready(); });
|
||||
@ -924,7 +927,7 @@ void Player::update(uint64_t) {
|
||||
|
||||
m_log->addPlayTime(WorldTimestep);
|
||||
|
||||
if (m_ageItemsTimer.wrapTick(WorldTimestep)) {
|
||||
if (m_ageItemsTimer.wrapTick(dt)) {
|
||||
auto itemDatabase = Root::singleton().itemDatabase();
|
||||
m_inventory->forEveryItem([&](InventorySlot const&, ItemPtr& item) {
|
||||
itemDatabase->ageItem(item, m_ageItemsTimer.time);
|
||||
@ -948,9 +951,9 @@ void Player::update(uint64_t) {
|
||||
|
||||
} else {
|
||||
m_netGroup.tickNetInterpolation(WorldTimestep);
|
||||
m_movementController->tickSlave();
|
||||
m_techController->tickSlave();
|
||||
m_statusController->tickSlave();
|
||||
m_movementController->tickSlave(dt);
|
||||
m_techController->tickSlave(dt);
|
||||
m_statusController->tickSlave(dt);
|
||||
}
|
||||
|
||||
m_humanoid->setMovingBackwards(false);
|
||||
@ -967,7 +970,7 @@ void Player::update(uint64_t) {
|
||||
m_armor->setupHumanoidClothingDrawables(*m_humanoid, forceNude());
|
||||
|
||||
m_tools->suppressItems(!canUseTool());
|
||||
m_tools->tick(m_shifting, m_pendingMoves);
|
||||
m_tools->tick(dt, m_shifting, m_pendingMoves);
|
||||
|
||||
if (auto overrideFacingDirection = m_tools->setupHumanoidHandItems(*m_humanoid, position(), aimPosition()))
|
||||
m_movementController->controlFace(*overrideFacingDirection);
|
||||
@ -976,17 +979,22 @@ void Player::update(uint64_t) {
|
||||
if (m_movementController->facingDirection() == Direction::Left)
|
||||
m_effectsAnimator->scaleTransformationGroup("flip", Vec2F(-1, 1));
|
||||
|
||||
|
||||
if (m_state == State::Walk || m_state == State::Run) {
|
||||
if ((m_footstepTimer += dt) > m_config->footstepTiming) {
|
||||
m_footstepPending = true;
|
||||
m_footstepTimer = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isClient) {
|
||||
m_effectsAnimator->update(WorldTimestep, &m_effectsAnimatorDynamicTarget);
|
||||
m_effectsAnimator->update(dt, &m_effectsAnimatorDynamicTarget);
|
||||
m_effectsAnimatorDynamicTarget.updatePosition(position() + m_techController->parentOffset());
|
||||
} else {
|
||||
m_effectsAnimator->update(WorldTimestep, nullptr);
|
||||
m_effectsAnimator->update(dt, nullptr);
|
||||
}
|
||||
|
||||
if (!isTeleporting())
|
||||
processStateChanges();
|
||||
processStateChanges(dt);
|
||||
|
||||
m_damageSources = m_tools->damageSources();
|
||||
for (auto& damageSource : m_damageSources) {
|
||||
@ -1009,7 +1017,7 @@ void Player::update(uint64_t) {
|
||||
|
||||
m_effectEmitter->setDirection(facingDirection());
|
||||
|
||||
m_effectEmitter->tick(*entityMode());
|
||||
m_effectEmitter->tick(dt, *entityMode());
|
||||
|
||||
m_humanoid->setFacingDirection(m_movementController->facingDirection());
|
||||
m_humanoid->setMovingBackwards(m_movementController->facingDirection() != m_movementController->movingDirection());
|
||||
@ -1049,19 +1057,16 @@ void Player::render(RenderCallback* renderCallback) {
|
||||
renderCallback->addAudio(move(landingNoise));
|
||||
}
|
||||
|
||||
if (m_state == State::Walk || m_state == State::Run) {
|
||||
m_footstepTimer += WorldTimestep;
|
||||
if (m_footstepTimer > m_config->footstepTiming) {
|
||||
if (m_footstepPending) {
|
||||
auto stepNoise = make_shared<AudioInstance>(*footstepAudio);
|
||||
stepNoise->setPosition(position() + feetOffset());
|
||||
stepNoise->setVolume(1 - Random::randf(0, m_footstepVolumeVariance));
|
||||
renderCallback->addAudio(move(stepNoise));
|
||||
m_footstepTimer = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_footstepTimer = m_config->footstepTiming;
|
||||
}
|
||||
m_footstepPending = false;
|
||||
m_landingNoisePending = false;
|
||||
|
||||
renderCallback->addAudios(m_effectsAnimatorDynamicTarget.pullNewAudios());
|
||||
@ -1653,7 +1658,7 @@ void Player::processControls() {
|
||||
stopLounging();
|
||||
}
|
||||
|
||||
void Player::processStateChanges() {
|
||||
void Player::processStateChanges(float dt) {
|
||||
if (isMaster()) {
|
||||
|
||||
// Set the current player state based on what movement controller tells us
|
||||
@ -1713,7 +1718,7 @@ void Player::processStateChanges() {
|
||||
}
|
||||
}
|
||||
|
||||
m_humanoid->animate(WorldTimestep);
|
||||
m_humanoid->animate(dt);
|
||||
|
||||
if (auto techState = m_techController->parentState()) {
|
||||
if (techState == TechController::ParentState::Stand) {
|
||||
@ -2260,10 +2265,10 @@ bool Player::invisible() const {
|
||||
return m_statusController->statPositive("invisible");
|
||||
}
|
||||
|
||||
void Player::animatePortrait() {
|
||||
m_humanoid->animate(WorldTimestep);
|
||||
void Player::animatePortrait(float dt) {
|
||||
m_humanoid->animate(dt);
|
||||
if (m_emoteCooldownTimer) {
|
||||
m_emoteCooldownTimer -= WorldTimestep;
|
||||
m_emoteCooldownTimer -= dt;
|
||||
if (m_emoteCooldownTimer <= 0) {
|
||||
m_emoteCooldownTimer = 0;
|
||||
m_emoteState = HumanoidEmote::Idle;
|
||||
|
@ -182,7 +182,7 @@ public:
|
||||
|
||||
Maybe<Json> receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args = {}) override;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
|
||||
@ -404,7 +404,7 @@ public:
|
||||
|
||||
bool invisible() const;
|
||||
|
||||
void animatePortrait();
|
||||
void animatePortrait(float dt);
|
||||
|
||||
bool isOutside();
|
||||
|
||||
@ -494,7 +494,7 @@ private:
|
||||
void processControls();
|
||||
|
||||
// state changes and effect animations (master and slave) that happen AFTER movement/tech controller updates
|
||||
void processStateChanges();
|
||||
void processStateChanges(float dt);
|
||||
|
||||
void getNetStates(bool initial);
|
||||
void setNetStates();
|
||||
@ -504,7 +504,7 @@ private:
|
||||
List<Particle> particles();
|
||||
String getFootstepSound(Vec2I const& sensor) const;
|
||||
|
||||
void tickShared();
|
||||
void tickShared(float dt);
|
||||
|
||||
HumanoidEmote detectEmotes(String const& chatter);
|
||||
|
||||
@ -544,6 +544,7 @@ private:
|
||||
float m_footstepVolumeVariance;
|
||||
float m_landingVolume;
|
||||
bool m_landingNoisePending;
|
||||
bool m_footstepPending;
|
||||
|
||||
String m_teleportAnimationType;
|
||||
NetworkedAnimatorPtr m_effectsAnimator;
|
||||
|
@ -114,8 +114,8 @@ Maybe<Json> PlayerCompanions::receiveMessage(String const& message, bool localMe
|
||||
return m_scriptComponent.handleMessage(message, localMessage, args);
|
||||
}
|
||||
|
||||
void PlayerCompanions::update() {
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
void PlayerCompanions::update(float dt) {
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
}
|
||||
|
||||
LuaCallbacks PlayerCompanions::makeCompanionsCallbacks() {
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
void dismissCompanion(String const& category, Uuid const& podUuid);
|
||||
|
||||
Maybe<Json> receiveMessage(String const& message, bool localMessage, JsonArray const& args = {});
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
LuaCallbacks makeCompanionsCallbacks();
|
||||
|
@ -80,8 +80,8 @@ Maybe<Json> PlayerDeployment::receiveMessage(String const& message, bool localMe
|
||||
return m_scriptComponent.handleMessage(message, localMessage, args);
|
||||
}
|
||||
|
||||
void PlayerDeployment::update() {
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
void PlayerDeployment::update(float dt) {
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
}
|
||||
|
||||
void PlayerDeployment::render(RenderCallback* renderCallback, Vec2F const& position) {
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
|
||||
void teleportOut();
|
||||
Maybe<Json> receiveMessage(String const& message, bool localMessage, JsonArray const& args = {});
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
void render(RenderCallback* renderCallback, Vec2F const& position);
|
||||
|
||||
|
@ -250,9 +250,11 @@ void Projectile::hitOther(EntityId entity, DamageRequest const&) {
|
||||
m_scriptComponent.invoke("hit", entity);
|
||||
}
|
||||
|
||||
void Projectile::update(uint64_t) {
|
||||
void Projectile::update(float dt, uint64_t) {
|
||||
m_movementController->setTimestep(dt);
|
||||
|
||||
if (isMaster()) {
|
||||
m_timeToLive -= WorldTimestep;
|
||||
m_timeToLive -= dt;
|
||||
if (m_timeToLive < 0)
|
||||
m_timeToLive = 0;
|
||||
|
||||
@ -261,17 +263,17 @@ void Projectile::update(uint64_t) {
|
||||
if (m_referenceVelocity)
|
||||
m_movementController->setVelocity(m_movementController->velocity() - *m_referenceVelocity);
|
||||
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
m_movementController->accelerate(m_movementController->velocity().normalized() * m_acceleration);
|
||||
|
||||
if (m_referenceVelocity)
|
||||
m_movementController->setVelocity(m_movementController->velocity() + *m_referenceVelocity);
|
||||
|
||||
m_movementController->tickMaster();
|
||||
m_movementController->tickMaster(dt);
|
||||
m_travelLine.min() = m_travelLine.max();
|
||||
m_travelLine.max() = m_movementController->position();
|
||||
|
||||
tickShared();
|
||||
tickShared(dt);
|
||||
|
||||
if (m_trackSourceEntity) {
|
||||
if (auto sourceEntity = world()->entity(m_sourceEntity)) {
|
||||
@ -335,13 +337,13 @@ void Projectile::update(uint64_t) {
|
||||
}
|
||||
} else {
|
||||
m_netGroup.tickNetInterpolation(WorldTimestep);
|
||||
m_movementController->tickSlave();
|
||||
m_movementController->tickSlave(dt);
|
||||
m_travelLine.min() = m_travelLine.max();
|
||||
m_travelLine.max() = m_movementController->position();
|
||||
|
||||
m_timeToLive -= WorldTimestep;
|
||||
m_timeToLive -= dt;
|
||||
|
||||
tickShared();
|
||||
tickShared(dt);
|
||||
}
|
||||
|
||||
if (world()->isClient())
|
||||
@ -853,19 +855,19 @@ void Projectile::processAction(Json const& action) {
|
||||
}
|
||||
}
|
||||
|
||||
void Projectile::tickShared() {
|
||||
void Projectile::tickShared(float dt) {
|
||||
if (!m_config->orientationLocked && !m_movementController->stickingDirection()) {
|
||||
auto apparentVelocity = m_movementController->velocity() - m_referenceVelocity.value();
|
||||
if (apparentVelocity != Vec2F())
|
||||
m_movementController->setRotation(apparentVelocity.angle());
|
||||
}
|
||||
|
||||
m_animationTimer += WorldTimestep;
|
||||
m_animationTimer += dt;
|
||||
setFrame(getFrame());
|
||||
|
||||
m_effectEmitter->setSourcePosition("normal", position());
|
||||
m_effectEmitter->setDirection(getAngleSide(m_movementController->rotation(), true).second);
|
||||
m_effectEmitter->tick(*entityMode());
|
||||
m_effectEmitter->tick(dt, *entityMode());
|
||||
|
||||
if (m_collisionEvent.pullOccurred()) {
|
||||
for (auto const& action : m_parameters.getArray("actionOnCollide", m_config->actionOnCollide))
|
||||
@ -879,7 +881,7 @@ void Projectile::tickShared() {
|
||||
if (get<0>(periodicAction).wrapTick())
|
||||
processAction(get<2>(periodicAction));
|
||||
} else {
|
||||
if (get<0>(periodicAction).tick()) {
|
||||
if (get<0>(periodicAction).tick(dt)) {
|
||||
processAction(get<2>(periodicAction));
|
||||
periodicActionIt.remove();
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
List<DamageSource> damageSources() const override;
|
||||
void hitOther(EntityId targetEntityId, DamageRequest const& dr) override;
|
||||
|
||||
void update(uint64_t currentStep) override;
|
||||
void update(float dt, uint64_t currentStep) override;
|
||||
void render(RenderCallback* renderCallback) override;
|
||||
void renderLightSources(RenderCallback* renderCallback) override;
|
||||
|
||||
@ -117,7 +117,7 @@ private:
|
||||
String drawableFrame();
|
||||
|
||||
void processAction(Json const& action);
|
||||
void tickShared();
|
||||
void tickShared(float dt);
|
||||
|
||||
void setup();
|
||||
|
||||
|
@ -342,7 +342,7 @@ Maybe<Json> QuestManager::receiveMessage(String const& message, bool localMessag
|
||||
return result;
|
||||
}
|
||||
|
||||
void QuestManager::update() {
|
||||
void QuestManager::update(float dt) {
|
||||
startInitialQuests();
|
||||
|
||||
if (m_trackedQuestId && !isActive(*m_trackedQuestId))
|
||||
@ -381,7 +381,7 @@ void QuestManager::update() {
|
||||
}
|
||||
}
|
||||
|
||||
serverQuests().exec([](QuestPtr const& quest) { quest->update(); });
|
||||
serverQuests().exec([dt](QuestPtr const& quest) { quest->update(dt); });
|
||||
}
|
||||
|
||||
List<QuestPtr> QuestManager::serverQuests() const {
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
StringSet interestingObjects();
|
||||
|
||||
Maybe<Json> receiveMessage(String const& message, bool localMessage, JsonArray const& args = {});
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
List<QuestPtr> serverQuests() const;
|
||||
|
@ -216,10 +216,10 @@ Maybe<Json> Quest::receiveMessage(String const& message, bool localMessage, Json
|
||||
return m_scriptComponent.handleMessage(message, localMessage, args);
|
||||
}
|
||||
|
||||
void Quest::update() {
|
||||
void Quest::update(float dt) {
|
||||
if (!m_inited)
|
||||
return;
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt());
|
||||
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
|
||||
}
|
||||
|
||||
void Quest::offer() {
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
void uninit();
|
||||
|
||||
Maybe<Json> receiveMessage(String const& message, bool localMessage, JsonArray const& args = {});
|
||||
void update();
|
||||
void update(float dt);
|
||||
|
||||
void offer();
|
||||
void declineOffer();
|
||||
|
@ -115,8 +115,7 @@ void Sky::stateUpdate() {
|
||||
m_lastWarpPhase = m_warpPhase;
|
||||
}
|
||||
|
||||
void Sky::update() {
|
||||
double dt = WorldTimestep;
|
||||
void Sky::update(double dt) {
|
||||
if (m_referenceClock) {
|
||||
m_time = m_referenceClock->time();
|
||||
if (!m_clockTrackingTime) {
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
// handles flying and warp state transitions
|
||||
void stateUpdate();
|
||||
void update();
|
||||
void update(double dt);
|
||||
|
||||
void setType(SkyType type);
|
||||
SkyType type() const;
|
||||
|
@ -73,7 +73,7 @@ void Spawner::activateEmptyRegion(RectF region) {
|
||||
m_activeSpawnCells[cell] = m_spawnCellLifetime;
|
||||
}
|
||||
|
||||
void Spawner::update() {
|
||||
void Spawner::update(float dt) {
|
||||
if (!m_facade)
|
||||
return;
|
||||
|
||||
@ -82,9 +82,8 @@ void Spawner::update() {
|
||||
activateRegion(window.padded(m_windowActivationBorder));
|
||||
}
|
||||
|
||||
eraseWhere(m_activeSpawnCells, [](auto& p) {
|
||||
p.second -= WorldTimestep;
|
||||
return p.second < 0.0f;
|
||||
eraseWhere(m_activeSpawnCells, [dt](auto& p) {
|
||||
return (p.second -= dt) < 0.0f;
|
||||
});
|
||||
|
||||
eraseWhere(m_spawnedEntities, [this](EntityId entityId) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user