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
}
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) {
return chunks.find(chunk) != chunks.end();
}

View File

@ -22,6 +22,7 @@ namespace ChunkManager {
void addNPC(int posX, int posY, int32_t id);
void addPlayer(int posX, int posY, 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);
std::pair<int, int> grabChunk(int posX, int posY);
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_5 = 0.29f;
// NPC classes
enum NPCClass {
NPC_BASE = 0,
NPC_MOB = 1,
NPC_BUS = 2,
NPC_EGG = 3
};
// nano powers
enum {
EST_NONE = 0,

View File

@ -5,6 +5,7 @@
class BaseNPC {
public:
sNPCAppearanceData appearanceData;
NPCClass npcClass;
BaseNPC() {};
BaseNPC(int x, int y, int z, int type) {
@ -20,4 +21,7 @@ public:
// hopefully no collisions happen :eyes:
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,6 +33,19 @@ void NPCManager::init() {
void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
BaseNPC* npc = NPCs[id];
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 };
for (Chunk* chunk : viewableChunks) {
for (CNSocket* sock : chunk->players) {
// send to socket
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;
@ -43,6 +56,8 @@ void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
sock->sendPacket((void*)&enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
}
}
break;
}
}
void NPCManager::removeNPC(int32_t id) {
@ -66,6 +81,25 @@ void NPCManager::removeNPC(int32_t id) {
Chunk* chunk = ChunkManager::chunks[pos];
chunk->NPCs.erase(id);
switch (entity->npcClass) {
case NPC_BUS:
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, exitBusData);
exitBusData.eTT = 3;
exitBusData.iT_ID = id;
for (Chunk* chunk : ChunkManager::grabChunks(pos)) {
for (CNSocket* sock : chunk->players) {
// send to socket
sock->sendPacket((void*)&exitBusData, P_FE2CL_TRANSPORTATION_EXIT, sizeof(sP_FE2CL_TRANSPORTATION_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;
@ -77,10 +111,8 @@ void NPCManager::removeNPC(int32_t id) {
sock->sendPacket((void*)&exitData, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT));
}
}
// remove from mob list if it's a mob
if (MobManager::Mobs.find(id) != MobManager::Mobs.end())
MobManager::Mobs.erase(id);
break;
}
// finally, remove it from the map and free it
NPCs.erase(id);
@ -89,6 +121,24 @@ void NPCManager::removeNPC(int32_t id) {
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) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY))
return; // malformed packet

View File

@ -22,6 +22,7 @@ namespace NPCManager {
void addNPC(std::vector<Chunk*> viewableChunks, int32_t);
void removeNPC(int32_t);
void updateNPCPosition(int32_t, int X, int Y, int Z);
void npcBarkHandler(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_ZIPLINE, PlayerManager::ziplinePlayer);
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_GOTO, PlayerManager::gotoPlayer);
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) {
INITSTRUCT(sP_FE2CL_NPC_EXIT, exitData);
INITSTRUCT(sP_FE2CL_PC_EXIT, exitPlayer);
// for chunks that need the player to be removed from
@ -87,8 +87,20 @@ void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket*
// remove NPCs
for (int32_t id : chunk->NPCs) {
BaseNPC* npc = NPCManager::NPCs[id];
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
@ -105,14 +117,24 @@ void PlayerManager::removePlayerFromChunks(std::vector<Chunk*> chunks, CNSocket*
}
void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock) {
INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
INITSTRUCT(sP_FE2CL_PC_NEW, newPlayer);
for (Chunk* chunk : chunks) {
// add npcs
for (int32_t id : chunk->NPCs) {
BaseNPC* npc = NPCManager::NPCs[id];
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
@ -528,6 +550,37 @@ void PlayerManager::movePlatformPlayer(CNSocket* sock, CNPacketData* data) {
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) {
if (data->size != sizeof(sP_CL2FE_REQ_PC_SLOPE))
return; // ignore the malformed packet

View File

@ -44,6 +44,7 @@ namespace PlayerManager {
void launchPlayer(CNSocket* sock, CNPacketData* data);
void ziplinePlayer(CNSocket* sock, CNPacketData* data);
void movePlatformPlayer(CNSocket* sock, CNPacketData* data);
void moveSliderPlayer(CNSocket* sock, CNPacketData* data);
void moveSlopePlayer(CNSocket* sock, CNPacketData* data);
void gotoPlayer(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++) {
point = _point.value();
WarpLocation coords = { point["iX"] , point["iY"] , point["iZ"] };
// Calculate distance between this point and the last
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
}
TransportManager::lerp(&points, last, coords, pathData["iMonkeySpeed"]);
points.push(coords); // add keyframe to the queue
last = coords; // update start pos
}

View File

@ -4,17 +4,31 @@
#include "TransportManager.hpp"
#include <unordered_map>
#include <cmath>
std::map<int32_t, TransportRoute> TransportManager::Routes;
std::map<int32_t, TransportLocation> TransportManager::Locations;
std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths;
std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues;
std::unordered_map<int32_t, std::queue<WarpLocation>> TransportManager::NPCQueues;
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_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) {
@ -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));
}
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.
* 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
std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin();
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, 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<int32_t, std::queue<WarpLocation>> NPCQueues; // NPC ids with queued pathing points
void init();
void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data);
void transportWarpHandler(CNSocket* sock, CNPacketData* data);
void transportRegisterLocationHandler(CNSocket*, CNPacketData*);
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);
}