Abstracted the CDClient tables

There is now an option to utilize shared memory for some CDClient tables by adding `CD_PROVIDER_MEMORY=1` to the CMakeVariables.txt file.

Allows masterconfig.ini to specify another run command for the world server, to allow for easier debugging through `valgrind`.
This commit is contained in:
wincent 2022-08-11 16:36:03 +02:00
parent 45ae46f6f1
commit 56f371216b
23 changed files with 661 additions and 328 deletions

View File

@ -171,6 +171,9 @@ void CatchUnhandled(int sig) {
ErrorCallback,
nullptr);
// Print error code
printf("Error code: %d\n", sig);
struct bt_ctx ctx = {state, 0};
Bt(state);

View File

@ -34,12 +34,19 @@ void dConfig::ProcessLine(const std::string& line) {
seglist.push_back(segment);
}
if (seglist.size() != 2) return;
if (seglist.size() < 2) return;
// Segment #1 is combined with the rest of the line to form the value
std::string key = seglist[0];
std::string value = seglist[1];
for (size_t i = 2; i < seglist.size(); ++i) {
value += "=" + seglist[i];
}
//Make sure that on Linux, we remove special characters:
if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r')
seglist[1].erase(seglist[1].size() - 1);
if (!value.empty() && value[value.size() - 1] == '\r')
value.erase(value.size() - 1);
m_Keys.push_back(seglist[0]);
m_Values.push_back(seglist[1]);
m_Keys.push_back(key);
m_Values.push_back(value);
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
template <
typename KeyType,
typename MappedType
>
class CDAbstractProvider
{
public:
virtual void LoadClient() = 0;
virtual void LoadHost() = 0;
virtual const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) = 0;
};

View File

@ -0,0 +1,124 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
#include "CDAbstractProvider.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>
template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryMap : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> Map;
public:
std::map<KeyType, MappedType> m_CacheMap;
std::string m_Name;
size_t m_Size;
bool m_Host;
Map* m_HostEntries;
boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;
CDAbstractSharedMemoryMap(std::string name, size_t size)
{
m_Name = name;
m_Size = size;
m_Host = false;
m_HostEntries = nullptr;
m_ClientAllocInst = nullptr;
m_ClientEntires = nullptr;
LoadClient();
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
const auto& cacheIt = m_CacheMap.find(key);
if (cacheIt != m_CacheMap.end()) {
return cacheIt->second;
}
const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end()) {
return defaultValue;
}
return it->second;
}
const void SetEntry(const KeyType& key, const MappedType& value) {
if (m_Host) {
// If we are already hosting, we cannot add to the map, throw an error
throw std::runtime_error("Can not add to a map that is already being hosted");
}
m_CacheMap.emplace(key, value);
}
void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_Name.c_str());
m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());
m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;
if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}
} catch (std::exception &e) {
// Not open
}
}
void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_Name.c_str());
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_Name.c_str(), m_Size);
ShmemAllocator alloc(segment.get_segment_manager());
m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc);
// Copy cache
for (const auto& pair : m_CacheMap) {
m_HostEntries->insert(std::make_pair(pair.first, pair.second));
}
m_Host = true;
LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_Name.c_str());
throw e;
}
}
};

View File

@ -0,0 +1,150 @@
#pragma once
#include "CDAbstractProvider.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>
#include <mutex>
template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryProvider : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> Map;
public:
std::string m_Name;
std::string m_MapName;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;
std::function <int32_t(int32_t)> m_CalculateSize;
bool m_Cache;
std::unordered_map<KeyType, MappedType> m_CacheMap;
bool m_Host;
Map* m_HostEntries;
boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;
CDAbstractSharedMemoryProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, std::function <int32_t(int32_t)> calculateSize, bool cache)
{
m_Name = name;
m_MapName = name + "Map";
m_ParseEntry = parseEntry;
m_CalculateSize = calculateSize;
m_Cache = cache;
m_Host = false;
m_HostEntries = nullptr;
LoadClient();
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
if (m_Host) {
auto it = m_HostEntries->find(key);
if (it == m_HostEntries->end())
{
return defaultValue;
}
return it->second;
}
if (m_Cache) {
auto it = m_CacheMap.find(key);
if (it != m_CacheMap.end()) {
return it->second;
}
}
const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end())
{
if (m_Cache) {
m_CacheMap.emplace(key, defaultValue);
}
return defaultValue;
}
if (m_Cache) {
m_CacheMap.emplace(key, it->second);
}
return it->second;
}
void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_MapName.c_str());
m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());
m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;
if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}
} catch (boost::interprocess::interprocess_exception& e) {
// Not open
}
}
void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());
auto sizeQuery = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);
if (sizeQuery.eof()) {
throw std::runtime_error("Could not get size of table " + m_Name);
return;
}
int32_t size = sizeQuery.getIntField(0);
size = m_CalculateSize(size);
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_MapName.c_str(), size);
ShmemAllocator alloc_inst (segment.get_segment_manager());
m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc_inst);
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);
while (!tableData.eof()) {
ValueType entry = m_ParseEntry(tableData);
m_HostEntries->insert(entry);
tableData.nextRow();
}
tableData.finalize();
m_Host = true;
LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());
throw e;
}
}
};

