Skip to content

Commit

Permalink
improve: walking system independent of server response
Browse files Browse the repository at this point in the history
  • Loading branch information
mehah authored Feb 1, 2025
1 parent 188fec2 commit 617d256
Show file tree
Hide file tree
Showing 12 changed files with 59 additions and 52 deletions.
4 changes: 2 additions & 2 deletions modules/game_walk/walk.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ local function walk(dir)
if not canChangeFloor(toPos, 1) and not canChangeFloor(toPos, -1) then
return false
end
elseif not player:isPreWalking() then
else
player:preWalk(dir)
end
end
Expand All @@ -88,7 +88,7 @@ local function addWalkEvent(dir, delay)
walk(smartWalkDir or dir)
end

walkEvent = delay == 0 and addEvent(walkCallback) or scheduleEvent(walkCallback, delay or 10)
walkEvent = delay == 0 and addEvent(walkCallback) or scheduleEvent(walkCallback, delay or 5)
end

--- Initiates a smart walk in the given direction.
Expand Down
4 changes: 2 additions & 2 deletions src/client/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ void Creature::updateWalkingTile()

// only render creatures where bottom right is inside tile rect
if (virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
newWalkingTile = g_map.getOrCreateTile(getPosition().translated(xi, yi, 0));
}
}
}
Expand Down Expand Up @@ -655,7 +655,7 @@ void Creature::nextWalkUpdate()

void Creature::updateWalk()
{
const float walkTicksPerPixel = (getStepDuration(true) + 8.f) / static_cast<float>(g_gameConfig.getSpriteSize());
const float walkTicksPerPixel = getStepDuration(true) / static_cast<float>(g_gameConfig.getSpriteSize());

const int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, g_gameConfig.getSpriteSize());

Expand Down
4 changes: 2 additions & 2 deletions src/client/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ minHeight,
bool canShoot(int distance);

protected:
virtual void updateWalkOffset(uint8_t totalPixelsWalked);
virtual void terminateWalk();
void updateWalkOffset(uint8_t totalPixelsWalked);
void updateWalk();

ThingType* getThingType() const override;
Expand All @@ -202,6 +202,7 @@ minHeight,
Otc::Direction m_direction{ Otc::South };

Timer m_walkTimer;
Position m_lastStepToPosition;

private:
void nextWalkUpdate();
Expand Down Expand Up @@ -245,7 +246,6 @@ minHeight,
CachedStep m_stepCache;

Position m_lastStepFromPosition;
Position m_lastStepToPosition;
Position m_oldPosition;

Timer m_footTimer;
Expand Down
4 changes: 4 additions & 0 deletions src/client/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ void Game::resetGameStates()
m_serverBeat = 50;
m_seq = 0;
m_ping = -1;
m_walkTicks = 0;
setCanReportBugs(false);
m_fightMode = Otc::FightBalanced;
m_chaseMode = Otc::DontChase;
Expand Down Expand Up @@ -684,6 +685,9 @@ void Game::forceWalk(const Otc::Direction direction)
if (!canPerformGameAction())
return;

m_walkTimer.restart();
m_walkTicks = -1;

switch (direction) {
case Otc::North:
m_protocolGame->sendWalkNorth();
Expand Down
4 changes: 4 additions & 0 deletions src/client/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,8 @@ class Game
void requestBossSlootInfo();
void requestBossSlotAction(uint8_t action, uint32_t raceId);
void sendStatusTrackerBestiary(uint16_t raceId, bool status);
auto getServerWalkTicks() const { return m_walkTicks; }
auto getWalkTicksElapsed() const { return m_walkTimer.ticksElapsed(); }
protected:
void enableBotCall() { m_denyBotCall = false; }
void disableBotCall() { m_denyBotCall = true; }
Expand Down Expand Up @@ -827,6 +829,8 @@ class Game
stdext::timer m_pingTimer;

ticks_t m_ping{ -1 };
ticks_t m_walkTicks{ 0 };
Timer m_walkTimer;
};

extern Game g_game;
49 changes: 17 additions & 32 deletions src/client/localplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,42 @@ bool LocalPlayer::canWalk(const Otc::Direction dir, const bool ignoreLock)
if (isPreWalking()) return false; // allow only single prewalk
}

return m_walkTimer.ticksElapsed() >= getStepDuration(); // allow only if walk done, ex. diagonals may need additional ticks before taking another step
if (g_game.getServerWalkTicks() == -1)
return false;

// allow only if walk done, ex. diagonals may need additional ticks before taking another step
return m_walkTimer.ticksElapsed() >= std::max<int>(getStepDuration(), g_game.getServerWalkTicks());
}

