From 9dc1eb7312a1bf5d8a606ac4e47395e5334e60f6 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sun, 17 Mar 2024 17:33:31 +1100 Subject: [PATCH] InterpolationTracker operates on time in seconds instead of steps now --- source/game/StarInterpolationTracker.cpp | 42 +++++++++++----------- source/game/StarInterpolationTracker.hpp | 26 +++++++------- source/game/StarNetPackets.cpp | 17 ++++++--- source/game/StarNetPackets.hpp | 6 ++-- source/game/StarProjectile.cpp | 2 +- source/game/StarWorldClient.cpp | 36 ++++++++++--------- source/game/StarWorldClient.hpp | 10 +++--- source/game/StarWorldServer.cpp | 36 ++++++++++--------- source/game/StarWorldServer.hpp | 11 +++--- source/game/interfaces/StarWorld.hpp | 2 +- source/game/objects/StarFarmableObject.cpp | 2 +- 11 files changed, 107 insertions(+), 83 deletions(-) diff --git a/source/game/StarInterpolationTracker.cpp b/source/game/StarInterpolationTracker.cpp index fb1188c..86259d2 100644 --- a/source/game/StarInterpolationTracker.cpp +++ b/source/game/StarInterpolationTracker.cpp @@ -4,6 +4,8 @@ namespace Star { +constexpr double VanillaStepsPerSecond = 60.0; + InterpolationTracker::InterpolationTracker(Json config) { if (config.isNull()) { config = JsonObject(); @@ -13,13 +15,13 @@ InterpolationTracker::InterpolationTracker(Json config) { } m_interpolationEnabled = config.getBool("interpolationEnabled", false); - m_entityUpdateDelta = config.getUInt("entityUpdateDelta", 3); - m_stepLead = config.getUInt("stepLead", 0); + m_entityUpdateDelta = config.getDouble("entityUpdateDelta", 3) / VanillaStepsPerSecond; + m_timeLead = config.getDouble("stepLead", 0) / VanillaStepsPerSecond; m_extrapolationHint = config.getUInt("extrapolationHint", 0); - m_stepTrackFactor = config.getDouble("stepTrackFactor", 1.0); - m_stepMaxDistance = config.getDouble("stepMaxDistance", 0.0); + m_timeTrackFactor = config.getDouble("stepTrackFactor", 1.0); + m_timeMaxDistance = config.getDouble("stepMaxDistance", 0.0) / VanillaStepsPerSecond; - m_currentStep = 0.0; + m_currentTime = 0.0; } bool InterpolationTracker::interpolationEnabled() const { @@ -33,31 +35,31 @@ unsigned InterpolationTracker::extrapolationHint() const { return 0; } -unsigned InterpolationTracker::entityUpdateDelta() const { +float InterpolationTracker::entityUpdateDelta() const { return m_entityUpdateDelta; } -void InterpolationTracker::receiveStepUpdate(double remoteStep) { - m_lastStepUpdate = remoteStep; +void InterpolationTracker::receiveTimeUpdate(double remoteStep) { + m_lastTimeUpdate = remoteStep; } -void InterpolationTracker::update(double newLocalStep) { - double dt = newLocalStep - m_currentStep; - m_currentStep = newLocalStep; - if (!m_predictedStep || !m_lastStepUpdate || dt < 0.0f) { - m_predictedStep = m_lastStepUpdate; +void InterpolationTracker::update(double newLocalTime) { + double dt = newLocalTime - m_currentTime; + m_currentTime = newLocalTime; + if (!m_predictedTime || !m_lastTimeUpdate || dt < 0.0f) { + m_predictedTime = m_lastTimeUpdate; } else { - *m_lastStepUpdate += dt; - *m_predictedStep += dt; - *m_predictedStep += (*m_lastStepUpdate - *m_predictedStep) * m_stepTrackFactor; - m_predictedStep = clamp(*m_predictedStep, *m_lastStepUpdate - m_stepMaxDistance, *m_lastStepUpdate + m_stepMaxDistance); + *m_lastTimeUpdate += dt; + *m_predictedTime += dt; + *m_predictedTime += (*m_lastTimeUpdate - *m_predictedTime) * m_timeTrackFactor; + m_predictedTime = clamp(*m_predictedTime, *m_lastTimeUpdate - m_timeMaxDistance, *m_lastTimeUpdate + m_timeMaxDistance); } } -float InterpolationTracker::interpolationLeadSteps() const { - if (!m_interpolationEnabled || !m_predictedStep || !m_lastStepUpdate) +float InterpolationTracker::interpolationLeadTime() const { + if (!m_interpolationEnabled || !m_predictedTime || !m_lastTimeUpdate) return 0.0f; - return *m_lastStepUpdate - *m_predictedStep + m_stepLead; + return *m_lastTimeUpdate - *m_predictedTime + m_timeLead; } } diff --git a/source/game/StarInterpolationTracker.hpp b/source/game/StarInterpolationTracker.hpp index 336f461..1233c5f 100644 --- a/source/game/StarInterpolationTracker.hpp +++ b/source/game/StarInterpolationTracker.hpp @@ -13,27 +13,27 @@ public: bool interpolationEnabled() const; unsigned extrapolationHint() const; - // Steps in between entity updates - unsigned entityUpdateDelta() const; + // Time in-between entity updates + float entityUpdateDelta() const; - void receiveStepUpdate(double remoteStep); - void update(double newLocalStep); + void receiveTimeUpdate(double remoteTime); + void update(double newLocalTime); - // Lead steps that incoming interpolated data as of this moment should be + // Lead time that incoming interpolated data as of this moment should be // marked for. If interpolation is disabled, this is always 0.0 - float interpolationLeadSteps() const; + float interpolationLeadTime() const; private: bool m_interpolationEnabled; - unsigned m_entityUpdateDelta; - unsigned m_stepLead; + float m_entityUpdateDelta; + double m_timeLead; unsigned m_extrapolationHint; - double m_stepTrackFactor; - double m_stepMaxDistance; + double m_timeTrackFactor; + double m_timeMaxDistance; - double m_currentStep; - Maybe m_lastStepUpdate; - Maybe m_predictedStep; + double m_currentTime; + Maybe m_lastTimeUpdate; + Maybe m_predictedTime; }; } diff --git a/source/game/StarNetPackets.cpp b/source/game/StarNetPackets.cpp index 2f03283..aa3947e 100644 --- a/source/game/StarNetPackets.cpp +++ b/source/game/StarNetPackets.cpp @@ -1103,16 +1103,25 @@ void PongPacket::write(DataStream& ds) const { ds.write(false); } -StepUpdatePacket::StepUpdatePacket() : remoteStep(0) {} +StepUpdatePacket::StepUpdatePacket() : remoteTime(0.0) {} -StepUpdatePacket::StepUpdatePacket(uint64_t remoteStep) : remoteStep(remoteStep) {} +StepUpdatePacket::StepUpdatePacket(double remoteStep) : remoteTime(remoteTime) {} + +void StepUpdatePacket::readLegacy(DataStream& ds) { + auto steps = ds.readVlqU(); + remoteTime = double(steps) / 60.0; +} void StepUpdatePacket::read(DataStream& ds) { - ds.vuread(remoteStep); + ds.write(remoteTime); +} + +void StepUpdatePacket::writeLegacy(DataStream& ds) const { + ds.writeVlqU((uint64_t)round(remoteTime * 60.0)); } void StepUpdatePacket::write(DataStream& ds) const { - ds.vuwrite(remoteStep); + ds.write(remoteTime); } SystemWorldStartPacket::SystemWorldStartPacket() {} diff --git a/source/game/StarNetPackets.hpp b/source/game/StarNetPackets.hpp index dd2acfa..432dca4 100644 --- a/source/game/StarNetPackets.hpp +++ b/source/game/StarNetPackets.hpp @@ -820,12 +820,14 @@ struct UpdateWorldPropertiesPacket : PacketBase { StepUpdatePacket(); - StepUpdatePacket(uint64_t remoteStep); + StepUpdatePacket(double remoteTime); + void readLegacy(DataStream& ds) override; void read(DataStream& ds) override; + void writeLegacy(DataStream& ds) const override; void write(DataStream& ds) const override; - uint64_t remoteStep; + double remoteTime; }; struct SystemWorldStartPacket : PacketBase { diff --git a/source/game/StarProjectile.cpp b/source/game/StarProjectile.cpp index 116fd08..cfb93ba 100644 --- a/source/game/StarProjectile.cpp +++ b/source/game/StarProjectile.cpp @@ -572,7 +572,7 @@ void Projectile::processAction(Json const& action) { if (stepsDelay == 0) function(world()); else - world()->timer(stepsDelay, function); + world()->timer((float)stepsDelay / 60.f, function); }; if (command == "tile") { diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index b60e2c2..1068c2b 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -35,7 +35,7 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) { m_clientConfig = assets->json("/client.config"); m_currentStep = 0; - m_currentServerStep = 0.0; + m_currentTime = 0; m_fullBright = false; m_asyncLighting = false; m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime")); @@ -184,11 +184,11 @@ SkyConstPtr WorldClient::currentSky() const { return m_sky; } -void WorldClient::timer(int stepsDelay, WorldAction worldAction) { +void WorldClient::timer(float delay, WorldAction worldAction) { if (!inWorld()) return; - m_timers.append({stepsDelay, worldAction}); + m_timers.append({delay, worldAction}); } EntityPtr WorldClient::closestEntity(Vec2F const& center, float radius, EntityFilter selector) const { @@ -788,13 +788,13 @@ void WorldClient::handleIncomingPackets(List const& packets) { // Delay appearance of new slaved entities to match with interplation // state. m_startupHiddenEntities.add(entityCreate->entityId); - timer(round(m_interpolationTracker.interpolationLeadSteps()), [this, entityId = entityCreate->entityId](World*) { + timer(m_interpolationTracker.interpolationLeadTime(), [this, entityId = entityCreate->entityId](World*) { m_startupHiddenEntities.remove(entityId); }); } } else if (auto entityUpdateSet = as(packet)) { - float interpolationLeadTime = m_interpolationTracker.interpolationLeadSteps() * GlobalTimestep; + float interpolationLeadTime = m_interpolationTracker.interpolationLeadTime(); m_entityMap->forAllEntities([&](EntityPtr const& entity) { EntityId entityId = entity->entityId(); if (connectionForEntity(entityId) == entityUpdateSet->forConnection) { @@ -805,7 +805,7 @@ void WorldClient::handleIncomingPackets(List const& packets) { } else if (auto entityDestroy = as(packet)) { if (auto entity = m_entityMap->entity(entityDestroy->entityId)) { - entity->readNetState(entityDestroy->finalNetState, m_interpolationTracker.interpolationLeadSteps() * GlobalTimestep); + entity->readNetState(entityDestroy->finalNetState, m_interpolationTracker.interpolationLeadTime()); // Before destroying the entity, we should make sure that the entity is // using the absolute latest data, so we disable interpolation. @@ -813,7 +813,7 @@ void WorldClient::handleIncomingPackets(List const& packets) { if (m_interpolationTracker.interpolationEnabled() && entityDestroy->death) { // Delay death packets by the interpolation step to give time for // interpolation to catch up. - timer(round(m_interpolationTracker.interpolationLeadSteps()), [this, entity, entityDestroy](World*) { + timer(m_interpolationTracker.interpolationLeadTime(), [this, entity, entityDestroy](World*) { entity->disableInterpolation(); removeEntity(entityDestroy->entityId, entityDestroy->death); }); @@ -917,8 +917,7 @@ void WorldClient::handleIncomingPackets(List const& packets) { tryGiveMainPlayerItem(itemDatabase->item(giveItem->item)); } else if (auto stepUpdate = as(packet)) { - m_currentServerStep = ((double)stepUpdate->remoteStep * (GlobalTimestep / ServerGlobalTimestep)); - m_interpolationTracker.receiveStepUpdate(m_currentServerStep); + m_interpolationTracker.receiveTimeUpdate(stepUpdate->remoteTime); } else if (auto environmentUpdatePacket = as(packet)) { m_sky->readUpdate(environmentUpdatePacket->skyDelta); @@ -1118,17 +1117,18 @@ void WorldClient::update(float dt) { m_mainPlayer->effectsAnimator()->setGlobalTag("\0SE_VOICE_SIGNING_KEY"s, publicKeyString); ++m_currentStep; - //m_interpolationTracker.update(m_currentStep); - m_interpolationTracker.update(Time::monotonicTime()); + m_currentTime += dt; + m_interpolationTracker.update(m_currentTime); List triggeredActions; - eraseWhere(m_timers, [&triggeredActions](pair& timer) { - if (--timer.first <= 0) { + eraseWhere(m_timers, [&triggeredActions, dt](pair& timer) { + if ((timer.first -= dt) <= 0) { triggeredActions.append(timer.second); return true; } return false; }); + for (auto const& action : triggeredActions) action(this); @@ -1232,7 +1232,7 @@ void WorldClient::update(float dt) { for (EntityId entityId : toRemove) removeEntity(entityId, true); - queueUpdatePackets(); + queueUpdatePackets(m_entityUpdateTimer.wrapTick(dt)); if (m_pingTime.isNothing()) { m_pingTime = Time::monotonicMilliseconds(); @@ -1432,7 +1432,7 @@ void WorldClient::setTileProtection(DungeonId dungeonId, bool isProtected) { } } -void WorldClient::queueUpdatePackets() { +void WorldClient::queueUpdatePackets(bool sendEntityUpdates) { auto& root = Root::singleton(); auto assets = root.assets(); auto entityFactory = root.entityFactory(); @@ -1444,7 +1444,7 @@ void WorldClient::queueUpdatePackets() { m_entityMap->forAllEntities([&](EntityPtr const& entity) { notifyEntityCreate(entity); }); - if (m_currentStep % m_interpolationTracker.entityUpdateDelta() == 0) { + if (sendEntityUpdates) { auto entityUpdateSet = make_shared(); entityUpdateSet->forConnection = *m_clientId; m_entityMap->forAllEntities([&](EntityPtr const& entity) { @@ -1677,6 +1677,8 @@ void WorldClient::initWorld(WorldStartPacket const& startPacket) { else m_interpolationTracker = InterpolationTracker(m_clientConfig.query("interpolationSettings.normal")); + m_entityUpdateTimer = GameTimer(m_interpolationTracker.entityUpdateDelta()); + m_clientId = startPacket.clientId; auto entitySpace = connectionEntitySpace(startPacket.clientId); m_worldTemplate = make_shared(startPacket.templateData); @@ -1757,7 +1759,7 @@ void WorldClient::clearWorld() { waitForLighting(); m_currentStep = 0; - m_currentServerStep = 0.0; + m_currentTime = 0; m_inWorld = false; m_clientId.reset(); diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp index 56a24e5..3fe66eb 100644 --- a/source/game/StarWorldClient.hpp +++ b/source/game/StarWorldClient.hpp @@ -14,6 +14,7 @@ #include "StarWorld.hpp" #include "StarGameTimers.hpp" #include "StarLuaRoot.hpp" +#include "StarTickRateMonitor.hpp" namespace Star { @@ -88,7 +89,7 @@ public: List forceRegions() const override; Json getProperty(String const& propertyName, Json const& def = Json()) const override; void setProperty(String const& propertyName, Json const& property) override; - void timer(int stepsDelay, WorldAction worldAction) override; + void timer(float delay, WorldAction worldAction) override; double epochTime() const override; uint32_t day() const override; float dayLength() const override; @@ -218,7 +219,7 @@ private: void notifyEntityCreate(EntityPtr const& entity); // Queues pending (step based) updates to server, - void queueUpdatePackets(); + void queueUpdatePackets(bool sendEntityUpdates); void handleDamageNotifications(); void sparkDamagedBlocks(); @@ -262,7 +263,7 @@ private: WorldGeometry m_geometry; uint64_t m_currentStep; - double m_currentServerStep; + double m_currentTime; bool m_fullBright; bool m_asyncLighting; CellularLightingCalculator m_lightingCalculator; @@ -312,6 +313,7 @@ private: HashMap m_masterEntitiesNetVersion; InterpolationTracker m_interpolationTracker; + GameTimer m_entityUpdateTimer; List m_outgoingPackets; Maybe m_pingTime; @@ -333,7 +335,7 @@ private: AmbientManager m_musicTrack; AmbientManager m_altMusicTrack; - List> m_timers; + List> m_timers; Map m_damageNumbers; float m_damageNotificationBatchDuration; diff --git a/source/game/StarWorldServer.cpp b/source/game/StarWorldServer.cpp index e28c666..876e98c 100644 --- a/source/game/StarWorldServer.cpp +++ b/source/game/StarWorldServer.cpp @@ -241,9 +241,10 @@ bool WorldServer::addClient(ConnectionId clientId, SpawnTarget const& spawnTarge else tracker = InterpolationTracker(m_serverConfig.query("interpolationSettings.normal")); - tracker.update(m_currentStep); + tracker.update(m_currentTime); - auto clientInfo = m_clientInfo.add(clientId, make_shared(clientId, tracker)); + auto& clientInfo = m_clientInfo.add(clientId, make_shared(clientId, tracker)); + clientInfo->local = isLocal; auto worldStartPacket = make_shared(); worldStartPacket->templateData = m_worldTemplate->store(); @@ -340,7 +341,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List c continue; } else if (auto heartbeat = as(packet)) { - clientInfo->interpolationTracker.receiveStepUpdate(heartbeat->remoteStep); + clientInfo->interpolationTracker.receiveTimeUpdate(heartbeat->remoteTime); } else if (auto wcsPacket = as(packet)) { clientInfo->clientState.readDelta(wcsPacket->worldClientStateDelta); @@ -430,7 +431,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List c } } else if (auto entityUpdateSet = as(packet)) { - float interpolationLeadTime = clientInfo->interpolationTracker.interpolationLeadSteps() * GlobalTimestep; + float interpolationLeadTime = clientInfo->interpolationTracker.interpolationLeadTime(); m_entityMap->forAllEntities([&](EntityPtr const& entity) { EntityId entityId = entity->entityId(); if (connectionForEntity(entityId) == clientId) { @@ -442,7 +443,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List c } else if (auto entityDestroy = as(packet)) { if (auto entity = m_entityMap->entity(entityDestroy->entityId)) { - entity->readNetState(entityDestroy->finalNetState, clientInfo->interpolationTracker.interpolationLeadSteps() * GlobalTimestep); + entity->readNetState(entityDestroy->finalNetState, clientInfo->interpolationTracker.interpolationLeadTime()); // Before destroying the entity, we should make sure that the entity is // using the absolute latest data, so we disable interpolation. entity->disableInterpolation(); @@ -565,13 +566,13 @@ void WorldServer::setExpiryTime(float expiryTime) { } void WorldServer::update(float dt) { - ++m_currentStep; + m_currentTime += dt; for (auto const& pair : m_clientInfo) - pair.second->interpolationTracker.update(m_currentStep); + pair.second->interpolationTracker.update(m_currentTime); List triggeredActions; - eraseWhere(m_timers, [&triggeredActions](pair& timer) { - if (--timer.first <= 0) { + eraseWhere(m_timers, [&triggeredActions, dt](pair& timer) { + if ((timer.first -= dt) <= 0) { triggeredActions.append(timer.second); return true; } @@ -582,7 +583,7 @@ void WorldServer::update(float dt) { m_spawner.update(dt); - bool doBreakChecks = m_tileEntityBreakCheckTimer.wrapTick(m_currentStep) && m_needsGlobalBreakCheck; + bool doBreakChecks = m_tileEntityBreakCheckTimer.wrapTick(m_currentTime) && m_needsGlobalBreakCheck; if (doBreakChecks) m_needsGlobalBreakCheck = false; @@ -661,10 +662,11 @@ void WorldServer::update(float dt) { for (EntityId entityId : toRemove) removeEntity(entityId, true); + bool sendRemoteUpdates = m_entityUpdateTimer.wrapTick(dt); for (auto const& pair : m_clientInfo) { for (auto const& monitoredRegion : pair.second->monitoringRegions(m_entityMap)) signalRegion(monitoredRegion.padded(jsonToVec2I(m_serverConfig.get("playerActiveRegionPad")))); - queueUpdatePackets(pair.first); + queueUpdatePackets(pair.first, sendRemoteUpdates); } m_netStateCache.clear(); @@ -1236,6 +1238,7 @@ void WorldServer::init(bool firstTime) { m_worldStorage->setFloatingDungeonWorld(isFloatingDungeonWorld()); + m_currentTime = 0; m_currentStep = 0; m_generatingDungeon = false; m_geometry = WorldGeometry(m_worldTemplate->size()); @@ -1258,6 +1261,7 @@ void WorldServer::init(bool firstTime) { return m_tileArray->tile({x, y}).getCollision(); }); + m_entityUpdateTimer = GameTimer(m_serverConfig.query("interpolationSettings.normal").getFloat("entityUpdateDelta") / 60.f); m_tileEntityBreakCheckTimer = GameTimer(m_serverConfig.getFloat("tileEntityBreakCheckInterval")); m_liquidEngine = make_shared>(liquidsDatabase->liquidEngineParameters(), make_shared(this)); @@ -1756,9 +1760,9 @@ List WorldServer::destroyBlock(TileLayer layer, Vec2I const& pos return drops; } -void WorldServer::queueUpdatePackets(ConnectionId clientId) { +void WorldServer::queueUpdatePackets(ConnectionId clientId, bool sendRemoteUpdates) { auto const& clientInfo = m_clientInfo.get(clientId); - clientInfo->outgoingPackets.append(make_shared(m_currentStep)); + clientInfo->outgoingPackets.append(make_shared(m_currentTime)); if (shouldRunThisStep("environmentUpdate")) { ByteArray skyDelta; @@ -1828,7 +1832,7 @@ void WorldServer::queueUpdatePackets(ConnectionId clientId) { } HashMap> updateSetPackets; - if (m_currentStep % clientInfo->interpolationTracker.entityUpdateDelta() == 0) + if (sendRemoteUpdates || clientInfo->local) updateSetPackets.add(ServerConnectionId, make_shared(ServerConnectionId)); for (auto const& p : m_clientInfo) { if (p.first != clientId && p.second->pendingForward) @@ -2149,8 +2153,8 @@ void WorldServer::setProperty(String const& propertyName, Json const& property) } } -void WorldServer::timer(int stepsDelay, WorldAction worldAction) { - m_timers.append({stepsDelay, worldAction}); +void WorldServer::timer(float delay, WorldAction worldAction) { + m_timers.append({delay, worldAction}); } void WorldServer::startFlyingSky(bool enterHyperspace, bool startInWarp) { diff --git a/source/game/StarWorldServer.hpp b/source/game/StarWorldServer.hpp index 7142d51..4c11217 100644 --- a/source/game/StarWorldServer.hpp +++ b/source/game/StarWorldServer.hpp @@ -169,7 +169,7 @@ public: List forceRegions() const override; Json getProperty(String const& propertyName, Json const& def = Json()) const override; void setProperty(String const& propertyName, Json const& property) override; - void timer(int stepsDelay, WorldAction worldAction) override; + void timer(float delay, WorldAction worldAction) override; double epochTime() const override; uint32_t day() const override; float dayLength() const override; @@ -275,6 +275,7 @@ private: WorldClientState clientState; bool pendingForward; bool started; + bool local; List outgoingPackets; @@ -308,7 +309,7 @@ private: TileModificationList doApplyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap, bool ignoreTileProtection = false); // Queues pending (step based) updates to the given player - void queueUpdatePackets(ConnectionId clientId); + void queueUpdatePackets(ConnectionId clientId, bool sendRemoteUpdates); void updateDamage(float dt); void updateDamagedBlocks(float dt); @@ -361,7 +362,8 @@ private: StringMap m_scriptContexts; WorldGeometry m_geometry; - uint64_t m_currentStep{}; + double m_currentTime; + uint64_t m_currentStep; mutable CellularLightIntensityCalculator m_lightIntensityCalculator; SkyPtr m_sky; @@ -373,6 +375,7 @@ private: HashMap, pair> m_netStateCache; OrderedHashMap> m_clientInfo; + GameTimer m_entityUpdateTimer; GameTimer m_tileEntityBreakCheckTimer; shared_ptr> m_liquidEngine; @@ -384,7 +387,7 @@ private: // is removed / uninitialized HashMap m_tileEntitySpaces; - List> m_timers; + List> m_timers; bool m_needsGlobalBreakCheck; diff --git a/source/game/interfaces/StarWorld.hpp b/source/game/interfaces/StarWorld.hpp index 95fe7ae..d718786 100644 --- a/source/game/interfaces/StarWorld.hpp +++ b/source/game/interfaces/StarWorld.hpp @@ -130,7 +130,7 @@ public: virtual Json getProperty(String const& propertyName, Json const& def = {}) const = 0; virtual void setProperty(String const& propertyName, Json const& property) = 0; - virtual void timer(int stepsDelay, WorldAction worldAction) = 0; + virtual void timer(float delay, WorldAction worldAction) = 0; virtual double epochTime() const = 0; virtual uint32_t day() const = 0; virtual float dayLength() const = 0; diff --git a/source/game/objects/StarFarmableObject.cpp b/source/game/objects/StarFarmableObject.cpp index 8504b64..cfb550d 100644 --- a/source/game/objects/StarFarmableObject.cpp +++ b/source/game/objects/StarFarmableObject.cpp @@ -131,7 +131,7 @@ void FarmableObject::enterStage(int newStage) { if (anySpacesOccupied(plant->spaces()) || !allSpacesOccupied(plant->roots())) { newStage = 0; } else { - world()->timer(2, [plant](World* world) { + world()->timer(2.f / 60.f, [plant](World* world) { world->addEntity(plant); });