View File

@ -0,0 +1,74 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
#include "CDAbstractProvider.h"
template <
typename KeyType,
typename MappedType
>
class CDAbstractSqliteProvider : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
public:
std::string m_Name;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;
std::unordered_map<KeyType, MappedType> m_Entries;
CDAbstractSqliteProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, bool cache)
{
m_Name = name;
m_ParseEntry = parseEntry;
LoadClient();
}
void LoadClient() override {
// First, get the size of the table
uint32_t size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
m_Entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);
while (!tableData.eof()) {
auto entry = m_ParseEntry(tableData);
m_Entries.insert(entry);
tableData.nextRow();
}
tableData.finalize();
}
void LoadHost() override {
return;
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
auto it = m_Entries.find(key);
if (it != m_Entries.end()) {
return it->second;
}
return defaultValue;
}
};

View File

@ -5,6 +5,8 @@ CDClientManager * CDClientManager::m_Address = nullptr;
//! Initializes the manager
void CDClientManager::Initialize(void) {
CDTable::Initalize();
tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable()));
UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable())));
tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable()));
@ -44,3 +46,11 @@ void CDClientManager::Initialize(void) {
tables.insert(std::make_pair("FeatureGating", new CDFeatureGatingTable()));
tables.insert(std::make_pair("RailActivatorComponent", new CDRailActivatorComponentTable()));
}
void CDClientManager::LoadHost() {
for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) {
itr->second->LoadHost();
}
CDTable::InitalizeHost();
}

View File

@ -93,4 +93,6 @@ public:
return nullptr;
}
void LoadHost();
};

41
dDatabase/CDProvider.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "CDAbstractProvider.h"
/**
* Shared memory provider with CDAbstractSharedMemoryProvider<key, value>
*
* Depends on the boost::interprocess library header only
*
* Requires that CD_PROVIDER_MEMORY is defined and CD_PROVIDER_SQLITE is not defined
*/
#if defined(CD_PROVIDER_MEMORY) && !defined(CD_PROVIDER_SQLITE)
#include "CDAbstractSharedMemoryProvider.h"
#define CD_PROVIDER(provider, key, value) CDAbstractSharedMemoryProvider<key, value>* provider; typedef key CD_KEY; typedef value CD_VALUE
#define NEW_CD_PROVIDER(provider, name, parser, size_calculator, cache) provider = new CDAbstractSharedMemoryProvider<CD_KEY, CD_VALUE>(name, parser, size_calculator, cache)
template<typename KeyType, typename MappedType>
using CDProvider = CDAbstractSharedMemoryProvider<KeyType, MappedType>;
#endif
/**
* SQLite provider with CDAbstractSqliteProvider<key, value>
*
* No extra dependencies
*
* Requires that CD_PROVIDER_SQLITE or CD_PROVIDER_MEMORY is not defined the default option
*/
#if defined(CD_PROVIDER_SQLITE) || !defined(CD_PROVIDER_MEMORY)
#include "CDAbstractSqliteProvider.h"
#define CD_PROVIDER(provider, key, value) CDAbstractSqliteProvider<key, value>* provider; typedef key CD_KEY; typedef value CD_VALUE
#define NEW_CD_PROVIDER(provider, name, parser, size_calculator, cache) provider = new CDAbstractSqliteProvider<CD_KEY, CD_VALUE>(name, parser, cache)
template<typename KeyType, typename MappedType>
using CDProvider = CDAbstractSqliteProvider<KeyType, MappedType>;
#endif

View File

