mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
Merge pull request #110 from kamilprzyb/vehicles_pr
Fixed Time and implemented vehicles expiring
This commit is contained in:
commit
63c14aff58
@ -33,6 +33,7 @@
|
|||||||
std::string U16toU8(char16_t* src);
|
std::string U16toU8(char16_t* src);
|
||||||
size_t U8toU16(std::string src, char16_t* des); // returns number of char16_t that was written at des
|
size_t U8toU16(std::string src, char16_t* des); // returns number of char16_t that was written at des
|
||||||
time_t getTime();
|
time_t getTime();
|
||||||
|
time_t getTimestamp();
|
||||||
|
|
||||||
// The PROTOCOL_VERSION definition is defined by the build system.
|
// The PROTOCOL_VERSION definition is defined by the build system.
|
||||||
#if !defined(PROTOCOL_VERSION)
|
#if !defined(PROTOCOL_VERSION)
|
||||||
|
@ -128,7 +128,7 @@ int Database::addAccount(std::string login, std::string password)
|
|||||||
account.Login = login;
|
account.Login = login;
|
||||||
account.Password = password;
|
account.Password = password;
|
||||||
account.Selected = 1;
|
account.Selected = 1;
|
||||||
account.Created = getTime();
|
account.Created = getTimestamp();
|
||||||
return db.insert(account);
|
return db.insert(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ void Database::updateSelected(int accountId, int slot)
|
|||||||
Account acc = db.get<Account>(accountId);
|
Account acc = db.get<Account>(accountId);
|
||||||
acc.Selected = slot;
|
acc.Selected = slot;
|
||||||
//timestamp
|
//timestamp
|
||||||
acc.LastLogin = getTime();
|
acc.LastLogin = getTimestamp();
|
||||||
db.update(acc);
|
db.update(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
|
|||||||
DbPlayer create = {};
|
DbPlayer create = {};
|
||||||
|
|
||||||
//set timestamp
|
//set timestamp
|
||||||
create.Created = getTime();
|
create.Created = getTimestamp();
|
||||||
// save packet data
|
// save packet data
|
||||||
create.FirstName = U16toU8(save->szFirstName);
|
create.FirstName = U16toU8(save->szFirstName);
|
||||||
create.LastName = U16toU8(save->szLastName);
|
create.LastName = U16toU8(save->szLastName);
|
||||||
@ -380,7 +380,7 @@ Database::DbPlayer Database::playerToDb(Player *player)
|
|||||||
appendBlob(&result.QuestFlag, flag);
|
appendBlob(&result.QuestFlag, flag);
|
||||||
}
|
}
|
||||||
//timestamp
|
//timestamp
|
||||||
result.LastLogin = getTime();
|
result.LastLogin = getTimestamp();
|
||||||
result.Created = getDbPlayerById(player->iID).Created;
|
result.Created = getDbPlayerById(player->iID).Created;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -432,8 +432,9 @@ Player Database::DbToPlayer(DbPlayer player) {
|
|||||||
result.aSkywayLocationFlag[1] = player.SkywayLocationFlag2;
|
result.aSkywayLocationFlag[1] = player.SkywayLocationFlag2;
|
||||||
|
|
||||||
Database::getInventory(&result);
|
Database::getInventory(&result);
|
||||||
|
Database::removeExpiredVehicles(&result);
|
||||||
Database::getNanos(&result);
|
Database::getNanos(&result);
|
||||||
Database::getQuests(&result);
|
Database::getQuests(&result);
|
||||||
|
|
||||||
std::vector<char>::iterator it = player.QuestFlag.begin();
|
std::vector<char>::iterator it = player.QuestFlag.begin();
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
@ -606,6 +607,39 @@ void Database::getInventory(Player* player) {
|
|||||||
player->QInven[current.slot - AEQUIP_COUNT - AINVEN_COUNT - ABANK_COUNT] = toSet;
|
player->QInven[current.slot - AEQUIP_COUNT - AINVEN_COUNT - ABANK_COUNT] = toSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::removeExpiredVehicles(Player* player) {
|
||||||
|
int32_t currentTime = getTimestamp();
|
||||||
|
// remove from bank immediately
|
||||||
|
for (int i = 0; i < ABANK_COUNT; i++) {
|
||||||
|
if (player->Bank[i].iType == 10 && player->Bank[i].iTimeLimit < currentTime)
|
||||||
|
player->Bank[i] = {};
|
||||||
|
}
|
||||||
|
// for the rest, we want to leave only 1 expired vehicle on player to delete it with the client packet
|
||||||
|
std::vector<sItemBase*> toRemove;
|
||||||
|
|
||||||
|
// equiped vehicle
|
||||||
|
if (player->Equip[8].iOpt > 0 && player->Equip[8].iTimeLimit < currentTime)
|
||||||
|
{
|
||||||
|
toRemove.push_back(&player->Equip[8]);
|
||||||
|
player->toRemoveVehicle.eIL = 0;
|
||||||
|
player->toRemoveVehicle.iSlotNum = 8;
|
||||||
|
}
|
||||||
|
// inventory
|
||||||
|
for (int i = 0; i < AINVEN_COUNT; i++) {
|
||||||
|
if (player->Inven[i].iType == 10 && player->Inven[i].iTimeLimit < currentTime) {
|
||||||
|
toRemove.push_back(&player->Inven[i]);
|
||||||
|
player->toRemoveVehicle.eIL = 1;
|
||||||
|
player->toRemoveVehicle.iSlotNum = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all but one vehicles, leave last one for ceremonial deletion
|
||||||
|
for (int i = 0; i < (int)toRemove.size()-1; i++) {
|
||||||
|
memset(toRemove[i], 0, sizeof(sItemBase));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::getNanos(Player* player) {
|
void Database::getNanos(Player* player) {
|
||||||
|
@ -126,6 +126,7 @@ namespace Database {
|
|||||||
void updateQuests(Player* player);
|
void updateQuests(Player* player);
|
||||||
|
|
||||||
void getInventory(Player* player);
|
void getInventory(Player* player);
|
||||||
|
void removeExpiredVehicles(Player* player);
|
||||||
void getNanos(Player* player);
|
void getNanos(Player* player);
|
||||||
void getQuests(Player* player);
|
void getQuests(Player* player);
|
||||||
|
|
||||||
|
@ -767,3 +767,38 @@ Item* ItemManager::getItemData(int32_t id, int32_t type) {
|
|||||||
return &ItemData[std::pair<int32_t, int32_t>(id, type)];
|
return &ItemData[std::pair<int32_t, int32_t>(id, type)];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemManager::checkItemExpire(CNSocket* sock, Player* player) {
|
||||||
|
if (player->toRemoveVehicle.eIL == 0 && player->toRemoveVehicle.iSlotNum == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* prepare packet
|
||||||
|
* yes, this is a varadic packet, however analyzing client behavior and code
|
||||||
|
* it only checks takes the first item sent into account
|
||||||
|
* yes, this is very stupid
|
||||||
|
* therefore, we delete all but 1 expired vehicle while loading player
|
||||||
|
* to delete the last one here so player gets a notification
|
||||||
|
*/
|
||||||
|
|
||||||
|
const size_t resplen = sizeof(sP_FE2CL_PC_DELETE_TIME_LIMIT_ITEM) + sizeof(sTimeLimitItemDeleteInfo2CL);
|
||||||
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
|
// we know it's only one trailing struct, so we can skip full validation
|
||||||
|
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
||||||
|
sP_FE2CL_PC_DELETE_TIME_LIMIT_ITEM* packet = (sP_FE2CL_PC_DELETE_TIME_LIMIT_ITEM*)respbuf;
|
||||||
|
sTimeLimitItemDeleteInfo2CL* itemData = (sTimeLimitItemDeleteInfo2CL*)(respbuf + sizeof(sP_FE2CL_PC_DELETE_TIME_LIMIT_ITEM));
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
|
packet->iItemListCount = 1;
|
||||||
|
itemData->eIL = player->toRemoveVehicle.eIL;
|
||||||
|
itemData->iSlotNum = player->toRemoveVehicle.iSlotNum;
|
||||||
|
sock->sendPacket((void*)&respbuf, P_FE2CL_PC_DELETE_TIME_LIMIT_ITEM, resplen);
|
||||||
|
|
||||||
|
// delete serverside
|
||||||
|
if (player->toRemoveVehicle.eIL == 0)
|
||||||
|
memset(&player->Equip[8], 0, sizeof(sItemBase));
|
||||||
|
else
|
||||||
|
memset(&player->Inven[player->toRemoveVehicle.iSlotNum], 0, sizeof(sItemBase));
|
||||||
|
|
||||||
|
player->toRemoveVehicle.eIL = 0;
|
||||||
|
player->toRemoveVehicle.iSlotNum = 0;
|
||||||
|
}
|
||||||
|
@ -47,4 +47,5 @@ namespace ItemManager {
|
|||||||
|
|
||||||
int findFreeSlot(Player *plr);
|
int findFreeSlot(Player *plr);
|
||||||
Item* getItemData(int32_t id, int32_t type);
|
Item* getItemData(int32_t id, int32_t type);
|
||||||
|
void checkItemExpire(CNSocket* sock, Player* player);
|
||||||
}
|
}
|
||||||
|
@ -369,7 +369,13 @@ void MissionManager::mobKilled(CNSocket *sock, int mobid) {
|
|||||||
if (task["m_iCSUNumToKill"][j] != 0)
|
if (task["m_iCSUNumToKill"][j] != 0)
|
||||||
{
|
{
|
||||||
missionmob = true;
|
missionmob = true;
|
||||||
plr->RemainingNPCCount[i][j]--;
|
// sanity check
|
||||||
|
if (plr->RemainingNPCCount[i][j] == 0) {
|
||||||
|
std::cout << "[WARN] RemainingNPCCount tries to go below 0?!" << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
plr->RemainingNPCCount[i][j]--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// drop quest item
|
// drop quest item
|
||||||
if (task["m_iCSUItemNumNeeded"][j] != 0 && !isQuestItemFull(sock, task["m_iCSUItemID"][j], task["m_iCSUItemNumNeeded"][j]) ) {
|
if (task["m_iCSUItemNumNeeded"][j] != 0 && !isQuestItemFull(sock, task["m_iCSUItemID"][j], task["m_iCSUItemNumNeeded"][j]) ) {
|
||||||
|
@ -115,6 +115,10 @@ void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) {
|
|||||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL));
|
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if vehicle
|
||||||
|
if (req->Item.iType == 10)
|
||||||
|
// set time limit: current time + 7days
|
||||||
|
req->Item.iTimeLimit = getTimestamp() + 604800;
|
||||||
|
|
||||||
if (slot != req->iInvenSlotNum) {
|
if (slot != req->iInvenSlotNum) {
|
||||||
// possible item stacking?
|
// possible item stacking?
|
||||||
|
@ -49,4 +49,6 @@ struct Player {
|
|||||||
int RemainingNPCCount[ACTIVE_MISSION_COUNT][3];
|
int RemainingNPCCount[ACTIVE_MISSION_COUNT][3];
|
||||||
sItemBase QInven[AQINVEN_COUNT];
|
sItemBase QInven[AQINVEN_COUNT];
|
||||||
int32_t CurrentMissionID;
|
int32_t CurrentMissionID;
|
||||||
|
|
||||||
|
sTimeLimitItemDeleteInfo2CL toRemoveVehicle;
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "CNShardServer.hpp"
|
#include "CNShardServer.hpp"
|
||||||
#include "CNShared.hpp"
|
#include "CNShared.hpp"
|
||||||
#include "MissionManager.hpp"
|
#include "MissionManager.hpp"
|
||||||
|
#include "ItemManager.hpp"
|
||||||
|
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
||||||
@ -287,6 +288,8 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN));
|
sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN));
|
||||||
|
|
||||||
addPlayer(sock, plr);
|
addPlayer(sock, plr);
|
||||||
|
//check if there is an expiring vehicle
|
||||||
|
ItemManager::checkItemExpire(sock, getPlayer(sock));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
||||||
@ -327,7 +330,7 @@ void PlayerManager::movePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
sP_CL2FE_REQ_PC_MOVE* moveData = (sP_CL2FE_REQ_PC_MOVE*)data->buf;
|
sP_CL2FE_REQ_PC_MOVE* moveData = (sP_CL2FE_REQ_PC_MOVE*)data->buf;
|
||||||
updatePlayerPosition(sock, moveData->iX, moveData->iY, moveData->iZ, moveData->iAngle);
|
updatePlayerPosition(sock, moveData->iX, moveData->iY, moveData->iZ, moveData->iAngle);
|
||||||
|
|
||||||
players[sock].plr->angle = moveData->iAngle;
|
players[sock].plr->angle = moveData->iAngle;
|
||||||
uint64_t tm = getTime();
|
uint64_t tm = getTime();
|
||||||
|
|
||||||
@ -692,7 +695,7 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||||
PlayerView& plr = PlayerManager::players[sock];
|
PlayerView& plr = PlayerManager::players[sock];
|
||||||
|
|
||||||
if (plr.plr->Equip[8].iID > 0) {
|
if (plr.plr->Equip[8].iID > 0 && plr.plr->Equip[8].iTimeLimit>getTimestamp()) {
|
||||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_SUCC, response);
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_SUCC, sizeof(sP_FE2CL_PC_VEHICLE_ON_SUCC));
|
||||||
|
|
||||||
@ -710,6 +713,14 @@ void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
|||||||
} else {
|
} else {
|
||||||
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response);
|
INITSTRUCT(sP_FE2CL_PC_VEHICLE_ON_FAIL, response);
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
|
sock->sendPacket((void*)&response, P_FE2CL_PC_VEHICLE_ON_FAIL, sizeof(sP_FE2CL_PC_VEHICLE_ON_FAIL));
|
||||||
|
|
||||||
|
// check if vehicle didn't expire
|
||||||
|
if (plr.plr->Equip[8].iTimeLimit < getTimestamp())
|
||||||
|
{
|
||||||
|
plr.plr->toRemoveVehicle.eIL = 0;
|
||||||
|
plr.plr->toRemoveVehicle.iSlotNum = 8;
|
||||||
|
ItemManager::checkItemExpire(sock, plr.plr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,3 +150,12 @@ time_t getTime() {
|
|||||||
|
|
||||||
return (time_t)value.count();
|
return (time_t)value.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns system time in seconds
|
||||||
|
time_t getTimestamp() {
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
seconds value = duration_cast<seconds>((time_point_cast<seconds>(system_clock::now())).time_since_epoch());
|
||||||
|
|
||||||
|
return (time_t)value.count();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user