void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
{
m_autoWalkRetries = 0;

if (isPreWalking()) {
if (newPos == m_lastPrewalkDestination) {
m_lastPrewalkDestination = {};
updateWalk();
if (oldPos.z == newPos.z) {
if (m_lastPrewalkDestination == newPos || g_game.getWalkTicksElapsed() <= 1)
return;
}

m_lastPrewalkDestination = {};
if (g_game.getServerWalkTicks() - getStepDuration() > g_game.getWalkTicksElapsed())
return;
}

m_serverWalk = true;

Creature::walk(oldPos, newPos);
}

void LocalPlayer::preWalk(const Otc::Direction direction)
{
auto pos = m_position.translatedToDirection(direction);
// avoid reanimating prewalks
if (m_lastPrewalkDestination.isValid() || m_lastPrewalkDestination == pos)
if (m_lastPrewalkDestination.isValid())
return;

auto pos = m_position.translatedToDirection(direction);

if (m_lastPrewalkDestination == pos)
return;

// start walking to direction
m_lastPrewalkDestination = pos;
Creature::walk(m_position, m_lastPrewalkDestination);
Creature::walk(m_position, m_lastPrewalkDestination = std::move(pos));
}

bool LocalPlayer::retryAutoWalk()
Expand Down Expand Up @@ -185,26 +190,6 @@ void LocalPlayer::stopAutoWalk()
m_autoWalkContinueEvent->cancel();
}

