Merge pull request #109 from gsemaj/slider

Basic slider implementation
This commit is contained in:
CPunch 2020-09-23 14:49:26 -05:00 committed by GitHub
commit 4caca07856
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 275 additions and 44 deletions

View File

@ -56,6 +56,17 @@ void ChunkManager::removePlayer(std::pair<int, int> chunkPos, CNSocket* sock) {
// TODO: if players and NPCs are empty, free chunk and remove it from surrounding views // TODO: if players and NPCs are empty, free chunk and remove it from surrounding views
} }
void ChunkManager::removeNPC(std::pair<int, int> chunkPos, int32_t id) {
if (!checkChunk(chunkPos))
return; // do nothing if chunk doesn't even exist
Chunk* chunk = chunks[chunkPos];
chunk->NPCs.erase(id); // gone
// TODO: if players and NPCs are empty, free chunk and remove it from surrounding views
}
bool ChunkManager::checkChunk(std::pair<int, int> chunk) { bool ChunkManager::checkChunk(std::pair<int, int> chunk) {
return chunks.find(chunk) != chunks.end(); return chunks.find(chunk) != chunks.end();
} }

View File

@ -22,6 +22,7 @@ namespace ChunkManager {
void addNPC(int posX, int posY, int32_t id); void addNPC(int posX, int posY, int32_t id);
void addPlayer(int posX, int posY, CNSocket* sock); void addPlayer(int posX, int posY, CNSocket* sock);
void removePlayer(std::pair<int, int> chunkPos, CNSocket* sock); void removePlayer(std::pair<int, int> chunkPos, CNSocket* sock);
void removeNPC(std::pair<int, int> chunkPos, int32_t id);
bool checkChunk(std::pair<int, int> chunk); bool checkChunk(std::pair<int, int> chunk);
std::pair<int, int> grabChunk(int posX, int posY); std::pair<int, int> grabChunk(int posX, int posY);
std::vector<Chunk*> grabChunks(std::pair<int, int> chunkPos); std::vector<Chunk*> grabChunks(std::pair<int, int> chunkPos);

View File

@ -16,6 +16,14 @@ const float CN_EP_RANK_3 = 0.5f;
const float CN_EP_RANK_4 = 0.3f; const float CN_EP_RANK_4 = 0.3f;
const float CN_EP_RANK_5 = 0.29f; const float CN_EP_RANK_5 = 0.29f;
// NPC classes
enum NPCClass {
NPC_BASE = 0,
NPC_MOB = 1,
NPC_BUS = 2,
NPC_EGG = 3
};
// nano powers // nano powers
enum { enum {
EST_NONE = 0, EST_NONE = 0,

View File

@ -5,6 +5,7 @@
class BaseNPC { class BaseNPC {
public: public:
sNPCAppearanceData appearanceData; sNPCAppearanceData appearanceData;
NPCClass npcClass;
BaseNPC() {}; BaseNPC() {};
BaseNPC(int x, int y, int z, int type) { BaseNPC(int x, int y, int z, int type) {
@ -20,4 +21,7 @@ public:
// hopefully no collisions happen :eyes: // hopefully no collisions happen :eyes:
appearanceData.iNPC_ID = (int32_t)rand(); appearanceData.iNPC_ID = (int32_t)rand();
}; };
BaseNPC(int x, int y, int z, int type, NPCClass classType) : BaseNPC(x, y, z, type) {
npcClass = classType;
}
}; };

View File

@ -33,15 +33,30 @@ void NPCManager::init() {
void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) { void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
BaseNPC* npc = NPCs[id]; BaseNPC* npc = NPCs[id];
// create struct switch (npc->npcClass) {
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData); case NPC_BUS:
enterData.NPCAppearanceData = npc->appearanceData; INITSTRUCT(sP_FE2CL_TRANSPORTATION_ENTER, enterBusData);
enterBusData.AppearanceData = { 3, npc->appearanceData.iNPC_ID, npc->appearanceData.iNPCType, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ };
for (Chunk* chunk : viewableChunks) { for (Chunk* chunk : viewableChunks) {
for (CNSocket* sock : chunk->players) { for (CNSocket* sock : chunk->players) {
// send to socket // send to socket
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER)); sock->sendPacket((void*)&enterBusData, P_FE2CL_TRANSPORTATION_ENTER, sizeof(sP_FE2CL_TRANSPORTATION_ENTER));
}
} }
break;
default:
// create struct
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
enterData.NPCAppearanceData = npc->appearanceData;
for (Chunk* chunk : viewableChunks) {
for (CNSocket* sock : chunk->players) {
// send to socket
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
}
}
break;
} }
} }
@ -66,21 +81,38 @@ void NPCManager::removeNPC(int32_t id) {
Chunk* chunk = ChunkManager::chunks[pos]; Chunk* chunk = ChunkManager::chunks[pos];
chunk->NPCs.erase(id); chunk->NPCs.erase(id);
// create struct switch (entity->npcClass) {
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData); case NPC_BUS:
exitData.iNPC_ID = id; INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, exitBusData);
exitBusData.eTT = 3;
exitBusData.iT_ID = id;
// remove it from the clients for (Chunk* chunk : ChunkManager::grabChunks(pos)) {
for (Chunk* chunk : ChunkManager::grabChunks(pos)) { for (CNSocket* sock : chunk->players) {
for (CNSocket* sock : chunk->players) { // send to socket
// send to socket sock->sendPacket((void*)&exitBusData, P_FE2CL_TRANSPORTATION_EXIT, sizeof(sP_FE2CL_TRANSPORTATION_EXIT));
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT)); }
} }
} break;
case NPC_MOB:
// remove from mob list if it's a mob
if (MobManager::Mobs.find(id) != MobManager::Mobs.end())
MobManager::Mobs.erase(id);
// fall through
default:
// create struct
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
exitData.iNPC_ID = id;
// remove from mob list if it's a mob // remove it from the clients
if (MobManager::Mobs.find(id) != MobManager::Mobs.end()) for (Chunk* chunk : ChunkManager::grabChunks(pos)) {
MobManager::Mobs.erase(id); for (CNSocket* sock : chunk->players) {
// send to socket
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
}
}
break;
}
// finally, remove it from the map and free it // finally, remove it from the map and free it
NPCs.erase(id); NPCs.erase(id);
@ -89,6 +121,24 @@ void NPCManager::removeNPC(int32_t id) {
std::cout << "npc removed!" << std::endl; std::cout << "npc removed!" << std::endl;
} }
void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z) {
BaseNPC* npc = NPCs[id];
std::pair<int, int> oldPos = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY);
npc->appearanceData.iX = X;
npc->appearanceData.iY = Y;
npc->appearanceData.iZ = Z;
std::pair<int, int> newPos = ChunkManager::grabChunk(X, Y);
// nothing to be done
if (newPos == oldPos)
return;
// pull NPC from old chunk and add to new chunk
ChunkManager::removeNPC(oldPos, npc->appearanceData.iNPC_ID);
ChunkManager::addNPC(X, Y, npc->appearanceData.iNPC_ID);
}
void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) { void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY)) if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY))
return; // malformed packet return; // malformed packet