@ -5,47 +5,27 @@
#include "dLogger.h"
#include "dServer.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <functional>
#include <utility>
#include <chrono>
#include "CDProvider.h"
typedef size_t KeyType;
typedef float MappedType;
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> CDBehaviorParameterMap;
CDBehaviorParameterMap *table = nullptr;
boost::interprocess::managed_shared_memory segment;
ShmemAllocator* alloc_inst;
boost::interprocess::offset_ptr<CDBehaviorParameterMap> m;
CD_PROVIDER(BehaviorParameterProvider, size_t, float);
//! Constructor
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
try {
segment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, "CDBehaviorParameterTable");
NEW_CD_PROVIDER(BehaviorParameterProvider, "BehaviorParameter", [](CppSQLite3Query& query) {
size_t hash = 0;
alloc_inst = new ShmemAllocator(segment.get_segment_manager());
int32_t behaviorID = query.getIntField(0, -1);
std::string parameterID = query.getStringField(1, "");
m = segment.find<CDBehaviorParameterMap>("CDBehaviorParameter").first;
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, parameterID);
if (m == nullptr) {
Game::logger->Log("CDBehaviorParameterTable", "CDBehaviorParameter segment is nullptr!\n");
}
float value = query.getFloatField(2, -1.0f);
// Load the entire table into m_Entries
/*for (auto it = m->begin(); it != m->end(); ++it) {
m_Entries.insert(std::make_pair(it->first, it->second));
}*/
} catch (std::exception &e) {
// Not open, we are master
}
return std::make_pair(hash, value);
}, [](int32_t size) {
return 40 * 1000 * 1000;
}, false);
}
//! Destructor
@ -62,95 +42,10 @@ float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::s
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, name);
// Search for specific parameter
try {
/*boost::interprocess::managed_shared_memory segment(boost::interprocess::open_read_only, "CDBehaviorParameterTable");
// If the segment manager is not null, then the segment exists
// Get the table from the segment
ShmemAllocator alloc_inst (segment.get_segment_manager());
boost::interprocess::offset_ptr<CDBehaviorParameterMap> m = segment.find<CDBehaviorParameterMap>("CDBehaviorParameter").first;
if (m == nullptr) {
Game::logger->Log("CDBehaviorParameterTable", "CDBehaviorParameter segment is nullptr!\n");
return defaultValue;
}*/
// Start a timer
auto start = std::chrono::high_resolution_clock::now();
auto it = m->find(hash);
bool found = it != m->end();
// End the timer
auto end = std::chrono::high_resolution_clock::now();
// Get duraction
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
// Reset the timer
/*start = std::chrono::high_resolution_clock::now();
auto nativeIt = m_Entries.find(hash);
bool nativeFound = nativeIt != m_Entries.end();
// End the timer
end = std::chrono::high_resolution_clock::now();
// Get duraction
auto nativeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);*/
//Game::logger->Log("CDBehaviorParameterTable", "Duration: (sm) %fms / (m) %fms -> %f\n", duration.count() / 1000000.0f, nativeDuration.count() / 1000000.0f, (double) duration.count() / (double) nativeDuration.count());
if (found) {
return it->second;
}
return defaultValue;
}
catch (std::exception &e) {
Game::logger->Log("CDBehaviorParameterTable", "Failed to find entry for behaviorID: %d, parameterID: %s\n%e\n", behaviorID, name.c_str(), e.what());
return defaultValue;
}
return BehaviorParameterProvider->GetEntry(hash, defaultValue);
}
void CDBehaviorParameterTable::CreateSharedMap()
void CDBehaviorParameterTable::LoadHost()
{
boost::interprocess::shared_memory_object::remove("CDBehaviorParameterTable");
Game::logger->Log("CDBehaviorParameterTable", "Create shared memory segment.\n");
// Create the segment, TODO: calculate size
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "CDBehaviorParameterTable", 40 * 1000 * 1000);
ShmemAllocator alloc_inst (segment.get_segment_manager());
table = segment.construct<CDBehaviorParameterMap>("CDBehaviorParameter") (std::less<KeyType>(), alloc_inst);
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
size_t hash = 0;
while (!tableData.eof()) {
hash = 0;
int32_t behaviorID = tableData.getIntField(0, -1);
std::string parameterID = tableData.getStringField(1, "");
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, parameterID);
float value = tableData.getFloatField(2, -1.0f);
table->insert(ValueType(hash, value));
tableData.nextRow();
}
tableData.finalize();
BehaviorParameterProvider->LoadHost();
}

View File