void LocalPlayer::updateWalkOffset(const uint8_t totalPixelsWalked)
{
if (!isPreWalking()) {
Creature::updateWalkOffset(totalPixelsWalked);
return;
}

// pre walks offsets are calculated in the oposite direction
m_walkOffset = {};
if (m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
m_walkOffset.y = -totalPixelsWalked;
else if (m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
m_walkOffset.y = totalPixelsWalked;

if (m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
m_walkOffset.x = totalPixelsWalked;
else if (m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
m_walkOffset.x = -totalPixelsWalked;
}

void LocalPlayer::terminateWalk()
{
Creature::terminateWalk();
Expand Down
5 changes: 2 additions & 3 deletions src/client/localplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class LocalPlayer final : public Player

bool hasSight(const Position& pos);
bool isKnown() { return m_known; }
bool isServerWalking() { return m_serverWalk; }
bool isPreWalking() { return m_lastPrewalkDestination.isValid(); }
bool isAutoWalking() { return m_autoWalkDestination.isValid(); }
bool isPremium() { return m_premium; }
Expand All @@ -117,13 +118,11 @@ class LocalPlayer final : public Player
void onPositionChange(const Position& newPos, const Position& oldPos) override;

void preWalk(Otc::Direction direction);
Position getLastPrewalkingPosition() { return m_lastPrewalkDestination; }

bool isServerWalking() { return m_serverWalk; }
Position getPosition() override { return m_lastStepToPosition.isValid() && m_lastStepToPosition.z == m_position.z && m_position.distance(m_lastStepToPosition) < 2 ? m_lastStepToPosition : m_position; }

protected:
void walk(const Position& oldPos, const Position& newPos) override;
void updateWalkOffset(uint8_t totalPixelsWalked) override;
void terminateWalk() override;

friend class Game;
Expand Down
2 changes: 0 additions & 2 deletions src/client/luafunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<LocalPlayer>("getBlessings", &LocalPlayer::getBlessings);
g_lua.bindClassMemberFunction<LocalPlayer>("isPremium", &LocalPlayer::isPremium);
g_lua.bindClassMemberFunction<LocalPlayer>("isKnown", &LocalPlayer::isKnown);
g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("preWalk", &LocalPlayer::preWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("getLastPrewalkingPosition", &LocalPlayer::getLastPrewalkingPosition);
g_lua.bindClassMemberFunction<LocalPlayer>("hasSight", &LocalPlayer::hasSight);
g_lua.bindClassMemberFunction<LocalPlayer>("isAutoWalking", &LocalPlayer::isAutoWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("stopAutoWalk", &LocalPlayer::stopAutoWalk);
Expand Down
4 changes: 2 additions & 2 deletions src/client/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ bool Map::removeThing(const ThingPtr& thing)
return false;

if (thing->isMissile()) {
auto& missiles = m_floors[thing->getPosition().z].missiles;
auto& missiles = m_floors[thing->getServerPosition().z].missiles;
const auto it = std::ranges::find(missiles, thing->static_self_cast<Missile>());
if (it == missiles.end())
return false;
Expand All @@ -255,7 +255,7 @@ bool Map::removeThing(const ThingPtr& thing)

if (const auto& tile = thing->getTile()) {
if (tile->removeThing(thing)) {
notificateTileUpdate(thing->getPosition(), thing, Otc::OPERATION_REMOVE);
notificateTileUpdate(thing->getServerPosition(), thing, Otc::OPERATION_REMOVE);
return true;
}
}
Expand Down
15 changes: 10 additions & 5 deletions src/client/protocolgameparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,11 @@ void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
const auto& creature = thing->static_self_cast<Creature>();
creature->allowAppearWalk();

if (creature->isLocalPlayer() && g_game.m_walkTicks == -1) {
g_game.m_walkTicks = g_game.m_walkTimer.ticksElapsed();
g_game.m_walkTimer.restart();
}

g_map.addThing(thing, newPos, -1);
}

Expand Down Expand Up @@ -3867,17 +3872,17 @@ void ProtocolGame::parseCyclopediaHousesInfo(const InputMessagePtr& msg)
// TO-DO Lua // Otui
}

void ProtocolGame::parseCyclopediaHouseList(const InputMessagePtr& msg)
void ProtocolGame::parseCyclopediaHouseList(const InputMessagePtr& msg)
{
const uint16_t housesCount = msg->getU16(); // housesCount
for (auto i = 0; i < housesCount; ++i) {
msg->getU32(); // clientId
msg->getU8(); // 0x00 = Renovation, 0x01 = Available

const auto type = static_cast<Otc::CyclopediaHouseState_t>(msg->getU8());
switch (type) {
case Otc::CYCLOPEDIA_HOUSE_STATE_AVAILABLE: {
std::string bidderName = msg->getString();
std::string bidderName = msg->getString();
const auto isBidder = static_cast<bool>(msg->getU8());
msg->getU8(); // disableIndex

Expand All @@ -3893,7 +3898,7 @@ void ProtocolGame::parseCyclopediaHouseList(const InputMessagePtr& msg)
case Otc::CYCLOPEDIA_HOUSE_STATE_RENTED: {
msg->getString(); // ownerName
msg->getU32(); // paidUntil

const auto isRented = static_cast<bool>(msg->getU8());
if (isRented) {
msg->getU8(); // unknown
Expand All @@ -3913,7 +3918,7 @@ void ProtocolGame::parseCyclopediaHouseList(const InputMessagePtr& msg)
msg->getString(); // bidderName
msg->getU8(); // unknown
msg->getU64(); // internalBid

const auto isNewOwner = static_cast<bool>(msg->getU8());
if (isNewOwner) {
msg->getU8(); // acceptTransferError
Expand Down
3 changes: 2 additions & 1 deletion src/client/thing.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class Thing : public AttachableObject
virtual uint32_t getId() { return m_clientId; }
uint16_t getClientId() const { return m_clientId; }

Position getPosition() { return m_position; }
virtual Position getPosition() { return m_position; }
Position getServerPosition() { return m_position; }

const TilePtr& getTile();
ContainerPtr getParentContainer();
Expand Down
13 changes: 12 additions & 1 deletion src/client/tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,16 @@ void Tile::drawCreature(const Point& dest, const int flags, const bool forceDraw
if (!forceDraw && !m_drawTopAndCreature)
return;

bool localPlayerDrawed = false;
if (hasCreature()) {
for (const auto& thing : m_things) {
if (!thing->isCreature() || thing->static_self_cast<Creature>()->isWalking()) continue;

if (thing->isLocalPlayer()) {
if (thing->getPosition() != m_position) continue;
localPlayerDrawed = true;
}

drawThing(thing, dest, flags, drawElevation);
}
}
Expand All @@ -129,6 +135,11 @@ void Tile::drawCreature(const Point& dest, const int flags, const bool forceDraw

creature->draw(cDest, flags & Otc::DrawThings);
}

// draw the local character if he is on a virtual tile, that is, his visual position is not the same as the server.
if (!localPlayerDrawed && g_game.getLocalPlayer() && !g_game.getLocalPlayer()->isWalking() && g_game.getLocalPlayer()->getPosition() == m_position) {
drawThing(g_game.getLocalPlayer(), dest, flags, drawElevation);
}
}

void Tile::drawTop(const Point& dest, const int flags, const bool forceDraw, uint8_t drawElevation)
Expand Down Expand Up @@ -977,4 +988,4 @@ bool Tile::canShoot(int distance)
if (distance > 0 && std::max<int>(std::abs(m_position.x - playerPos.x), std::abs(m_position.y - playerPos.y)) > distance)
return false;
return g_map.isSightClear(playerPos, m_position);
}
}

0 comments on commit 617d256

Please sign in to comment.