mirror of
https://github.com/microvolts/MicrovoltsEmulator
synced 2026-08-24 06:26:03 -04:00
Bug fixes, more refactoring
This commit is contained in:
parent
35a94d1240
commit
195dbc4e1e
33 changed files with 693 additions and 332 deletions
|
|
@ -30,6 +30,7 @@
|
|||
<ClInclude Include="include\ConstantDatabase\Structures\CdbCapsuleDisplay.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbCapsuleInfo.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbItemInfo.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbItemsInfo.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbMapInfo.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbUpgradeInfo.h" />
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbWeaponsInfo.h" />
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@
|
|||
<ClInclude Include="include\ConstantDatabase\Structures\CdbCapsuleDisplay.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ConstantDatabase\Structures\CdbItemsInfo.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Cryptography\Crypt.cpp">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "Cdb.h"
|
||||
#include <string>
|
||||
#include "Structures/CdbItemInfo.h"
|
||||
#include "Structures/CdbItemsInfo.h"
|
||||
#include "Structures/CdbWeaponsInfo.h"
|
||||
|
||||
namespace Common
|
||||
|
|
@ -15,7 +16,6 @@ namespace Common
|
|||
{
|
||||
private:
|
||||
inline static Cdb<T> m_cdb{};
|
||||
inline static std::unordered_map<std::uint32_t, std::vector<std::uint32_t>> m_gambleItems; // [type][itemIds]
|
||||
inline static std::unordered_map<std::uint32_t, std::uint32_t> m_itemByType; // [itemId][Type]
|
||||
|
||||
public:
|
||||
|
|
@ -24,61 +24,30 @@ namespace Common
|
|||
return m_cdb;
|
||||
}
|
||||
|
||||
static const auto& getGambleItems()
|
||||
{
|
||||
return m_gambleItems;
|
||||
}
|
||||
|
||||
static std::uint32_t getItemType(std::uint32_t itemId)
|
||||
{
|
||||
return m_itemByType[itemId];
|
||||
}
|
||||
|
||||
static void initialize(const std::string& filePath, const std::string& fileName)
|
||||
requires std::same_as<T, Common::ConstantDatabase::CdbWeaponInfo>
|
||||
{
|
||||
m_cdb.parse(filePath, fileName);
|
||||
auto entries = m_cdb.getEntries();
|
||||
for (const auto& [id, structType] : entries)
|
||||
{
|
||||
if ((strcmp(structType.ii_name_time, "Unlimited") == 0) && structType.ii_is_trade && structType.ii_upgradable)
|
||||
{
|
||||
m_gambleItems[structType.ii_type].push_back(static_cast<std::uint32_t>(structType.ii_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void initializeItemTypes(const std::string& filePath, const std::string& weaponFileName, const std::string& itemFileName)
|
||||
requires std::same_as<T, Common::ConstantDatabase::CdbItemInfo>
|
||||
requires std::same_as<T, Common::ConstantDatabase::CdbItemsInfoCMV>
|
||||
{
|
||||
/*
|
||||
Cdb<CdbWeaponInfo> cdbWeapon{};
|
||||
cdbWeapon.parse(filePath, weaponFileName);
|
||||
auto entries = cdbWeapon.getEntries();
|
||||
for (const auto& [id, structType] : entries)
|
||||
{
|
||||
m_itemByType[structType.ii_id] = structType.ii_type;
|
||||
}
|
||||
}*/
|
||||
|
||||
Cdb<CdbItemInfo> cdbItem{};
|
||||
Cdb<Common::ConstantDatabase::CdbItemsInfoCMV> cdbItem{};
|
||||
cdbItem.parse(filePath, itemFileName);
|
||||
auto entries2 = cdbItem.getEntries();
|
||||
for (const auto& [id, structType] : entries2)
|
||||
{
|
||||
m_itemByType[structType.ii_id] = structType.ii_type;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize(const std::string& filePath, const std::string& fileName)
|
||||
requires std::same_as<T, Common::ConstantDatabase::CdbItemInfo>
|
||||
{
|
||||
m_cdb.parse(filePath, fileName);
|
||||
auto entries = m_cdb.getEntries();
|
||||
auto entries = cdbItem.getEntries();
|
||||
for (const auto& [id, structType] : entries)
|
||||
{
|
||||
if ((strcmp(structType.ii_name_time, "Unlimited") == 0) && structType.ii_is_trade)
|
||||
{
|
||||
m_gambleItems[structType.ii_type].push_back(static_cast<std::uint32_t>(structType.ii_id));
|
||||
}
|
||||
m_itemByType[structType.ii_id] = structType.ii_type;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "visit_struct/visit_struct.hpp"
|
||||
|
||||
// This is used for MVSurge, refer to "CdbItemsInfo" for CMV
|
||||
namespace Common
|
||||
{
|
||||
namespace ConstantDatabase
|
||||
|
|
|
|||
81
Common/include/ConstantDatabase/Structures/CdbItemsInfo.h
Normal file
81
Common/include/ConstantDatabase/Structures/CdbItemsInfo.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef CDB_ITEMSINFOS_STRUCT_H
|
||||
#define CDB_ITEMSINFOS_STRUCT_H
|
||||
|
||||
#include "visit_struct/visit_struct.hpp"
|
||||
|
||||
// This is for CMV, equivalent to ItemInfo + WeaponInfo on Surge (for CMV they both were placed in a single file)
|
||||
namespace Common
|
||||
{
|
||||
namespace ConstantDatabase
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct CdbItemsInfoCMV
|
||||
{
|
||||
int ii_id;
|
||||
char ii_name[50];
|
||||
char ii_name_option[50];
|
||||
char ii_name_time[50];
|
||||
int ii_type;
|
||||
int ii_type_inven;
|
||||
bool ii_inven_usable;
|
||||
int ii_type_pcbang;
|
||||
int ii_package_result;
|
||||
bool ii_dress;
|
||||
bool ii_hide_hair;
|
||||
bool ii_hide_face;
|
||||
bool ii_hide_back;
|
||||
bool ii_class_a;
|
||||
bool ii_class_b;
|
||||
bool ii_class_c;
|
||||
bool ii_class_d;
|
||||
bool ii_class_e;
|
||||
int ii_grade;
|
||||
int ii_stocks;
|
||||
bool ii_usable;
|
||||
bool ii_upgradable;
|
||||
bool ii_consumable;
|
||||
int ii_weaponinfo;
|
||||
int ii_durable_value;
|
||||
int ii_durable_factor;
|
||||
int ii_durable_repair_type;
|
||||
bool ii_limited_mod;
|
||||
int ii_limited_time;
|
||||
int ii_buy_coupon;
|
||||
int ii_buy_cash;
|
||||
int ii_buy_point;
|
||||
int ii_sell_point;
|
||||
int ii_bonus_point;
|
||||
int ii_bonus_pack;
|
||||
int ii_dioramainfo;
|
||||
int ii_dummyinfo;
|
||||
int ii_icon;
|
||||
int ii_iconsmall;
|
||||
char ii_meshfilename[50];
|
||||
char ii_nodename[50];
|
||||
char ii_color_ambient[50];
|
||||
char ii_color_diffuse[50];
|
||||
char ii_color_specular[50];
|
||||
char ii_color_emittance[50];
|
||||
int ii_sfx;
|
||||
int ef_effect_1;
|
||||
int ef_target_1;
|
||||
int ef_effect_2;
|
||||
int ef_target_2;
|
||||
int ef_effect_3;
|
||||
int ef_target_3;
|
||||
char ii_desc[200];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
||||
|
||||
VISITABLE_STRUCT(Common::ConstantDatabase::CdbItemsInfoCMV, ii_id, ii_name, ii_name_option, ii_name_time, ii_type, ii_type_inven, ii_inven_usable, ii_type_pcbang, ii_package_result, ii_dress, ii_hide_hair, ii_hide_face, ii_hide_back, ii_class_a, ii_class_b,
|
||||
ii_class_c, ii_class_d, ii_class_e, ii_grade, ii_stocks, ii_usable,
|
||||
ii_upgradable, ii_consumable, ii_weaponinfo, ii_durable_value, ii_durable_factor, ii_durable_repair_type, ii_limited_mod, ii_limited_time, ii_buy_coupon, ii_buy_cash, ii_buy_point,
|
||||
ii_sell_point, ii_bonus_point, ii_bonus_pack, ii_dioramainfo, ii_dummyinfo, ii_icon, ii_iconsmall, ii_meshfilename, ii_nodename, ii_color_ambient, ii_color_diffuse, ii_color_specular, ii_color_emittance,
|
||||
ii_sfx, ef_effect_1, ef_target_1, ef_effect_2, ef_target_2, ef_effect_3, ef_target_3, ii_desc
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "visit_struct/visit_struct.hpp"
|
||||
|
||||
// This is used for MVSurge, refer to "CdbItemsInfo" for CMV
|
||||
namespace Common
|
||||
{
|
||||
namespace ConstantDatabase
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -178,6 +178,7 @@
|
|||
<ClCompile Include="src\ChatCommands\SimpleCommands\Shutdown.cpp" />
|
||||
<ClCompile Include="src\ChatCommands\SimpleRoomCommands\BreakroomCommand.cpp" />
|
||||
<ClCompile Include="src\ChatCommands\SimpleRoomCommands\UnmuteRoom.cpp" />
|
||||
<ClCompile Include="src\Classes\CapsuleManager.cpp" />
|
||||
<ClCompile Include="src\Classes\Player.cpp" />
|
||||
<ClCompile Include="src\Classes\Room.cpp" />
|
||||
<ClCompile Include="src\Classes\RoomsManager.cpp" />
|
||||
|
|
@ -214,6 +215,7 @@
|
|||
<ClInclude Include="include\ChatCommands\SimpleCommands\Shutdown.h" />
|
||||
<ClInclude Include="include\ChatCommands\SimpleRoomCommands\BreakroomCommand.h" />
|
||||
<ClInclude Include="include\ChatCommands\SimpleRoomCommands\UnmuteRoom.h" />
|
||||
<ClInclude Include="include\Classes\CapsuleManager.h" />
|
||||
<ClInclude Include="include\Classes\Player.h" />
|
||||
<ClInclude Include="include\Classes\RoomsManager.h" />
|
||||
<ClInclude Include="include\Handlers\CapsuleReqHandler.h" />
|
||||
|
|
@ -233,6 +235,7 @@
|
|||
<ClInclude Include="include\Handlers\Room\EliminationNextRoundHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Room\MatchLeaveHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Room\RoomChangeHostHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Room\RoomInviteJoin.h" />
|
||||
<ClInclude Include="include\Handlers\Room\RoomJoinHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Player\LobbyAccountInfoHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Player\Mailbox\MailboxDeleteHandler.h" />
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<ClCompile Include="src\ChatCommands\SimpleRoomCommands\Muteroom.cpp" />
|
||||
<ClCompile Include="src\ChatCommands\SimpleRoomCommands\UnmuteRoom.cpp" />
|
||||
<ClCompile Include="src\ChatCommands\ComplexCommands\OneArgumentCommands\ChangeHost.cpp" />
|
||||
<ClCompile Include="src\Classes\CapsuleManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\ChatCommands\AllCommandsIncludes.h" />
|
||||
|
|
@ -135,5 +136,7 @@
|
|||
<ClInclude Include="include\Handlers\CapsuleReqHandler.h" />
|
||||
<ClInclude Include="include\Structures\ClientData\Structures.h" />
|
||||
<ClInclude Include="include\Handlers\Item\ItemAndCapsuleHandler.h" />
|
||||
<ClInclude Include="include\Handlers\Room\RoomInviteJoin.h" />
|
||||
<ClInclude Include="include\Classes\CapsuleManager.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -30,8 +30,8 @@ namespace Main
|
|||
std::uint32_t itemId{};
|
||||
std::uint32_t m_maxCapsuleItems{};
|
||||
|
||||
using cdbItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbItemInfo>;
|
||||
using cdbWeapons = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbWeaponInfo>;
|
||||
using cdbItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbItemsInfoCMV>;
|
||||
//using cdbWeapons = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbWeaponInfo>;
|
||||
using cdbUpgrades = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbUpgradeInfo>;
|
||||
using cdbCapsuleInfos = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbCapsuleInfo>;
|
||||
using cdbCapsulePackageInfos = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbCapsulePackageInfo>;
|
||||
|
|
@ -68,32 +68,17 @@ namespace Main
|
|||
|
||||
std::optional<ItemTypePricePair> getItemPrice() const
|
||||
{
|
||||
const auto itemInfoMapPrice = getItemPriceInternal(cdbItems::getInstance());
|
||||
if (itemInfoMapPrice == std::nullopt)
|
||||
{
|
||||
return getItemPriceInternal(cdbWeapons::getInstance());
|
||||
}
|
||||
return itemInfoMapPrice;
|
||||
return getItemPriceInternal(cdbItems::getInstance());
|
||||
}
|
||||
|
||||
std::optional<std::uint16_t> getItemDurability() const
|
||||
{
|
||||
const auto itemDurability = getDurabilityInternal(cdbItems::getInstance());
|
||||
if (itemDurability == std::nullopt)
|
||||
{
|
||||
return getDurabilityInternal(cdbWeapons::getInstance());
|
||||
}
|
||||
return itemDurability;
|
||||
return getDurabilityInternal(cdbItems::getInstance());
|
||||
}
|
||||
|
||||
std::optional<std::uint16_t> getItemRefundPrice() const
|
||||
{
|
||||
const auto refundValue = getRefundValue(cdbItems::getInstance());
|
||||
if (refundValue == std::nullopt)
|
||||
{
|
||||
return getRefundValue(cdbWeapons::getInstance());
|
||||
}
|
||||
return refundValue;
|
||||
return getRefundValue(cdbItems::getInstance());
|
||||
}
|
||||
|
||||
std::optional<Common::ConstantDatabase::CdbRewardInfo> getRewardInfoForMode(std::uint32_t mode) const
|
||||
|
|
@ -116,34 +101,14 @@ namespace Main
|
|||
return entry;
|
||||
}
|
||||
|
||||
std::optional<bool> isImmediatelySet() const
|
||||
{
|
||||
const auto isItemImmediatelySet = isImmediatelySetInternal(cdbItems::getInstance());
|
||||
if (isItemImmediatelySet == std::nullopt)
|
||||
{
|
||||
return isImmediatelySetInternal(cdbWeapons::getInstance());
|
||||
}
|
||||
return isItemImmediatelySet;
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> getItemDuration() const
|
||||
{
|
||||
const auto itemInfoMapExpiration = getItemDurationInternal(cdbItems::getInstance());
|
||||
if (itemInfoMapExpiration == std::nullopt)
|
||||
{
|
||||
return getItemDurationInternal(cdbWeapons::getInstance());
|
||||
}
|
||||
return itemInfoMapExpiration;
|
||||
return getItemDurationInternal(cdbItems::getInstance());
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> getItemType() const
|
||||
{
|
||||
const auto itemType = getItemTypeInternal(cdbItems::getInstance());
|
||||
if (itemType == std::nullopt)
|
||||
{
|
||||
return getItemTypeInternal(cdbWeapons::getInstance());
|
||||
}
|
||||
return itemType;
|
||||
return getItemTypeInternal(cdbItems::getInstance());
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> getBatteryNeededForUpgrade() const
|
||||
|
|
|
|||
29
MainServer/include/Classes/CapsuleManager.h
Normal file
29
MainServer/include/Classes/CapsuleManager.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef CAPSULE_MANAGER_H
|
||||
#define CAPSULE_MANAGER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "../Persistence/MainScheduler.h"
|
||||
|
||||
namespace Main
|
||||
{
|
||||
namespace Classes
|
||||
{
|
||||
class CapsuleManager
|
||||
{
|
||||
private:
|
||||
std::uint32_t m_jackpot{};
|
||||
Main::Persistence::MainScheduler& m_scheduler;
|
||||
Main::Persistence::PersistentDatabase& database;
|
||||
|
||||
public:
|
||||
explicit CapsuleManager(Main::Persistence::MainScheduler& m_scheduler, Main::Persistence::PersistentDatabase& database);
|
||||
|
||||
std::uint32_t getJackpot();
|
||||
void addJackpot(uint32_t value);
|
||||
void subJackpot(uint32_t value);
|
||||
void setJackpot(uint32_t jackpot);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef CAPSULE_REQ_HANDLER_H
|
||||
#define CAPSULE_REQ_HANDLER_H
|
||||
|
||||
#include "../Network/MainSession.h"
|
||||
#include "../Network/MainSessionManager.h"
|
||||
#include "Network/Packet.h"
|
||||
#include <ConstantDatabase/Structures/SetItemInfo.h>
|
||||
#include <Utils/Utils.h>
|
||||
#include "../Classes/CapsuleManager.h"
|
||||
|
||||
#include "../Utilities.h"
|
||||
|
||||
|
|
@ -13,13 +12,13 @@ namespace Main
|
|||
{
|
||||
namespace Handlers
|
||||
{
|
||||
inline void handleCapsuleReq(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
|
||||
inline void handleCapsuleReq(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::CapsuleManager& capsule)
|
||||
{
|
||||
// capsules are all completely client sided
|
||||
Common::Network::Packet response;
|
||||
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
|
||||
response.setOrder(83);
|
||||
std::uint32_t mpJackpot = 0;
|
||||
std::uint32_t mpJackpot = capsule.getJackpot();
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&mpJackpot), sizeof(mpJackpot));
|
||||
session.asyncWrite(response);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "../../include/Structures/AccountInfo/MainAccountInfo.h"
|
||||
#include "Network/Packet.h"
|
||||
#include "../Structures/Capsule/CapsuleSpin.h"
|
||||
#include "../Classes/CapsuleManager.h"
|
||||
#include <random>
|
||||
|
||||
namespace Main
|
||||
|
|
@ -30,33 +31,43 @@ namespace Main
|
|||
NORMAL_SPIN = 1
|
||||
};
|
||||
|
||||
enum CapsuleSpinLuckyRewards
|
||||
{
|
||||
GoldLuck = 7304,
|
||||
SilverLuck = 7305,
|
||||
BronzeLuck = 7306,
|
||||
SemiLuck = 7307,
|
||||
NotSoLuck = 7308,
|
||||
ToughLuck = 7309
|
||||
};
|
||||
|
||||
inline std::pair<std::uint32_t, std::uint32_t> itemSelectionAlgorithm(const Main::ConstantDatabase::CdbUtil& cdbUtil, std::uint32_t gi_itemid,
|
||||
std::uint32_t gi_price, std::uint32_t gi_type)
|
||||
std::uint32_t gi_price, std::uint32_t gi_type)
|
||||
{
|
||||
static std::array<double, 3> averageSpinCostByCurrency = cdbUtil.getAverageSpinCostByCurrency();
|
||||
auto items = cdbUtil.getAllEntriesWhereId(gi_itemid);
|
||||
|
||||
constexpr const std::uint32_t maxProbability = 200'000;
|
||||
constexpr const double priceFactor = 0.2;
|
||||
constexpr const double priceFactor = 0.2;
|
||||
|
||||
std::vector<std::pair<std::pair<std::uint32_t, std::uint32_t>, double>> itemProbabilities;
|
||||
for (const auto& item : items)
|
||||
for (const auto& item : items)
|
||||
{
|
||||
if (!item.pi_type) continue;
|
||||
double probability = static_cast<double>(item.pi_prob) / maxProbability * 100.0;
|
||||
if (gi_price > averageSpinCostByCurrency[gi_type] && item.pi_type == 2) // Increase chance for rare
|
||||
{
|
||||
probability *= (1.0 + priceFactor);
|
||||
probability *= (1.0 + priceFactor);
|
||||
}
|
||||
else if (gi_price < averageSpinCostByCurrency[gi_type] && item.pi_type == 2) // decrease chance for rare
|
||||
{
|
||||
probability *= (1.0 - priceFactor);
|
||||
probability *= (1.0 - priceFactor);
|
||||
}
|
||||
itemProbabilities.emplace_back(std::pair{ item.pi_valueA, item.pi_type }, probability);
|
||||
}
|
||||
|
||||
std::vector<double> probabilities;
|
||||
for (const auto& pair : itemProbabilities)
|
||||
for (const auto& pair : itemProbabilities)
|
||||
{
|
||||
probabilities.push_back(pair.second);
|
||||
}
|
||||
|
|
@ -64,8 +75,42 @@ namespace Main
|
|||
std::discrete_distribution<int> itemDistribution(probabilities.begin(), probabilities.end());
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
int randomIndex = itemDistribution(gen);
|
||||
|
||||
return itemProbabilities[itemDistribution(gen)].first;
|
||||
return itemProbabilities[randomIndex].first;
|
||||
}
|
||||
|
||||
inline Common::ConstantDatabase::CdbCapsulePackageInfo luckySelectionAlgorithm(const ConstantDatabase::CdbUtil& cdbUtil, std::uint32_t gi_itemid,
|
||||
std::uint32_t gi_type, Classes::CapsuleManager capsuleManager)
|
||||
{
|
||||
auto items = cdbUtil.getAllEntriesWhereId(gi_itemid);
|
||||
|
||||
constexpr const std::uint32_t maxProbability = 860400;
|
||||
std::vector<std::pair<Common::ConstantDatabase::CdbCapsulePackageInfo, double>> itemProbabilities;
|
||||
for (const auto& item : items)
|
||||
{
|
||||
double probability = static_cast<double>(item.pi_prob) / maxProbability * 100.0;
|
||||
itemProbabilities.emplace_back(item, probability);
|
||||
}
|
||||
|
||||
std::vector<double> probabilities;
|
||||
for (const auto& pair : itemProbabilities)
|
||||
{
|
||||
probabilities.push_back(pair.second);
|
||||
}
|
||||
|
||||
std::discrete_distribution<int> itemDistribution(probabilities.begin(), probabilities.end());
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
int randomIndex = itemDistribution(gen);
|
||||
for (int i = 0; i < itemProbabilities.size(); i++)
|
||||
{
|
||||
if (itemProbabilities[i].first.pi_id == SilverLuck)
|
||||
{
|
||||
randomIndex = i;
|
||||
}
|
||||
}
|
||||
return itemProbabilities[randomIndex].first;
|
||||
}
|
||||
|
||||
inline void removeCurrencyByCapsuleType(Main::Network::Session& session, const Main::Structures::AccountInfo& accountInfo, CapsuleCurrencyType capsuleCurrencyType,
|
||||
|
|
@ -81,30 +126,10 @@ namespace Main
|
|||
}
|
||||
}
|
||||
|
||||
inline void handleCapsuleSpin(const Common::Network::Packet& request, Main::Network::Session& session)
|
||||
inline void handleItemSpin(const Common::Network::Packet& request, Network::Session& session, Common::Network::Packet& response,
|
||||
ConstantDatabase::CdbUtil& cdbUtil, Common::ConstantDatabase::CdbCapsuleInfo capsuleInfo, Structures::AccountInfo accountInfo,
|
||||
Classes::CapsuleManager& capsuleManager)
|
||||
{
|
||||
auto response = request;
|
||||
response.setOption(1); // number of items per spin in newer versions
|
||||
|
||||
Main::ConstantDatabase::CdbUtil cdbUtil;
|
||||
const auto& capsuleInfo = cdbUtil.getCapsuleInfoById(request.getOption());
|
||||
if (capsuleInfo == std::nullopt)
|
||||
{
|
||||
// Apparently there's no error message in this case in CMV, just resend the packet given by the client...
|
||||
session.asyncWrite(response);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& accountInfo = session.getAccountInfo();
|
||||
if (capsuleInfo->gi_type == CapsuleCurrencyType::ROCKTOTENS && accountInfo.rockTotens < capsuleInfo->gi_pay_cash * request.getOption()
|
||||
|| capsuleInfo->gi_type == CapsuleCurrencyType::MICROPOINTS && accountInfo.microPoints < capsuleInfo->gi_pay_point * request.getOption())
|
||||
{
|
||||
response.setExtra(CapsuleSpinExtra::NOT_ENOUGH_CURRENCY);
|
||||
response.setOption(capsuleInfo->gi_type);
|
||||
session.asyncWrite(response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session.hasEnoughInventorySpace(request.getOption()))
|
||||
{
|
||||
response.setExtra(CapsuleSpinExtra::INVENTORY_FULL);
|
||||
|
|
@ -112,37 +137,26 @@ namespace Main
|
|||
return;
|
||||
}
|
||||
|
||||
constexpr const std::uint32_t maxLuckySpin = 1000;
|
||||
std::size_t i = 0;
|
||||
|
||||
Main::Structures::CapsuleSpin capsuleSpin;
|
||||
if (session.getLuckyPoints() > maxLuckySpin)
|
||||
{
|
||||
session.setLuckyPoints(0);
|
||||
//response.setMission(CapsuleSpinMission::LUCKY_SPIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
//response.setMission(CapsuleSpinMission::NORMAL_SPIN);
|
||||
}
|
||||
capsuleSpin.itemSerialInfo.itemNumber = session.getLatestItemNumber() + 1;
|
||||
session.setLatestItemNumber(capsuleSpin.itemSerialInfo.itemNumber);
|
||||
|
||||
// Unsure how to handle this for CMV, currently only RT capsules are enabled, the rest are prices = 0
|
||||
// Here I'm assuming that to enable e.g. the MP capsule, we just need to
|
||||
std::uint32_t price = 0;
|
||||
if (capsuleInfo->gi_type == CapsuleCurrencyType::ROCKTOTENS)
|
||||
if (capsuleInfo.gi_type == CapsuleCurrencyType::ROCKTOTENS) // rt
|
||||
{
|
||||
price = capsuleInfo->gi_pay_cash;
|
||||
price = capsuleInfo.gi_pay_cash;
|
||||
}
|
||||
else if (capsuleInfo->gi_type == CapsuleCurrencyType::MICROPOINTS)
|
||||
else if (capsuleInfo.gi_type == CapsuleCurrencyType::MICROPOINTS) // mp
|
||||
{
|
||||
price = capsuleInfo->gi_pay_point;
|
||||
}
|
||||
price = capsuleInfo.gi_pay_point;
|
||||
}
|
||||
|
||||
const std::pair<std::uint32_t, std::uint32_t> wonItemIdAndType = itemSelectionAlgorithm(cdbUtil, capsuleInfo->gi_itemid, price, capsuleInfo->gi_type);
|
||||
const std::pair<std::uint32_t, std::uint32_t> wonItemIdAndType = itemSelectionAlgorithm(cdbUtil, capsuleInfo.gi_itemid, price, capsuleInfo.gi_type);
|
||||
capsuleSpin.winItemId = wonItemIdAndType.first;
|
||||
cdbUtil.setItemId(capsuleSpin.winItemId);
|
||||
|
||||
if (cdbUtil.getItemDurability() == std::nullopt)
|
||||
{
|
||||
// Apparently there's no error message in this case in CMV, just resend the packet given by the client...
|
||||
|
|
@ -154,17 +168,105 @@ namespace Main
|
|||
item.expirationDate = *cdbUtil.getItemDuration();
|
||||
item.serialInfo = capsuleSpin.itemSerialInfo;
|
||||
item.id = capsuleSpin.winItemId;
|
||||
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&capsuleSpin), sizeof(Main::Structures::CapsuleSpin));
|
||||
session.asyncWrite(response);
|
||||
session.addItem(item);
|
||||
removeCurrencyByCapsuleType(session, accountInfo, static_cast<CapsuleCurrencyType>(capsuleInfo->gi_type), price);
|
||||
removeCurrencyByCapsuleType(session, accountInfo, static_cast<CapsuleCurrencyType>(capsuleInfo.gi_type), price);
|
||||
capsuleManager.addJackpot(400);
|
||||
|
||||
if (response.getMission() != 0)
|
||||
{
|
||||
session.addLuckyPoints(capsuleInfo->gi_bonus_lucky);
|
||||
session.addLuckyPoints(capsuleInfo.gi_bonus_lucky);
|
||||
}
|
||||
}
|
||||
|
||||
inline void handleLuckySpin(const Common::Network::Packet& request, Network::Session& session, Common::Network::Packet& response,
|
||||
ConstantDatabase::CdbUtil& cdbUtil, Common::ConstantDatabase::CdbCapsuleInfo capsuleInfo, Structures::AccountInfo accountInfo,
|
||||
Classes::CapsuleManager& capsuleManager, Network::SessionsManager sessionsManager)
|
||||
{
|
||||
const auto selectedItem = luckySelectionAlgorithm(cdbUtil, capsuleInfo.gi_itemid, capsuleInfo.gi_type, capsuleManager);
|
||||
|
||||
std::uint32_t mpAmountToReturn;
|
||||
std::uint32_t mpAmountToAdd;
|
||||
auto const jackpotValue = capsuleManager.getJackpot();
|
||||
std::string winMessage;
|
||||
|
||||
switch (selectedItem.pi_id)
|
||||
{
|
||||
case GoldLuck:
|
||||
mpAmountToReturn = jackpotValue;
|
||||
mpAmountToAdd = jackpotValue;
|
||||
winMessage = std::string("[") + session.getPlayerName() + "] won a Gold Luck Charm and earned " + std::to_string(mpAmountToAdd) + " MP!";
|
||||
break;
|
||||
case SilverLuck:
|
||||
mpAmountToReturn = selectedItem.pi_valueA * 1000; // % of the jackpot we won, 300000 = 30%, pi_valueA = 300
|
||||
mpAmountToAdd = jackpotValue * (selectedItem.pi_valueA / 10) / 100; // 30% of the jackpot
|
||||
winMessage = std::string("[") + session.getPlayerName() + "] won a Silver Luck Charm and earned " + std::to_string(mpAmountToAdd) + " MP!";
|
||||
break;
|
||||
case BronzeLuck:
|
||||
mpAmountToReturn = jackpotValue; // 10% of this value results in the MP amount we get
|
||||
mpAmountToAdd = jackpotValue * (selectedItem.pi_valueA / 10) / 100; // 10% of the jackpot
|
||||
winMessage = std::string("[") + session.getPlayerName() + "] won a Copper Luck Charm and earned " + std::to_string(mpAmountToAdd) + " MP!";
|
||||
break;
|
||||
case SemiLuck:
|
||||
case NotSoLuck:
|
||||
case ToughLuck:
|
||||
mpAmountToReturn = selectedItem.pi_valueB;
|
||||
mpAmountToAdd = selectedItem.pi_valueB;
|
||||
break;
|
||||
}
|
||||
|
||||
Structures::CapsuleSpin capsuleSpin;
|
||||
capsuleSpin.winItemId = selectedItem.pi_id;
|
||||
capsuleSpin.mpAmount = mpAmountToReturn;
|
||||
|
||||
session.setAccountMicroPoints(accountInfo.microPoints + mpAmountToAdd);
|
||||
capsuleManager.subJackpot(mpAmountToAdd);
|
||||
|
||||
response.setExtra(37);
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&capsuleSpin), sizeof(Main::Structures::CapsuleSpin));
|
||||
session.asyncWrite(response);
|
||||
session.setLuckyPoints(0);
|
||||
sessionsManager.broadcastMessageExceptSelf(session.getSessionId(), winMessage);
|
||||
}
|
||||
|
||||
inline void handleCapsuleSpin(const Common::Network::Packet& request, Main::Network::Session& session, Classes::CapsuleManager& capsuleManager, Network::SessionsManager sessionsManager)
|
||||
{
|
||||
auto response = request;
|
||||
response.setOption(1); // number of items per spin (e.g 2 if we want to add addiitonal coupon)
|
||||
|
||||
Main::ConstantDatabase::CdbUtil cdbUtil;
|
||||
const auto& capsuleInfo = cdbUtil.getCapsuleInfoById(request.getOption());
|
||||
if (capsuleInfo == std::nullopt)
|
||||
{
|
||||
// Apparently there's no error message in this case in CMV, just resend the packet given by the client...
|
||||
session.asyncWrite(response);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& accountInfo = session.getAccountInfo();
|
||||
|
||||
if (capsuleInfo->gi_type == CapsuleCurrencyType::COINS &&
|
||||
capsuleInfo->gi_type == CapsuleCurrencyType::ROCKTOTENS && accountInfo.rockTotens < capsuleInfo->gi_pay_cash * request.getOption()
|
||||
|| capsuleInfo->gi_type == CapsuleCurrencyType::MICROPOINTS && accountInfo.microPoints < capsuleInfo->gi_pay_point * request.getOption())
|
||||
{
|
||||
response.setExtra(CapsuleSpinExtra::NOT_ENOUGH_CURRENCY);
|
||||
response.setOption(capsuleInfo->gi_type);
|
||||
session.asyncWrite(response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.getLuckyPoints() >= 1000)
|
||||
{
|
||||
handleLuckySpin(request, session, response, cdbUtil, capsuleInfo.value(), accountInfo, capsuleManager, sessionsManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleItemSpin(request, session, response, cdbUtil, capsuleInfo.value(), accountInfo, capsuleManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -16,11 +16,12 @@ namespace Main
|
|||
namespace Handlers
|
||||
{
|
||||
inline void handleGeneralItem(const Common::Network::Packet& request, Main::Network::Session& session, Main::Persistence::PersistentDatabase& db,
|
||||
const std::unordered_map<std::uint32_t, std::unique_ptr<Main::Box::IBox>>& m_boxes, const Main::Structures::ItemSerialInfo& openedItemSerialInfo)
|
||||
const std::unordered_map<std::uint32_t, std::unique_ptr<Main::Box::IBox>>& m_boxes, const Main::Structures::ItemSerialInfo& openedItemSerialInfo,
|
||||
Classes::CapsuleManager capsuleManager, Network::SessionsManager sessionsManager)
|
||||
{
|
||||
if (request.getMission() == 2) // capsule spin
|
||||
{
|
||||
Main::Handlers::handleCapsuleSpin(request, session);
|
||||
Main::Handlers::handleCapsuleSpin(request, session, capsuleManager, sessionsManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ namespace Main
|
|||
session.setAccountMicroPoints(accountInfo.microPoints - *mpNeededForUpgrade);
|
||||
session.sendCurrency();
|
||||
}
|
||||
else if (request.getExtra() == 55)
|
||||
else if (request.getExtra() == 53)
|
||||
{
|
||||
// Item Reset
|
||||
}
|
||||
|
|
|
|||
145
MainServer/include/Handlers/Room/RoomInviteJoin.h
Normal file
145
MainServer/include/Handlers/Room/RoomInviteJoin.h
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#ifndef ROOM_INVITE_JOIN_HANDLER_H
|
||||
#define ROOM_INVITE_JOIN_HANDLER_H
|
||||
|
||||
#include "../../Network/MainSession.h"
|
||||
#include "../../../include/Structures/AccountInfo/MainAccountInfo.h"
|
||||
#include "../../../include/Structures/Room/RoomSettingsUpdate.h"
|
||||
#include "Network/Packet.h"
|
||||
#include <span>
|
||||
#include "../Room/RoomJoinHandler.h"
|
||||
#include "../Room/RoomLeaveHandler.h"
|
||||
#include "../../Utilities.h"
|
||||
#include "../../Structures/ClientData/Structures.h"
|
||||
|
||||
|
||||
namespace Main
|
||||
{
|
||||
namespace Handlers
|
||||
{
|
||||
enum RoomInviteJoinExtra
|
||||
{
|
||||
USER_INVITING_FRIEND = 0,
|
||||
USER_READY = 5,
|
||||
USER_OFFLINE = 0xD,
|
||||
ROOM_FULL = 0xE,
|
||||
ROOM_SENDINVITE_TOTARGET = 44,
|
||||
USER_JOINING_FRIEND = 28,
|
||||
};
|
||||
|
||||
// Room invites/join, not fully implemented, also not working in certain scenarios, recheck + refactor this function
|
||||
inline void handleJoinAndInvites(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
|
||||
Main::Network::SessionsManager& sessionsManager)
|
||||
{
|
||||
auto response = request;
|
||||
if (request.getExtra() == RoomInviteJoinExtra::USER_JOINING_FRIEND)
|
||||
{
|
||||
std::uint32_t targetAccountId;
|
||||
std::memcpy(&targetAccountId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), sizeof(targetAccountId));
|
||||
|
||||
if (auto* targetSession = sessionsManager.getSessionByAccountId(targetAccountId))
|
||||
{
|
||||
const std::uint32_t targetRoomNum = targetSession->getRoomNumber();
|
||||
const std::uint32_t selfRoomNum = session.getRoomNumber();
|
||||
if (targetRoomNum)
|
||||
{
|
||||
if (!session.isInLobby() && !selfRoomNum)
|
||||
{ // User is neither in lobby and in room, join should not work in this case
|
||||
Main::Details::sendMessage("You can only join a friend's room while being in a different room or in the lobby!", session);
|
||||
return;
|
||||
}
|
||||
else if (targetRoomNum == selfRoomNum)
|
||||
{ // User attempting to join the same room, disallow this
|
||||
Main::Details::sendMessage("You cannot join this friend as you're already in their room.", session);
|
||||
return;
|
||||
}
|
||||
else if (selfRoomNum)
|
||||
{ // if the player is in a room, leave it first
|
||||
response.setCommand(137, 0, 0, 0);
|
||||
Main::Handlers::handleRoomLeave(response, session, sessionsManager, roomsManager, 4, Details::parseData<Main::Structures::UniqueId>(response));
|
||||
}
|
||||
|
||||
Main::ClientData::RoomInfo joinInfo{ targetRoomNum - 1 };
|
||||
response.setCommand(136, 0, 0, 0);
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&joinInfo), sizeof(joinInfo));
|
||||
|
||||
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(targetRoomNum))
|
||||
{
|
||||
Main::Handlers::handleRoomJoin(response, session, roomsManager, joinInfo, !room->getPassword().empty());
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("Room not found.", session);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("This friend is currently not inside a room.", session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("The friend you're trying to join went offline.", session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (request.getExtra() == RoomInviteJoinExtra::USER_INVITING_FRIEND && request.getOption() == 2) // Currently doesn't work, something's wrong here
|
||||
{
|
||||
char targetNickname[16];
|
||||
std::ranges::copy(std::span(reinterpret_cast<const char*>(request.getData()), sizeof(targetNickname)), targetNickname);
|
||||
|
||||
Main::Network::Session* targetSession = sessionsManager.findSessionByName(targetNickname);
|
||||
if (targetSession)
|
||||
{
|
||||
if (!targetSession->isInLobby())
|
||||
{
|
||||
Details::sendMessage("This player is currently not in the lobby.", session);
|
||||
}
|
||||
else if (targetSession->getRoomNumber() == session.getRoomNumber())
|
||||
{
|
||||
Details::sendMessage("The player you are trying to invite is already in your room.", session);
|
||||
}
|
||||
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
|
||||
{
|
||||
response.setCommand(319, 0, 0, 0);
|
||||
response.setSession(targetSession->getId());
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Response
|
||||
{
|
||||
std::uint32_t serverId = 4; // unsure whether this really is the server's id
|
||||
char sourceNickname[16]{}; // OK
|
||||
std::uint16_t roomNumber{};
|
||||
std::uint16_t unknown{ 2 };
|
||||
char roomTitle[32]{};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
Response responseStruct;
|
||||
responseStruct.roomNumber = session.getRoomNumber() - 1; // correct
|
||||
std::ranges::copy(std::span(room->getRoomTitle().c_str(), sizeof(responseStruct.roomTitle) - 1), responseStruct.roomTitle);
|
||||
responseStruct.roomTitle[sizeof(responseStruct.roomTitle) - 1] = '\0';
|
||||
std::ranges::copy(std::span(session.getAccountInfo().nickname, sizeof(responseStruct.sourceNickname) - 1), responseStruct.sourceNickname);
|
||||
responseStruct.sourceNickname[sizeof(responseStruct.sourceNickname) - 1] = '\0';
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&responseStruct), sizeof(responseStruct));
|
||||
targetSession->asyncWrite(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
Details::sendMessage("You must be in a room to invite a player.", session);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Details::sendMessage("The player you invited is offline.", session);
|
||||
}
|
||||
}
|
||||
else if (session.getRoomNumber())
|
||||
{
|
||||
roomsManager.broadcastToRoom(session.getRoomNumber(), const_cast<Common::Network::Packet&>(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -42,7 +42,6 @@ namespace Main
|
|||
inline void handleRoomLeave(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
|
||||
Main::Classes::RoomsManager& roomsManager, std::uint32_t serverId, const Main::Structures::UniqueId& uniqueId)
|
||||
{
|
||||
auto roomOpt = roomsManager.getRoomByNumber(session.getRoomNumber());
|
||||
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
|
||||
{
|
||||
if (request.getExtra() == ClientExtra::KICK_PLAYER)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include "../../../include/Structures/AccountInfo/MainAccountInfo.h"
|
||||
#include "../../../include/Structures/Room/RoomSettingsUpdate.h"
|
||||
#include "Network/Packet.h"
|
||||
#include <span>
|
||||
#include "../Room/RoomJoinHandler.h"
|
||||
#include "../Room/RoomLeaveHandler.h"
|
||||
|
||||
|
|
@ -14,136 +13,6 @@ namespace Main
|
|||
{
|
||||
namespace Handlers
|
||||
{
|
||||
enum RoomInviteJoinExtra
|
||||
{
|
||||
USER_INVITING_FRIEND = 0,
|
||||
USER_READY = 5,
|
||||
USER_OFFLINE = 0xD,
|
||||
ROOM_FULL = 0xE,
|
||||
ROOM_SENDINVITE_TOTARGET = 44,
|
||||
USER_JOINING_FRIEND = 28,
|
||||
};
|
||||
|
||||
// Room invites/join, not fully implemented, also not working in certain scenarios, recheck + refactor this function
|
||||
inline void unknown(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
|
||||
Main::Network::SessionsManager& sessionsManager)
|
||||
{
|
||||
auto response = request;
|
||||
|
||||
if (request.getExtra() == RoomInviteJoinExtra::USER_JOINING_FRIEND)
|
||||
{
|
||||
response.setOrder(136);
|
||||
std::uint32_t targetAccountId;
|
||||
std::memcpy(&targetAccountId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), sizeof(targetAccountId));
|
||||
auto* targetSession = sessionsManager.getSessionByAccountId(targetAccountId);
|
||||
if (targetSession)
|
||||
{
|
||||
const std::uint32_t targetRoomNum = targetSession->getRoomNumber();
|
||||
const std::uint32_t selfRoomNum = session.getRoomNumber();
|
||||
if (targetRoomNum)
|
||||
{
|
||||
if (!session.isInLobby() && !selfRoomNum)
|
||||
{ // User is neither in lobby and in room, join should not work in this case
|
||||
Main::Details::sendMessage("You can only join a friend's room while being in a different room or in the lobby!", session);
|
||||
return;
|
||||
}
|
||||
else if (targetRoomNum == selfRoomNum)
|
||||
{ // User attempting to join the same room, disallow this
|
||||
Main::Details::sendMessage("You cannot join this friend as you're already in their room.", session);
|
||||
return;
|
||||
}
|
||||
else if (selfRoomNum)
|
||||
{ // if the player is in a room, leave it first
|
||||
Common::Network::Packet response;
|
||||
response.setTcpHeader(session.getId(), Common::Enums::USER_LARGE_ENCRYPTION);
|
||||
response.setOrder(137);
|
||||
Main::Handlers::handleRoomLeave(response, session, sessionsManager, roomsManager, 4, Details::parseData<Main::Structures::UniqueId>(response));
|
||||
}
|
||||
|
||||
struct JoinInfo
|
||||
{
|
||||
std::uint16_t roomNum = 0;
|
||||
std::uint16_t unknown = 2; // seemingly always 2 for some reason
|
||||
};
|
||||
|
||||
JoinInfo joinInfo{ targetRoomNum - 1 };
|
||||
response.setOption(0);
|
||||
response.setExtra(0);
|
||||
response.setMission(0);
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&joinInfo), sizeof(joinInfo));
|
||||
|
||||
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
|
||||
{
|
||||
// Currently passworded room not handled!
|
||||
//Main::Handlers::handleRoomJoin(response, session, roomsManager, !roomOpt->get().getPassword().empty());
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("Room not found.", session);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("This friend is currently not inside a room.", session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Main::Details::sendMessage("The friend you're trying to join went offline.", session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (request.getExtra() == RoomInviteJoinExtra::USER_INVITING_FRIEND) // Currently doesn't work, something's wrong here
|
||||
{
|
||||
char targetNickname[16];
|
||||
std::ranges::copy(std::span(reinterpret_cast<const char*>(request.getData()), sizeof(targetNickname)), targetNickname);
|
||||
|
||||
Main::Network::Session* targetSession = sessionsManager.findSessionByName(targetNickname);
|
||||
if (targetSession)
|
||||
{
|
||||
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
|
||||
{
|
||||
response.setOrder(319); // Room invite request
|
||||
response.setExtra(44); // Room invite request
|
||||
response.setOption(0);
|
||||
response.setSession(targetSession->getId());
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Response
|
||||
{
|
||||
std::uint32_t serverId = 4; // unsure
|
||||
char sourceNickname[16]{};
|
||||
std::uint16_t roomNumber{};
|
||||
std::uint16_t unknown{ 2 }; // same as for RoomJoin structure, always 2
|
||||
char roomTitle[30]{};
|
||||
std::uint16_t padding = 0;
|
||||
char password[8]{};
|
||||
std::uint64_t padding2 = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
Response responseStruct;
|
||||
responseStruct.roomNumber = session.getRoomNumber() - 1;
|
||||
std::ranges::copy(std::span(room->getRoomTitle().c_str(), sizeof(responseStruct.roomTitle) - 1), responseStruct.roomTitle);
|
||||
responseStruct.roomTitle[sizeof(responseStruct.roomTitle) - 1] = '\0';
|
||||
std::ranges::copy(std::span(session.getAccountInfo().nickname, sizeof(responseStruct.sourceNickname) - 1), responseStruct.sourceNickname);
|
||||
responseStruct.sourceNickname[sizeof(responseStruct.sourceNickname) - 1] = '\0';
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&responseStruct), sizeof(responseStruct));
|
||||
targetSession->asyncWrite(response);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else if (session.getRoomNumber())
|
||||
{
|
||||
roomsManager.broadcastToRoom(session.getRoomNumber(), const_cast<Common::Network::Packet&>(request));
|
||||
}
|
||||
}
|
||||
|
||||
// Takes care of settings that are inside the "Room Settings" button + switching team
|
||||
inline void handleRoomMiscellaneous(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
|
||||
std::uint64_t m_latestServerRestart)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,6 @@ namespace Main
|
|||
{
|
||||
namespace Handlers
|
||||
{
|
||||
std::uint64_t getUtcTimeMs()
|
||||
{
|
||||
const auto durationSinceEpoch = std::chrono::system_clock::now().time_since_epoch();
|
||||
return static_cast<std::uint64_t>(duration_cast<std::chrono::milliseconds>(durationSinceEpoch).count());
|
||||
}
|
||||
|
||||
inline void handleRoomStart(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
|
||||
std::uint64_t timeSinceLastServerRestart)
|
||||
{
|
||||
|
|
@ -26,6 +20,7 @@ namespace Main
|
|||
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
|
||||
auto selfUniqueId = session.getAccountInfo().uniqueId;
|
||||
|
||||
// Do NOT touch this part, or you risk breaking the match-start mechanism!
|
||||
if (request.getExtra() == 38) // host or non-host clicks on "start" button (n.b: SingleWave's extra is 6)
|
||||
{
|
||||
response.setCommand(request.getOrder(), 0, 38, room->getRoomSettings().map);
|
||||
|
|
@ -37,6 +32,11 @@ namespace Main
|
|||
Utils::MapInfo mapInfo{ room->getRoomSettings().map, selfUniqueId.session };
|
||||
Utils::IPCManager::ipc_mainToCast(mapInfo, std::to_string(room->getRoomNumber()), "map_info");
|
||||
}
|
||||
else if (room->hasMatchStarted())
|
||||
{
|
||||
room->setStateFor(selfUniqueId, static_cast<Common::Enums::PlayerState>(11));
|
||||
session.setIsInMatch(true);
|
||||
}
|
||||
}
|
||||
else if (request.getExtra() == 41)
|
||||
{
|
||||
|
|
@ -44,11 +44,11 @@ namespace Main
|
|||
|
||||
if (room->isHost(selfUniqueId)) // broadcast the tick to the room
|
||||
{
|
||||
std::uint64_t roomTick = getUtcTimeMs() - timeSinceLastServerRestart;
|
||||
std::uint64_t roomTick = Details::getUtcTimeMs() - timeSinceLastServerRestart;
|
||||
response.setCommand(258, 0, 1, 0);
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&roomTick), sizeof(roomTick));
|
||||
room->broadcastToRoom(response);
|
||||
room->startMatch(selfUniqueId);
|
||||
room->startMatch(selfUniqueId); // don't move this anywhere else!
|
||||
}
|
||||
else // Tell the other players in the match that we joined
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "Network/MainSessionManager.h"
|
||||
#include "ChatCommands/ChatCommands.h"
|
||||
#include "Classes/RoomsManager.h"
|
||||
#include "Classes/CapsuleManager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "Boxes/BoxBase.h"
|
||||
|
|
@ -27,12 +28,14 @@ namespace Main
|
|||
std::uint16_t m_serverId;
|
||||
Main::Persistence::PersistentDatabase m_database;
|
||||
Main::Persistence::MainScheduler m_scheduler;
|
||||
Main::Classes::CapsuleManager m_capsuleManager;
|
||||
Main::Network::SessionsManager m_sessionsManager;
|
||||
Main::Classes::RoomsManager m_roomsManager;
|
||||
Main::Command::ChatCommands m_chatCommands;
|
||||
std::unordered_map<std::uint32_t, std::unique_ptr<Main::Box::IBox>> m_boxes;
|
||||
std::uint64_t m_timeSinceLastRestart{};
|
||||
|
||||
|
||||
// For auth server communication
|
||||
tcp::acceptor m_authServerAcceptor;
|
||||
std::optional<tcp::socket> m_authSocket;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ namespace Main
|
|||
public:
|
||||
explicit Session(Main::Persistence::MainScheduler& scheduler, tcp::socket&& socket, std::function<void(std::size_t)> fnct);
|
||||
|
||||
~Session()
|
||||
{
|
||||
m_scheduler.immediatePersist(m_player.getAccountID(), &Main::Persistence::PersistentDatabase::updateOfflineStatus, m_player.getAccountID());
|
||||
m_scheduler.persistFor(m_player.getAccountID());
|
||||
}
|
||||
|
||||
std::size_t getSessionId() const;
|
||||
|
||||
void onPacket(std::vector<std::uint8_t>& data) override;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ namespace Main
|
|||
std::vector<Main::Network::Session*> m_sessionsVector{};
|
||||
Main::Classes::RoomsManager* roomsManager;
|
||||
|
||||
Common::Network::Packet prepareMessage(const std::string& message) const;
|
||||
|
||||
public:
|
||||
void setRoomsManager(Main::Classes::RoomsManager* roomsManager);
|
||||
|
||||
|
|
@ -37,6 +39,9 @@ namespace Main
|
|||
|
||||
void broadcastToClan(std::uint64_t selfSessionId, const Common::Network::Packet& message) const;
|
||||
|
||||
void broadcastMessage(const std::string& message) const;
|
||||
void broadcastMessageExceptSelf(std::size_t selfSessionId, const std::string& message) const;
|
||||
|
||||
Main::Network::Session* findSessionByName(const char* nickname);
|
||||
|
||||
Main::Network::Session* getSessionByAccountId(std::uint32_t aid);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ namespace Main
|
|||
playerInfoStructure.accountKey = static_cast<std::uint32_t>(query.getColumn("AccountKey").getInt());
|
||||
playerInfoStructure.totalKills = static_cast<std::uint32_t>(query.getColumn("Kills").getInt());
|
||||
playerInfoStructure.deaths = static_cast<std::uint32_t>(query.getColumn("Deaths").getInt());
|
||||
//playerInfoStructure.assists = static_cast<std::uint32_t>(query.getColumn("Assists").getInt());
|
||||
playerInfoStructure.wins = static_cast<std::uint32_t>(query.getColumn("Wins").getInt());
|
||||
playerInfoStructure.losses = static_cast<std::uint32_t>(query.getColumn("Loses").getInt());
|
||||
playerInfoStructure.draws = static_cast<std::uint32_t>(query.getColumn("Draws").getInt());
|
||||
|
|
@ -127,6 +128,7 @@ namespace Main
|
|||
playerInfoStructure.playerLevel = static_cast<std::uint64_t>(query.getColumn("Level").getInt()) + 1;
|
||||
playerInfoStructure.battery = static_cast<std::uint64_t>(query.getColumn("Battery").getInt());
|
||||
playerInfoStructure.luckyPoints = static_cast<std::uint64_t>(query.getColumn("LuckyPoints").getInt());
|
||||
//playerInfoStructure.coins = static_cast<std::uint64_t>(query.getColumn("Coins").getInt());
|
||||
playerInfoStructure.playerGrade = static_cast<std::uint64_t>(query.getColumn("Grade").getInt());
|
||||
playerInfoStructure.experience = static_cast<std::uint32_t>(query.getColumn("Experience").getInt());
|
||||
playerInfoStructure.microPoints = static_cast<std::uint64_t>(query.getColumn("MicroPoints").getInt64());
|
||||
|
|
@ -137,6 +139,7 @@ namespace Main
|
|||
playerInfoStructure.singleWaveAttempts = static_cast<std::uint32_t>(query.getColumn("SingleWaveAttempts").getInt());
|
||||
playerInfoStructure.highestSinglewaveStage = static_cast<std::uint32_t>(query.getColumn("SingleWaveAttempts").getInt());
|
||||
playerInfoStructure.highestSingleWaveScore = static_cast<std::uint32_t>(query.getColumn("HighestSinglewaveScore").getInt());
|
||||
//playerInfoStructure.vipExperience = static_cast<std::uint32_t>(query.getColumn("VipExperience").getInt());
|
||||
playerInfoStructure.clanContribution = static_cast<std::uint64_t>(query.getColumn("ClanContribution").getInt64());
|
||||
playerInfoStructure.clanLogoFrontId = static_cast<std::uint64_t>(query.getColumn("ClanFrontIcon").getInt());
|
||||
playerInfoStructure.clanLogoBackId = static_cast<std::uint64_t>(query.getColumn("ClanBackIcon").getInt());
|
||||
|
|
@ -207,7 +210,7 @@ namespace Main
|
|||
SQLite::Transaction transaction(db);
|
||||
SQLite::Statement query(db, queryStr);
|
||||
query.bind(1, nickname);
|
||||
|
||||
|
||||
if (!query.exec())
|
||||
{
|
||||
std::cerr << "[Main::Database::UnbanPlayer] Error executing query: " << query.getExpandedSQL() << '\n';
|
||||
|
|
@ -256,6 +259,7 @@ namespace Main
|
|||
}
|
||||
|
||||
|
||||
// Returing const& causes exceptions later...?
|
||||
auto getPlayerItems(std::uint32_t playerID) const
|
||||
-> std::pair<std::vector<Item>, std::unordered_map<std::uint16_t, std::vector<EquippedItem>>>
|
||||
{
|
||||
|
|
@ -281,7 +285,7 @@ namespace Main
|
|||
item.serialInfo.itemNumber = ++itemNum;
|
||||
SQLite::Statement updateItemNumberQuery(db, "UPDATE UserItems SET ItemNumber = :itemNumber WHERE rowid = :rowid");
|
||||
updateItemNumberQuery.bind(":itemNumber", static_cast<std::int64_t>(item.serialInfo.itemNumber));
|
||||
updateItemNumberQuery.bind(":rowid" ,rowId);
|
||||
updateItemNumberQuery.bind(":rowid", rowId);
|
||||
if (!updateItemNumberQuery.exec())
|
||||
{
|
||||
std::cerr << "ItemNumberUpdate error in getPlayerItems(): " << updateItemNumberQuery.getExtendedErrorCode() << '\n';
|
||||
|
|
@ -302,8 +306,44 @@ namespace Main
|
|||
}
|
||||
item.expirationDate = static_cast<__time32_t>(newExpDate);
|
||||
}
|
||||
|
||||
// REMOVE THIS
|
||||
//Main::ConstantDatabase::CdbUtil cdbUtil(item.id);
|
||||
//auto durability = *(cdbUtil.getItemDurability());
|
||||
//auto duration = *(cdbUtil.getItemDuration());
|
||||
////
|
||||
|
||||
item.durability = static_cast<std::uint16_t>(allItemsQuery.getColumn("durability").getInt());
|
||||
item.energy = static_cast<std::uint16_t>(allItemsQuery.getColumn("energy").getInt());
|
||||
|
||||
/*item.isSealed = static_cast<std::uint32_t>(allItemsQuery.getColumn("isSealed").getInt());
|
||||
item.sealLevel = static_cast<std::uint32_t>(allItemsQuery.getColumn("sealLevel").getInt());
|
||||
item.experienceEnhancement = static_cast<std::uint32_t>(allItemsQuery.getColumn("expEnhancement").getInt());
|
||||
item.mpEnhancement = static_cast<std::uint32_t>(allItemsQuery.getColumn("mpEnhancement").getInt());
|
||||
item.unknown = static_cast<std::uint32_t>(allItemsQuery.getColumn("unknown"));
|
||||
*/
|
||||
|
||||
// REMOVE THIS
|
||||
/*
|
||||
SQLite::Statement updateDurabilityQuery(db, "UPDATE UserItems SET durability = :durability WHERE rowid = :rowid");
|
||||
updateDurabilityQuery.bind(":durability", durability);
|
||||
updateDurabilityQuery.bind(":rowid", rowId);
|
||||
if (!updateDurabilityQuery.exec())
|
||||
{
|
||||
std::cerr << "DurabilityUpdate error in getPlayerItems(): " << updateDurabilityQuery.getExtendedErrorCode() << '\n';
|
||||
std::cerr << "Error message: " << updateDurabilityQuery.getErrorMsg() << '\n';
|
||||
}
|
||||
|
||||
SQLite::Statement updateDuration(db, "UPDATE UserItems SET ItemDuration = :duration WHERE rowid = :rowid");
|
||||
updateDuration.bind(":duration", duration);
|
||||
updateDuration.bind(":rowid", rowId);
|
||||
if (!updateDuration.exec())
|
||||
{
|
||||
std::cerr << "DurabilityUpdate error in getPlayerItems(): " << updateDuration.getExtendedErrorCode() << '\n';
|
||||
std::cerr << "Error message: " << updateDuration.getErrorMsg() << '\n';
|
||||
}*/
|
||||
////
|
||||
|
||||
if (allItemsQuery.getColumn("IsEquipped").getInt() == 1)
|
||||
{
|
||||
Main::Structures::EquippedItem equippedItem{ item };
|
||||
|
|
@ -332,7 +372,7 @@ namespace Main
|
|||
}
|
||||
}
|
||||
|
||||
void replaceItem(std::uint32_t accountID, std::uint32_t itemNum, const Main::Structures::ItemSerialInfo& newSerialInfo,
|
||||
void replaceItem(std::uint32_t accountID, std::uint32_t itemNum, const Main::Structures::ItemSerialInfo& newSerialInfo,
|
||||
std::uint64_t newExpiration)
|
||||
{
|
||||
try
|
||||
|
|
@ -572,8 +612,8 @@ namespace Main
|
|||
try
|
||||
{
|
||||
SQLite::Transaction transaction(db);
|
||||
SQLite::Statement query(db, "UPDATE Users SET MeleeKills = ?, RifleKills = ?, ShotgunKills = ?, SniperKills = ?, GatlingKills = ?, "
|
||||
"BazookaKills = ? , GrenadeKills = ? , HighestKillstreak = ? , Kills = ? , Deaths = ? , Headshots = ? , Assists = ?, "
|
||||
SQLite::Statement query(db, "UPDATE Users SET MeleeKills = ?, RifleKills = ?, ShotgunKills = ?, SniperKills = ?, GatlingKills = ?, "
|
||||
"BazookaKills = ? , GrenadeKills = ? , HighestKillstreak = ? , Kills = ? , Deaths = ? , Headshots = ? , Assists = ?, "
|
||||
" Experience = ?, MicroPoints = ?, Wins = ?, Loses = ?, Draws = ?, Level = ? WHERE AccountID = ?");
|
||||
|
||||
query.bind(1, updatedAccountInfo.meleeKills);
|
||||
|
|
@ -587,6 +627,7 @@ namespace Main
|
|||
query.bind(9, updatedAccountInfo.totalKills);
|
||||
query.bind(10, updatedAccountInfo.deaths);
|
||||
query.bind(11, static_cast<std::uint32_t>(updatedAccountInfo.headshots));
|
||||
// query.bind(12, updatedAccountInfo.assists);
|
||||
query.bind(13, updatedAccountInfo.experience);
|
||||
query.bind(14, static_cast<std::uint32_t>(updatedAccountInfo.microPoints));
|
||||
query.bind(15, updatedAccountInfo.wins);
|
||||
|
|
@ -1152,7 +1193,7 @@ namespace Main
|
|||
std::cerr << "[Main::Database::addPendingFriendRequestFor] Error message: " << findPlayerByAccountId.getErrorMsg() << '\n';
|
||||
return Main::Enums::AddFriendServerExtra::TARGET_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
// 2. Check if the target player has less than 30 friends.
|
||||
SQLite::Statement findTotalFriends(db, "SELECT * FROM Friendlist WHERE AccountID = ?");
|
||||
findTotalFriends.bind(1, targetAid);
|
||||
|
|
@ -1163,7 +1204,7 @@ namespace Main
|
|||
std::cerr << "[Main::Database::addPendingFriendRequestFor::findTotalFriends] Error message: " << findTotalFriends.getErrorMsg() << '\n';
|
||||
totalCount = 0;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
totalCount = 1;
|
||||
while (findTotalFriends.executeStep())
|
||||
|
|
@ -1313,14 +1354,14 @@ namespace Main
|
|||
{
|
||||
try
|
||||
{
|
||||
std::uint32_t accountId = 0;
|
||||
std::uint32_t accountId = 0;
|
||||
const std::string retrieveAccountIdQuery = "SELECT AccountID FROM Users WHERE Nickname = ?";
|
||||
SQLite::Statement retrieveQuery(db, retrieveAccountIdQuery);
|
||||
retrieveQuery.bind(1, mailbox.nickname);
|
||||
|
||||
if (retrieveQuery.executeStep())
|
||||
{
|
||||
accountId = retrieveQuery.getColumn("AccountID").getInt();
|
||||
accountId = retrieveQuery.getColumn("AccountID").getInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1337,7 +1378,7 @@ namespace Main
|
|||
//query.bind(3, mailbox.uniqueId);
|
||||
query.bind(4, senderNickname);
|
||||
query.bind(5, mailbox.message);
|
||||
query.bind(6, false);
|
||||
query.bind(6, false);
|
||||
query.bind(7, true);
|
||||
|
||||
if (!query.exec())
|
||||
|
|
@ -1491,8 +1532,75 @@ namespace Main
|
|||
}
|
||||
}
|
||||
|
||||
void updatePlayerLuckyPoints(std::uint32_t accountID, std::uint32_t luckyPoints)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string updateLevelQuery = "UPDATE Users SET LuckyPoints = ? WHERE AccountID = ?";
|
||||
SQLite::Transaction transaction(db);
|
||||
SQLite::Statement query(db, updateLevelQuery);
|
||||
query.bind(1, luckyPoints);
|
||||
query.bind(2, accountID);
|
||||
|
||||
if (!query.exec())
|
||||
{
|
||||
std::cerr << "[Main::Database::updatePlayerLuckyPoints] Error executing query: " << query.getExpandedSQL() << '\n';
|
||||
std::cerr << "[Main::Database::updatePlayerLuckyPoints] Error message: " << query.getErrorMsg() << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "[Main::Database::updatePlayerLuckyPoints] SQLite exception: " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getCapsuleJackpot()
|
||||
{
|
||||
uint32_t jackpot = 0;
|
||||
try
|
||||
{
|
||||
SQLite::Statement query(db, "SELECT Value FROM GameParameters WHERE Key = \"Jackpot\"");
|
||||
if (query.executeStep())
|
||||
{
|
||||
jackpot = static_cast<std::uint32_t>(query.getColumn("Value").getInt());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "[Main::Database::getCapsuleJackpot] SQLite exception: " << e.what() << '\n';
|
||||
}
|
||||
|
||||
return jackpot;
|
||||
}
|
||||
|
||||
void updateCapsuleJackpot(uint32_t jackpotValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string updateJackpotQuery("UPDATE GameParameters SET Value = ? WHERE Key = \"Jackpot\"");
|
||||
SQLite::Transaction transaction(db);
|
||||
SQLite::Statement query(db, updateJackpotQuery);
|
||||
query.bind(1, jackpotValue);
|
||||
|
||||
if (!query.exec())
|
||||
{
|
||||
std::cerr << "[Main::Database::updateCapsuleJackpot] Error executing query: " << query.getExpandedSQL() << '\n';
|
||||
std::cerr << "[Main::Database::updateCapsuleJackpot] Error message: " << query.getErrorMsg() << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "[Main::Database::updateCapsuleJackpot] SQLite exception: " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -13,7 +13,7 @@ namespace Main
|
|||
struct CapsuleSpin
|
||||
{
|
||||
std::uint32_t winItemId{};
|
||||
std::uint32_t unknown1{0}; // was 1 originally, try to change this and check what it does
|
||||
std::uint32_t mpAmount{};
|
||||
Main::Structures::ItemSerialInfo itemSerialInfo{};
|
||||
|
||||
CapsuleSpin()
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Main
|
|||
struct RoomInfo
|
||||
{
|
||||
std::uint16_t roomNumber{};
|
||||
std::uint16_t unknown{};
|
||||
std::uint16_t unknown{2}; // seemingly always 2 for some reason
|
||||
char password[8]{};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include "Classes/RoomsManager.h"
|
||||
#include "Network/Packet.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace Main
|
||||
{
|
||||
namespace Details
|
||||
|
|
@ -46,13 +48,19 @@ namespace Main
|
|||
session.asyncWrite(response);
|
||||
}
|
||||
|
||||
inline void sendPlayerState(Main::Network::Session& session, Main::Structures::UniqueId uniqueId)
|
||||
inline void sendPlayerState(Main::Network::Session& session, Main::Structures::UniqueId uniqueId, Main::Classes::Room& room, std::uint32_t state = 11)
|
||||
{
|
||||
Common::Network::Packet response;
|
||||
response.setTcpHeader(session.getId(), Common::Enums::USER_LARGE_ENCRYPTION);
|
||||
response.setCommand(312, 0, 0, 2);
|
||||
response.setCommand(312, 0, 0, state);
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
|
||||
session.asyncWrite(response);
|
||||
room.broadcastToRoom(response);
|
||||
}
|
||||
|
||||
inline std::uint64_t getUtcTimeMs()
|
||||
{
|
||||
const auto durationSinceEpoch = std::chrono::system_clock::now().time_since_epoch();
|
||||
return static_cast<std::uint64_t>(duration_cast<std::chrono::milliseconds>(durationSinceEpoch).count());
|
||||
}
|
||||
|
||||
inline void broadcastPlayerItems(Main::Classes::RoomsManager& roomsManager, Main::Network::Session& session, const Common::Network::Packet& request)
|
||||
|
|
|
|||
35
MainServer/src/Classes/CapsuleManager.cpp
Normal file
35
MainServer/src/Classes/CapsuleManager.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "../../include/Classes/CapsuleManager.h"
|
||||
|
||||
namespace Main
|
||||
{
|
||||
namespace Classes
|
||||
{
|
||||
CapsuleManager::CapsuleManager(Main::Persistence::MainScheduler& m_scheduler, Main::Persistence::PersistentDatabase& database)
|
||||
: m_scheduler{ m_scheduler }
|
||||
, database{ database }
|
||||
{
|
||||
}
|
||||
|
||||
std::uint32_t CapsuleManager::getJackpot()
|
||||
{
|
||||
m_jackpot = database.getCapsuleJackpot();
|
||||
return m_jackpot;
|
||||
}
|
||||
|
||||
void CapsuleManager::addJackpot(std::uint32_t value)
|
||||
{
|
||||
setJackpot(m_jackpot + value);
|
||||
}
|
||||
|
||||
void CapsuleManager::subJackpot(std::uint32_t value)
|
||||
{
|
||||
setJackpot(m_jackpot - value);
|
||||
}
|
||||
|
||||
void CapsuleManager::setJackpot(std::uint32_t value)
|
||||
{
|
||||
m_jackpot = value < 300000 ? 300000 : value;
|
||||
m_scheduler.immediatePersist(0, &Main::Persistence::PersistentDatabase::updateCapsuleJackpot, m_jackpot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -232,6 +232,7 @@ namespace Main
|
|||
m_players[bestMsPlayerIdxInMatch].second->asyncWrite(removePlayerFromRoomServerRequest);
|
||||
m_players[bestMsPlayerIdxInMatch].second->leaveRoom();
|
||||
broadcastToRoomExceptSelf(removePlayerFromMatchServerRequest, originalHostUniqueId);
|
||||
|
||||
// NOTE: This decrements all player indexes inside the client! Call it ONLY AFTER sending the packet to change the host!
|
||||
Main::Handlers::notifyRoomPlayerLeaves(originalHostUniqueId, *this);
|
||||
|
||||
|
|
@ -372,12 +373,13 @@ namespace Main
|
|||
|
||||
// Remove the player from the room
|
||||
playerIter->second->asyncWrite(removePlayerFromRoomServerRequest);
|
||||
playerIter->second->leaveRoom();
|
||||
playerIter->second->leaveRoom();
|
||||
|
||||
// NOTE: This decrements all player indexes in the client! Do it always after sending the change host packet!
|
||||
Main::Handlers::notifyRoomPlayerLeaves(playerIter->second->getAccountInfo().uniqueId, *this);
|
||||
m_players.erase(playerIter);
|
||||
|
||||
// unmap original host
|
||||
// unmap
|
||||
m_playerSessionIdToVecIdx.erase(originalSessionId);
|
||||
|
||||
logger.log("Removed player from room. " + playerIter->second->getPlayerInfoAsString(),
|
||||
|
|
@ -649,7 +651,7 @@ namespace Main
|
|||
|
||||
bool Room::isHost(const Main::Structures::UniqueId& uniqueId) const
|
||||
{
|
||||
return m_players[0].first.uniqueId == uniqueId;
|
||||
return m_players[0].first.uniqueId.session == uniqueId.session;
|
||||
}
|
||||
|
||||
void Room::setSpecificSetting(std::uint8_t setting)
|
||||
|
|
@ -784,6 +786,7 @@ namespace Main
|
|||
|
||||
void Room::setStateFor(const Main::Structures::UniqueId& uniqueId, const Common::Enums::PlayerState& playerState)
|
||||
{
|
||||
std::cout << "Changing Player State of SessionID: " << uniqueId.session << " to state: " << (uint32_t)playerState << '\n';
|
||||
auto playerIt = m_playerSessionIdToVecIdx.find(uniqueId.session);
|
||||
if (playerIt != m_playerSessionIdToVecIdx.end())
|
||||
{
|
||||
|
|
@ -801,36 +804,23 @@ namespace Main
|
|||
}
|
||||
}
|
||||
|
||||
// ABSOLUTELY DO NOT MODIFY THIS!
|
||||
void Room::startMatch(const Main::Structures::UniqueId& uniqueId)
|
||||
{
|
||||
if (m_hasMatchStarted)
|
||||
m_players[0].second->setIsInMatch(true);
|
||||
setStateFor(uniqueId, static_cast<Common::Enums::PlayerState>(11));
|
||||
Details::sendPlayerState(*m_players[0].second, m_players[0].second->getAccountInfo().uniqueId, *this);
|
||||
|
||||
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
|
||||
{
|
||||
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
|
||||
if (roomInfo.state == Common::Enums::STATE_READY)
|
||||
{
|
||||
if (roomInfo.uniqueId == uniqueId)
|
||||
{
|
||||
Main::Details::sendPlayerState(*session, uniqueId);
|
||||
setStateFor(uniqueId, static_cast<Common::Enums::PlayerState>(2));
|
||||
session->setIsInMatch(true);
|
||||
return;
|
||||
}
|
||||
Main::Details::sendPlayerState(*session, uniqueId, *this);
|
||||
setStateFor(roomInfo.uniqueId, static_cast<Common::Enums::PlayerState>(11));
|
||||
session->setIsInMatch(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_players[0].first.state = Common::Enums::STATE_PLAYING;
|
||||
m_players[0].second->setIsInMatch(true);
|
||||
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
|
||||
{
|
||||
if (roomInfo.state == Common::Enums::STATE_READY)
|
||||
{
|
||||
Main::Details::sendPlayerState(*session, uniqueId);
|
||||
setStateFor(uniqueId, static_cast<Common::Enums::PlayerState>(2));
|
||||
session->setIsInMatch(true);
|
||||
}
|
||||
}
|
||||
m_hasMatchStarted = true;
|
||||
}
|
||||
m_hasMatchStarted = true;
|
||||
}
|
||||
|
||||
bool Room::isObserverFull() const
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "../include/Boxes/MpBox.h"
|
||||
#include "../include/Network/AuthSession.h"
|
||||
#include "../include/Handlers/Item/ItemAndCapsuleHandler.h"
|
||||
#include "../include/Handlers/Room/RoomInviteJoin.h"
|
||||
|
||||
|
||||
namespace Main
|
||||
|
|
@ -58,7 +59,9 @@ namespace Main
|
|||
, m_authServerAcceptor{ io_context, tcp::endpoint(tcp::v4(), authPort) }
|
||||
, m_serverId{ serverId }
|
||||
, m_database{ "../ExternalLibraries/Database/GameDatabase.db" }
|
||||
, m_scheduler{ 5, m_database }
|
||||
, m_scheduler{ 300, m_database }
|
||||
, m_capsuleManager{ m_scheduler, m_database }
|
||||
|
||||
{
|
||||
const auto durationSinceEpoch = std::chrono::system_clock::now().time_since_epoch();
|
||||
m_timeSinceLastRestart = static_cast<std::uint64_t>(duration_cast<std::chrono::milliseconds>(durationSinceEpoch).count());
|
||||
|
|
@ -89,6 +92,8 @@ namespace Main
|
|||
Main::Network::Session& session) { Main::Handlers::handlePing(request, session, m_roomsManager, Details::parseData<Main::ClientData::Ping>(request)); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(74, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleCharacterSelection(request, session, m_roomsManager); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(83, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleCapsuleReq(request, session, m_capsuleManager); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(84, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleLobbyUserList(request, session, m_sessionsManager); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(85, [&](const Common::Network::Packet& request,
|
||||
|
|
@ -106,7 +111,8 @@ namespace Main
|
|||
Common::Network::Session::addCallback<Main::Network::Session>(97, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleItemUpgrade(request, session, Details::parseData<Main::ClientData::ItemUpgrade>(request)); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(98, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleGeneralItem(request, session, m_database, m_boxes, Details::parseData<Main::Structures::ItemSerialInfo>(request)); });
|
||||
Main::Network::Session& session) { Main::Handlers::handleGeneralItem(request, session, m_database, m_boxes, Details::parseData<Main::Structures::ItemSerialInfo>(request),
|
||||
m_capsuleManager, m_sessionsManager); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(99, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::handleMailboxDelete(request, session, Details::parseData<std::uint32_t>(request, 4)); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(100, [&](const Common::Network::Packet& request,
|
||||
|
|
@ -174,12 +180,11 @@ namespace Main
|
|||
Main::Network::Session& session) { Main::Handlers::handleMapEvents(request, session, m_database); });
|
||||
*/
|
||||
|
||||
// These 2 following handlers must be fully implemented still. Also check whether they're related to Bomb Battle (for host side)!
|
||||
// Also requires to be refactored
|
||||
// Invites are currently not working correctly, + refactor this handler
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(156, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::unknown(request, session, m_roomsManager, m_sessionsManager); });
|
||||
Main::Network::Session& session) { Main::Handlers::handleJoinAndInvites(request, session, m_roomsManager, m_sessionsManager); });
|
||||
Common::Network::Session::addCallback<Main::Network::Session>(159, [&](const Common::Network::Packet& request,
|
||||
Main::Network::Session& session) { Main::Handlers::unknown(request, session, m_roomsManager, m_sessionsManager); });
|
||||
Main::Network::Session& session) { Main::Handlers::handleJoinAndInvites(request, session, m_roomsManager, m_sessionsManager); });
|
||||
|
||||
|
||||
// This handler also needs to refactored + checked (not fully working, e.g. for level up, different match ending scoreboards, etc)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ void initializeCdbFiles()
|
|||
const std::string cdbRewardInfo = "rewardinfo.cdb";
|
||||
const std::string cdbGradeInfo = "gradeinfo.cdb";
|
||||
|
||||
using cdbItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbItemInfo>;
|
||||
using cdbItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbItemsInfoCMV>;
|
||||
using setItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::SetItemInfo>;
|
||||
using cdbWeapons = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbWeaponInfo>;
|
||||
//using cdbWeapons = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbWeaponInfo>;
|
||||
using upgradeInfos = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbUpgradeInfo>;
|
||||
using capsulePackageInfos = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbCapsulePackageInfo>;
|
||||
using capsuleInfos = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::CdbCapsuleInfo>;
|
||||
|
|
@ -52,7 +52,7 @@ void initializeCdbFiles()
|
|||
cdbItems::initialize(cdbItemInfoPath, cdbItemInfoName);
|
||||
cdbItems::initializeItemTypes(cdbItemInfoPath, cdbWeaponItemInfoName, cdbItemInfoName);
|
||||
setItems::initialize(cdbItemInfoPath, cdbSetItemInfoName);
|
||||
cdbWeapons::initialize(cdbItemInfoPath, cdbWeaponItemInfoName);
|
||||
//cdbWeapons::initialize(cdbItemInfoPath, cdbWeaponItemInfoName);
|
||||
upgradeInfos::initialize(cdbItemInfoPath, cdbUpgradeInfoName);
|
||||
capsuleInfos::initialize(cdbItemInfoPath, cdbCapsuleInfoName);
|
||||
capsulePackageInfos::initialize(cdbItemInfoPath, cdbCapsulePackageInfoName);
|
||||
|
|
|
|||
|
|
@ -540,11 +540,13 @@ namespace Main
|
|||
void Session::addLuckyPoints(std::uint32_t points)
|
||||
{
|
||||
m_player.addLuckyPoints(points);
|
||||
m_scheduler.immediatePersist(m_player.getAccountID(), &Persistence::PersistentDatabase::updatePlayerLuckyPoints, m_player.getAccountID(), m_player.getLuckyPoints());
|
||||
}
|
||||
|
||||
void Session::setLuckyPoints(std::uint32_t points)
|
||||
{
|
||||
m_player.setLuckyPoints(points);
|
||||
m_scheduler.immediatePersist(m_player.getAccountID(), &Persistence::PersistentDatabase::updatePlayerLuckyPoints, m_player.getAccountID(), m_player.getLuckyPoints());
|
||||
}
|
||||
|
||||
std::uint32_t Session::getLuckyPoints() const
|
||||
|
|
|
|||
|
|
@ -67,9 +67,7 @@ namespace Main
|
|||
roomsManager->removeRoom(room->getRoomNumber());
|
||||
}
|
||||
}
|
||||
m_sessionsBySessionId[sessionId]->leaveRoom();
|
||||
}
|
||||
m_sessionsBySessionId[sessionId]->clear();
|
||||
m_sessionsBySessionId.erase(sessionId);
|
||||
|
||||
auto it = std::find_if(m_sessionsVector.begin(), m_sessionsVector.end(),
|
||||
|
|
@ -183,5 +181,35 @@ namespace Main
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::Network::Packet SessionsManager::prepareMessage(const std::string& message) const
|
||||
{
|
||||
Common::Network::Packet response;
|
||||
response.setOrder(316);
|
||||
response.setExtra(1);
|
||||
std::string m_confirmationMessage{ std::string(16, '0') };
|
||||
m_confirmationMessage += message;
|
||||
response.setData(reinterpret_cast<std::uint8_t*>(m_confirmationMessage.data()), m_confirmationMessage.size());
|
||||
return response;
|
||||
}
|
||||
|
||||
void SessionsManager::broadcastMessage(const std::string& message) const
|
||||
{
|
||||
auto response = prepareMessage(message);
|
||||
for (auto& currentSession : m_sessionsVector)
|
||||
{
|
||||
currentSession->asyncWrite(response);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionsManager::broadcastMessageExceptSelf(std::size_t selfSessionId, const std::string& message) const
|
||||
{
|
||||
auto response = prepareMessage(message);
|
||||
for (auto& currentSession : m_sessionsVector)
|
||||
{
|
||||
if (currentSession->getId() == selfSessionId) continue;
|
||||
currentSession->asyncWrite(response);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue