mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-09-30 19:50:05 +00:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d840b0bbd0 | ||
![]() |
4da178d16c | ||
![]() |
0d65fc2653 | ||
![]() |
6d97aaa1d0 | ||
![]() |
4ab686bc46 | ||
![]() |
2302c28ac5 | ||
c8497a4856 | |||
177c5f0f17 | |||
2782706355 | |||
![]() |
a969988b5c | ||
![]() |
bf3c19764b | ||
cc06fdcf60 | |||
3b5af415fb | |||
![]() |
2b650b0bed | ||
![]() |
512647974d | ||
c9f9b093f4 | |||
![]() |
49d8ed2e36 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ build/
|
||||
*.db
|
||||
version.h
|
||||
infer-out
|
||||
gmon.out
|
||||
|
@@ -16,14 +16,11 @@ tl;dr:
|
||||
|
||||
From then on, any time you want to run the "game":
|
||||
|
||||
3. Run `Server/winfusion.exe`
|
||||
3. Run `OpenFusion/winfusion.exe` (optional if you're using the public server)
|
||||
4. Run `FreeClient/OpenFusionClient.exe`
|
||||
|
||||
Currently the client by default connects to a public server hosted by Cake. Change the loginInfo.php to point to your own server if you want to host your own.
|
||||
|
||||
You have two randomized characters available to you on the Character Selection screen, one boy, one girl.
|
||||
You can also make your own character and play through the tutorial. The tutorial can be skipped by pressing the ~ key.
|
||||
|
||||
If you want, [compiled binaries (artifacts) for each new commit can be found on AppVeyor.](https://ci.appveyor.com/project/OpenFusionProject/openfusion)
|
||||
|
||||
For a more detailed overview of the game's architecture and how to configure it, read the following sections.
|
||||
|
@@ -21,7 +21,7 @@ port=8002
|
||||
ip=127.0.0.1
|
||||
# distance at which other players and NPCs become visible.
|
||||
# this value is used for calculating chunk size
|
||||
viewdistance=30000
|
||||
viewdistance=25600
|
||||
# time, in milliseconds, to wait before kicking a non-responsive client
|
||||
# default is 1 minute
|
||||
timeout=60000
|
||||
|
@@ -31,7 +31,8 @@ void CNShardServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
||||
else if (settings::VERBOSITY > 0)
|
||||
std::cerr << "OpenFusion: SHARD UNIMPLM ERR. PacketType: " << Defines::p2str(CL2FE, data->type) << " (" << data->type << ")" << std::endl;
|
||||
|
||||
PlayerManager::players[sock].lastHeartbeat = getTime();
|
||||
if (PlayerManager::players.find(sock) != PlayerManager::players.end())
|
||||
PlayerManager::players[sock].lastHeartbeat = getTime();
|
||||
}
|
||||
|
||||
void CNShardServer::keepAliveTimer(CNServer* serv, time_t currTime) {
|
||||
|
@@ -411,6 +411,7 @@ void minfoCommand(std::string full, std::vector<std::string>& args, CNSocket* so
|
||||
ChatManager::sendServerMessage(sock, "[MINFO] Current task ID: " + std::to_string(plr->tasks[i]));
|
||||
ChatManager::sendServerMessage(sock, "[MINFO] Current task type: " + std::to_string((int)(task["m_iHTaskType"])));
|
||||
ChatManager::sendServerMessage(sock, "[MINFO] Current waypoint NPC ID: " + std::to_string((int)(task["m_iSTGrantWayPoint"])));
|
||||
ChatManager::sendServerMessage(sock, "[MINFO] Current terminator NPC ID: " + std::to_string((int)(task["m_iHTerminatorNPCID"])));
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
if ((int)(task["m_iCSUEnemyID"][j]) != 0)
|
||||
|
@@ -8,34 +8,72 @@ std::map<std::tuple<int, int, uint64_t>, Chunk*> ChunkManager::chunks;
|
||||
|
||||
void ChunkManager::init() {} // stubbed
|
||||
|
||||
void ChunkManager::newChunk(std::tuple<int, int, uint64_t> pos) {
|
||||
Chunk *chunk = new Chunk();
|
||||
|
||||
chunk->players = std::set<CNSocket*>();
|
||||
chunk->NPCs = std::set<int32_t>();
|
||||
|
||||
chunks[pos] = chunk;
|
||||
}
|
||||
|
||||
void ChunkManager::populateNewChunk(Chunk* chunk, std::tuple<int, int, uint64_t> pos) {// add the new chunk to every player and mob that's near it
|
||||
for (Chunk *c : grabChunks(pos)) {
|
||||
if (c == chunk)
|
||||
continue;
|
||||
|
||||
for (CNSocket *s : c->players)
|
||||
PlayerManager::players[s].currentChunks.push_back(chunk);
|
||||
|
||||
for (int32_t id : c->NPCs)
|
||||
NPCManager::NPCs[id]->currentChunks.push_back(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::addNPC(int posX, int posY, uint64_t instanceID, int32_t id) {
|
||||
std::tuple<int, int, uint64_t> pos = grabChunk(posX, posY, instanceID);
|
||||
|
||||
bool newChunkUsed = false;
|
||||
|
||||
// make chunk if it doesn't exist!
|
||||
if (chunks.find(pos) == chunks.end()) {
|
||||
chunks[pos] = new Chunk();
|
||||
chunks[pos]->players = std::set<CNSocket*>();
|
||||
chunks[pos]->NPCs = std::set<int32_t>();
|
||||
newChunk(pos);
|
||||
newChunkUsed = true;
|
||||
}
|
||||
|
||||
Chunk* chunk = chunks[pos];
|
||||
|
||||
if (newChunkUsed)
|
||||
NPCManager::NPCs[id]->currentChunks.push_back(chunk);
|
||||
|
||||
chunk->NPCs.insert(id);
|
||||
|
||||
// we must update other players after the NPC is added to chunk
|
||||
if (newChunkUsed)
|
||||
populateNewChunk(chunk, pos);
|
||||
}
|
||||
|
||||
void ChunkManager::addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock) {
|
||||
std::tuple<int, int, uint64_t> pos = grabChunk(posX, posY, instanceID);
|
||||
|
||||
bool newChunkUsed = false;
|
||||
|
||||
// make chunk if it doesn't exist!
|
||||
if (chunks.find(pos) == chunks.end()) {
|
||||
chunks[pos] = new Chunk();
|
||||
chunks[pos]->players = std::set<CNSocket*>();
|
||||
chunks[pos]->NPCs = std::set<int32_t>();
|
||||
newChunk(pos);
|
||||
newChunkUsed = true;
|
||||
}
|
||||
|
||||
Chunk* chunk = chunks[pos];
|
||||
|
||||
if (newChunkUsed)
|
||||
PlayerManager::players[sock].currentChunks.push_back(chunk);
|
||||
|
||||
chunk->players.insert(sock);
|
||||
|
||||
// we must update other players after this player is added to chunk
|
||||
if (newChunkUsed)
|
||||
populateNewChunk(chunk, pos);
|
||||
}
|
||||
|
||||
bool ChunkManager::removePlayer(std::tuple<int, int, uint64_t> chunkPos, CNSocket* sock) {
|
||||
@@ -212,7 +250,7 @@ void ChunkManager::createInstance(uint64_t instanceID) {
|
||||
BaseNPC* baseNPC = NPCManager::NPCs[npcID];
|
||||
if (baseNPC->npcClass == NPC_MOB) {
|
||||
Mob* newMob = new Mob(baseNPC->appearanceData.iX, baseNPC->appearanceData.iY, baseNPC->appearanceData.iZ, baseNPC->appearanceData.iAngle,
|
||||
instanceID, baseNPC->appearanceData.iNPCType, baseNPC->appearanceData.iHP, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], newID);
|
||||
instanceID, baseNPC->appearanceData.iNPCType, ((Mob*)baseNPC)->maxHealth, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], newID);
|
||||
NPCManager::NPCs[newID] = newMob;
|
||||
MobManager::Mobs[newID] = newMob;
|
||||
} else {
|
||||
|
@@ -26,6 +26,8 @@ namespace ChunkManager {
|
||||
|
||||
extern std::map<std::tuple<int, int, uint64_t>, Chunk*> chunks;
|
||||
|
||||
void newChunk(std::tuple<int, int, uint64_t> pos);
|
||||
void populateNewChunk(Chunk* chunk, std::tuple<int, int, uint64_t> pos);
|
||||
void addNPC(int posX, int posY, uint64_t instanceID, int32_t id);
|
||||
void addPlayer(int posX, int posY, uint64_t instanceID, CNSocket* sock);
|
||||
bool removePlayer(std::tuple<int, int, uint64_t> chunkPos, CNSocket* sock);
|
||||
|
@@ -29,12 +29,12 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To);
|
||||
|
||||
if (plr == nullptr || otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
||||
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
// fail if the group is full or the other player is already in a group
|
||||
if (plr->groupCnt >= 4 || otherPlr->groupCnt > 1) {
|
||||
@@ -50,9 +50,9 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE, resp);
|
||||
|
||||
resp.iHostID = plr->iIDGroup;
|
||||
resp.iHostID = plr->iIDGroup;
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE, sizeof(sP_FE2CL_PC_GROUP_INVITE));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE, sizeof(sP_FE2CL_PC_GROUP_INVITE));
|
||||
}
|
||||
|
||||
void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
@@ -61,7 +61,7 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
sP_CL2FE_REQ_PC_GROUP_INVITE_REFUSE* recv = (sP_CL2FE_REQ_PC_GROUP_INVITE_REFUSE*)data->buf;
|
||||
|
||||
CNSocket* otherSock = PlayerManager::getSockFromID(recv->iID_From);
|
||||
CNSocket* otherSock = PlayerManager::getSockFromID(recv->iID_From);
|
||||
|
||||
if (otherSock == nullptr)
|
||||
return;
|
||||
@@ -69,13 +69,13 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (plr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_REFUSE, resp);
|
||||
|
||||
resp.iID_To = plr->iID;
|
||||
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_REFUSE, sizeof(sP_FE2CL_PC_GROUP_INVITE_REFUSE));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_REFUSE, sizeof(sP_FE2CL_PC_GROUP_INVITE_REFUSE));
|
||||
}
|
||||
|
||||
void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) {
|
||||
@@ -87,12 +87,12 @@ void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) {
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_From);
|
||||
|
||||
if (plr == nullptr || otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
||||
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
// fail if the group is full or the other player is already in a group
|
||||
if (plr->groupCnt > 1 || plr->iIDGroup != plr->iID || otherPlr->groupCnt >= 4) {
|
||||
@@ -172,7 +172,7 @@ void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) {
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||
|
||||
if (plr == nullptr || otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
|
||||
@@ -184,14 +184,14 @@ void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
void GroupManager::menuChatGroup(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||
|
||||
if (plr == nullptr || otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
|
||||
@@ -276,7 +276,7 @@ void GroupManager::groupKickPlayer(Player* plr) {
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), otherPlr->groupCnt - 1, sizeof(sPCGroupMemberInfo))) {
|
||||
std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_LEAVE packet size\n";
|
||||
@@ -340,7 +340,7 @@ void GroupManager::groupKickPlayer(Player* plr) {
|
||||
CNSocket* sock = PlayerManager::getSockFromID(plr->iID);
|
||||
|
||||
if (sock == nullptr)
|
||||
return;
|
||||
return;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
|
||||
sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
|
||||
|
@@ -140,12 +140,12 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
|
||||
|
||||
equipChange.iPC_ID = plr.plr->iID;
|
||||
if (itemmove->eFrom == (int)SlotType::EQUIP) {
|
||||
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
|
||||
equipChange.EquipSlotItem = resp.ToSlotItem;
|
||||
} else {
|
||||
if (itemmove->eTo == (int)SlotType::EQUIP) {
|
||||
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
|
||||
equipChange.EquipSlotItem = resp.FromSlotItem;
|
||||
} else {
|
||||
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
|
||||
equipChange.EquipSlotItem = resp.ToSlotItem;
|
||||
}
|
||||
|
||||
// unequip vehicle if equip slot 8 is 0
|
||||
|
@@ -77,20 +77,27 @@ void MissionManager::taskStart(CNSocket* sock, CNPacketData* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
TaskData& task = *Tasks[missionData->iTaskNum];
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
response.iRemainTime = task["m_iSTGrantTimer"];
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
|
||||
|
||||
// HACK: auto-succeed Eduardo escort task
|
||||
// TODO: maybe check for iTaskType == 6 and skip all escort missions?
|
||||
if (missionData->iTaskNum == 576) {
|
||||
// HACK: auto-succeed escort task
|
||||
if (task["m_iHTaskType"] == 6) {
|
||||
std::cout << "Sending Eduardo success packet" << std::endl;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||
|
||||
endTask(sock, 576);
|
||||
response.iTaskNum = 576;
|
||||
endTask(sock, missionData->iTaskNum);
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
|
||||
// Give player their delivery items at the start.
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (task["m_iSTItemID"][i] != 0 && task["m_iSTItemNumNeeded"][i] > 0)
|
||||
dropQuestItem(sock, missionData->iTaskNum, task["m_iSTItemNumNeeded"][i], task["m_iSTItemID"][i], 0);
|
||||
}
|
||||
|
||||
void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||
@@ -98,6 +105,25 @@ void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf;
|
||||
|
||||
// failed timed missions give an iNPC_ID of 0
|
||||
if (missionData->iNPC_ID == 0) {
|
||||
TaskData* task = MissionManager::Tasks[missionData->iTaskNum];
|
||||
// double-checking
|
||||
if (task->task["m_iHTaskType"] == 3) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
int failTaskID = task->task["m_iFOutgoingTask"];
|
||||
if (failTaskID != 0) {
|
||||
MissionManager::quitTask(sock, missionData->iTaskNum, false);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
if (plr->tasks[i] == missionData->iTaskNum)
|
||||
plr->tasks[i] = failTaskID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
@@ -85,11 +85,12 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
damage.first = plr->pointDamage;
|
||||
|
||||
int difficulty = (int)mob->data["m_iNpcLevel"];
|
||||
|
||||
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW >= 11 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||
|
||||
if (plr->batteryW >= 11 + difficulty)
|
||||
plr->batteryW -= 11 + difficulty;
|
||||
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||
|
||||
if (plr->batteryW >= 6 + difficulty)
|
||||
plr->batteryW -= 6 + difficulty;
|
||||
else
|
||||
plr->batteryW = 0;
|
||||
|
||||
damage.first = hitMob(sock, mob, damage.first);
|
||||
|
||||
@@ -126,7 +127,7 @@ void MobManager::npcAttackPc(Mob *mob, time_t currTime) {
|
||||
sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf;
|
||||
sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs));
|
||||
|
||||
auto damage = getDamage(475 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, 1);
|
||||
auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, rand() % plr->level + 1);
|
||||
plr->HP -= damage.first;
|
||||
|
||||
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
@@ -330,8 +331,15 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
||||
mob->appearanceData.iHP -= damage;
|
||||
|
||||
// wake up sleeping monster
|
||||
// TODO: remove client-side bit somehow
|
||||
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) {
|
||||
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||
pkt1.eCT = 2;
|
||||
pkt1.iID = mob->appearanceData.iNPC_ID;
|
||||
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||
}
|
||||
|
||||
if (mob->appearanceData.iHP <= 0)
|
||||
killMob(mob->target, mob);
|
||||
@@ -467,7 +475,15 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
if (distance <= (int)mob->data["m_iAtkRange"]) {
|
||||
// attack logic
|
||||
if (mob->nextAttack == 0) {
|
||||
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; // I *think* this is what this is
|
||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
pkt.iSpeed = (int)mob->data["m_iRunSpeed"];
|
||||
pkt.iToX = mob->appearanceData.iX;
|
||||
pkt.iToY = mob->appearanceData.iY;
|
||||
pkt.iToZ = mob->target->plr->z;
|
||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||
|
||||
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; //I *think* this is what this is
|
||||
npcAttackPc(mob, currTime);
|
||||
} else if (mob->nextAttack != 0 && currTime >= mob->nextAttack) {
|
||||
mob->nextAttack = currTime + (int)mob->data["m_iDelayTime"] * 100;
|
||||
@@ -477,7 +493,9 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
// movement logic
|
||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||
return;
|
||||
mob->nextMovement = currTime + 500;
|
||||
mob->nextMovement = currTime + 400;
|
||||
if (currTime >= mob->nextAttack)
|
||||
mob->nextAttack = 0;
|
||||
|
||||
int speed = mob->data["m_iRunSpeed"];
|
||||
|
||||
@@ -485,7 +503,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
||||
speed /= 2;
|
||||
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->target->plr->x, mob->target->plr->y, speed);
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->target->plr->x, mob->target->plr->y,std::min(distance-(int)mob->data["m_iAtkRange"]+1, speed*2/5));
|
||||
|
||||
NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ);
|
||||
|
||||
@@ -495,7 +513,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
pkt.iSpeed = speed;
|
||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||
pkt.iToZ = mob->appearanceData.iZ;
|
||||
pkt.iToZ = mob->target->plr->z;
|
||||
|
||||
// notify all nearby players
|
||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||
@@ -578,25 +596,25 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
||||
}
|
||||
|
||||
void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||
// distance between spawn point and current location
|
||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||
return;
|
||||
|
||||
mob->nextMovement = currTime + 500;
|
||||
mob->nextMovement = currTime + 400;
|
||||
|
||||
// distance between spawn point and current location
|
||||
int distance = hypot(mob->appearanceData.iX - mob->roamX, mob->appearanceData.iY - mob->roamY);
|
||||
|
||||
//if (distance > mob->data["m_iIdleRange"]) {
|
||||
if (distance > 10) {
|
||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
||||
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->roamX, mob->roamY, (int)mob->data["m_iRunSpeed"] * 3);
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->roamX, mob->roamY, (int)mob->data["m_iRunSpeed"]*4/5);
|
||||
|
||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 3;
|
||||
pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 2;
|
||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||
pkt.iToZ = mob->appearanceData.iZ;
|
||||
pkt.iToZ = mob->appearanceData.iZ = mob->spawnZ;
|
||||
|
||||
// notify all nearby players
|
||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||
@@ -610,12 +628,15 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||
mob->killedTime = 0;
|
||||
mob->nextAttack = 0;
|
||||
mob->appearanceData.iConditionBitFlag = 0;
|
||||
|
||||
resendMobHP(mob);
|
||||
|
||||
// HACK: we haven't found a better way to refresh a mob's client-side status
|
||||
drainMobHP(mob, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
static time_t lastDrainTime = 0;
|
||||
|
||||
for (auto& pair : Mobs) {
|
||||
int x = pair.second->appearanceData.iX;
|
||||
int y = pair.second->appearanceData.iY;
|
||||
@@ -624,6 +645,30 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
if (!ChunkManager::inPopulatedChunks(x, y, pair.second->instanceID))
|
||||
continue;
|
||||
|
||||
// drain
|
||||
if (currTime - lastDrainTime >= 600 && pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
||||
drainMobHP(pair.second, pair.second->maxHealth * 3 / 50); // lose 10% every second
|
||||
}
|
||||
|
||||
// unbuffing
|
||||
std::unordered_map<int32_t, time_t>::iterator it = pair.second->unbuffTimes.begin();
|
||||
while (it != pair.second->unbuffTimes.end()) {
|
||||
|
||||
if (currTime >= it->second) {
|
||||
pair.second->appearanceData.iConditionBitFlag &= ~it->first;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||
pkt1.eCT = 2;
|
||||
pkt1.iID = pair.second->appearanceData.iNPC_ID;
|
||||
pkt1.iConditionBitFlag = pair.second->appearanceData.iConditionBitFlag;
|
||||
NPCManager::sendToViewable(pair.second, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||
|
||||
it = pair.second->unbuffTimes.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// skip mob movement and combat if disabled
|
||||
if (!simulateMobs && pair.second->state != MobState::DEAD
|
||||
&& pair.second->state != MobState::RETREAT)
|
||||
@@ -652,6 +697,9 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currTime - lastDrainTime >= 600)
|
||||
lastDrainTime = currTime;
|
||||
|
||||
// deallocate all NPCs queued for removal
|
||||
while (RemovalQueue.size() > 0) {
|
||||
@@ -667,8 +715,6 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
std::pair<int,int> MobManager::lerp(int x1, int y1, int x2, int y2, int speed) {
|
||||
std::pair<int,int> ret = {x1, y1};
|
||||
|
||||
speed /= 2;
|
||||
|
||||
if (speed == 0)
|
||||
return ret;
|
||||
|
||||
@@ -714,8 +760,10 @@ void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) {
|
||||
void MobManager::combatEnd(CNSocket *sock, CNPacketData *data) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (plr != nullptr)
|
||||
if (plr != nullptr) {
|
||||
plr->inCombat = false;
|
||||
plr->healCooldown = 4000;
|
||||
}
|
||||
}
|
||||
|
||||
void MobManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
||||
@@ -810,11 +858,14 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
|
||||
dealGooDamage(sock, PC_MAXHEALTH(plr->level) * 3 / 20);
|
||||
|
||||
// heal
|
||||
if (currTime - lastHealTime >= 6000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
||||
plr->HP += PC_MAXHEALTH(plr->level) / 5;
|
||||
if (plr->HP > PC_MAXHEALTH(plr->level))
|
||||
plr->HP = PC_MAXHEALTH(plr->level);
|
||||
transmit = true;
|
||||
if (currTime - lastHealTime >= 4000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
||||
if (currTime - lastHealTime - plr->healCooldown >= 4000) {
|
||||
plr->HP += PC_MAXHEALTH(plr->level) / 5;
|
||||
if (plr->HP > PC_MAXHEALTH(plr->level))
|
||||
plr->HP = PC_MAXHEALTH(plr->level);
|
||||
transmit = true;
|
||||
} else
|
||||
plr->healCooldown -= 4000;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
@@ -856,7 +907,7 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
|
||||
}
|
||||
|
||||
// if this was a heal tick, update the counter outside of the loop
|
||||
if (currTime - lastHealTime >= 6000)
|
||||
if (currTime - lastHealTime >= 4000)
|
||||
lastHealTime = currTime;
|
||||
}
|
||||
|
||||
@@ -869,15 +920,15 @@ std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool
|
||||
|
||||
// base calculation
|
||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
||||
damage = std::max(std::max(29, attackPower / 7), damage - defensePower * (12 + difficulty) / 65);
|
||||
damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 40);
|
||||
damage = damage * (rand() % 40 + 80) / 100;
|
||||
|
||||
// Adaptium/Blastons/Cosmix
|
||||
if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) {
|
||||
if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2)
|
||||
damage = damage * 5 / 4;
|
||||
if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2)
|
||||
damage = damage * 3 / 2;
|
||||
else
|
||||
damage = damage * 4 / 5;
|
||||
damage = damage * 2 / 3;
|
||||
}
|
||||
|
||||
// weapon boosts
|
||||
@@ -950,10 +1001,12 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
else
|
||||
damage.first = plr->pointDamage;
|
||||
|
||||
damage = getDamage(damage.first, target->defense, true, (plr->batteryW >= 12), -1, -1, 1);
|
||||
damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 1);
|
||||
|
||||
if (plr->batteryW >= 12)
|
||||
plr->batteryW -= 12;
|
||||
if (plr->batteryW >= 6 + plr->level)
|
||||
plr->batteryW -= 6 + plr->level;
|
||||
else
|
||||
plr->batteryW = 0;
|
||||
|
||||
target->HP -= damage.first;
|
||||
|
||||
@@ -979,11 +1032,13 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
|
||||
int difficulty = (int)mob->data["m_iNpcLevel"];
|
||||
|
||||
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW >= 11 + difficulty),
|
||||
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty),
|
||||
NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||
|
||||
if (plr->batteryW >= 11 + difficulty)
|
||||
plr->batteryW -= 11 + difficulty;
|
||||
if (plr->batteryW >= 6 + difficulty)
|
||||
plr->batteryW -= 6 + difficulty;
|
||||
else
|
||||
plr->batteryW = 0;
|
||||
|
||||
damage.first = hitMob(sock, mob, damage.first);
|
||||
|
||||
@@ -1007,25 +1062,24 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_CHARs, resplen);
|
||||
}
|
||||
|
||||
// HACK: we haven't found a better way to refresh a mob's client-side status
|
||||
void MobManager::resendMobHP(Mob *mob) {
|
||||
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Heal_HP);
|
||||
void MobManager::drainMobHP(Mob *mob, int amount) {
|
||||
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Damage);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||
|
||||
memset(respbuf, 0, resplen);
|
||||
|
||||
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
||||
sSkillResult_Heal_HP *heal = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
||||
sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK));
|
||||
|
||||
pkt->iID = mob->appearanceData.iNPC_ID;
|
||||
pkt->eCT = 4; // mob
|
||||
pkt->iTB_ID = ECSB_HEAL; // sSkillResult_Heal_HP
|
||||
pkt->iTB_ID = ECSB_BOUNDINGBALL;
|
||||
|
||||
heal->eCT = 4;
|
||||
heal->iID = mob->appearanceData.iNPC_ID;
|
||||
heal->iHealHP = 0;
|
||||
heal->iHP = mob->appearanceData.iHP;
|
||||
drain->eCT = 4;
|
||||
drain->iID = mob->appearanceData.iNPC_ID;
|
||||
drain->iDamage = amount;
|
||||
drain->iHP = mob->appearanceData.iHP -= amount;
|
||||
|
||||
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
||||
}
|
||||
@@ -1046,7 +1100,7 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) {
|
||||
if (plr->HP <= 0)
|
||||
continue;
|
||||
|
||||
int mobRange = mob->data["m_iSightRange"];
|
||||
int mobRange = mob->sightRange;
|
||||
|
||||
if (plr->iConditionBitFlag & CSB_BIT_UP_STEALTH)
|
||||
mobRange /= 3;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "contrib/JSON.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
enum class MobState {
|
||||
@@ -27,6 +28,8 @@ struct Mob : public BaseNPC {
|
||||
int spawnZ;
|
||||
int level;
|
||||
|
||||
std::unordered_map<int32_t,time_t> unbuffTimes;
|
||||
|
||||
// dead
|
||||
time_t killedTime = 0;
|
||||
time_t regenTime;
|
||||
@@ -35,13 +38,15 @@ struct Mob : public BaseNPC {
|
||||
|
||||
// roaming
|
||||
int idleRange;
|
||||
const int sightRange;
|
||||
time_t nextMovement = 0;
|
||||
bool staticPath = false;
|
||||
int roamX, roamY, roamZ;
|
||||
|
||||
// combat
|
||||
CNSocket *target = nullptr;
|
||||
time_t nextAttack = 0;
|
||||
int roamX, roamY, roamZ;
|
||||
|
||||
|
||||
// drop
|
||||
int dropType;
|
||||
@@ -50,7 +55,9 @@ struct Mob : public BaseNPC {
|
||||
nlohmann::json data;
|
||||
|
||||
Mob(int x, int y, int z, int angle, uint64_t iID, int type, int hp, nlohmann::json d, int32_t id)
|
||||
: BaseNPC(x, y, z, angle, iID, type, id), maxHealth(hp) {
|
||||
: BaseNPC(x, y, z, angle, iID, type, id),
|
||||
maxHealth(hp),
|
||||
sightRange(d["m_iSightRange"]) {
|
||||
state = MobState::ROAMING;
|
||||
|
||||
data = d;
|
||||
@@ -132,7 +139,7 @@ namespace MobManager {
|
||||
std::pair<int,int> getDamage(int, int, bool, bool, int, int, int);
|
||||
|
||||
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
||||
void resendMobHP(Mob *mob);
|
||||
void drainMobHP(Mob *mob, int amount);
|
||||
void incNextMovement(Mob *mob, time_t currTime=0);
|
||||
bool aggroCheck(Mob *mob, time_t currTime);
|
||||
}
|
||||
|
@@ -107,7 +107,7 @@ void NPCManager::addNPC(std::vector<Chunk*> viewableChunks, int32_t id) {
|
||||
void NPCManager::destroyNPC(int32_t id) {
|
||||
// sanity check
|
||||
if (NPCs.find(id) == NPCs.end()) {
|
||||
std::cout << "npc not found : " << id << std::endl;
|
||||
std::cout << "npc not found: " << id << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,8 +133,6 @@ void NPCManager::destroyNPC(int32_t id) {
|
||||
// finally, remove it from the map and free it
|
||||
NPCs.erase(id);
|
||||
delete entity;
|
||||
|
||||
std::cout << "npc removed!" << std::endl;
|
||||
}
|
||||
|
||||
void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, int angle) {
|
||||
@@ -586,29 +584,37 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
|
||||
if (Warps.find(warpId) == Warps.end())
|
||||
return;
|
||||
|
||||
MissionManager::failInstancedMissions(sock); // fail any missions that require the player's current instance
|
||||
|
||||
uint64_t fromInstance = plrv.plr->instanceID; // saved for post-warp
|
||||
|
||||
if (plrv.plr->instanceID == 0) {
|
||||
// save last uninstanced coords
|
||||
plrv.plr->lastX = plrv.plr->x;
|
||||
plrv.plr->lastY = plrv.plr->y;
|
||||
plrv.plr->lastZ = plrv.plr->z;
|
||||
plrv.plr->lastAngle = plrv.plr->angle;
|
||||
}
|
||||
|
||||
// std::cerr << "Warped to Map Num:" << Warps[warpId].instanceID << " NPC ID " << Warps[warpId].npcID << std::endl;
|
||||
if (Warps[warpId].isInstance) {
|
||||
uint64_t instanceID = Warps[warpId].instanceID;
|
||||
if (Warps[warpId].limitTaskID != 0) { // if warp requires you to be on a mission, it's gotta be a unique instance
|
||||
|
||||
// if warp requires you to be on a mission, it's gotta be a unique instance
|
||||
if (Warps[warpId].limitTaskID != 0 || instanceID == 14) { // 14 is a special case for the Time Lab
|
||||
instanceID += ((uint64_t)plrv.plr->iIDGroup << 32); // upper 32 bits are leader ID
|
||||
ChunkManager::createInstance(instanceID);
|
||||
}
|
||||
|
||||
PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
|
||||
} else {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp); // Can only be used for exiting instances because it sets the instance flag to false
|
||||
if (plrv.plr->iID == plrv.plr->iIDGroup && plrv.plr->groupCnt == 1)
|
||||
PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
|
||||
else {
|
||||
Player* leaderPlr = PlayerManager::getPlayerFromID(plrv.plr->iIDGroup);
|
||||
|
||||
for (int i = 0; i < leaderPlr->groupCnt; i++) {
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(leaderPlr->groupIDs[i]);
|
||||
CNSocket* sockTo = PlayerManager::getSockFromID(leaderPlr->groupIDs[i]);
|
||||
|
||||
if (otherPlr == nullptr || sockTo == nullptr)
|
||||
continue;
|
||||
|
||||
PlayerManager::sendPlayerTo(sockTo, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp); //Can only be used for exiting instances because it sets the instance flag to false
|
||||
resp.iX = Warps[warpId].x;
|
||||
resp.iY = Warps[warpId].y;
|
||||
resp.iZ = Warps[warpId].z;
|
||||
|
@@ -22,7 +22,7 @@ std::set<int> LeechPowers = {24, 51, 89};
|
||||
std::set<int> SleepPowers = {28, 30, 32, 49, 70, 71, 81, 85, 94};
|
||||
|
||||
// passive powers
|
||||
std::set<int> ScavangePowers = {3, 50, 99};
|
||||
std::set<int> ScavengePowers = {3, 50, 99};
|
||||
std::set<int> RunPowers = {4, 68, 86};
|
||||
std::set<int> GroupRunPowers = {8, 62, 73};
|
||||
std::set<int> BonusPowers = {6, 54, 104};
|
||||
@@ -33,9 +33,9 @@ std::set<int> FreedomPowers = {31, 39, 107};
|
||||
std::set<int> GroupFreedomPowers = {15, 55, 77};
|
||||
std::set<int> JumpPowers = {16, 44, 88};
|
||||
std::set<int> GroupJumpPowers = {35, 60, 100};
|
||||
std::set<int> SelfRevivePowers = {22, 48, 83};
|
||||
std::set<int> SelfRevivePowers = {22, 48, 84};
|
||||
std::set<int> SneakPowers = {29, 72, 80};
|
||||
std::set<int> GroupSneakPowers = {23, 65, 84};
|
||||
std::set<int> GroupSneakPowers = {23, 65, 83};
|
||||
std::set<int> TreasureFinderPowers = {26, 40, 74};
|
||||
|
||||
/*
|
||||
@@ -46,6 +46,7 @@ std::set<int> TreasureFinderPowers = {26, 40, 74};
|
||||
}; // namespace
|
||||
|
||||
std::map<int32_t, NanoData> NanoManager::NanoTable;
|
||||
std::map<int32_t, NanoTuning> NanoManager::NanoTunings;
|
||||
|
||||
void NanoManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler);
|
||||
@@ -187,7 +188,7 @@ void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) {
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skill = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skill->iNanoID, skill->iTuneID);
|
||||
setNanoSkill(sock, skill);
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) {
|
||||
@@ -195,7 +196,7 @@ void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) {
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skillGM = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skillGM->iNanoID, skillGM->iTuneID);
|
||||
setNanoSkill(sock, skillGM);
|
||||
}
|
||||
|
||||
void NanoManager::nanoRecallHandler(CNSocket* sock, CNPacketData* data) {
|
||||
@@ -347,8 +348,8 @@ void NanoManager::summonNano(CNSocket *sock, int slot) {
|
||||
plr->activeNano = nanoId;
|
||||
}
|
||||
|
||||
void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) {
|
||||
if (nanoId > 36)
|
||||
void NanoManager::setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) {
|
||||
if (skill->iNanoID > 36)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
@@ -356,25 +357,68 @@ void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId)
|
||||
if (plr == nullptr)
|
||||
return;
|
||||
|
||||
if (plr->activeNano > 0 && plr->activeNano == nanoId)
|
||||
if (plr->activeNano > 0 && plr->activeNano == skill->iNanoID)
|
||||
summonNano(sock, -1); // just unsummon the nano to prevent infinite buffs
|
||||
|
||||
sNano nano = plr->Nanos[nanoId];
|
||||
|
||||
nano.iSkillID = skillId;
|
||||
plr->Nanos[nanoId] = nano;
|
||||
sNano nano = plr->Nanos[skill->iNanoID];
|
||||
nano.iSkillID = skill->iTuneID;
|
||||
plr->Nanos[skill->iNanoID] = nano;
|
||||
|
||||
// Send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_TUNE_SUCC, resp);
|
||||
resp.iNanoID = nanoId;
|
||||
resp.iSkillID = skillId;
|
||||
resp.iNanoID = skill->iNanoID;
|
||||
resp.iSkillID = skill->iTuneID;
|
||||
resp.iPC_FusionMatter = plr->fusionmatter;
|
||||
resp.aItem[9] = plr->Inven[0]; // temp fix for a bug TODO: Use this for nano power changing later
|
||||
resp.aItem[9] = plr->Inven[0]; // quick fix to make sure item in slot 0 doesn't get yeeted by default
|
||||
|
||||
|
||||
// check if there's any garbage in the item slot array (this'll happen when a nano station isn't used)
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (skill->aiNeedItemSlotNum[i] < 0 || skill->aiNeedItemSlotNum[i] >= AINVEN_COUNT) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC));
|
||||
return; // stop execution, don't run consumption logic
|
||||
}
|
||||
}
|
||||
|
||||
if (plr->fusionmatter < (int)MissionManager::AvatarGrowth[plr->level]["m_iReqBlob_NanoTune"]) // sanity check
|
||||
return;
|
||||
|
||||
plr->fusionmatter -= (int)MissionManager::AvatarGrowth[plr->level]["m_iReqBlob_NanoTune"];
|
||||
|
||||
int reqItemCount = NanoTunings[skill->iTuneID].reqItemCount;
|
||||
int reqItemID = NanoTunings[skill->iTuneID].reqItems;
|
||||
int i = 0;
|
||||
while (reqItemCount > 0 && i < 10) {
|
||||
|
||||
sItemBase& item = plr->Inven[skill->aiNeedItemSlotNum[i]];
|
||||
if (item.iType == 7 && item.iID == reqItemID) {
|
||||
if (item.iOpt > reqItemCount) {
|
||||
item.iOpt -= reqItemCount;
|
||||
reqItemCount = 0;
|
||||
}
|
||||
else {
|
||||
reqItemCount -= item.iOpt;
|
||||
item.iID = 0;
|
||||
item.iType = 0;
|
||||
item.iOpt = 0;
|
||||
}
|
||||
}
|
||||
i++; // next slot
|
||||
}
|
||||
|
||||
resp.iPC_FusionMatter = plr->fusionmatter; // update fusion matter in packet
|
||||
// update items clientside
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (skill->aiNeedItemSlotNum[i]) { // non-zero check
|
||||
resp.aItem[i] = plr->Inven[skill->aiNeedItemSlotNum[i]];
|
||||
resp.aiItemSlotNum[i] = skill->aiNeedItemSlotNum[i];
|
||||
}
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC));
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl;
|
||||
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skill->iTuneID << " for nano: " << skill->iNanoID << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
@@ -407,14 +451,14 @@ bool doDebuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage_N_Debuff *re
|
||||
|
||||
Mob* mob = MobManager::Mobs[pktdata[i]];
|
||||
|
||||
int damage = MobManager::hitMob(sock, mob, amount);
|
||||
int damage = MobManager::hitMob(sock, mob, 0); // using amount for something else
|
||||
|
||||
respdata[i].eCT = 4;
|
||||
respdata[i].iDamage = damage;
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iHP = mob->appearanceData.iHP;
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= iCBFlag;
|
||||
|
||||
mob->unbuffTimes[iCBFlag] = getTime() + amount;
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl;
|
||||
|
||||
return true;
|
||||
@@ -428,10 +472,12 @@ bool doBuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Buff *respdata, int i
|
||||
}
|
||||
|
||||
Mob* mob = MobManager::Mobs[pktdata[i]];
|
||||
MobManager::hitMob(sock, mob, 0);
|
||||
|
||||
respdata[i].eCT = 4;
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= iCBFlag;
|
||||
mob->unbuffTimes[iCBFlag] = getTime() + amount;
|
||||
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl;
|
||||
|
||||
@@ -669,15 +715,15 @@ void activePower(CNSocket *sock, CNPacketData *data,
|
||||
|
||||
// active nano power dispatch table
|
||||
std::vector<ActivePower> ActivePowers = {
|
||||
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 0),
|
||||
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 25),
|
||||
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 25),
|
||||
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 2250),
|
||||
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 35),
|
||||
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 20),
|
||||
// TODO: Recall
|
||||
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 0),
|
||||
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 0),
|
||||
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 3000),
|
||||
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 4500),
|
||||
ActivePower(DamagePowers, activePower<sSkillResult_Damage, doDamage>, EST_DAMAGE, CSB_BIT_NONE, 12),
|
||||
ActivePower(LeechPowers, activePower<sSkillResult_Heal_HP, doLeech, LEECH>, EST_BLOODSUCKING, CSB_BIT_NONE, 18),
|
||||
ActivePower(SleepPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SLEEP, CSB_BIT_MEZ, 0),
|
||||
ActivePower(SleepPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SLEEP, CSB_BIT_MEZ, 4500),
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
@@ -825,7 +871,7 @@ int NanoManager::nanoStyle(int nanoId) {
|
||||
namespace NanoManager {
|
||||
|
||||
std::vector<PassivePower> PassivePowers = {
|
||||
PassivePower(ScavangePowers, EST_REWARDBLOB, CSB_BIT_REWARD_BLOB, ECSB_REWARD_BLOB, 0, false),
|
||||
PassivePower(ScavengePowers, EST_REWARDBLOB, CSB_BIT_REWARD_BLOB, ECSB_REWARD_BLOB, 0, false),
|
||||
PassivePower(RunPowers, EST_RUN, CSB_BIT_UP_MOVE_SPEED, ECSB_UP_MOVE_SPEED, 200, false),
|
||||
PassivePower(GroupRunPowers, EST_RUN, CSB_BIT_UP_MOVE_SPEED, ECSB_UP_MOVE_SPEED, 200, true),
|
||||
PassivePower(BonusPowers, EST_REWARDCASH, CSB_BIT_REWARD_CASH, ECSB_REWARD_CASH, 0, false),
|
||||
|
@@ -39,10 +39,16 @@ struct NanoData {
|
||||
int style;
|
||||
};
|
||||
|
||||
struct NanoTuning {
|
||||
int reqItemCount;
|
||||
int reqItems;
|
||||
};
|
||||
|
||||
namespace NanoManager {
|
||||
extern std::vector<ActivePower> ActivePowers;
|
||||
extern std::vector<PassivePower> PassivePowers;
|
||||
extern std::map<int32_t, NanoData> NanoTable;
|
||||
extern std::map<int32_t, NanoTuning> NanoTunings;
|
||||
void init();
|
||||
|
||||
void nanoSummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
@@ -58,7 +64,7 @@ namespace NanoManager {
|
||||
// Helper methods
|
||||
void addNano(CNSocket* sock, int16_t nanoId, int16_t slot, bool spendfm=false);
|
||||
void summonNano(CNSocket* sock, int slot);
|
||||
void setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId);
|
||||
void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill);
|
||||
void resetNanoSkill(CNSocket* sock, int16_t nanoId);
|
||||
|
||||
void nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t eSkillType, int32_t iCBFlag, int16_t eCharStatusTimeBuffID, int16_t iValue = 0, bool groupPower = false);
|
||||
|
@@ -50,6 +50,7 @@ struct Player {
|
||||
|
||||
bool inCombat;
|
||||
bool passiveNanoOut;
|
||||
int healCooldown;
|
||||
|
||||
int pointDamage;
|
||||
int groupDamage;
|
||||
|
@@ -222,15 +222,25 @@ void PlayerManager::updatePlayerChunk(CNSocket* sock, int X, int Y, uint64_t ins
|
||||
// now, add all the new npcs & players!
|
||||
addPlayerToChunks(ChunkManager::getDeltaChunks(allChunks, view.currentChunks), sock);
|
||||
|
||||
ChunkManager::addPlayer(X, Y, view.plr->instanceID, sock); // takes care of adding the player to the chunk if it exists or not
|
||||
view.chunkPos = newPos;
|
||||
view.currentChunks = allChunks;
|
||||
ChunkManager::addPlayer(X, Y, view.plr->instanceID, sock); // takes care of adding the player to the chunk if it exists or not
|
||||
}
|
||||
|
||||
void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I) {
|
||||
PlayerView& plrv = PlayerManager::players[sock];
|
||||
Player* plr = plrv.plr;
|
||||
|
||||
if (plrv.plr->instanceID == 0) {
|
||||
// save last uninstanced coords
|
||||
plrv.plr->lastX = plrv.plr->x;
|
||||
plrv.plr->lastY = plrv.plr->y;
|
||||
plrv.plr->lastZ = plrv.plr->z;
|
||||
plrv.plr->lastAngle = plrv.plr->angle;
|
||||
}
|
||||
|
||||
MissionManager::failInstancedMissions(sock); // fail any instanced missions
|
||||
|
||||
uint64_t fromInstance = plr->instanceID;
|
||||
|
||||
plr->instanceID = I;
|
||||
@@ -242,7 +252,6 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I
|
||||
sendPlayerTo(sock, X, Y, Z);
|
||||
} else {
|
||||
// annoying but necessary to set the flag back
|
||||
MissionManager::failInstancedMissions(sock); // fail any instanced missions
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp);
|
||||
resp.iX = X;
|
||||
resp.iY = Y;
|
||||
@@ -252,6 +261,7 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I
|
||||
PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock);
|
||||
plrv.currentChunks.clear();
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC));
|
||||
updatePlayerPosition(sock, X, Y, Z);
|
||||
}
|
||||
|
||||
ChunkManager::destroyInstanceIfEmpty(fromInstance);
|
||||
@@ -702,7 +712,6 @@ void PlayerManager::gotoPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
std::cout << "\tZ: " << gotoData->iToZ << std::endl;
|
||||
)
|
||||
|
||||
MissionManager::failInstancedMissions(sock); // this ensures warping by command still fails instanced missions
|
||||
sendPlayerTo(sock, gotoData->iToX, gotoData->iToY, gotoData->iToZ, 0);
|
||||
}
|
||||
|
||||
@@ -793,9 +802,7 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
NanoManager::nanoUnbuff(sock, CSB_BIT_PHOENIX, ECSB_PHOENIX, 0, false);
|
||||
plr->HP = PC_MAXHEALTH(plr->level);
|
||||
} else {
|
||||
plr->x = target.x;
|
||||
plr->y = target.y;
|
||||
plr->z = target.z;
|
||||
updatePlayerPosition(sock, target.x, target.y, target.z);
|
||||
|
||||
if (reviveData->iRegenType != 5)
|
||||
plr->HP = PC_MAXHEALTH(plr->level);
|
||||
|
@@ -175,6 +175,18 @@ void TableData::init() {
|
||||
}
|
||||
|
||||
std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nanos" << std::endl;
|
||||
|
||||
nlohmann::json nanoTuneInfo = xdtData["m_pNanoTable"]["m_pNanoTuneData"];
|
||||
for (nlohmann::json::iterator _nano = nanoTuneInfo.begin(); _nano != nanoTuneInfo.end(); _nano++) {
|
||||
auto nano = _nano.value();
|
||||
NanoTuning nanoData;
|
||||
nanoData.reqItems = nano["m_iReqItemID"];
|
||||
nanoData.reqItemCount = nano["m_iReqItemCount"];
|
||||
NanoManager::NanoTunings[nano["m_iSkillID"]] = nanoData;
|
||||
}
|
||||
|
||||
std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nano tunings" << std::endl;
|
||||
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << "[FATAL] Malformed xdt.json file! Reason:" << err.what() << std::endl;
|
||||
@@ -258,19 +270,22 @@ void TableData::loadPaths(int* nextId) {
|
||||
std::cout << "[INFO] Loaded " << TransportManager::SkywayPaths.size() << " skyway paths" << std::endl;
|
||||
|
||||
// slider circuit
|
||||
int sliders = 0;
|
||||
int stops = 0;
|
||||
int pos = 0;
|
||||
nlohmann::json pathDataSlider = pathData["slider"];
|
||||
for (nlohmann::json::iterator _sliderPoint = pathDataSlider.begin(); _sliderPoint != pathDataSlider.end(); _sliderPoint++) {
|
||||
auto sliderPoint = _sliderPoint.value();
|
||||
if (sliderPoint["stop"] && sliders % 2 == 0) { // check if this point in the circuit is a stop
|
||||
if (sliderPoint["stop"]) { // check if this point in the circuit is a stop
|
||||
// spawn a slider
|
||||
BaseNPC* slider = new BaseNPC(sliderPoint["iX"], sliderPoint["iY"], sliderPoint["iZ"], 0, INSTANCE_OVERWORLD, 1, (*nextId)++, NPC_BUS);
|
||||
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
|
||||
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->appearanceData.iX, slider->appearanceData.iY, slider->appearanceData.iZ);
|
||||
// set slider path to a rotation of the circuit
|
||||
constructPathSlider(pathDataSlider, 0, slider->appearanceData.iNPC_ID);
|
||||
sliders++;
|
||||
constructPathSlider(pathDataSlider, pos, slider->appearanceData.iNPC_ID);
|
||||
|
||||
stops++;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
// npc paths
|
||||
@@ -452,13 +467,14 @@ void TableData::constructPathSlider(nlohmann::json points, int rotations, int sl
|
||||
for (int i = 0; i < stopTime + 1; i++) // repeat point if it's a stop
|
||||
route.push(from); // add point A to the queue
|
||||
WarpLocation to = { point["iX"] , point["iY"] , point["iZ"] }; // point B coords
|
||||
// we may need to change this later; right now, the speed is cut before and after stops (no accel)
|
||||
float curve = 1;
|
||||
if (stopTime > 0) { // point A is a stop
|
||||
curve = 2.0f;
|
||||
curve = 0.375f;//2.0f;
|
||||
} else if (point["stop"]) { // point B is a stop
|
||||
curve = 0.35f;
|
||||
curve = 0.375f;//0.35f;
|
||||
}
|
||||
TransportManager::lerp(&route, from, to, SLIDER_SPEED, curve); // lerp from A to B (arbitrary speed)
|
||||
TransportManager::lerp(&route, from, to, SLIDER_SPEED * curve, 1); // lerp from A to B (arbitrary speed)
|
||||
from = to; // update point A
|
||||
stopTime = point["stop"] ? SLIDER_STOP_TICKS : 0;
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
const int SLIDER_SPEED = 1200;
|
||||
const int SLIDER_STOP_TICKS = 8;
|
||||
const int SLIDER_STOP_TICKS = 16;
|
||||
|
||||
struct WarpLocation;
|
||||
|
||||
|
@@ -236,8 +236,8 @@ namespace sqlite_orm {
|
||||
template<size_t N, size_t I, class L, class R>
|
||||
void move_tuple_impl(L &lhs, R &rhs) {
|
||||
std::get<I>(lhs) = std::move(std::get<I>(rhs));
|
||||
internal::static_if<std::integral_constant<bool, N != I + 1>{}>([](auto &lhs, auto &rhs) {
|
||||
move_tuple_impl<N, I + 1>(lhs, rhs);
|
||||
internal::static_if<std::integral_constant<bool, N != I + 1>{}>([](auto &l, auto &r) {
|
||||
move_tuple_impl<N, I + 1>(l, r);
|
||||
})(lhs, rhs);
|
||||
}
|
||||
}
|
||||
@@ -247,8 +247,8 @@ namespace sqlite_orm {
|
||||
template<size_t N, class L, class R>
|
||||
void move_tuple(L &lhs, R &rhs) {
|
||||
using bool_type = std::integral_constant<bool, N != 0>;
|
||||
static_if<bool_type{}>([](auto &lhs, auto &rhs) {
|
||||
tuple_helper::move_tuple_impl<N, 0>(lhs, rhs);
|
||||
static_if<bool_type{}>([](auto &l, auto &r) {
|
||||
tuple_helper::move_tuple_impl<N, 0>(l, r);
|
||||
})(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -577,8 +577,8 @@ namespace sqlite_orm {
|
||||
|
||||
const foreign_key_type &fk;
|
||||
|
||||
on_update_delete_t(decltype(fk) fk_, decltype(update) update, foreign_key_action action_) :
|
||||
on_update_delete_base{update}, fk(fk_), _action(action_) {}
|
||||
on_update_delete_t(decltype(fk) fk_, decltype(update) update_, foreign_key_action action_) :
|
||||
on_update_delete_base{update_}, fk(fk_), _action(action_) {}
|
||||
|
||||
foreign_key_action _action = foreign_key_action::none;
|
||||
|
||||
@@ -691,8 +691,8 @@ namespace sqlite_orm {
|
||||
foreign_key_intermediate_t(tuple_type columns_) : columns(std::move(columns_)) {}
|
||||
|
||||
template<class... Rs>
|
||||
foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>> references(Rs... references) {
|
||||
return {std::move(this->columns), std::make_tuple(std::forward<Rs>(references)...)};
|
||||
foreign_key_t<std::tuple<Cs...>, std::tuple<Rs...>> references(Rs... refs) {
|
||||
return {std::move(this->columns), std::make_tuple(std::forward<Rs>(refs)...)};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -1544,12 +1544,12 @@ namespace sqlite_orm {
|
||||
*/
|
||||
constraints_type constraints;
|
||||
|
||||
column_t(std::string name,
|
||||
column_t(std::string name_,
|
||||
member_pointer_t member_pointer_,
|
||||
getter_type getter_,
|
||||
setter_type setter_,
|
||||
constraints_type constraints_) :
|
||||
column_base{std::move(name)},
|
||||
column_base{std::move(name_)},
|
||||
member_pointer(member_pointer_), getter(getter_), setter(setter_), constraints(move(constraints_)) {}
|
||||
|
||||
/**
|
||||
@@ -1922,7 +1922,7 @@ namespace sqlite_orm {
|
||||
T expr;
|
||||
internal::collate_argument argument;
|
||||
|
||||
collate_t(T expr_, internal::collate_argument argument_) : expr(expr_), argument(argument_) {}
|
||||
collate_t(T expr_, internal::collate_argument argument_) : expr(std::move(expr_)), argument(argument_) {}
|
||||
|
||||
operator std::string() const {
|
||||
return constraints::collate_t{this->argument};
|
||||
@@ -2205,7 +2205,7 @@ namespace sqlite_orm {
|
||||
L l; // left expression
|
||||
A arg; // in arg
|
||||
|
||||
in_t(L l_, A arg_, bool negative) : in_base{negative}, l(l_), arg(std::move(arg_)) {}
|
||||
in_t(L l_, A arg_, bool negative_) : in_base{negative_}, l(l_), arg(std::move(arg_)) {}
|
||||
};
|
||||
|
||||
struct is_null_string {
|
||||
@@ -2344,8 +2344,8 @@ namespace sqlite_orm {
|
||||
struct dynamic_order_by_entry_t : order_by_base {
|
||||
std::string name;
|
||||
|
||||
dynamic_order_by_entry_t(decltype(name) name_, int asc_desc, std::string collate_argument) :
|
||||
order_by_base{asc_desc, move(collate_argument)}, name(move(name_)) {}
|
||||
dynamic_order_by_entry_t(decltype(name) name_, int asc_desc_, std::string collate_argument_) :
|
||||
order_by_base{asc_desc_, move(collate_argument_)}, name(move(name_)) {}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2463,8 +2463,8 @@ namespace sqlite_orm {
|
||||
sqlite_orm::internal::optional_container<escape_t>
|
||||
arg3; // not escape cause escape exists as a function here
|
||||
|
||||
like_t(arg_t arg_, pattern_t pattern_, sqlite_orm::internal::optional_container<escape_t> escape) :
|
||||
arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape)) {}
|
||||
like_t(arg_t arg_, pattern_t pattern_, sqlite_orm::internal::optional_container<escape_t> escape_) :
|
||||
arg(std::move(arg_)), pattern(std::move(pattern_)), arg3(std::move(escape_)) {}
|
||||
|
||||
template<class C>
|
||||
like_t<A, T, C> escape(C c) const {
|
||||
@@ -4332,8 +4332,8 @@ namespace sqlite_orm {
|
||||
using left_type = typename compound_operator<L, R>::left_type;
|
||||
using right_type = typename compound_operator<L, R>::right_type;
|
||||
|
||||
union_t(left_type l, right_type r, decltype(all) all) :
|
||||
compound_operator<L, R>(std::move(l), std::move(r)), union_base{all} {}
|
||||
union_t(left_type l, right_type r, decltype(all) all_) :
|
||||
compound_operator<L, R>(std::move(l), std::move(r)), union_base{all_} {}
|
||||
|
||||
union_t(left_type l, right_type r) : union_t(std::move(l), std::move(r), false) {}
|
||||
};
|
||||
@@ -4979,14 +4979,14 @@ namespace sqlite_orm {
|
||||
std::transform(str.begin(), str.end(), std::back_inserter(upper_str), [](char c) {
|
||||
return static_cast<char>(std::toupper(static_cast<int>(c)));
|
||||
});
|
||||
static std::array<journal_mode, 6> all = {
|
||||
static std::array<journal_mode, 6> all = {{
|
||||
journal_mode::DELETE,
|
||||
journal_mode::TRUNCATE,
|
||||
journal_mode::PERSIST,
|
||||
journal_mode::MEMORY,
|
||||
journal_mode::WAL,
|
||||
journal_mode::OFF,
|
||||
};
|
||||
}};
|
||||
for(auto j: all) {
|
||||
if(to_string(j) == upper_str) {
|
||||
return std::make_unique<journal_mode>(j);
|
||||
@@ -5400,8 +5400,8 @@ namespace sqlite_orm {
|
||||
using columns_type = std::tuple<Cols...>;
|
||||
using object_type = void;
|
||||
|
||||
index_t(std::string name, bool unique, columns_type columns_) :
|
||||
index_base{move(name), unique}, columns(move(columns_)) {}
|
||||
index_t(std::string name_, bool unique_, columns_type columns_) :
|
||||
index_base{move(name_), unique_}, columns(move(columns_)) {}
|
||||
|
||||
columns_type columns;
|
||||
};
|
||||
@@ -5990,22 +5990,22 @@ namespace sqlite_orm {
|
||||
// Make static_if have at least one input as a workaround for GCC bug:
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095
|
||||
if(!res) {
|
||||
static_if<std::is_same<C, member_pointer_t>{}>([&res, &obj, &col](const C &c) {
|
||||
if(compare_any(col.member_pointer, c)) {
|
||||
static_if<std::is_same<C, member_pointer_t>{}>([&res, &obj, &col](const C &c_) {
|
||||
if(compare_any(col.member_pointer, c_)) {
|
||||
res = &(obj.*col.member_pointer);
|
||||
}
|
||||
})(c);
|
||||
}
|
||||
if(!res) {
|
||||
static_if<std::is_same<C, getter_type>{}>([&res, &obj, &col](const C &c) {
|
||||
if(compare_any(col.getter, c)) {
|
||||
static_if<std::is_same<C, getter_type>{}>([&res, &obj, &col](const C &c_) {
|
||||
if(compare_any(col.getter, c_)) {
|
||||
res = &((obj).*(col.getter))();
|
||||
}
|
||||
})(c);
|
||||
}
|
||||
if(!res) {
|
||||
static_if<std::is_same<C, setter_type>{}>([&res, &obj, &col](const C &c) {
|
||||
if(compare_any(col.setter, c)) {
|
||||
static_if<std::is_same<C, setter_type>{}>([&res, &obj, &col](const C &c_) {
|
||||
if(compare_any(col.setter, c_)) {
|
||||
res = &((obj).*(col.getter))();
|
||||
}
|
||||
})(c);
|
||||
@@ -6271,7 +6271,7 @@ namespace sqlite_orm {
|
||||
struct storage_impl_base {
|
||||
|
||||
bool table_exists(const std::string &tableName, sqlite3 *db) const {
|
||||
auto res = false;
|
||||
auto result = false;
|
||||
std::stringstream ss;
|
||||
ss << "SELECT COUNT(*) FROM sqlite_master WHERE type = '"
|
||||
<< "table"
|
||||
@@ -6287,13 +6287,13 @@ namespace sqlite_orm {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
&res,
|
||||
&result,
|
||||
nullptr);
|
||||
if(rc != SQLITE_OK) {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
}
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
void rename_table(sqlite3 *db, const std::string &oldName, const std::string &newName) const {
|
||||
@@ -6355,7 +6355,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
std::vector<table_info> get_table_info(const std::string &tableName, sqlite3 *db) const {
|
||||
std::vector<table_info> res;
|
||||
std::vector<table_info> result;
|
||||
auto query = "PRAGMA table_info('" + tableName + "')";
|
||||
auto rc = sqlite3_exec(
|
||||
db,
|
||||
@@ -6375,13 +6375,13 @@ namespace sqlite_orm {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
&res,
|
||||
&result,
|
||||
nullptr);
|
||||
if(rc != SQLITE_OK) {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
}
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7184,8 +7184,8 @@ namespace sqlite_orm {
|
||||
|
||||
expression_type t;
|
||||
|
||||
prepared_statement_t(T t_, sqlite3_stmt *stmt, connection_ref con_) :
|
||||
prepared_statement_base{stmt, std::move(con_)}, t(std::move(t_)) {}
|
||||
prepared_statement_t(T t_, sqlite3_stmt *stmt_, connection_ref con_) :
|
||||
prepared_statement_base{stmt_, std::move(con_)}, t(std::move(t_)) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -7973,8 +7973,8 @@ namespace sqlite_orm {
|
||||
|
||||
template<class L>
|
||||
void operator()(const node_type &c, const L &l) const {
|
||||
c.case_expression.apply([&l](auto &c) {
|
||||
iterate_ast(c, l);
|
||||
c.case_expression.apply([&l](auto &c_) {
|
||||
iterate_ast(c_, l);
|
||||
});
|
||||
iterate_tuple(c.args, [&l](auto &pair) {
|
||||
iterate_ast(pair.first, l);
|
||||
@@ -8082,6 +8082,16 @@ namespace sqlite_orm {
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct ast_iterator<collate_t<T>, void> {
|
||||
using node_type = collate_t<T>;
|
||||
|
||||
template<class L>
|
||||
void operator()(const node_type &node, const L &l) const {
|
||||
iterate_ast(node.expr, l);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8189,6 +8199,14 @@ namespace sqlite_orm {
|
||||
|
||||
pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {}
|
||||
|
||||
void busy_timeout(int value) {
|
||||
this->set_pragma("busy_timeout", value);
|
||||
}
|
||||
|
||||
int busy_timeout() {
|
||||
return this->get_pragma<int>("busy_timeout");
|
||||
}
|
||||
|
||||
sqlite_orm::journal_mode journal_mode() {
|
||||
return this->get_pragma<sqlite_orm::journal_mode>("journal_mode");
|
||||
}
|
||||
@@ -8237,7 +8255,7 @@ namespace sqlite_orm {
|
||||
T get_pragma(const std::string &name) {
|
||||
auto connection = this->get_connection();
|
||||
auto query = "PRAGMA " + name;
|
||||
T res;
|
||||
T result;
|
||||
auto db = connection.get();
|
||||
auto rc = sqlite3_exec(
|
||||
db,
|
||||
@@ -8249,10 +8267,10 @@ namespace sqlite_orm {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
&res,
|
||||
&result,
|
||||
nullptr);
|
||||
if(rc == SQLITE_OK) {
|
||||
return res;
|
||||
return result;
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -8700,13 +8718,11 @@ namespace sqlite_orm {
|
||||
|
||||
bool transaction(const std::function<bool()> &f) {
|
||||
this->begin_transaction();
|
||||
auto con = this->get_connection();
|
||||
auto db = con.get();
|
||||
auto shouldCommit = f();
|
||||
if(shouldCommit) {
|
||||
this->commit(db);
|
||||
this->commit();
|
||||
} else {
|
||||
this->rollback(db);
|
||||
this->rollback();
|
||||
}
|
||||
return shouldCommit;
|
||||
}
|
||||
@@ -8744,10 +8760,10 @@ namespace sqlite_orm {
|
||||
db,
|
||||
sql.c_str(),
|
||||
[](void *data, int argc, char **argv, char * * /*columnName*/) -> int {
|
||||
auto &tableNames = *(data_t *)data;
|
||||
auto &tableNames_ = *(data_t *)data;
|
||||
for(int i = 0; i < argc; i++) {
|
||||
if(argv[i]) {
|
||||
tableNames.push_back(argv[i]);
|
||||
tableNames_.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -8863,6 +8879,27 @@ namespace sqlite_orm {
|
||||
return this->connection->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether connection to database is opened right now.
|
||||
* Returns always `true` for in memory databases.
|
||||
*/
|
||||
bool is_opened() const {
|
||||
return this->connection->retain_count() > 0;
|
||||
}
|
||||
|
||||
int busy_handler(std::function<int(int)> handler) {
|
||||
_busy_handler = move(handler);
|
||||
if(this->is_opened()) {
|
||||
if(_busy_handler) {
|
||||
return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this);
|
||||
} else {
|
||||
return sqlite3_busy_handler(this->connection->get(), nullptr, nullptr);
|
||||
}
|
||||
} else {
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
storage_base(const std::string &filename_, int foreignKeysCount) :
|
||||
pragma(std::bind(&storage_base::get_connection, this)),
|
||||
@@ -8900,6 +8937,7 @@ namespace sqlite_orm {
|
||||
std::unique_ptr<connection_holder> connection;
|
||||
std::map<std::string, collating_function> collatingFunctions;
|
||||
const int cachedForeignKeysCount;
|
||||
std::function<int(int)> _busy_handler;
|
||||
|
||||
connection_ref get_connection() {
|
||||
connection_ref res{*this->connection};
|
||||
@@ -8924,7 +8962,7 @@ namespace sqlite_orm {
|
||||
|
||||
bool foreign_keys(sqlite3 *db) {
|
||||
std::string query = "PRAGMA foreign_keys";
|
||||
auto res = false;
|
||||
auto result = false;
|
||||
auto rc = sqlite3_exec(
|
||||
db,
|
||||
query.c_str(),
|
||||
@@ -8935,13 +8973,13 @@ namespace sqlite_orm {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
&res,
|
||||
&result,
|
||||
nullptr);
|
||||
if(rc != SQLITE_OK) {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
}
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8972,6 +9010,10 @@ namespace sqlite_orm {
|
||||
sqlite3_limit(db, p.first, p.second);
|
||||
}
|
||||
|
||||
if(_busy_handler) {
|
||||
sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this);
|
||||
}
|
||||
|
||||
if(this->on_open) {
|
||||
this->on_open(db);
|
||||
}
|
||||
@@ -9035,7 +9077,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
std::string current_timestamp(sqlite3 *db) {
|
||||
std::string res;
|
||||
std::string result;
|
||||
std::stringstream ss;
|
||||
ss << "SELECT CURRENT_TIMESTAMP";
|
||||
auto query = ss.str();
|
||||
@@ -9051,13 +9093,13 @@ namespace sqlite_orm {
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
&res,
|
||||
&result,
|
||||
nullptr);
|
||||
if(rc != SQLITE_OK) {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
}
|
||||
return res;
|
||||
return result;
|
||||
}
|
||||
|
||||
void drop_table_internal(const std::string &tableName, sqlite3 *db) {
|
||||
@@ -9087,6 +9129,15 @@ namespace sqlite_orm {
|
||||
return f(leftLen, lhs, rightLen, rhs);
|
||||
}
|
||||
|
||||
static int busy_handler_callback(void *selfPointer, int triesCount) {
|
||||
auto &storage = *static_cast<storage_base *>(selfPointer);
|
||||
if(storage._busy_handler) {
|
||||
return storage._busy_handler(triesCount);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// returns foreign keys count in storage definition
|
||||
template<class T>
|
||||
static int foreign_keys_count(T &storageImpl) {
|
||||
@@ -9859,8 +9910,8 @@ namespace sqlite_orm {
|
||||
std::string operator()(const statement_type &c, const C &context) const {
|
||||
std::stringstream ss;
|
||||
ss << "CASE ";
|
||||
c.case_expression.apply([&ss, context](auto &c) {
|
||||
ss << serialize(c, context) << " ";
|
||||
c.case_expression.apply([&ss, context](auto &c_) {
|
||||
ss << serialize(c_, context) << " ";
|
||||
});
|
||||
iterate_tuple(c.args, [&ss, context](auto &pair) {
|
||||
ss << "WHEN " << serialize(pair.first, context) << " ";
|
||||
@@ -10545,17 +10596,17 @@ namespace sqlite_orm {
|
||||
}
|
||||
ss << "VALUES ";
|
||||
auto valuesString = [columnNamesCount] {
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
std::stringstream ss_;
|
||||
ss_ << "(";
|
||||
for(size_t i = 0; i < columnNamesCount; ++i) {
|
||||
ss << "?";
|
||||
ss_ << "?";
|
||||
if(i < columnNamesCount - 1) {
|
||||
ss << ", ";
|
||||
ss_ << ", ";
|
||||
} else {
|
||||
ss << ")";
|
||||
ss_ << ")";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
return ss_.str();
|
||||
}();
|
||||
auto valuesCount = static_cast<int>(std::distance(rep.range.first, rep.range.second));
|
||||
for(auto i = 0; i < valuesCount; ++i) {
|
||||
@@ -10600,17 +10651,17 @@ namespace sqlite_orm {
|
||||
}
|
||||
ss << "VALUES ";
|
||||
auto valuesString = [columnNamesCount] {
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
std::stringstream ss_;
|
||||
ss_ << "(";
|
||||
for(size_t i = 0; i < columnNamesCount; ++i) {
|
||||
ss << "?";
|
||||
ss_ << "?";
|
||||
if(i < columnNamesCount - 1) {
|
||||
ss << ", ";
|
||||
ss_ << ", ";
|
||||
} else {
|
||||
ss << ")";
|
||||
ss_ << ")";
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
return ss_.str();
|
||||
}();
|
||||
auto valuesCount = static_cast<int>(std::distance(statement.range.first, statement.range.second));
|
||||
for(auto i = 0; i < valuesCount; ++i) {
|
||||
@@ -11980,7 +12031,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
template<class T, class... Args>
|
||||
prepared_statement_t<get_all_t<T, Args...>> prepare(get_all_t<T, Args...> get) {
|
||||
prepared_statement_t<get_all_t<T, Args...>> prepare(get_all_t<T, Args...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -11988,9 +12039,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -11998,7 +12049,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
template<class T, class... Args>
|
||||
prepared_statement_t<get_all_pointer_t<T, Args...>> prepare(get_all_pointer_t<T, Args...> get) {
|
||||
prepared_statement_t<get_all_pointer_t<T, Args...>> prepare(get_all_pointer_t<T, Args...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -12006,9 +12057,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -12017,7 +12068,7 @@ namespace sqlite_orm {
|
||||
|
||||
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
|
||||
template<class T, class R, class... Args>
|
||||
prepared_statement_t<get_all_optional_t<T, R, Args...>> prepare(get_all_optional_t<T, R, Args...> get) {
|
||||
prepared_statement_t<get_all_optional_t<T, R, Args...>> prepare(get_all_optional_t<T, R, Args...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -12025,9 +12076,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -12073,7 +12124,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
template<class T, class... Ids>
|
||||
prepared_statement_t<get_t<T, Ids...>> prepare(get_t<T, Ids...> get) {
|
||||
prepared_statement_t<get_t<T, Ids...>> prepare(get_t<T, Ids...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -12081,9 +12132,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -12091,7 +12142,7 @@ namespace sqlite_orm {
|
||||
}
|
||||
|
||||
template<class T, class... Ids>
|
||||
prepared_statement_t<get_pointer_t<T, Ids...>> prepare(get_pointer_t<T, Ids...> get) {
|
||||
prepared_statement_t<get_pointer_t<T, Ids...>> prepare(get_pointer_t<T, Ids...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -12099,9 +12150,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -12110,7 +12161,7 @@ namespace sqlite_orm {
|
||||
|
||||
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
|
||||
template<class T, class... Ids>
|
||||
prepared_statement_t<get_optional_t<T, Ids...>> prepare(get_optional_t<T, Ids...> get) {
|
||||
prepared_statement_t<get_optional_t<T, Ids...>> prepare(get_optional_t<T, Ids...> get_) {
|
||||
auto con = this->get_connection();
|
||||
sqlite3_stmt *stmt;
|
||||
auto db = con.get();
|
||||
@@ -12118,9 +12169,9 @@ namespace sqlite_orm {
|
||||
context_t context{this->impl};
|
||||
context.skip_table_name = false;
|
||||
context.replace_bindable_with_question = true;
|
||||
auto query = serialize(get, context);
|
||||
auto query = serialize(get_, context);
|
||||
if(sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
return {std::move(get), stmt, con};
|
||||
return {std::move(get_), stmt, con};
|
||||
} else {
|
||||
throw std::system_error(std::error_code(sqlite3_errcode(db), get_sqlite_error_category()),
|
||||
sqlite3_errmsg(db));
|
||||
@@ -13315,8 +13366,8 @@ namespace sqlite_orm {
|
||||
++index;
|
||||
}
|
||||
if(index == N) {
|
||||
internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &result, auto &node) {
|
||||
result = const_cast<typename std::remove_reference<decltype(result)>::type>(&node);
|
||||
internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &r, auto &n) {
|
||||
r = const_cast<typename std::remove_reference<decltype(r)>::type>(&n);
|
||||
})(result, node);
|
||||
}
|
||||
});
|
||||
@@ -13338,8 +13389,8 @@ namespace sqlite_orm {
|
||||
++index;
|
||||
}
|
||||
if(index == N) {
|
||||
internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &result, auto &node) {
|
||||
result = const_cast<typename std::remove_reference<decltype(result)>::type>(&node);
|
||||
internal::static_if<std::is_same<result_tupe, node_type>{}>([](auto &r, auto &n) {
|
||||
r = const_cast<typename std::remove_reference<decltype(r)>::type>(&n);
|
||||
})(result, node);
|
||||
}
|
||||
});
|
||||
|
@@ -12,7 +12,7 @@ int settings::DBSAVEINTERVAL = 240;
|
||||
int settings::SHARDPORT = 8002;
|
||||
std::string settings::SHARDSERVERIP = "127.0.0.1";
|
||||
time_t settings::TIMEOUT = 60000;
|
||||
int settings::VIEWDISTANCE = 40000;
|
||||
int settings::VIEWDISTANCE = 25600;
|
||||
bool settings::SIMULATEMOBS = true;
|
||||
|
||||
// default spawn point is Sector V (future)
|
||||
|
2
tdata
2
tdata
Submodule tdata updated: aa4338202e...c77e75308d
Reference in New Issue
Block a user