void ProtocolGame::parseNewWalking(NetworkMessage& msg)
{
uint32_t playerWalkId = msg.get<uint32_t>();
int32_t predictiveWalkId = msg.get<int32_t>(); // extension for proxy system, currently not used
Position playerPosition = msg.getPosition(); // local player position before moving, including prewalk
uint8_t flags = msg.getByte(); // 0x01 - prewalk, 0x02 - autowalk
uint16_t numdirs = msg.get<uint16_t>();
if (numdirs == 0 || numdirs > 4096) {
return;
}
std::list<Direction> pathList;
for (uint16_t i = 0; i < numdirs; ++i) {
uint8_t rawdir = msg.getByte();
switch (rawdir) {
case 1: pathList.push_back(DIRECTION_EAST); break;
case 2: pathList.push_back(DIRECTION_NORTHEAST); break;
case 3: pathList.push_back(DIRECTION_NORTH); break;
case 4: pathList.push_back(DIRECTION_NORTHWEST); break;
case 5: pathList.push_back(DIRECTION_WEST); break;
case 6: pathList.push_back(DIRECTION_SOUTHWEST); break;
case 7: pathList.push_back(DIRECTION_SOUTH); break;
case 8: pathList.push_back(DIRECTION_SOUTHEAST); break;
default: break; // Optionally handle unexpected values
}
}
// Convert list to vector
std::vector<Direction> pathVector(pathList.begin(), pathList.end());
std::reverse(pathVector.begin(), pathVector.end()); // this is the tricky part about it that might mess up with your autowalk (pathfinding execution but pathfinding itself will be working correctly) (it have to be executed in reverse of list)
uint32_t playerId = player->getID();
auto self = getThis();
g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::WalkingC, self, playerWalkId, predictiveWalkId, playerId, playerPosition, flags, std::move(pathVector))));
}
void ProtocolGame::WalkingC(uint32_t playerWalkId, int32_t predictiveWalkId, uint32_t playerId, Position playerPosition, uint8_t flags, std::vector<Direction> path)
{
bool preWalk = flags & 0x01;
Position destination = getNextPosition(path.front(), playerPosition);
if (preWalk && predictiveWalkId < walkMatrix.get(destination)) {
walkId += 1;
sendWalkId();
return;
}
if (playerWalkId < walkId) {
// this walk has been sent before player received previous newCancelWalk, so it's invalid, ignore it
return;
}
g_game.playerNewWalk(playerId, playerPosition, flags, path);
}
void ProtocolGame::checkPredictiveWalking(const Position& pos)
{
if (!otclientV8)
return;
if (walkMatrix.inRange(pos) && !g_game.map.canWalkTo(*player, pos)) {
int newValue = walkMatrix.update(pos);
sendPredictiveCancel(pos, newValue);
}
}
void ProtocolGame::sendPredictiveCancel(const Position& pos, int value)
{
if (!otclientV8)
return;
NetworkMessage msg;
msg.addByte(0x46);
msg.addPosition(pos);
msg.addByte(player->getDirection());
writeToOutputBuffer(msg);
}
void ProtocolGame::sendWalkId()
{
if (!otclientV8)
return;
NetworkMessage msg;
msg.addByte(0x47);
msg.add<uint32_t>(walkId);
writeToOutputBuffer(msg);
}
void ProtocolGame::sendNewCancelWalk()
{
if (!otclientV8)
return;
NetworkMessage msg;
msg.addByte(0x45);
msg.addByte(player->getDirection());
writeToOutputBuffer(msg);
walkId += 1;
sendWalkId();
}