View File

@ -22,6 +22,7 @@ namespace NPCManager {
void addNPC(std::vector<Chunk*> viewableChunks, int32_t); void addNPC(std::vector<Chunk*> viewableChunks, int32_t);
void removeNPC(int32_t); void removeNPC(int32_t);
void updateNPCPosition(int32_t, int X, int Y, int Z);
void npcBarkHandler(CNSocket* sock, CNPacketData* data); void npcBarkHandler(CNSocket* sock, CNPacketData* data);
void npcSummonHandler(CNSocket* sock, CNPacketData* data); void npcSummonHandler(CNSocket* sock, CNPacketData* data);

View File

@ -27,6 +27,7 @@ void PlayerManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LAUNCHER, PlayerManager::launchPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LAUNCHER, PlayerManager::launchPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ZIPLINE, PlayerManager::ziplinePlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ZIPLINE, PlayerManager::ziplinePlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVEPLATFORM, PlayerManager::movePlatformPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVEPLATFORM, PlayerManager::movePlatformPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_MOVETRANSPORTATION, PlayerManager::moveSliderPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SLOPE, PlayerManager::moveSlopePlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SLOPE, PlayerManager::moveSlopePlayer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GOTO, PlayerManager::gotoPlayer);
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer); REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SET_VALUE, PlayerManager::setSpecialPlayer);
@ -79,7 +80,6 @@ void PlayerManager::removePlayer(CNSocket* key) {
} }
void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket* sock) { void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPlayer); INITSTRUCT(sP_FE2CL_PC_EXIT, exitPlayer);
// for chunks that need the player to be removed from // for chunks that need the player to be removed from
@ -87,8 +87,20 @@ void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket*
// remove NPCs // remove NPCs
for (int32_t id : chunk->NPCs) { for (int32_t id : chunk->NPCs) {
exitData.iNPC_ID = id; BaseNPC* npc = NPCManager::NPCs[id];
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT)); switch (npc->npcClass) {
case NPC_BUS:
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, exitBusData);
exitBusData.eTT = 3;
exitBusData.iT_ID = id;
sock->sendPacket((void*)&exitBusData, P_FE2CL_TRANSPORTATION_EXIT, sizeof(sP_FE2CL_TRANSPORTATION_EXIT));
break;
default:
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
exitData.iNPC_ID = id;
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
break;
}
} }
// remove players from eachother // remove players from eachother
@ -105,14 +117,24 @@ void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket*
} }
void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock) { void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer); INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer);
for (Chunk* chunk : chunks) { for (Chunk* chunk : chunks) {
// add npcs // add npcs
for (int32_t id : chunk->NPCs) { for (int32_t id : chunk->NPCs) {
enterData.NPCAppearanceData = NPCManager::NPCs[id]->appearanceData; BaseNPC* npc = NPCManager::NPCs[id];
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER)); switch (npc->npcClass) {
case NPC_BUS:
INITSTRUCT(sP_FE2CL_TRANSPORTATION_ENTER, enterBusData);
enterBusData.AppearanceData = { 3, npc->appearanceData.iNPC_ID, npc->appearanceData.iNPCType, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ };
sock->sendPacket((void*)&enterBusData, P_FE2CL_TRANSPORTATION_ENTER, sizeof(sP_FE2CL_TRANSPORTATION_ENTER));
break;
default:
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
enterData.NPCAppearanceData = NPCManager::NPCs[id]->appearanceData;
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
break;
}
} }
// add players // add players
@ -528,6 +550,37 @@ void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
sendToViewable(sock, (void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM)); sendToViewable(sock, (void*)&platResponse, P_FE2CL_PC_MOVEPLATFORM, sizeof(sP_FE2CL_PC_MOVEPLATFORM));
} }
void PlayerManager::moveSliderPlayer(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_MOVETRANSPORTATION))
return; // ignore the malformed packet
sP_CL2FE_REQ_PC_MOVETRANSPORTATION* sliderData = (sP_CL2FE_REQ_PC_MOVETRANSPORTATION*)data->buf;
updatePlayerPosition(sock, sliderData->iX, sliderData->iY, sliderData->iZ, sliderData->iAngle);
uint64_t tm = getTime();
INITSTRUCT(sP_FE2CL_PC_MOVETRANSPORTATION, sliderResponse);
sliderResponse.iPC_ID = players[sock].plr->iID;
sliderResponse.iCliTime = sliderData->iCliTime;
sliderResponse.iSvrTime = tm;
sliderResponse.iX = sliderData->iX;
sliderResponse.iY = sliderData->iY;
sliderResponse.iZ = sliderData->iZ;
sliderResponse.iAngle = sliderData->iAngle;
sliderResponse.fVX = sliderData->fVX;
sliderResponse.fVY = sliderData->fVY;
sliderResponse.fVZ = sliderData->fVZ;
sliderResponse.iLcX = sliderData->iLcX;
sliderResponse.iLcY = sliderData->iLcY;
sliderResponse.iLcZ = sliderData->iLcZ;
sliderResponse.iSpeed = sliderData->iSpeed;
sliderResponse.cKeyValue = sliderData->cKeyValue;
sliderResponse.iT_ID = sliderData->iT_ID;
sendToViewable(sock, (void*)&sliderResponse, P_FE2CL_PC_MOVETRANSPORTATION, sizeof(sP_FE2CL_PC_MOVETRANSPORTATION));
}
void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) { void PlayerManager::moveSlopePlayer(CNSocket* sock, CNPacketData* data) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_SLOPE)) if (data->size != sizeof(sP_CL2FE_REQ_PC_SLOPE))
return; // ignore the malformed packet return; // ignore the malformed packet