@ -19,10 +19,8 @@ struct CDBehaviorParameter {
//! BehaviorParameter table
class CDBehaviorParameterTable : public CDTable {
private:
std::unordered_map<size_t, float> m_Entries;
public:
static void CreateSharedMap();
void LoadHost() override;
//! Constructor
CDBehaviorParameterTable(void);

View File

@ -1,43 +1,25 @@
#include "CDBehaviorTemplateTable.h"
#include "CDProvider.h"
CDBehaviorTemplate EmptyBehaviorTemplate {0, 0, 0, 0};
CD_PROVIDER(BehaviorTemplateProvider, uint32_t, CDBehaviorTemplate);
//! Constructor
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
while (!tableData.eof()) {
NEW_CD_PROVIDER(BehaviorTemplateProvider, "BehaviorTemplate", [](CppSQLite3Query& query) {
CDBehaviorTemplate entry;
entry.behaviorID = tableData.getIntField(0, -1);
entry.templateID = tableData.getIntField(1, -1);
entry.effectID = tableData.getIntField(2, -1);
auto candidateToAdd = tableData.getStringField(3, "");
auto parameter = m_EffectHandles.find(candidateToAdd);
if (parameter != m_EffectHandles.end()) {
entry.effectHandle = parameter;
} else {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
}
this->entries.push_back(entry);
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow();
}
entry.behaviorID = query.getIntField(0, -1);
entry.templateID = query.getIntField(1, -1);
entry.effectID = query.getIntField(2, -1);
entry.effectHandle = CDTable::SetString(query.getStringField(3, ""));
tableData.finalize();
return std::make_pair(entry.behaviorID, entry);
}, [](int32_t size) {
return 40 * 1000 * 1000;
}, false);
}
//! Destructor
@ -48,30 +30,10 @@ std::string CDBehaviorTemplateTable::GetName(void) const {
return "BehaviorTemplate";
}
//! Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
const CDBehaviorTemplate& CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) const {
return BehaviorTemplateProvider->GetEntry(behaviorID, EmptyBehaviorTemplate);
}
//! Gets all the entries in the table
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
if (entry == this->entriesMappedByBehaviorID.end()) {
CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end();
entryToReturn.effectID = 0;
return entryToReturn;
} else {
return entry->second;
}
void CDBehaviorTemplateTable::LoadHost() {
BehaviorTemplateProvider->LoadHost();
}

View File

@ -15,17 +15,14 @@ struct CDBehaviorTemplate {
unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT)
unsigned int effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
size_t effectHandle; //!< The effect handle
};
//! BehaviorTemplate table
class CDBehaviorTemplateTable : public CDTable {
private:
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public:
void LoadHost() override;
//! Constructor
CDBehaviorTemplateTable(void);
@ -39,17 +36,5 @@ public:
*/
std::string GetName(void) const override;
//! Queries the table with a custom "where" clause
/*!
\param predicate The predicate
*/
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
//! Gets all the entries in the table
/*!
\return The entries
*/
std::vector<CDBehaviorTemplate> GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
const CDBehaviorTemplate& GetByBehaviorID(const uint32_t behaviorID) const;
};

View File

