InterpolationTracker operates on time in seconds instead of steps now
This commit is contained in:
parent
4e0d7598e1
commit
9dc1eb7312
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
|
constexpr double VanillaStepsPerSecond = 60.0;
|
||||||
|
|
||||||
InterpolationTracker::InterpolationTracker(Json config) {
|
InterpolationTracker::InterpolationTracker(Json config) {
|
||||||
if (config.isNull()) {
|
if (config.isNull()) {
|
||||||
config = JsonObject();
|
config = JsonObject();
|
||||||
@ -13,13 +15,13 @@ InterpolationTracker::InterpolationTracker(Json config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_interpolationEnabled = config.getBool("interpolationEnabled", false);
|
m_interpolationEnabled = config.getBool("interpolationEnabled", false);
|
||||||
m_entityUpdateDelta = config.getUInt("entityUpdateDelta", 3);
|
m_entityUpdateDelta = config.getDouble("entityUpdateDelta", 3) / VanillaStepsPerSecond;
|
||||||
m_stepLead = config.getUInt("stepLead", 0);
|
m_timeLead = config.getDouble("stepLead", 0) / VanillaStepsPerSecond;
|
||||||
m_extrapolationHint = config.getUInt("extrapolationHint", 0);
|
m_extrapolationHint = config.getUInt("extrapolationHint", 0);
|
||||||
m_stepTrackFactor = config.getDouble("stepTrackFactor", 1.0);
|
m_timeTrackFactor = config.getDouble("stepTrackFactor", 1.0);
|
||||||
m_stepMaxDistance = config.getDouble("stepMaxDistance", 0.0);
|
m_timeMaxDistance = config.getDouble("stepMaxDistance", 0.0) / VanillaStepsPerSecond;
|
||||||
|
|
||||||
m_currentStep = 0.0;
|
m_currentTime = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterpolationTracker::interpolationEnabled() const {
|
bool InterpolationTracker::interpolationEnabled() const {
|
||||||
@ -33,31 +35,31 @@ unsigned InterpolationTracker::extrapolationHint() const {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned InterpolationTracker::entityUpdateDelta() const {
|
float InterpolationTracker::entityUpdateDelta() const {
|
||||||
return m_entityUpdateDelta;
|
return m_entityUpdateDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpolationTracker::receiveStepUpdate(double remoteStep) {
|
void InterpolationTracker::receiveTimeUpdate(double remoteStep) {
|
||||||
m_lastStepUpdate = remoteStep;
|
m_lastTimeUpdate = remoteStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpolationTracker::update(double newLocalStep) {
|
void InterpolationTracker::update(double newLocalTime) {
|
||||||
double dt = newLocalStep - m_currentStep;
|
double dt = newLocalTime - m_currentTime;
|
||||||
m_currentStep = newLocalStep;
|
m_currentTime = newLocalTime;
|
||||||
if (!m_predictedStep || !m_lastStepUpdate || dt < 0.0f) {
|
if (!m_predictedTime || !m_lastTimeUpdate || dt < 0.0f) {
|
||||||
m_predictedStep = m_lastStepUpdate;
|
m_predictedTime = m_lastTimeUpdate;
|
||||||
} else {
|
} else {
|
||||||
*m_lastStepUpdate += dt;
|
*m_lastTimeUpdate += dt;
|
||||||
*m_predictedStep += dt;
|
*m_predictedTime += dt;
|
||||||
*m_predictedStep += (*m_lastStepUpdate - *m_predictedStep) * m_stepTrackFactor;
|
*m_predictedTime += (*m_lastTimeUpdate - *m_predictedTime) * m_timeTrackFactor;
|
||||||
m_predictedStep = clamp<double>(*m_predictedStep, *m_lastStepUpdate - m_stepMaxDistance, *m_lastStepUpdate + m_stepMaxDistance);
|
m_predictedTime = clamp<double>(*m_predictedTime, *m_lastTimeUpdate - m_timeMaxDistance, *m_lastTimeUpdate + m_timeMaxDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float InterpolationTracker::interpolationLeadSteps() const {
|
float InterpolationTracker::interpolationLeadTime() const {
|
||||||
if (!m_interpolationEnabled || !m_predictedStep || !m_lastStepUpdate)
|
if (!m_interpolationEnabled || !m_predictedTime || !m_lastTimeUpdate)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
return *m_lastStepUpdate - *m_predictedStep + m_stepLead;
|
return *m_lastTimeUpdate - *m_predictedTime + m_timeLead;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,27 +13,27 @@ public:
|
|||||||
bool interpolationEnabled() const;
|
bool interpolationEnabled() const;
|
||||||
unsigned extrapolationHint() const;
|
unsigned extrapolationHint() const;
|
||||||
|
|
||||||
// Steps in between entity updates
|
// Time in-between entity updates
|
||||||
unsigned entityUpdateDelta() const;
|
float entityUpdateDelta() const;
|
||||||
|
|
||||||
void receiveStepUpdate(double remoteStep);
|
void receiveTimeUpdate(double remoteTime);
|
||||||
void update(double newLocalStep);
|
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
|
// marked for. If interpolation is disabled, this is always 0.0
|
||||||
float interpolationLeadSteps() const;
|
float interpolationLeadTime() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_interpolationEnabled;
|
bool m_interpolationEnabled;
|
||||||
unsigned m_entityUpdateDelta;
|
float m_entityUpdateDelta;
|
||||||
unsigned m_stepLead;
|
double m_timeLead;
|
||||||
unsigned m_extrapolationHint;
|
unsigned m_extrapolationHint;
|
||||||
double m_stepTrackFactor;
|
double m_timeTrackFactor;
|
||||||
double m_stepMaxDistance;
|
double m_timeMaxDistance;
|
||||||
|
|
||||||
double m_currentStep;
|
double m_currentTime;
|
||||||
Maybe<double> m_lastStepUpdate;
|
Maybe<double> m_lastTimeUpdate;
|
||||||
Maybe<double> m_predictedStep;
|
Maybe<double> m_predictedTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1103,16 +1103,25 @@ void PongPacket::write(DataStream& ds) const {
|
|||||||
ds.write<bool>(false);
|
ds.write<bool>(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) {
|
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 {
|
void StepUpdatePacket::write(DataStream& ds) const {
|
||||||
ds.vuwrite(remoteStep);
|
ds.write(remoteTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemWorldStartPacket::SystemWorldStartPacket() {}
|
SystemWorldStartPacket::SystemWorldStartPacket() {}
|
||||||
|
@ -820,12 +820,14 @@ struct UpdateWorldPropertiesPacket : PacketBase<PacketType::UpdateWorldPropertie
|
|||||||
|
|
||||||
struct StepUpdatePacket : PacketBase<PacketType::StepUpdate> {
|
struct StepUpdatePacket : PacketBase<PacketType::StepUpdate> {
|
||||||
StepUpdatePacket();
|
StepUpdatePacket();
|
||||||
StepUpdatePacket(uint64_t remoteStep);
|
StepUpdatePacket(double remoteTime);
|
||||||
|
|
||||||
|
void readLegacy(DataStream& ds) override;
|
||||||
void read(DataStream& ds) override;
|
void read(DataStream& ds) override;
|
||||||
|
void writeLegacy(DataStream& ds) const override;
|
||||||
void write(DataStream& ds) const override;
|
void write(DataStream& ds) const override;
|
||||||
|
|
||||||
uint64_t remoteStep;
|
double remoteTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SystemWorldStartPacket : PacketBase<PacketType::SystemWorldStart> {
|
struct SystemWorldStartPacket : PacketBase<PacketType::SystemWorldStart> {
|
||||||
|
@ -572,7 +572,7 @@ void Projectile::processAction(Json const& action) {
|
|||||||
if (stepsDelay == 0)
|
if (stepsDelay == 0)
|
||||||
function(world());
|
function(world());
|
||||||
else
|
else
|
||||||
world()->timer(stepsDelay, function);
|
world()->timer((float)stepsDelay / 60.f, function);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (command == "tile") {
|
if (command == "tile") {
|
||||||
|
@ -35,7 +35,7 @@ WorldClient::WorldClient(PlayerPtr mainPlayer) {
|
|||||||
m_clientConfig = assets->json("/client.config");
|
m_clientConfig = assets->json("/client.config");
|
||||||
|
|
||||||
m_currentStep = 0;
|
m_currentStep = 0;
|
||||||
m_currentServerStep = 0.0;
|
m_currentTime = 0;
|
||||||
m_fullBright = false;
|
m_fullBright = false;
|
||||||
m_asyncLighting = false;
|
m_asyncLighting = false;
|
||||||
m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime"));
|
m_worldDimTimer = GameTimer(m_clientConfig.getFloat("worldDimTime"));
|
||||||
@ -184,11 +184,11 @@ SkyConstPtr WorldClient::currentSky() const {
|
|||||||
return m_sky;
|
return m_sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldClient::timer(int stepsDelay, WorldAction worldAction) {
|
void WorldClient::timer(float delay, WorldAction worldAction) {
|
||||||
if (!inWorld())
|
if (!inWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_timers.append({stepsDelay, worldAction});
|
m_timers.append({delay, worldAction});
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityPtr WorldClient::closestEntity(Vec2F const& center, float radius, EntityFilter selector) const {
|
EntityPtr WorldClient::closestEntity(Vec2F const& center, float radius, EntityFilter selector) const {
|
||||||
@ -788,13 +788,13 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
|||||||
// Delay appearance of new slaved entities to match with interplation
|
// Delay appearance of new slaved entities to match with interplation
|
||||||
// state.
|
// state.
|
||||||
m_startupHiddenEntities.add(entityCreate->entityId);
|
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);
|
m_startupHiddenEntities.remove(entityId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (auto entityUpdateSet = as<EntityUpdateSetPacket>(packet)) {
|
} else if (auto entityUpdateSet = as<EntityUpdateSetPacket>(packet)) {
|
||||||
float interpolationLeadTime = m_interpolationTracker.interpolationLeadSteps() * GlobalTimestep;
|
float interpolationLeadTime = m_interpolationTracker.interpolationLeadTime();
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
||||||
EntityId entityId = entity->entityId();
|
EntityId entityId = entity->entityId();
|
||||||
if (connectionForEntity(entityId) == entityUpdateSet->forConnection) {
|
if (connectionForEntity(entityId) == entityUpdateSet->forConnection) {
|
||||||
@ -805,7 +805,7 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
|||||||
|
|
||||||
} else if (auto entityDestroy = as<EntityDestroyPacket>(packet)) {
|
} else if (auto entityDestroy = as<EntityDestroyPacket>(packet)) {
|
||||||
if (auto entity = m_entityMap->entity(entityDestroy->entityId)) {
|
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
|
// Before destroying the entity, we should make sure that the entity is
|
||||||
// using the absolute latest data, so we disable interpolation.
|
// using the absolute latest data, so we disable interpolation.
|
||||||
@ -813,7 +813,7 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
|||||||
if (m_interpolationTracker.interpolationEnabled() && entityDestroy->death) {
|
if (m_interpolationTracker.interpolationEnabled() && entityDestroy->death) {
|
||||||
// Delay death packets by the interpolation step to give time for
|
// Delay death packets by the interpolation step to give time for
|
||||||
// interpolation to catch up.
|
// interpolation to catch up.
|
||||||
timer(round(m_interpolationTracker.interpolationLeadSteps()), [this, entity, entityDestroy](World*) {
|
timer(m_interpolationTracker.interpolationLeadTime(), [this, entity, entityDestroy](World*) {
|
||||||
entity->disableInterpolation();
|
entity->disableInterpolation();
|
||||||
removeEntity(entityDestroy->entityId, entityDestroy->death);
|
removeEntity(entityDestroy->entityId, entityDestroy->death);
|
||||||
});
|
});
|
||||||
@ -917,8 +917,7 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
|||||||
tryGiveMainPlayerItem(itemDatabase->item(giveItem->item));
|
tryGiveMainPlayerItem(itemDatabase->item(giveItem->item));
|
||||||
|
|
||||||
} else if (auto stepUpdate = as<StepUpdatePacket>(packet)) {
|
} else if (auto stepUpdate = as<StepUpdatePacket>(packet)) {
|
||||||
m_currentServerStep = ((double)stepUpdate->remoteStep * (GlobalTimestep / ServerGlobalTimestep));
|
m_interpolationTracker.receiveTimeUpdate(stepUpdate->remoteTime);
|
||||||
m_interpolationTracker.receiveStepUpdate(m_currentServerStep);
|
|
||||||
|
|
||||||
} else if (auto environmentUpdatePacket = as<EnvironmentUpdatePacket>(packet)) {
|
} else if (auto environmentUpdatePacket = as<EnvironmentUpdatePacket>(packet)) {
|
||||||
m_sky->readUpdate(environmentUpdatePacket->skyDelta);
|
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_mainPlayer->effectsAnimator()->setGlobalTag("\0SE_VOICE_SIGNING_KEY"s, publicKeyString);
|
||||||
|
|
||||||
++m_currentStep;
|
++m_currentStep;
|
||||||
//m_interpolationTracker.update(m_currentStep);
|
m_currentTime += dt;
|
||||||
m_interpolationTracker.update(Time::monotonicTime());
|
m_interpolationTracker.update(m_currentTime);
|
||||||
|
|
||||||
List<WorldAction> triggeredActions;
|
List<WorldAction> triggeredActions;
|
||||||
eraseWhere(m_timers, [&triggeredActions](pair<int, WorldAction>& timer) {
|
eraseWhere(m_timers, [&triggeredActions, dt](pair<float, WorldAction>& timer) {
|
||||||
if (--timer.first <= 0) {
|
if ((timer.first -= dt) <= 0) {
|
||||||
triggeredActions.append(timer.second);
|
triggeredActions.append(timer.second);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto const& action : triggeredActions)
|
for (auto const& action : triggeredActions)
|
||||||
action(this);
|
action(this);
|
||||||
|
|
||||||
@ -1232,7 +1232,7 @@ void WorldClient::update(float dt) {
|
|||||||
for (EntityId entityId : toRemove)
|
for (EntityId entityId : toRemove)
|
||||||
removeEntity(entityId, true);
|
removeEntity(entityId, true);
|
||||||
|
|
||||||
queueUpdatePackets();
|
queueUpdatePackets(m_entityUpdateTimer.wrapTick(dt));
|
||||||
|
|
||||||
if (m_pingTime.isNothing()) {
|
if (m_pingTime.isNothing()) {
|
||||||
m_pingTime = Time::monotonicMilliseconds();
|
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& root = Root::singleton();
|
||||||
auto assets = root.assets();
|
auto assets = root.assets();
|
||||||
auto entityFactory = root.entityFactory();
|
auto entityFactory = root.entityFactory();
|
||||||
@ -1444,7 +1444,7 @@ void WorldClient::queueUpdatePackets() {
|
|||||||
|
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) { notifyEntityCreate(entity); });
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) { notifyEntityCreate(entity); });
|
||||||
|
|
||||||
if (m_currentStep % m_interpolationTracker.entityUpdateDelta() == 0) {
|
if (sendEntityUpdates) {
|
||||||
auto entityUpdateSet = make_shared<EntityUpdateSetPacket>();
|
auto entityUpdateSet = make_shared<EntityUpdateSetPacket>();
|
||||||
entityUpdateSet->forConnection = *m_clientId;
|
entityUpdateSet->forConnection = *m_clientId;
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
||||||
@ -1677,6 +1677,8 @@ void WorldClient::initWorld(WorldStartPacket const& startPacket) {
|
|||||||
else
|
else
|
||||||
m_interpolationTracker = InterpolationTracker(m_clientConfig.query("interpolationSettings.normal"));
|
m_interpolationTracker = InterpolationTracker(m_clientConfig.query("interpolationSettings.normal"));
|
||||||
|
|
||||||
|
m_entityUpdateTimer = GameTimer(m_interpolationTracker.entityUpdateDelta());
|
||||||
|
|
||||||
m_clientId = startPacket.clientId;
|
m_clientId = startPacket.clientId;
|
||||||
auto entitySpace = connectionEntitySpace(startPacket.clientId);
|
auto entitySpace = connectionEntitySpace(startPacket.clientId);
|
||||||
m_worldTemplate = make_shared<WorldTemplate>(startPacket.templateData);
|
m_worldTemplate = make_shared<WorldTemplate>(startPacket.templateData);
|
||||||
@ -1757,7 +1759,7 @@ void WorldClient::clearWorld() {
|
|||||||
waitForLighting();
|
waitForLighting();
|
||||||
|
|
||||||
m_currentStep = 0;
|
m_currentStep = 0;
|
||||||
m_currentServerStep = 0.0;
|
m_currentTime = 0;
|
||||||
m_inWorld = false;
|
m_inWorld = false;
|
||||||
m_clientId.reset();
|
m_clientId.reset();
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "StarWorld.hpp"
|
#include "StarWorld.hpp"
|
||||||
#include "StarGameTimers.hpp"
|
#include "StarGameTimers.hpp"
|
||||||
#include "StarLuaRoot.hpp"
|
#include "StarLuaRoot.hpp"
|
||||||
|
#include "StarTickRateMonitor.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ public:
|
|||||||
List<PhysicsForceRegion> forceRegions() const override;
|
List<PhysicsForceRegion> forceRegions() const override;
|
||||||
Json getProperty(String const& propertyName, Json const& def = Json()) const override;
|
Json getProperty(String const& propertyName, Json const& def = Json()) const override;
|
||||||
void setProperty(String const& propertyName, Json const& property) 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;
|
double epochTime() const override;
|
||||||
uint32_t day() const override;
|
uint32_t day() const override;
|
||||||
float dayLength() const override;
|
float dayLength() const override;
|
||||||
@ -218,7 +219,7 @@ private:
|
|||||||
void notifyEntityCreate(EntityPtr const& entity);
|
void notifyEntityCreate(EntityPtr const& entity);
|
||||||
|
|
||||||
// Queues pending (step based) updates to server,
|
// Queues pending (step based) updates to server,
|
||||||
void queueUpdatePackets();
|
void queueUpdatePackets(bool sendEntityUpdates);
|
||||||
void handleDamageNotifications();
|
void handleDamageNotifications();
|
||||||
|
|
||||||
void sparkDamagedBlocks();
|
void sparkDamagedBlocks();
|
||||||
@ -262,7 +263,7 @@ private:
|
|||||||
|
|
||||||
WorldGeometry m_geometry;
|
WorldGeometry m_geometry;
|
||||||
uint64_t m_currentStep;
|
uint64_t m_currentStep;
|
||||||
double m_currentServerStep;
|
double m_currentTime;
|
||||||
bool m_fullBright;
|
bool m_fullBright;
|
||||||
bool m_asyncLighting;
|
bool m_asyncLighting;
|
||||||
CellularLightingCalculator m_lightingCalculator;
|
CellularLightingCalculator m_lightingCalculator;
|
||||||
@ -312,6 +313,7 @@ private:
|
|||||||
HashMap<EntityId, uint64_t> m_masterEntitiesNetVersion;
|
HashMap<EntityId, uint64_t> m_masterEntitiesNetVersion;
|
||||||
|
|
||||||
InterpolationTracker m_interpolationTracker;
|
InterpolationTracker m_interpolationTracker;
|
||||||
|
GameTimer m_entityUpdateTimer;
|
||||||
|
|
||||||
List<PacketPtr> m_outgoingPackets;
|
List<PacketPtr> m_outgoingPackets;
|
||||||
Maybe<int64_t> m_pingTime;
|
Maybe<int64_t> m_pingTime;
|
||||||
@ -333,7 +335,7 @@ private:
|
|||||||
AmbientManager m_musicTrack;
|
AmbientManager m_musicTrack;
|
||||||
AmbientManager m_altMusicTrack;
|
AmbientManager m_altMusicTrack;
|
||||||
|
|
||||||
List<pair<int, WorldAction>> m_timers;
|
List<pair<float, WorldAction>> m_timers;
|
||||||
|
|
||||||
Map<DamageNumberKey, DamageNumber> m_damageNumbers;
|
Map<DamageNumberKey, DamageNumber> m_damageNumbers;
|
||||||
float m_damageNotificationBatchDuration;
|
float m_damageNotificationBatchDuration;
|
||||||
|
@ -241,9 +241,10 @@ bool WorldServer::addClient(ConnectionId clientId, SpawnTarget const& spawnTarge
|
|||||||
else
|
else
|
||||||
tracker = InterpolationTracker(m_serverConfig.query("interpolationSettings.normal"));
|
tracker = InterpolationTracker(m_serverConfig.query("interpolationSettings.normal"));
|
||||||
|
|
||||||
tracker.update(m_currentStep);
|
tracker.update(m_currentTime);
|
||||||
|
|
||||||
auto clientInfo = m_clientInfo.add(clientId, make_shared<ClientInfo>(clientId, tracker));
|
auto& clientInfo = m_clientInfo.add(clientId, make_shared<ClientInfo>(clientId, tracker));
|
||||||
|
clientInfo->local = isLocal;
|
||||||
|
|
||||||
auto worldStartPacket = make_shared<WorldStartPacket>();
|
auto worldStartPacket = make_shared<WorldStartPacket>();
|
||||||
worldStartPacket->templateData = m_worldTemplate->store();
|
worldStartPacket->templateData = m_worldTemplate->store();
|
||||||
@ -340,7 +341,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List<PacketPtr> c
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (auto heartbeat = as<StepUpdatePacket>(packet)) {
|
} else if (auto heartbeat = as<StepUpdatePacket>(packet)) {
|
||||||
clientInfo->interpolationTracker.receiveStepUpdate(heartbeat->remoteStep);
|
clientInfo->interpolationTracker.receiveTimeUpdate(heartbeat->remoteTime);
|
||||||
|
|
||||||
} else if (auto wcsPacket = as<WorldClientStateUpdatePacket>(packet)) {
|
} else if (auto wcsPacket = as<WorldClientStateUpdatePacket>(packet)) {
|
||||||
clientInfo->clientState.readDelta(wcsPacket->worldClientStateDelta);
|
clientInfo->clientState.readDelta(wcsPacket->worldClientStateDelta);
|
||||||
@ -430,7 +431,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List<PacketPtr> c
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (auto entityUpdateSet = as<EntityUpdateSetPacket>(packet)) {
|
} else if (auto entityUpdateSet = as<EntityUpdateSetPacket>(packet)) {
|
||||||
float interpolationLeadTime = clientInfo->interpolationTracker.interpolationLeadSteps() * GlobalTimestep;
|
float interpolationLeadTime = clientInfo->interpolationTracker.interpolationLeadTime();
|
||||||
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
m_entityMap->forAllEntities([&](EntityPtr const& entity) {
|
||||||
EntityId entityId = entity->entityId();
|
EntityId entityId = entity->entityId();
|
||||||
if (connectionForEntity(entityId) == clientId) {
|
if (connectionForEntity(entityId) == clientId) {
|
||||||
@ -442,7 +443,7 @@ void WorldServer::handleIncomingPackets(ConnectionId clientId, List<PacketPtr> c
|
|||||||
|
|
||||||
} else if (auto entityDestroy = as<EntityDestroyPacket>(packet)) {
|
} else if (auto entityDestroy = as<EntityDestroyPacket>(packet)) {
|
||||||
if (auto entity = m_entityMap->entity(entityDestroy->entityId)) {
|
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
|
// Before destroying the entity, we should make sure that the entity is
|
||||||
// using the absolute latest data, so we disable interpolation.
|
// using the absolute latest data, so we disable interpolation.
|
||||||
entity->disableInterpolation();
|
entity->disableInterpolation();
|
||||||
@ -565,13 +566,13 @@ void WorldServer::setExpiryTime(float expiryTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::update(float dt) {
|
void WorldServer::update(float dt) {
|
||||||
++m_currentStep;
|
m_currentTime += dt;
|
||||||
for (auto const& pair : m_clientInfo)
|
for (auto const& pair : m_clientInfo)
|
||||||
pair.second->interpolationTracker.update(m_currentStep);
|
pair.second->interpolationTracker.update(m_currentTime);
|
||||||
|
|
||||||
List<WorldAction> triggeredActions;
|
List<WorldAction> triggeredActions;
|
||||||
eraseWhere(m_timers, [&triggeredActions](pair<int, WorldAction>& timer) {
|
eraseWhere(m_timers, [&triggeredActions, dt](pair<float, WorldAction>& timer) {
|
||||||
if (--timer.first <= 0) {
|
if ((timer.first -= dt) <= 0) {
|
||||||
triggeredActions.append(timer.second);
|
triggeredActions.append(timer.second);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -582,7 +583,7 @@ void WorldServer::update(float dt) {
|
|||||||
|
|
||||||
m_spawner.update(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)
|
if (doBreakChecks)
|
||||||
m_needsGlobalBreakCheck = false;
|
m_needsGlobalBreakCheck = false;
|
||||||
|
|
||||||
@ -661,10 +662,11 @@ void WorldServer::update(float dt) {
|
|||||||
for (EntityId entityId : toRemove)
|
for (EntityId entityId : toRemove)
|
||||||
removeEntity(entityId, true);
|
removeEntity(entityId, true);
|
||||||
|
|
||||||
|
bool sendRemoteUpdates = m_entityUpdateTimer.wrapTick(dt);
|
||||||
for (auto const& pair : m_clientInfo) {
|
for (auto const& pair : m_clientInfo) {
|
||||||
for (auto const& monitoredRegion : pair.second->monitoringRegions(m_entityMap))
|
for (auto const& monitoredRegion : pair.second->monitoringRegions(m_entityMap))
|
||||||
signalRegion(monitoredRegion.padded(jsonToVec2I(m_serverConfig.get("playerActiveRegionPad"))));
|
signalRegion(monitoredRegion.padded(jsonToVec2I(m_serverConfig.get("playerActiveRegionPad"))));
|
||||||
queueUpdatePackets(pair.first);
|
queueUpdatePackets(pair.first, sendRemoteUpdates);
|
||||||
}
|
}
|
||||||
m_netStateCache.clear();
|
m_netStateCache.clear();
|
||||||
|
|
||||||
@ -1236,6 +1238,7 @@ void WorldServer::init(bool firstTime) {
|
|||||||
|
|
||||||
m_worldStorage->setFloatingDungeonWorld(isFloatingDungeonWorld());
|
m_worldStorage->setFloatingDungeonWorld(isFloatingDungeonWorld());
|
||||||
|
|
||||||
|
m_currentTime = 0;
|
||||||
m_currentStep = 0;
|
m_currentStep = 0;
|
||||||
m_generatingDungeon = false;
|
m_generatingDungeon = false;
|
||||||
m_geometry = WorldGeometry(m_worldTemplate->size());
|
m_geometry = WorldGeometry(m_worldTemplate->size());
|
||||||
@ -1258,6 +1261,7 @@ void WorldServer::init(bool firstTime) {
|
|||||||
return m_tileArray->tile({x, y}).getCollision();
|
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_tileEntityBreakCheckTimer = GameTimer(m_serverConfig.getFloat("tileEntityBreakCheckInterval"));
|
||||||
|
|
||||||
m_liquidEngine = make_shared<LiquidCellEngine<LiquidId>>(liquidsDatabase->liquidEngineParameters(), make_shared<LiquidWorld>(this));
|
m_liquidEngine = make_shared<LiquidCellEngine<LiquidId>>(liquidsDatabase->liquidEngineParameters(), make_shared<LiquidWorld>(this));
|
||||||
@ -1756,9 +1760,9 @@ List<ItemDescriptor> WorldServer::destroyBlock(TileLayer layer, Vec2I const& pos
|
|||||||
return drops;
|
return drops;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::queueUpdatePackets(ConnectionId clientId) {
|
void WorldServer::queueUpdatePackets(ConnectionId clientId, bool sendRemoteUpdates) {
|
||||||
auto const& clientInfo = m_clientInfo.get(clientId);
|
auto const& clientInfo = m_clientInfo.get(clientId);
|
||||||
clientInfo->outgoingPackets.append(make_shared<StepUpdatePacket>(m_currentStep));
|
clientInfo->outgoingPackets.append(make_shared<StepUpdatePacket>(m_currentTime));
|
||||||
|
|
||||||
if (shouldRunThisStep("environmentUpdate")) {
|
if (shouldRunThisStep("environmentUpdate")) {
|
||||||
ByteArray skyDelta;
|
ByteArray skyDelta;
|
||||||
@ -1828,7 +1832,7 @@ void WorldServer::queueUpdatePackets(ConnectionId clientId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HashMap<ConnectionId, shared_ptr<EntityUpdateSetPacket>> updateSetPackets;
|
HashMap<ConnectionId, shared_ptr<EntityUpdateSetPacket>> updateSetPackets;
|
||||||
if (m_currentStep % clientInfo->interpolationTracker.entityUpdateDelta() == 0)
|
if (sendRemoteUpdates || clientInfo->local)
|
||||||
updateSetPackets.add(ServerConnectionId, make_shared<EntityUpdateSetPacket>(ServerConnectionId));
|
updateSetPackets.add(ServerConnectionId, make_shared<EntityUpdateSetPacket>(ServerConnectionId));
|
||||||
for (auto const& p : m_clientInfo) {
|
for (auto const& p : m_clientInfo) {
|
||||||
if (p.first != clientId && p.second->pendingForward)
|
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) {
|
void WorldServer::timer(float delay, WorldAction worldAction) {
|
||||||
m_timers.append({stepsDelay, worldAction});
|
m_timers.append({delay, worldAction});
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::startFlyingSky(bool enterHyperspace, bool startInWarp) {
|
void WorldServer::startFlyingSky(bool enterHyperspace, bool startInWarp) {
|
||||||
|
@ -169,7 +169,7 @@ public:
|
|||||||
List<PhysicsForceRegion> forceRegions() const override;
|
List<PhysicsForceRegion> forceRegions() const override;
|
||||||
Json getProperty(String const& propertyName, Json const& def = Json()) const override;
|
Json getProperty(String const& propertyName, Json const& def = Json()) const override;
|
||||||
void setProperty(String const& propertyName, Json const& property) 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;
|
double epochTime() const override;
|
||||||
uint32_t day() const override;
|
uint32_t day() const override;
|
||||||
float dayLength() const override;
|
float dayLength() const override;
|
||||||
@ -275,6 +275,7 @@ private:
|
|||||||
WorldClientState clientState;
|
WorldClientState clientState;
|
||||||
bool pendingForward;
|
bool pendingForward;
|
||||||
bool started;
|
bool started;
|
||||||
|
bool local;
|
||||||
|
|
||||||
List<PacketPtr> outgoingPackets;
|
List<PacketPtr> outgoingPackets;
|
||||||
|
|
||||||
@ -308,7 +309,7 @@ private:
|
|||||||
TileModificationList doApplyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap, bool ignoreTileProtection = false);
|
TileModificationList doApplyTileModifications(TileModificationList const& modificationList, bool allowEntityOverlap, bool ignoreTileProtection = false);
|
||||||
|
|
||||||
// Queues pending (step based) updates to the given player
|
// Queues pending (step based) updates to the given player
|
||||||
void queueUpdatePackets(ConnectionId clientId);
|
void queueUpdatePackets(ConnectionId clientId, bool sendRemoteUpdates);
|
||||||
void updateDamage(float dt);
|
void updateDamage(float dt);
|
||||||
|
|
||||||
void updateDamagedBlocks(float dt);
|
void updateDamagedBlocks(float dt);
|
||||||
@ -361,7 +362,8 @@ private:
|
|||||||
StringMap<ScriptComponentPtr> m_scriptContexts;
|
StringMap<ScriptComponentPtr> m_scriptContexts;
|
||||||
|
|
||||||
WorldGeometry m_geometry;
|
WorldGeometry m_geometry;
|
||||||
uint64_t m_currentStep{};
|
double m_currentTime;
|
||||||
|
uint64_t m_currentStep;
|
||||||
mutable CellularLightIntensityCalculator m_lightIntensityCalculator;
|
mutable CellularLightIntensityCalculator m_lightIntensityCalculator;
|
||||||
SkyPtr m_sky;
|
SkyPtr m_sky;
|
||||||
|
|
||||||
@ -373,6 +375,7 @@ private:
|
|||||||
HashMap<pair<EntityId, uint64_t>, pair<ByteArray, uint64_t>> m_netStateCache;
|
HashMap<pair<EntityId, uint64_t>, pair<ByteArray, uint64_t>> m_netStateCache;
|
||||||
OrderedHashMap<ConnectionId, shared_ptr<ClientInfo>> m_clientInfo;
|
OrderedHashMap<ConnectionId, shared_ptr<ClientInfo>> m_clientInfo;
|
||||||
|
|
||||||
|
GameTimer m_entityUpdateTimer;
|
||||||
GameTimer m_tileEntityBreakCheckTimer;
|
GameTimer m_tileEntityBreakCheckTimer;
|
||||||
|
|
||||||
shared_ptr<LiquidCellEngine<LiquidId>> m_liquidEngine;
|
shared_ptr<LiquidCellEngine<LiquidId>> m_liquidEngine;
|
||||||
@ -384,7 +387,7 @@ private:
|
|||||||
// is removed / uninitialized
|
// is removed / uninitialized
|
||||||
HashMap<EntityId, TileEntitySpaces> m_tileEntitySpaces;
|
HashMap<EntityId, TileEntitySpaces> m_tileEntitySpaces;
|
||||||
|
|
||||||
List<pair<int, WorldAction>> m_timers;
|
List<pair<float, WorldAction>> m_timers;
|
||||||
|
|
||||||
bool m_needsGlobalBreakCheck;
|
bool m_needsGlobalBreakCheck;
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ public:
|
|||||||
virtual Json getProperty(String const& propertyName, Json const& def = {}) const = 0;
|
virtual Json getProperty(String const& propertyName, Json const& def = {}) const = 0;
|
||||||
virtual void setProperty(String const& propertyName, Json const& property) = 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 double epochTime() const = 0;
|
||||||
virtual uint32_t day() const = 0;
|
virtual uint32_t day() const = 0;
|
||||||
virtual float dayLength() const = 0;
|
virtual float dayLength() const = 0;
|
||||||
|
@ -131,7 +131,7 @@ void FarmableObject::enterStage(int newStage) {
|
|||||||
if (anySpacesOccupied(plant->spaces()) || !allSpacesOccupied(plant->roots())) {
|
if (anySpacesOccupied(plant->spaces()) || !allSpacesOccupied(plant->roots())) {
|
||||||
newStage = 0;
|
newStage = 0;
|
||||||
} else {
|
} else {
|
||||||
world()->timer(2, [plant](World* world) {
|
world()->timer(2.f / 60.f, [plant](World* world) {
|
||||||
world->addEntity(plant);
|
world->addEntity(plant);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user