View File

@ -44,6 +44,7 @@ namespace PlayerManager {
void launchPlayer(CNSocket* sock, CNPacketData* data); void launchPlayer(CNSocket* sock, CNPacketData* data);
void ziplinePlayer(CNSocket* sock, CNPacketData* data); void ziplinePlayer(CNSocket* sock, CNPacketData* data);
void movePlatformPlayer(CNSocket* sock, CNPacketData* data); void movePlatformPlayer(CNSocket* sock, CNPacketData* data);
void moveSliderPlayer(CNSocket* sock, CNPacketData* data);
void moveSlopePlayer(CNSocket* sock, CNPacketData* data); void moveSlopePlayer(CNSocket* sock, CNPacketData* data);
void gotoPlayer(CNSocket* sock, CNPacketData* data); void gotoPlayer(CNSocket* sock, CNPacketData* data);
void setSpecialPlayer(CNSocket* sock, CNPacketData* data); void setSpecialPlayer(CNSocket* sock, CNPacketData* data);

View File

@ -263,19 +263,7 @@ void TableData::constructPath(nlohmann::json::iterator _pathData) {
for (_point++; _point != pathPoints.end(); _point++) { for (_point++; _point != pathPoints.end(); _point++) {
point = _point.value(); point = _point.value();
WarpLocation coords = { point["iX"] , point["iY"] , point["iZ"] }; WarpLocation coords = { point["iX"] , point["iY"] , point["iZ"] };
// Calculate distance between this point and the last TransportManager::lerp(&points, last, coords, pathData["iMonkeySpeed"]);
int dXY = hypot(last.x - coords.x, last.y - coords.y); // XY plane distance
int distanceBetween = hypot(dXY, last.z - coords.z); // total distance
int lerps = distanceBetween / (int)pathData["iMonkeySpeed"]; // integer division to ensure a whole number of in-between points
for (int i = 0; i < lerps; i++) {
WarpLocation lerp;
// lerp math
float frac = (i + 1) * 1.0f / (lerps + 1);
lerp.x = (last.x * (1.0f - frac)) + (coords.x * frac);
lerp.y = (last.y * (1.0f - frac)) + (coords.y * frac);
lerp.z = (last.z * (1.0f - frac)) + (coords.z * frac);
points.push(lerp); // add lerp'd point to the queue
}
points.push(coords); // add keyframe to the queue points.push(coords); // add keyframe to the queue
last = coords; // update start pos last = coords; // update start pos
} }

View File

@ -4,17 +4,31 @@
#include "TransportManager.hpp" #include "TransportManager.hpp"
#include <unordered_map> #include <unordered_map>
#include <cmath>
std::map<int32_t, TransportRoute> TransportManager::Routes; std::map<int32_t, TransportRoute> TransportManager::Routes;
std::map<int32_t, TransportLocation> TransportManager::Locations; std::map<int32_t, TransportLocation> TransportManager::Locations;
std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths; std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths;
std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues; std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues;
std::unordered_map<int32_t, std::queue<WarpLocation>> TransportManager::NPCQueues;
void TransportManager::init() { void TransportManager::init() {
REGISTER_SHARD_TIMER(tickSkywaySystem, 1000); REGISTER_SHARD_TIMER(tickTransportationSystem, 1000);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler);
BaseNPC* bus = new BaseNPC(220447, 162431, -3650, 1, NPC_BUS);
NPCManager::NPCs[bus->appearanceData.iNPC_ID] = bus;
ChunkManager::addNPC(bus->appearanceData.iX, bus->appearanceData.iY, bus->appearanceData.iNPC_ID);
std::queue<WarpLocation> busPoints;
WarpLocation start = { bus->appearanceData.iX, bus->appearanceData.iY, -3650 };
WarpLocation end = { 220441, 188102, -3653 };
busPoints.push(start);
TransportManager::lerp(&busPoints, start, end, 1000);
busPoints.push(end);
TransportManager::lerp(&busPoints, end, start, 1000);
NPCQueues[bus->appearanceData.iNPC_ID] = busPoints;
} }
void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) { void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) {
@ -174,13 +188,17 @@ void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data)
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC)); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_TRANSPORTATION_SUCC));
} }
void TransportManager::tickTransportationSystem(CNServer* serv, time_t currTime) {
stepNPCPathing();
stepSkywaySystem();
}
/* /*
* Go through every socket that has broomstick points queued up, and advance to the next point. * Go through every socket that has broomstick points queued up, and advance to the next point.
* If the player has disconnected or finished the route, clean up and remove them from the queue. * If the player has disconnected or finished the route, clean up and remove them from the queue.
*/ */
void TransportManager::tickSkywaySystem(CNServer* serv, time_t currTime) { void TransportManager::stepSkywaySystem() {
//std::cout << SkywayQueue.size();
// using an unordered map so we can remove finished players in one iteration // using an unordered map so we can remove finished players in one iteration
std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin(); std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin();
while (it != SkywayQueues.end()) { while (it != SkywayQueues.end()) {
@ -228,3 +246,94 @@ void TransportManager::tickSkywaySystem(CNServer* serv, time_t currTime) {
} }
} }
} }
void TransportManager::stepNPCPathing() {
// all NPC pathing queues
std::unordered_map<int32_t, std::queue<WarpLocation>>::iterator it = NPCQueues.begin();
while (it != NPCQueues.end()) {
std::queue<WarpLocation>* queue = &it->second;
BaseNPC* npc = nullptr;
if (NPCManager::NPCs.find(it->first) != NPCManager::NPCs.end())
npc = NPCManager::NPCs[it->first];
if (npc == nullptr) {
// pluck out dead path + update iterator
it = NPCQueues.erase(it);
continue;
}
WarpLocation point = queue->front(); // get point
queue->pop(); // remove point from front of queue
// calculate displacement
int dXY = hypot(point.x - npc->appearanceData.iX, point.y - npc->appearanceData.iY); // XY plane distance
int distanceBetween = hypot(dXY, point.z - npc->appearanceData.iZ); // total distance
// update NPC location to update viewables
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z);
// get chunks in view
auto chunk = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY);
auto chunks = ChunkManager::grabChunks(chunk);
switch (npc->npcClass) {
case NPC_BUS:
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
busMove.eTT = 3;
busMove.iT_ID = npc->appearanceData.iNPC_ID;
busMove.iMoveStyle = 0; // ???
busMove.iToX = point.x;
busMove.iToY = point.y;
busMove.iToZ = point.z;
busMove.iSpeed = distanceBetween; // set to distance to match how monkeys work
// send packet to players in view
for (Chunk* chunk : chunks) {
for (CNSocket* s : chunk->players) {
s->sendPacket(&busMove, P_FE2CL_TRANSPORTATION_MOVE, sizeof(sP_FE2CL_TRANSPORTATION_MOVE));
}
}
break;
default:
INITSTRUCT(sP_FE2CL_NPC_MOVE, move);
move.iNPC_ID = npc->appearanceData.iNPC_ID;
move.iMoveStyle = 0; // ???
move.iToX = point.x;
move.iToY = point.y;
move.iToZ = point.z;
move.iSpeed = 600; // TODO: figure out a way to make this variable
// send packet to players in view
for (Chunk* chunk : chunks) {
for (CNSocket* s : chunk->players) {
s->sendPacket(&move, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
}
}
break;
}
queue->push(point); // move processed point to the back to maintain cycle
it++; // go to next entry in map
}
}
/*
* Linearly interpolate between two points and insert the results into a queue.
*/
void TransportManager::lerp(std::queue<WarpLocation>* queue, WarpLocation start, WarpLocation end, int gapSize) {
int dXY = hypot(end.x - start.x, end.y - start.y); // XY plane distance
int distanceBetween = hypot(dXY, end.z - start.z); // total distance
int lerps = distanceBetween / gapSize; // integer division to ensure a whole number of in-between points
for (int i = 0; i < lerps; i++) {
WarpLocation lerp;
// lerp math
float frac = (i + 1) * 1.0f / (lerps + 1);
lerp.x = (start.x * (1.0f - frac)) + (end.x * frac);
lerp.y = (start.y * (1.0f - frac)) + (end.y * frac);
lerp.z = (start.z * (1.0f - frac)) + (end.z * frac);
queue->push(lerp); // add lerp'd point
}
}