@ -1,58 +1,30 @@
#include "CDComponentsRegistryTable.h"
#define CDCLIENT_CACHE_ALL
#include "CDProvider.h"
CD_PROVIDER(ComponentsRegistryProvider, size_t, int32_t);
//! Constructor
CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
NEW_CD_PROVIDER(ComponentsRegistryProvider, "ComponentsRegistry", [](CppSQLite3Query& query) {
size_t hash = 0;
#ifdef CDCLIENT_CACHE_ALL
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ComponentsRegistry");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
int32_t componentID = query.getIntField(0, -1);
int32_t componentType = query.getIntField(1, -1);
tableSize.nextRow();
}
hash = componentID;
hash = hash << 32;
hash |= componentType;
tableSize.finalize();
int32_t componentHandle = query.getIntField(2, -1);
// Reserve the size
//this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField(0, -1);
entry.component_type = tableData.getIntField(1, -1);
entry.component_id = tableData.getIntField(2, -1);
this->mappedEntries.insert_or_assign(((uint64_t) entry.component_type) << 32 | ((uint64_t) entry.id), entry.component_id);
//this->entries.push_back(entry);
/*
//Darwin's stuff:
const auto& it = this->mappedEntries.find(entry.id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(entry.component_type);
if (iter == it->second.end()) {
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
}
}
else {
std::map<unsigned int, unsigned int> map;
map.insert(std::make_pair(entry.component_type, entry.component_id));
this->mappedEntries.insert(std::make_pair(entry.id, map));
}
*/
tableData.nextRow();
}
tableData.finalize();
#endif
return std::make_pair(hash, componentHandle);
}, [](int32_t size) {
return 10 * 1000 * 1000;
}, true);
}
//! Destructor
@ -63,69 +35,15 @@ std::string CDComponentsRegistryTable::GetName(void) const {
return "ComponentsRegistry";
}
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue)
{
const auto& iter = this->mappedEntries.find(((uint64_t) componentType) << 32 | ((uint64_t) id));
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue) {
size_t hash = 0;
hash = id;
hash = hash << 32;
hash |= componentType;
if (iter == this->mappedEntries.end())
{
return defaultValue;
}
return iter->second;
/*
const auto& it = this->mappedEntries.find(id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(componentType);
if (iter != it->second.end()) {
return iter->second;
}
}
*/
#ifndef CDCLIENT_CACHE_ALL
// Now get the data
std::stringstream query;
query << "SELECT * FROM ComponentsRegistry WHERE id = " << std::to_string(id);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField(0, -1);
entry.component_type = tableData.getIntField(1, -1);
entry.component_id = tableData.getIntField(2, -1);
//this->entries.push_back(entry);
//Darwin's stuff:
const auto& it = this->mappedEntries.find(entry.id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(entry.component_type);
if (iter == it->second.end()) {
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
}
}
else {
std::map<unsigned int, unsigned int> map;
map.insert(std::make_pair(entry.component_type, entry.component_id));
this->mappedEntries.insert(std::make_pair(entry.id, map));
}
tableData.nextRow();
}
tableData.finalize();
const auto& it2 = this->mappedEntries.find(id);
if (it2 != mappedEntries.end()) {
const auto& iter = it2->second.find(componentType);
if (iter != it2->second.end()) {
return iter->second;
}
}
return defaultValue;
#endif
return ComponentsRegistryProvider->GetEntry(hash, defaultValue);
}
void CDComponentsRegistryTable::LoadHost() {
ComponentsRegistryProvider->LoadHost();
}

View File

@ -23,6 +23,7 @@ private:
std::map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
public:
void LoadHost() override;
//! Constructor
CDComponentsRegistryTable(void);

View File

@ -0,0 +1,70 @@
#include "CDTable.h"
#if defined(CD_PROVIDER_MEMORY)
#include "CDAbstractSharedMemoryMap.h"
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> my_string;
CDAbstractSharedMemoryMap<size_t, boost::interprocess::string>* CDStringMap;
void CDTable::InitalizeHost()
{
CDStringMap->LoadHost();
}
void CDTable::Initalize()
{
CDStringMap = new CDAbstractSharedMemoryMap<size_t, boost::interprocess::string>("CDStringMap", 10 * 1000 * 1000);
}
std::string CDTable::GetString(size_t handle)
{
std::string str = std::string(CDStringMap->GetEntry(handle, "").c_str());
Game::logger->Log("CDTable", "GetString: %s\n", str.c_str());
return str;
}
size_t CDTable::SetString(std::string value)
{
size_t hash = 0;
GeneralUtils::hash_combine(hash, value);
CDStringMap->SetEntry(hash, boost::interprocess::string(value.c_str()));
return hash;
}
#else
std::unordered_map<size_t, std::string> CDStringMap;
void CDTable::InitalizeHost()
{
}
void CDTable::Initalize()
{
}
std::string CDTable::GetString(size_t handle)
{
return CDStringMap[handle];
}
size_t CDTable::SetString(std::string value)
{
size_t hash = 0;
GeneralUtils::hash_combine(hash, value);
CDStringMap[hash] = value;
return hash;
}
#endif

View File

@ -38,4 +38,27 @@ public:
\return The table name
*/
virtual std::string GetName() const = 0;
//! Loads the table into shared memory
virtual void LoadHost() {};
//! Initalizes the table services
static void Initalize();
//! Initalizes the table services as host
static void InitalizeHost();
//! Get a string from a handle
/*!
\param handle The handle to get the string from
\return The string
*/
static std::string GetString(size_t handle);
//! Set a string
/*!
\param value The string to set
\return The handle to the string
*/
static size_t SetString(std::string value);
};

View File

@ -1,4 +1,4 @@
set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp"
set(DDATABASE_TABLES_SOURCES "CDTable.cpp" "CDActivitiesTable.cpp"
"CDActivityRewardsTable.cpp"
"CDAnimationsTable.cpp"
"CDBehaviorParameterTable.cpp"

View File

@ -445,7 +445,7 @@ Behavior::Behavior(const uint32_t behaviorId)
this->m_effectId = templateInDatabase.effectID;
this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr;
this->m_effectHandle = new std::string(CDTable::GetString(templateInDatabase.effectHandle));
}