View File

@ -20,11 +20,16 @@ namespace TransportManager {
extern std::map<int32_t, TransportLocation> Locations; extern std::map<int32_t, TransportLocation> Locations;
extern std::map<int32_t, std::queue<WarpLocation>> SkywayPaths; // predefined skyway paths with points extern std::map<int32_t, std::queue<WarpLocation>> SkywayPaths; // predefined skyway paths with points
extern std::unordered_map<CNSocket*, std::queue<WarpLocation>> SkywayQueues; // player sockets with queued broomstick points extern std::unordered_map<CNSocket*, std::queue<WarpLocation>> SkywayQueues; // player sockets with queued broomstick points
extern std::unordered_map<int32_t, std::queue<WarpLocation>> NPCQueues; // NPC ids with queued pathing points
void init(); void init();
void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data); void transportRegisterLocationHandler(CNSocket*, CNPacketData*);
void transportWarpHandler(CNSocket* sock, CNPacketData* data); void transportWarpHandler(CNSocket*, CNPacketData*);
void tickSkywaySystem(CNServer* serv, time_t currTime); void tickTransportationSystem(CNServer*, time_t);
void stepNPCPathing();
void stepSkywaySystem();
void lerp(std::queue<WarpLocation>*, WarpLocation, WarpLocation, int);
} }