View File

@ -1754,6 +1754,40 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
#ifdef __linux__
if (chatCommand == "statm" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER)
{
// Print and format the output of /proc/self/statm
std::ifstream statm("/proc/self/statm");
if (!statm.is_open())
{
ChatPackets::SendSystemMessage(sysAddr, u"Failed to open /proc/self/statm");
return;
}
// Scan for the different fields
uint64_t size, resident, share, text, lib, data, dirty;
statm >> size >> resident >> share >> text >> lib >> data >> dirty;
// Get the page size
size_t pageSize = sysconf(_SC_PAGESIZE);
// Print the output
ChatPackets::SendSystemMessage(
sysAddr,
u"Size: " + GeneralUtils::to_u16string((float) ((double) size * pageSize / 1.024e6)) +
u"MB\nResident: " + GeneralUtils::to_u16string((float) ((double) resident * pageSize / 1.024e6)) +
u"MB\nShared: " + GeneralUtils::to_u16string((float) ((double) share * pageSize / 1.024e6)) +
u"MB\nText: " + GeneralUtils::to_u16string((float) ((double) text * pageSize / 1.024e6)) +
u"MB\nLibrary: " + GeneralUtils::to_u16string((float) ((double) lib * pageSize / 1.024e6)) +
u"MB\nData: " + GeneralUtils::to_u16string((float) ((double) data * pageSize / 1.024e6)) +
u"MB\nDirty: " + GeneralUtils::to_u16string((float) ((double) dirty * pageSize / 1.024e6)) +
u"MB"
);
}
#endif
if (chatCommand == "rollloot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && args.size() >= 3) {
uint32_t lootMatrixIndex = 0;
uint32_t targetLot = 0;

View File

@ -48,16 +48,28 @@ Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, L
//Start the actual process:
#ifdef _WIN32
std::string cmd = "start ./WorldServer.exe -zone ";
std::string cmd = "start ./WorldServer.exe";
#else
std::string cmd;
if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) {
cmd = "sudo ./WorldServer -zone ";
Game::logger->Log("InstanceManager", "world_command: %s\n", Game::config->GetValue("world_command").c_str());
if (!Game::config->GetValue("world_command").empty()) {
cmd = Game::config->GetValue("world_command");
// Replace %map%_%instance%_%time% with the correct values
cmd = cmd.replace(cmd.find("%map%"), 5, std::to_string(mapID));
cmd = cmd.replace(cmd.find("%instance%"), 10, std::to_string(instance->GetInstanceID()));
cmd = cmd.replace(cmd.find("%time%"), 5, std::to_string(time(nullptr)));
// Remove any other %
cmd = cmd.replace(cmd.find("%"), 1, "");
} else if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) {
cmd = "sudo ./WorldServer";
} else {
cmd = "./WorldServer -zone ";
cmd = "./WorldServer";
}
#endif
cmd.append(" -zone ");
cmd.append(std::to_string(mapID));
cmd.append(" -port ");
cmd.append(std::to_string(port));
@ -73,6 +85,8 @@ Instance * InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, L
cmd.append("&"); //Sends our next process to the background on Linux
#endif
Game::logger->Log("InstanceManager", "Starting instance %i with command: %s\n", instance->GetInstanceID(), cmd.c_str());
system(cmd.c_str());
m_Instances.push_back(instance);

View File

@ -226,7 +226,7 @@ int main(int argc, char** argv) {
ObjectIDManager::Instance()->Initialize(Game::logger);
Game::im = new InstanceManager(Game::logger, Game::server->GetIP());
CDBehaviorParameterTable::CreateSharedMap();
CDClientManager::Instance()->LoadHost();
//Depending on the config, start up servers:
if (config.GetValue("prestart_servers") != "" && config.GetValue("prestart_servers") == "1") {

View File

@ -35,7 +35,7 @@ void AuthPackets::HandleHandshake(dServer* server, Packet* packet) {
void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort) {
RakNet::BitStream bitStream;
PacketUtils::WriteHeader(bitStream, SERVER, MSG_SERVER_VERSION_CONFIRM);
bitStream.Write<unsigned int>(NET_VERSION);
bitStream.Write<unsigned int>(171023);
bitStream.Write(uint32_t(0x93));
if (nextServerPort == 1001) bitStream.Write(uint32_t(1)); //Conn: auth