refactor(Core/Misc): add braces and impove codestyle (#6402)

This commit is contained in:
Kargatum
2021-06-25 00:50:18 +07:00
committed by GitHub
parent 33c271cc7c
commit 3c24b511f2
72 changed files with 1486 additions and 401 deletions

View File

@@ -31,11 +31,17 @@ namespace Acore::Net
inline boost::asio::ip::address_v4 GetDefaultNetmaskV4(boost::asio::ip::address_v4 const& networkAddress)
{
if ((address_to_uint(networkAddress) & 0x80000000) == 0)
{
return boost::asio::ip::address_v4(0xFF000000);
}
if ((address_to_uint(networkAddress) & 0xC0000000) == 0x80000000)
{
return boost::asio::ip::address_v4(0xFFFF0000);
}
if ((address_to_uint(networkAddress) & 0xE0000000) == 0xC0000000)
{
return boost::asio::ip::address_v4(0xFFFFFF00);
}
return boost::asio::ip::address_v4(0xFFFFFFFF);
}

View File

@@ -47,7 +47,9 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
// perform quick consistency checks
G3D::Vector3 d( gridBox.hi - gridBox.lo );
if (d.x < 0 || d.y < 0 || d.z < 0)
{
throw std::logic_error("negative node extents");
}
for (int i = 0; i < 3; i++)
{
if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
@@ -76,7 +78,9 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
// stay left
i++;
if (clipL < maxb)
{
clipL = maxb;
}
}
else
{
@@ -86,7 +90,9 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
dat.indices[right] = t;
right--;
if (clipR > minb)
{
clipR = minb;
}
}
nodeL = std::min(nodeL, minb);
nodeR = std::max(nodeR, maxb);
@@ -212,7 +218,9 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
tempTree.push_back(0);
}
else
{
nextIndex -= 3;
}
// allocate right node
if (nr > 0)
{
@@ -233,13 +241,21 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
nodeBoxR.lo[axis] = clipR;
// recurse
if (nl > 0)
{
subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
}
else
{
stats.updateLeaf(depth + 1, 0);
}
if (nr > 0)
{
subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
}
else
{
stats.updateLeaf(depth + 1, 0);
}
}
bool BIH::writeToFile(FILE* wf) const

View File

@@ -90,11 +90,15 @@ public:
BuildStats stats;
buildHierarchy(tempTree, dat, stats);
if (printStats)
{
stats.printStats();
}
objects.resize(dat.numPrims);
for (uint32 i = 0; i < dat.numPrims; ++i)
{
objects[i] = dat.indices[i];
}
//nObjects = dat.numPrims;
tree = tempTree;
delete[] dat.primBound;
@@ -118,20 +122,30 @@ public:
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
float t2 = (bounds.high()[i] - org[i]) * invDir[i];
if (t1 > t2)
{
std::swap(t1, t2);
}
if (t1 > intervalMin)
{
intervalMin = t1;
}
if (t2 < intervalMax || intervalMax < 0.f)
{
intervalMax = t2;
}
// intervalMax can only become smaller for other axis,
// and intervalMin only larger respectively, so stop early
if (intervalMax <= 0 || intervalMin >= maxDist)
{
return;
}
}
}
if (intervalMin > intervalMax)
{
return;
}
intervalMin = std::max(intervalMin, 0.f);
intervalMax = std::min(intervalMax, maxDist);
@@ -174,7 +188,9 @@ public:
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
// ray passes between clip zones
if (tf < intervalMin && tb > intervalMax)
{
break;
}
int back = offset + offsetBack3[axis];
node = back;
// ray passes through far node only
@@ -207,7 +223,7 @@ public:
while (n > 0)
{
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirstHit);
if (stopAtFirstHit && hit) return;
if (stopAtFirstHit && hit) { return; }
--n;
++offset;
}
@@ -217,14 +233,18 @@ public:
else
{
if (axis > 2)
return; // should not happen
{
return; // should not happen
}
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
node = offset;
intervalMin = (tf >= intervalMin) ? tf : intervalMin;
intervalMax = (tb <= intervalMax) ? tb : intervalMax;
if (intervalMin > intervalMax)
{
break;
}
continue;
}
} // traversal loop
@@ -232,12 +252,16 @@ public:
{
// stack is empty?
if (stackPos == 0)
{
return;
}
// move back up the stack
stackPos--;
intervalMin = stack[stackPos].tnear;
if (maxDist < intervalMin)
{
continue;
}
node = stack[stackPos].node;
intervalMax = stack[stackPos].tfar;
break;
@@ -249,7 +273,9 @@ public:
void intersectPoint(const G3D::Vector3& p, IsectCallback& intersectCallback) const
{
if (!bounds.contains(p))
{
return;
}
StackNode stack[MAX_STACK_SIZE];
int stackPos = 0;
@@ -272,7 +298,9 @@ public:
float tr = intBitsToFloat(tree[node + 2]);
// point is between clip zones
if (tl < p[axis] && tr > p[axis])
{
break;
}
int right = offset + 3;
node = right;
// point is in right node only
@@ -308,19 +336,25 @@ public:
else // BVH2 node (empty space cut off left and right)
{
if (axis > 2)
return; // should not happen
{
return; // should not happen
}
float tl = intBitsToFloat(tree[node + 1]);
float tr = intBitsToFloat(tree[node + 2]);
node = offset;
if (tl > p[axis] || tr < p[axis])
{
break;
}
continue;
}
} // traversal loop
// stack is empty?
if (stackPos == 0)
{
return;
}
// move back up the stack
stackPos--;
node = stack[stackPos].node;
@@ -366,7 +400,7 @@ protected:
public:
BuildStats()
{
for (int & i : numLeavesN) i = 0;
for (int& i : numLeavesN) { i = 0; }
}
void updateInner() { numNodes++; }

View File

@@ -28,9 +28,13 @@ class BIHWrap
bool operator() (const G3D::Ray& ray, uint32 idx, float& maxDist, bool stopAtFirstHit)
{
if (idx >= objects_size)
{
return false;
}
if (const T* obj = objects[idx])
{
return _callback(ray, *obj, maxDist, stopAtFirstHit);
}
return false;
}
@@ -38,9 +42,13 @@ class BIHWrap
void operator() (const G3D::Vector3& p, uint32 idx)
{
if (idx >= objects_size)
{
return;
}
if (const T* obj = objects[idx])
{
_callback(p, *obj);
}
}
};
@@ -67,15 +75,21 @@ public:
uint32 Idx = 0;
const T* temp;
if (m_obj2Idx.getRemove(&obj, temp, Idx))
{
m_objects[Idx] = nullptr;
}
else
{
m_objects_to_push.remove(&obj);
}
}
void balance()
{
if (unbalanced_times == 0)
{
return;
}
unbalanced_times = 0;
m_objects.fastClear();

View File

@@ -72,14 +72,18 @@ struct DynTreeImpl : public ParentTree
void update(uint32 difftime)
{
if (!size())
{
return;
}
rebalance_timer.Update(difftime);
if (rebalance_timer.Passed())
{
rebalance_timer.Reset(CHECK_TREE_PERIOD);
if (unbalanced_times > 0)
{
balance();
}
}
}
@@ -133,7 +137,9 @@ struct DynamicTreeIntersectionCallback
{
bool result = obj.intersectRay(r, distance, stopAtFirstHit, phase_mask);
if (result)
{
did_hit = result;
}
return result;
}
bool didHit() const { return did_hit;}
@@ -146,7 +152,9 @@ bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray&
DynamicTreeIntersectionCallback callback(phasemask);
impl->intersectRay(ray, callback, distance, endPos, false);
if (callback.didHit())
{
maxDist = distance;
}
return callback.didHit();
}
@@ -173,12 +181,18 @@ bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const G3D::Vector3&
if (modifyDist < 0)
{
if ((resultHit - startPos).magnitude() > -modifyDist)
{
resultHit = resultHit + dir * modifyDist;
}
else
{
resultHit = startPos;
}
}
else
{
resultHit = resultHit + dir * modifyDist;
}
result = true;
}
@@ -197,7 +211,9 @@ bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, flo
float maxDist = (v2 - v1).magnitude();
if (!G3D::fuzzyGt(maxDist, 0) )
{
return true;
}
G3D::Ray r(v1, (v2 - v1) / maxDist);
DynamicTreeIntersectionCallback callback(phasemask);
@@ -214,7 +230,11 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
impl->intersectZAllignedRay(r, callback, maxSearchDist);
if (callback.didHit())
{
return v.z - maxSearchDist;
}
else
{
return -G3D::finf();
}
}

View File

@@ -27,7 +27,7 @@ public:
~DynamicMapTree();
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2,
float z2, uint32 phasemask) const;
float z2, uint32 phasemask) const;
bool getIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
const G3D::Vector3& endPos, float& maxDist) const;

View File

@@ -18,7 +18,9 @@ namespace MMAP
MMapManager* MMapFactory::createOrGetMMapManager()
{
if (g_MMapManager == nullptr)
{
g_MMapManager = new MMapManager();
}
return g_MMapManager;
}
@@ -29,7 +31,9 @@ namespace MMAP
int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1};
uint32 i = 0;
while (f[i] >= 0)
{
forbiddenMaps[f[i++]] = true;
}
}
void MMapFactory::clear()

View File

@@ -20,7 +20,9 @@ namespace MMAP
MMapManager::~MMapManager()
{
for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
{
delete i->second;
}
// by now we should not have maps loaded
// if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
@@ -30,7 +32,9 @@ namespace MMAP
{
// the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
for (const uint32& mapId : mapIds)
{
loadedMMaps.emplace(mapId, nullptr);
}
thread_safe_environment = false;
}
@@ -40,7 +44,9 @@ namespace MMAP
// return the iterator if found or end() if not found/NULL
MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
if (itr != loadedMMaps.cend() && !itr->second)
{
itr = loadedMMaps.cend();
}
return itr;
}
@@ -52,14 +58,20 @@ namespace MMAP
if (itr != loadedMMaps.end())
{
if (itr->second)
{
return true;
}
}
else
{
if (thread_safe_environment)
{
itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
}
else
{
ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
}
}
// load and init dtNavMesh - read parameters from file
@@ -107,7 +119,9 @@ namespace MMAP
{
// make sure the mmap is loaded and ready to load tiles
if (!loadMapData(mapId))
{
return false;
}
// get this mmap data
MMapData* mmap = loadedMMaps[mapId];
@@ -243,7 +257,9 @@ namespace MMAP
uint32 y = (i.first & 0x0000FFFF);
if (dtStatusFailed(mmap->navMesh->removeTile(i.second, nullptr, nullptr)))
{
LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
}
else
{
--loadedTiles;
@@ -289,7 +305,9 @@ namespace MMAP
{
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
{
return nullptr;
}
return itr->second->navMesh;
}
@@ -298,7 +316,9 @@ namespace MMAP
{
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
{
return nullptr;
}
MMapData* mmap = itr->second;
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())

View File

@@ -40,10 +40,14 @@ namespace MMAP
~MMapData()
{
for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
{
dtFreeNavMeshQuery(i->second);
}
if (navMesh)
{
dtFreeNavMesh(navMesh);
}
}
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe

View File

@@ -16,7 +16,9 @@ namespace VMAP
VMapManager2* VMapFactory::createOrGetVMapManager()
{
if (!gVMapManager)
{
gVMapManager = new VMapManager2();
}
return gVMapManager;
}

View File

@@ -57,7 +57,9 @@ namespace VMAP
{
// the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
for (const uint32& mapId : mapIds)
{
iInstanceMapTrees.emplace(mapId, nullptr);
}
thread_safe_environment = false;
}
@@ -78,7 +80,9 @@ namespace VMAP
// return the iterator if found or end() if not found/NULL
InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId);
if (itr != iInstanceMapTrees.cend() && !itr->second)
{
itr = iInstanceMapTrees.cend();
}
return itr;
}
@@ -99,9 +103,13 @@ namespace VMAP
if (isMapLoadingEnabled())
{
if (_loadMap(mapId, basePath, x, y))
{
result = VMAP_LOAD_RESULT_OK;
}
else
{
result = VMAP_LOAD_RESULT_ERROR;
}
}
return result;
@@ -114,10 +122,12 @@ namespace VMAP
if (instanceTree == iInstanceMapTrees.end())
{
if (thread_safe_environment)
{
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first;
}
else
ASSERT(false, "Invalid mapId %u tile [%u, %u] passed to VMapManager2 after startup in thread unsafe environment",
mapId, tileX, tileY);
mapId, tileX, tileY);
}
if (!instanceTree->second)
@@ -167,7 +177,9 @@ namespace VMAP
{
#if defined(ENABLE_VMAP_CHECKS)
if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
{
return true;
}
#endif
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
@@ -232,7 +244,9 @@ namespace VMAP
Vector3 pos = convertPositionToInternalRep(x, y, z);
float height = instanceTree->second->getHeight(pos, maxSearchDist);
if (!(height < G3D::finf()))
return height = VMAP_INVALID_HEIGHT_VALUE; // No height
{
return height = VMAP_INVALID_HEIGHT_VALUE; // No height
}
return height;
}
@@ -278,9 +292,13 @@ namespace VMAP
ASSERT(floor < std::numeric_limits<float>::max());
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
{
return false;
}
if (info.hitInstance->GetLiquidLevel(pos, info, level))
{
return true;
}
}
}
}

View File

@@ -22,7 +22,7 @@ struct MmapTileHeader
uint32 mmapVersion{MMAP_VERSION};
uint32 size{0};
char usesLiquids{true};
char padding[3]{};
char padding[3] {};
MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) { }
};

View File

@@ -27,7 +27,9 @@ namespace VMAP
{
bool result = prims[entry].intersectRay(ray, distance, StopAtFirstHit);
if (result)
{
hit = true;
}
return result;
}
bool didHit() { return hit; }
@@ -62,7 +64,9 @@ namespace VMAP
LOG_DEBUG("maps", "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
#endif
if (prims[entry].GetLocationInfo(point, locInfo))
{
result = true;
}
}
ModelInstance* prims;
@@ -133,7 +137,9 @@ namespace VMAP
MapRayCallback intersectionCallBack(iTreeValues);
iTree.intersectRay(pRay, intersectionCallBack, distance, StopAtFirstHit);
if (intersectionCallBack.didHit())
{
pMaxDist = distance;
}
return intersectionCallBack.didHit();
}
//=========================================================
@@ -143,17 +149,23 @@ namespace VMAP
float maxDist = (pos2 - pos1).magnitude();
// return false if distance is over max float, in case of cheater teleporting to the end of the universe
if (maxDist == std::numeric_limits<float>::max() || !std::isfinite(maxDist))
{
return false;
}
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
ASSERT(maxDist < std::numeric_limits<float>::max());
// prevent NaN values which can cause BIH intersection to enter infinite loop
if (maxDist < 1e-10f)
{
return true;
}
// direction with length of 1
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1) / maxDist);
if (getIntersectionTime(ray, maxDist, true))
{
return false;
}
return true;
}
@@ -227,12 +239,16 @@ namespace VMAP
{
std::string basePath = vmapPath;
if (basePath.length() > 0 && basePath[basePath.length() - 1] != '/' && basePath[basePath.length() - 1] != '\\')
{
basePath.push_back('/');
}
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
bool success = true;
FILE* rf = fopen(fullname.c_str(), "rb");
if (!rf)
{
return false;
}
// TODO: check magic number when implemented...
char tiled;
char chunk[8];
@@ -246,11 +262,15 @@ namespace VMAP
std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
FILE* tf = fopen(tilefile.c_str(), "rb");
if (!tf)
{
success = false;
}
else
{
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
{
success = false;
}
fclose(tf);
}
}
@@ -267,7 +287,9 @@ namespace VMAP
std::string fullname = iBasePath + fname;
FILE* rf = fopen(fullname.c_str(), "rb");
if (!rf)
{
return false;
}
char chunk[8];
char tiled = '\0';
@@ -317,7 +339,9 @@ namespace VMAP
{
iTreeValues[i->first].setUnloaded();
for (uint32 refCount = 0; refCount < i->second; ++refCount)
{
vm->releaseModelInstance(iTreeValues[i->first].name);
}
}
iLoadedSpawns.clear();
iLoadedTiles.clear();
@@ -348,10 +372,14 @@ namespace VMAP
char chunk[8];
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
{
result = false;
}
uint32 numSpawns = 0;
if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
{
result = false;
}
for (uint32 i = 0; i < numSpawns && result; ++i)
{
// read model spawns
@@ -362,7 +390,9 @@ namespace VMAP
// acquire model instance
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
if (!model)
{
LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
}
// update tree
uint32 referencedVal;
@@ -386,21 +416,29 @@ namespace VMAP
++iLoadedSpawns[referencedVal];
#if defined(VMAP_DEBUG)
if (iTreeValues[referencedVal].ID != spawn.ID)
{
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
}
else if (iTreeValues[referencedVal].name != spawn.name)
{
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
}
#endif
}
}
else
{
result = false;
}
}
}
iLoadedTiles[packTileID(tileX, tileY)] = true;
fclose(tf);
}
else
{
iLoadedTiles[packTileID(tileX, tileY)] = false;
}
return result;
}
@@ -424,10 +462,14 @@ namespace VMAP
bool result = true;
char chunk[8];
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
{
result = false;
}
uint32 numSpawns;
if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
{
result = false;
}
for (uint32 i = 0; i < numSpawns && result; ++i)
{
// read model spawns
@@ -442,11 +484,15 @@ namespace VMAP
uint32 referencedNode;
if (fread(&referencedNode, sizeof(uint32), 1, tf) != 1)
{
result = false;
}
else
{
if (!iLoadedSpawns.count(referencedNode))
{
LOG_ERROR("maps", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
}
else if (--iLoadedSpawns[referencedNode] == 0)
{
iTreeValues[referencedNode].setUnloaded();

View File

@@ -27,7 +27,7 @@ namespace VMAP
{
bool readChunk(FILE* rf, char* dest, const char* compare, uint32 len)
{
if (fread(dest, sizeof(char), len, rf) != len) return false;
if (fread(dest, sizeof(char), len, rf) != len) { return false; }
return memcmp(dest, compare, len) == 0;
}
@@ -56,7 +56,9 @@ namespace VMAP
{
bool success = readMapSpawns();
if (!success)
{
return false;
}
// export Map data
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
@@ -71,7 +73,9 @@ namespace VMAP
if (entry->second.flags & MOD_M2)
{
if (!calculateTransformedBound(entry->second))
{
break;
}
}
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
{
@@ -99,7 +103,9 @@ namespace VMAP
// ===> possibly move this code to StaticMapTree class
std::map<uint32, uint32> modelNodeIdx;
for (uint32 i = 0; i < mapSpawns.size(); ++i)
{
modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
}
// write map tree file
std::stringstream mapfilename;
@@ -113,16 +119,16 @@ namespace VMAP
}
//general info
if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) success = false;
if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) { success = false; }
uint32 globalTileID = StaticMapTree::packTileID(65, 65);
pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO
if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) success = false;
if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) { success = false; }
// Nodes
if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false;
if (success) success = pTree.writeToFile(mapfile);
if (success && fwrite("NODE", 4, 1, mapfile) != 1) { success = false; }
if (success) { success = pTree.writeToFile(mapfile); }
// global map spawns (WDT), if any (most instances)
if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) success = false;
if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) { success = false; }
for (TileMap::iterator glob = globalRange.first; glob != globalRange.second && success; ++glob)
{
@@ -140,7 +146,9 @@ namespace VMAP
{
const ModelSpawn& spawn = map_iter->second->UniqueEntries[tile->second];
if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
{
continue;
}
uint32 nSpawns = tileEntries.count(tile->first);
std::stringstream tilefilename;
tilefilename.fill('0');
@@ -151,19 +159,21 @@ namespace VMAP
if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
{
// file header
if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) success = false;
if (success && fwrite(VMAP_MAGIC, 1, 8, tilefile) != 8) { success = false; }
// write number of tile spawns
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) success = false;
if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) { success = false; }
// write tile spawns
for (uint32 s = 0; s < nSpawns; ++s)
{
if (s)
{
++tile;
}
const ModelSpawn& spawn2 = map_iter->second->UniqueEntries[tile->second];
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
// MapTree nodes to update when loading tile:
std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID);
if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) success = false;
if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) { success = false; }
}
fclose(tilefile);
}
@@ -212,11 +222,15 @@ namespace VMAP
// read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
check = fread(&mapID, sizeof(uint32), 1, dirf);
if (check == 0) // EoF...
{
break;
}
check += fread(&tileX, sizeof(uint32), 1, dirf);
check += fread(&tileY, sizeof(uint32), 1, dirf);
if (!ModelSpawn::readFromFile(dirf, spawn))
{
break;
}
MapSpawns* current;
MapData::iterator map_iter = mapData.find(mapID);
@@ -226,7 +240,9 @@ namespace VMAP
mapData[mapID] = current = new MapSpawns();
}
else
{
current = map_iter->second;
}
current->UniqueEntries.emplace(spawn.ID, spawn);
current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
@@ -249,11 +265,15 @@ namespace VMAP
WorldModel_Raw raw_model;
if (!raw_model.Read(modelFilename.c_str()))
{
return false;
}
uint32 groups = raw_model.groupsArray.size();
if (groups != 1)
{
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
}
AABox modelBound;
bool boundEmpty = true;
@@ -274,9 +294,13 @@ namespace VMAP
Vector3 v = modelPosition.transform(vertices[i]);
if (boundEmpty)
{
modelBound = AABox(v, v), boundEmpty = false;
}
else
{
modelBound.merge(v);
}
}
}
spawn.iBound = modelBound + spawn.iPos;
@@ -300,12 +324,16 @@ namespace VMAP
bool success = true;
std::string filename = iSrcDir;
if (filename.length() > 0)
{
filename.push_back('/');
}
filename.append(pModelFilename);
WorldModel_Raw raw_model;
if (!raw_model.Read(filename.c_str()))
{
return false;
}
// write WorldModel
WorldModel model;
@@ -335,11 +363,15 @@ namespace VMAP
{
FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
if (!model_list)
{
return;
}
char ident[8];
if (fread(ident, 1, 8, model_list) != 8 || memcmp(ident, VMAP::RAW_VMAP_MAGIC, 8) != 0)
{
return;
}
FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
if (!model_list_copy)
@@ -357,12 +389,14 @@ namespace VMAP
{
if (fread(&displayId, sizeof(uint32), 1, model_list) != 1)
if (feof(model_list)) // EOF flag is only set after failed reading attempt
{
break;
}
if (fread(&isWmo, sizeof(uint8), 1, model_list) != 1
|| fread(&name_length, sizeof(uint32), 1, model_list) != 1
|| name_length >= sizeof(buff)
|| fread(&buff, sizeof(char), name_length, model_list) != name_length)
|| fread(&name_length, sizeof(uint32), 1, model_list) != 1
|| name_length >= sizeof(buff)
|| fread(&buff, sizeof(char), name_length, model_list) != name_length)
{
std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
break;
@@ -372,7 +406,9 @@ namespace VMAP
WorldModel_Raw raw_model;
if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
{
continue;
}
spawnedModelFiles.insert(model_name);
AABox bounds;
@@ -386,9 +422,13 @@ namespace VMAP
{
Vector3& v = vertices[i];
if (boundEmpty)
{
bounds = AABox(v, v), boundEmpty = false;
}
else
{
bounds.merge(v);
}
}
}
@@ -454,7 +494,9 @@ namespace VMAP
READ_OR_RETURN_WITH_DELETE(indexarray, nindexes * sizeof(uint16));
triangles.reserve(nindexes / 3);
for (uint32 i = 0; i < nindexes; i += 3)
{
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i + 1], indexarray[i + 2]));
}
delete[] indexarray;
}
@@ -471,7 +513,9 @@ namespace VMAP
float* vectorarray = new float[nvectors * 3];
READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors * sizeof(float) * 3);
for (uint32 i = 0; i < nvectors; ++i)
{
vertexArray.push_back( Vector3(vectorarray + 3 * i) );
}
delete[] vectorarray;
}
@@ -526,10 +570,14 @@ namespace VMAP
groupsArray.resize(groups);
bool succeed = true;
for (uint32 g = 0; g < groups && succeed; ++g)
{
succeed = groupsArray[g].Read(rf);
}
if (succeed) /// rf will be freed inside Read if the function had any errors.
{
fclose(rf);
}
return succeed;
}

View File

@@ -80,23 +80,23 @@ namespace VMAP
class TileAssembler
{
private:
std::string iDestDir;
std::string iSrcDir;
G3D::Table<std::string, unsigned int > iUniqueNameIds;
MapData mapData;
std::set<std::string> spawnedModelFiles;
private:
std::string iDestDir;
std::string iSrcDir;
G3D::Table<std::string, unsigned int > iUniqueNameIds;
MapData mapData;
std::set<std::string> spawnedModelFiles;
public:
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
virtual ~TileAssembler();
public:
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
virtual ~TileAssembler();
bool convertWorld2();
bool readMapSpawns();
bool calculateTransformedBound(ModelSpawn &spawn);
void exportGameobjectModels();
bool convertWorld2();
bool readMapSpawns();
bool calculateTransformedBound(ModelSpawn& spawn);
void exportGameobjectModels();
bool convertRawFile(const std::string& pModelFilename);
bool convertRawFile(const std::string& pModelFilename);
};
} // VMAP

View File

@@ -55,14 +55,16 @@ void LoadGameObjectModelList(std::string const& dataPath)
Vector3 v1, v2;
if (fread(&displayId, sizeof(uint32), 1, model_list_file) != 1)
if (feof(model_list_file)) // EOF flag is only set after failed reading attempt
{
break;
}
if (fread(&isWmo, sizeof(uint8), 1, model_list_file) != 1
|| fread(&name_length, sizeof(uint32), 1, model_list_file) != 1
|| name_length >= sizeof(buff)
|| fread(&buff, sizeof(char), name_length, model_list_file) != name_length
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|| fread(&v2, sizeof(Vector3), 1, model_list_file) != 1)
|| fread(&name_length, sizeof(uint32), 1, model_list_file) != 1
|| name_length >= sizeof(buff)
|| fread(&buff, sizeof(char), name_length, model_list_file) != name_length
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|| fread(&v2, sizeof(Vector3), 1, model_list_file) != 1)
{
LOG_ERROR("maps", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
fclose(model_list_file);
@@ -72,7 +74,7 @@ void LoadGameObjectModelList(std::string const& dataPath)
if (v1.isNaN() || v2.isNaN())
{
LOG_ERROR("maps", "File '%s' Model '%s' has invalid v1%s v2%s values!",
VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str());
VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str());
continue;
}
@@ -88,14 +90,18 @@ void LoadGameObjectModelList(std::string const& dataPath)
GameObjectModel::~GameObjectModel()
{
if (iModel)
{
VMAP::VMapFactory::createOrGetVMapManager()->releaseModelInstance(name);
}
}
bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath)
{
ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId());
if (it == model_list.end())
{
return false;
}
G3D::AABox mdl_box(it->second.bound);
// ignore models with no bounds
@@ -108,7 +114,9 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> model
iModel = VMAP::VMapFactory::createOrGetVMapManager()->acquireModelInstance(dataPath + "vmaps/", it->second.name);
if (!iModel)
{
return false;
}
name = it->second.name;
iPos = modelOwner->GetPosition();
@@ -122,7 +130,9 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> model
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
AABox rotated_bounds;
for (int i = 0; i < 8; ++i)
{
rotated_bounds.merge(iRotation * mdl_box.corner(i));
}
iBound = rotated_bounds + iPos;
@@ -154,11 +164,15 @@ GameObjectModel* GameObjectModel::Create(std::unique_ptr<GameObjectModelOwnerBas
bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const
{
if (!(phasemask & ph_mask) || !owner->IsSpawned())
{
return false;
}
float time = ray.intersectionTime(iBound);
if (time == G3D::inf())
{
return false;
}
// child bounds are defined in object space:
Vector3 p = iInvRot * (ray.origin() - iPos) * iInvScale;
@@ -176,11 +190,15 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto
bool GameObjectModel::UpdatePosition()
{
if (!iModel)
{
return false;
}
ModelList::const_iterator it = model_list.find(owner->GetDisplayId());
if (it == model_list.end())
{
return false;
}
G3D::AABox mdl_box(it->second.bound);
@@ -200,7 +218,9 @@ bool GameObjectModel::UpdatePosition()
AABox rotated_bounds;
for (int i = 0; i < 8; ++i)
{
rotated_bounds.merge(iRotation * mdl_box.corner(i));
}
iBound = rotated_bounds + iPos;
#ifdef SPAWN_CORNERS

View File

@@ -65,9 +65,13 @@ namespace VMAP
// M2 files don't contain area info, only WMO files
if (flags & MOD_M2)
{
return;
}
if (!iBound.contains(p))
{
return;
}
// child bounds are defined in object space:
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
@@ -99,9 +103,13 @@ namespace VMAP
// M2 files don't contain area info, only WMO files
if (flags & MOD_M2)
{
return false;
}
if (!iBound.contains(p))
{
return false;
}
// child bounds are defined in object space:
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
@@ -147,7 +155,9 @@ namespace VMAP
if (!check)
{
if (ferror(rf))
{
std::cout << "Error reading ModelSpawn!\n";
}
return false;
}
check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
@@ -202,9 +212,9 @@ namespace VMAP
}
uint32 nameLen = spawn.name.length();
check += fwrite(&nameLen, sizeof(uint32), 1, wf);
if (check != uint32(has_bound ? 17 : 11)) return false;
if (check != uint32(has_bound ? 17 : 11)) { return false; }
check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
if (check != nameLen) return false;
if (check != nameLen) { return false; }
return true;
}

View File

@@ -113,7 +113,9 @@ namespace VMAP
WmoLiquid& WmoLiquid::operator=(const WmoLiquid& other)
{
if (this == &other)
{
return *this;
}
iTilesX = other.iTilesX;
iTilesY = other.iTilesY;
iCorner = other.iCorner;
@@ -126,14 +128,18 @@ namespace VMAP
memcpy(iHeight, other.iHeight, (iTilesX + 1) * (iTilesY + 1)*sizeof(float));
}
else
{
iHeight = 0;
}
if (other.iFlags)
{
iFlags = new uint8[iTilesX * iTilesY];
memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
}
else
{
iFlags = 0;
}
return *this;
}
@@ -142,16 +148,22 @@ namespace VMAP
float tx_f = (pos.x - iCorner.x) / LIQUID_TILE_SIZE;
uint32 tx = uint32(tx_f);
if (tx_f < 0.0f || tx >= iTilesX)
{
return false;
}
float ty_f = (pos.y - iCorner.y) / LIQUID_TILE_SIZE;
uint32 ty = uint32(ty_f);
if (ty_f < 0.0f || ty >= iTilesY)
{
return false;
}
// check if tile shall be used for liquid level
// checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
if ((iFlags[tx + ty * iTilesX] & 0x0F) == 0x0F)
{
return false;
}
// (dx, dy) coordinates inside tile, in [0, 1]^2
float dx = tx_f - (float)tx;
@@ -234,9 +246,13 @@ namespace VMAP
}
if (!result)
{
delete liquid;
}
else
{
out = liquid;
}
return result;
}
@@ -255,7 +271,9 @@ namespace VMAP
vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0)
{
if (other.iLiquid)
{
iLiquid = new WmoLiquid(*other.iLiquid);
}
}
void GroupModel::setMeshData(std::vector<Vector3>& vert, std::vector<MeshTriangle>& tri)
@@ -271,43 +289,45 @@ namespace VMAP
bool result = true;
uint32 chunkSize, count;
if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) result = false;
if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) { result = false; }
if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) { result = false; }
// write vertices
if (result && fwrite("VERT", 1, 4, wf) != 4) result = false;
if (result && fwrite("VERT", 1, 4, wf) != 4) { result = false; }
count = vertices.size();
chunkSize = sizeof(uint32) + sizeof(Vector3) * count;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) { result = false; }
if (!count) // models without (collision) geometry end here, unsure if they are useful
{
return result;
if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) result = false;
}
if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) { result = false; }
// write triangle mesh
if (result && fwrite("TRIM", 1, 4, wf) != 4) result = false;
if (result && fwrite("TRIM", 1, 4, wf) != 4) { result = false; }
count = triangles.size();
chunkSize = sizeof(uint32) + sizeof(MeshTriangle) * count;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) result = false;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) { result = false; }
// write mesh BIH
if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false;
if (result) result = meshTree.writeToFile(wf);
if (result && fwrite("MBIH", 1, 4, wf) != 4) { result = false; }
if (result) { result = meshTree.writeToFile(wf); }
// write liquid data
if (result && fwrite("LIQU", 1, 4, wf) != 4) result = false;
if (result && fwrite("LIQU", 1, 4, wf) != 4) { result = false; }
if (!iLiquid)
{
chunkSize = 0;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
return result;
}
chunkSize = iLiquid->GetFileSize();
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result) result = iLiquid->writeToFile(wf);
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result) { result = iLiquid->writeToFile(wf); }
return result;
}
@@ -323,35 +343,39 @@ namespace VMAP
delete iLiquid;
iLiquid = nullptr;
if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) result = false;
if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) { result = false; }
if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) { result = false; }
// read vertices
if (result && !readChunk(rf, chunk, "VERT", 4)) result = false;
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
if (result && !readChunk(rf, chunk, "VERT", 4)) { result = false; }
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) { result = false; }
if (!count) // models without (collision) geometry end here, unsure if they are useful
{
return result;
if (result) vertices.resize(count);
if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) result = false;
}
if (result) { vertices.resize(count); }
if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) { result = false; }
// read triangle mesh
if (result && !readChunk(rf, chunk, "TRIM", 4)) result = false;
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
if (result) triangles.resize(count);
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false;
if (result && !readChunk(rf, chunk, "TRIM", 4)) { result = false; }
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result) { triangles.resize(count); }
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) { result = false; }
// read mesh BIH
if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false;
if (result) result = meshTree.readFromFile(rf);
if (result && !readChunk(rf, chunk, "MBIH", 4)) { result = false; }
if (result) { result = meshTree.readFromFile(rf); }
// write liquid data
if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false;
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
if (result && !readChunk(rf, chunk, "LIQU", 4)) { result = false; }
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result && chunkSize > 0)
{
result = WmoLiquid::readFromFile(rf, iLiquid);
}
return result;
}
@@ -362,7 +386,7 @@ namespace VMAP
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool /*StopAtFirstHit*/)
{
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
if (result) hit = true;
if (result) { hit = true; }
return hit;
}
std::vector<Vector3>::const_iterator vertices;
@@ -373,7 +397,9 @@ namespace VMAP
bool GroupModel::IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const
{
if (triangles.empty())
{
return false;
}
GModelRayCallback callback(triangles, vertices);
meshTree.intersectRay(ray, callback, distance, stopAtFirstHit);
@@ -383,28 +409,36 @@ namespace VMAP
bool GroupModel::IsInsideObject(const Vector3& pos, const Vector3& down, float& z_dist) const
{
if (triangles.empty() || !iBound.contains(pos))
{
return false;
}
GModelRayCallback callback(triangles, vertices);
Vector3 rPos = pos - 0.1f * down;
float dist = G3D::inf();
G3D::Ray ray(rPos, down);
bool hit = IntersectRay(ray, dist, false);
if (hit)
{
z_dist = dist - 0.1f;
}
return hit;
}
bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const
{
if (iLiquid)
{
return iLiquid->GetLiquidHeight(pos, liqHeight);
}
return false;
}
uint32 GroupModel::GetLiquidType() const
{
if (iLiquid)
{
return iLiquid->GetType();
}
return 0;
}
@@ -429,7 +463,7 @@ namespace VMAP
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool StopAtFirstHit)
{
bool result = models[entry].IntersectRay(ray, distance, StopAtFirstHit);
if (result) hit = true;
if (result) { hit = true; }
return hit;
}
std::vector<GroupModel>::const_iterator models;
@@ -441,7 +475,9 @@ namespace VMAP
// small M2 workaround, maybe better make separate class with virtual intersection funcs
// in any case, there's no need to use a bound tree if we only have one submodel
if (groupModels.size() == 1)
{
return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
}
WModelRayCallBack isc(groupModels);
groupTree.intersectRay(ray, isc, distance, stopAtFirstHit);
@@ -489,7 +525,9 @@ namespace VMAP
bool WorldModel::IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const
{
if (groupModels.empty())
{
return false;
}
WModelAreaCallback callback(groupModels, down);
groupTree.intersectPoint(p, callback);
@@ -508,7 +546,9 @@ namespace VMAP
bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const
{
if (groupModels.empty())
{
return false;
}
WModelAreaCallback callback(groupModels, down);
groupTree.intersectPoint(p, callback);
@@ -525,29 +565,33 @@ namespace VMAP
{
FILE* wf = fopen(filename.c_str(), "wb");
if (!wf)
{
return false;
}
uint32 chunkSize, count;
bool result = fwrite(VMAP_MAGIC, 1, 8, wf) == 8;
if (result && fwrite("WMOD", 1, 4, wf) != 4) result = false;
if (result && fwrite("WMOD", 1, 4, wf) != 4) { result = false; }
chunkSize = sizeof(uint32) + sizeof(uint32);
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) { result = false; }
// write group models
count = groupModels.size();
if (count)
{
if (result && fwrite("GMOD", 1, 4, wf) != 4) result = false;
if (result && fwrite("GMOD", 1, 4, wf) != 4) { result = false; }
//chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count;
//if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false;
if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) { result = false; }
for (uint32 i = 0; i < groupModels.size() && result; ++i)
{
result = groupModels[i].writeToFile(wf);
}
// write group BIH
if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false;
if (result) result = groupTree.writeToFile(wf);
if (result && fwrite("GBIH", 1, 4, wf) != 4) { result = false; }
if (result) { result = groupTree.writeToFile(wf); }
}
fclose(wf);
@@ -558,32 +602,36 @@ namespace VMAP
{
FILE* rf = fopen(filename.c_str(), "rb");
if (!rf)
{
return false;
}
bool result = true;
uint32 chunkSize = 0;
uint32 count = 0;
char chunk[8]; // Ignore the added magic header
if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) result = false;
if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) { result = false; }
if (result && !readChunk(rf, chunk, "WMOD", 4)) result = false;
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) result = false;
if (result && !readChunk(rf, chunk, "WMOD", 4)) { result = false; }
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) { result = false; }
// read group models
if (result && readChunk(rf, chunk, "GMOD", 4))
{
//if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false;
if (result) groupModels.resize(count);
if (result && fread(&count, sizeof(uint32), 1, rf) != 1) { result = false; }
if (result) { groupModels.resize(count); }
//if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
for (uint32 i = 0; i < count && result; ++i)
{
result = groupModels[i].readFromFile(rf);
}
// read group BIH
if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false;
if (result) result = groupTree.readFromFile(rf);
if (result && !readChunk(rf, chunk, "GBIH", 4)) { result = false; }
if (result) { result = groupTree.readFromFile(rf); }
}
fclose(rf);

View File

@@ -22,7 +22,9 @@ public:
return;
}
else if (_nodes[i] == n)
{
return;
}
}
Node* _nodes[9];
};
@@ -64,7 +66,9 @@ public:
{
for (int x = 0; x < CELL_NUMBER; ++x)
for (int y = 0; y < CELL_NUMBER; ++y)
{
delete nodes[x][y];
}
}
void insert(const T& value)
@@ -85,7 +89,9 @@ public:
{
Cell c = Cell::ComputeCell(pos[i].x, pos[i].y);
if (!c.isValid())
{
continue;
}
Node& node = getGridFor(pos[i].x, pos[i].y);
na.AddNode(&node);
}
@@ -93,9 +99,13 @@ public:
for (uint8 i = 0; i < 9; ++i)
{
if (na._nodes[i])
{
na._nodes[i]->insert(value);
}
else
{
break;
}
}
memberTable.set(&value, na);
@@ -107,9 +117,13 @@ public:
for (uint8 i = 0; i < 9; ++i)
{
if (na._nodes[i])
{
na._nodes[i]->remove(value);
}
else
{
break;
}
}
// Remove the member
@@ -121,7 +135,9 @@ public:
for (int x = 0; x < CELL_NUMBER; ++x)
for (int y = 0; y < CELL_NUMBER; ++y)
if (Node* n = nodes[x][y])
{
n->balance();
}
}
bool contains(const T& value) const { return memberTable.containsKey(&value); }
@@ -151,7 +167,9 @@ public:
{
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
if (!nodes[x][y])
{
nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
}
return *nodes[x][y];
}
@@ -166,14 +184,18 @@ public:
{
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
if (!cell.isValid())
{
return;
}
Cell last_cell = Cell::ComputeCell(end.x, end.y);
if (cell == last_cell)
{
if (Node* node = nodes[cell.x][cell.y])
{
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
}
return;
}
@@ -222,7 +244,9 @@ public:
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
}
if (cell == last_cell)
{
break;
}
if (tMaxX < tMaxY)
{
tMaxX += tDeltaX;
@@ -242,9 +266,13 @@ public:
{
Cell cell = Cell::ComputeCell(point.x, point.y);
if (!cell.isValid())
{
return;
}
if (Node* node = nodes[cell.x][cell.y])
{
node->intersectPoint(point, intersectCallback);
}
}
// Optimized verson of intersectRay function for rays with vertical directions
@@ -253,9 +281,13 @@ public:
{
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
if (!cell.isValid())
{
return;
}
if (Node* node = nodes[cell.x][cell.y])
{
node->intersectRay(ray, intersectCallback, max_dist, false);
}
}
};

View File

@@ -23,7 +23,9 @@ LocaleConstant GetLocaleByName(const std::string& name)
{
for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
if (name == localeNames[i])
{
return LocaleConstant(i);
}
return LOCALE_enUS; // including enGB case
}
@@ -31,7 +33,7 @@ LocaleConstant GetLocaleByName(const std::string& name)
void CleanStringForMysqlQuery(std::string& str)
{
std::string::size_type n = 0;
while ((n = str.find('\\')) != str.npos) str.erase(n, 1);
while ((n = str.find('"')) != str.npos) str.erase(n, 1);
while ((n = str.find('\'')) != str.npos) str.erase(n, 1);
while ((n = str.find('\\')) != str.npos) { str.erase(n, 1); }
while ((n = str.find('"')) != str.npos) { str.erase(n, 1); }
while ((n = str.find('\'')) != str.npos) { str.erase(n, 1); }
}

View File

@@ -153,7 +153,9 @@ namespace
// No lines read
if (!count)
{
throw ConfigException(Acore::StringFormat("Config::LoadFile: Empty file '%s'", file.c_str()));
}
// Add correct keys if file load without errors
for (auto const& [entry, key] : fileConfigs)
@@ -200,7 +202,9 @@ ConfigMgr* ConfigMgr::instance()
bool ConfigMgr::Reload()
{
if (!LoadAppConfigs())
{
return false;
}
return LoadModulesConfigs();
}
@@ -287,7 +291,9 @@ std::vector<std::string> ConfigMgr::GetKeysByString(std::string const& name)
for (auto const& [optionName, key] : _configOptions)
if (!optionName.compare(0, name.length(), name))
{
keys.emplace_back(optionName);
}
return keys;
}
@@ -324,7 +330,9 @@ void ConfigMgr::Configure(std::string const& initFileName, std::vector<std::stri
{
Tokenizer configFileList(modulesConfigList, ',');
for (auto const& itr : configFileList)
{
_additonalFiles.emplace_back(std::string(itr));
}
}
}
@@ -332,11 +340,15 @@ bool ConfigMgr::LoadAppConfigs()
{
// #1 - Load init config file .conf.dist
if (!LoadInitial(_filename + ".dist"))
{
return false;
}
// #2 - Load .conf file
if (!LoadAdditionalFile(_filename))
{
return false;
}
return true;
}
@@ -344,7 +356,9 @@ bool ConfigMgr::LoadAppConfigs()
bool ConfigMgr::LoadModulesConfigs()
{
if (_additonalFiles.empty())
{
return true;
}
// Start loading module configs
std::string const& moduleConfigPath = GetConfigPath() + "modules/";
@@ -356,20 +370,30 @@ bool ConfigMgr::LoadModulesConfigs()
std::string defaultFileName = distFileName;
if (!defaultFileName.empty())
{
defaultFileName.erase(defaultFileName.end() - 5, defaultFileName.end());
}
// Load .conf.dist config
if (!LoadAdditionalFile(moduleConfigPath + distFileName))
{
isExistDistConfig = false;
}
// Load .conf config
if (!LoadAdditionalFile(moduleConfigPath + defaultFileName))
{
isExistDefaultConfig = false;
}
if (isExistDefaultConfig && isExistDistConfig)
{
_moduleConfigFiles.emplace_back(defaultFileName);
}
else if (!isExistDefaultConfig && isExistDistConfig)
{
_moduleConfigFiles.emplace_back(distFileName);
}
}
// If module configs not exist - no load
@@ -383,7 +407,9 @@ void ConfigMgr::PrintLoadedModulesConfigs()
LOG_INFO("server.loading", "Using modules configuration:");
for (auto const& itr : _moduleConfigFiles)
{
LOG_INFO("server.loading", "> %s", itr.c_str());
}
LOG_INFO("server.loading", " ");
}

View File

@@ -30,24 +30,34 @@ bool Acore::Crypto::AES::Process(IV const& iv, uint8* data, size_t length, Tag&
ASSERT(length <= static_cast<size_t>(std::numeric_limits<int>::max()));
int len = static_cast<int>(length);
if (!EVP_CipherInit_ex(_ctx, nullptr, nullptr, nullptr, iv.data(), -1))
{
return false;
}
int outLen;
if (!EVP_CipherUpdate(_ctx, data, &outLen, data, len))
{
return false;
}
len -= outLen;
if (!_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_TAG, sizeof(tag), tag))
{
return false;
}
if (!EVP_CipherFinal_ex(_ctx, data + outLen, &outLen))
{
return false;
}
ASSERT(len == outLen);
if (_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_GET_TAG, sizeof(tag), tag))
{
return false;
}
return true;
}

View File

@@ -20,7 +20,9 @@
);
if (status == ARGON2_OK)
{
return std::string(buf);
}
return {};
}

View File

@@ -30,7 +30,7 @@ void AuthCrypt::Init(SessionKey const& K)
void AuthCrypt::DecryptRecv(uint8* data, size_t len)
{
ASSERT(_initialized);
ASSERT(_initialized);
_clientDecrypt.UpdateData(data, len);
}

View File

@@ -48,13 +48,13 @@ using SRP6 = Acore::Crypto::SRP6;
// find position of first nonzero byte
size_t p = 0;
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) ++p;
if (p & 1) ++p; // skip one extra byte if p is odd
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) { ++p; }
if (p & 1) { ++p; } // skip one extra byte if p is odd
p /= 2; // offset into buffers
// hash each of the halves, starting at the first nonzero byte
SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH / 2 - p);
SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH / 2 - p);
// stick the two hashes back together
SessionKey K;
@@ -76,7 +76,9 @@ std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, S
BigNumber const _A(A);
if ((_A % _N).IsZero())
{
return std::nullopt;
}
BigNumber const u(SHA1::GetDigestOf(A, B));
EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
@@ -91,7 +93,11 @@ std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, S
SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
if (ourM == clientM)
{
return K;
}
else
{
return std::nullopt;
}
}

View File

@@ -18,53 +18,53 @@ namespace Acore::Crypto
{
class SRP6
{
public:
static constexpr size_t SALT_LENGTH = 32;
using Salt = std::array<uint8, SALT_LENGTH>;
static constexpr size_t VERIFIER_LENGTH = 32;
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
public:
static constexpr size_t SALT_LENGTH = 32;
using Salt = std::array<uint8, SALT_LENGTH>;
static constexpr size_t VERIFIER_LENGTH = 32;
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
static std::array<uint8, 1> const g;
static std::array<uint8, 32> const N;
static std::array<uint8, 1> const g;
static std::array<uint8, 32> const N;
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static bool CheckLogin(std::string const& username, std::string const& password, Salt const& salt, Verifier const& verifier)
{
return (verifier == CalculateVerifier(username, password, salt));
}
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static bool CheckLogin(std::string const& username, std::string const& password, Salt const& salt, Verifier const& verifier)
{
return (verifier == CalculateVerifier(username, password, salt));
}
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
{
return SHA1::GetDigestOf(A, clientM, K);
}
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
{
return SHA1::GetDigestOf(A, clientM, K);
}
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
private:
bool _used = false; // a single instance can only be used to verify once
private:
bool _used = false; // a single instance can only be used to verify once
static Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt);
static SessionKey SHA1Interleave(EphemeralKey const& S);
static Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt);
static SessionKey SHA1Interleave(EphemeralKey const& S);
/* global algorithm parameters */
static BigNumber const _g; // a [g]enerator for the ring of integers mod N, algorithm parameter
static BigNumber const _N; // the modulus, an algorithm parameter; all operations are mod this
/* global algorithm parameters */
static BigNumber const _g; // a [g]enerator for the ring of integers mod N, algorithm parameter
static BigNumber const _N; // the modulus, an algorithm parameter; all operations are mod this
static EphemeralKey _B(BigNumber const& b, BigNumber const& v) { return ((_g.ModExp(b,_N) + (v * 3)) % N).ToByteArray<EPHEMERAL_KEY_LENGTH>(); }
static EphemeralKey _B(BigNumber const& b, BigNumber const& v) { return ((_g.ModExp(b, _N) + (v * 3)) % N).ToByteArray<EPHEMERAL_KEY_LENGTH>(); }
/* per-instantiation parameters, set on construction */
SHA1::Digest const _I; // H(I) - the username, all uppercase
BigNumber const _b; // b - randomly chosen by the server, 19 bytes, never given out
BigNumber const _v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
/* per-instantiation parameters, set on construction */
SHA1::Digest const _I; // H(I) - the username, all uppercase
BigNumber const _b; // b - randomly chosen by the server, 19 bytes, never given out
BigNumber const _v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
public:
Salt const s; // s - the user's password salt, random, used to calculate v on registration
EphemeralKey const B; // B = 3v + g^b
public:
Salt const s; // s - the user's password salt, random, used to calculate v on registration
EphemeralKey const B; // B = 3v + g^b
};
}

View File

@@ -27,7 +27,9 @@ void BigNumber::SetDword(int32 val)
{
SetDword(uint32(abs(val)));
if (val < 0)
{
BN_set_negative(_bn, 1);
}
}
void BigNumber::SetDword(uint32 val)
@@ -50,7 +52,9 @@ void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
uint8* array = new uint8[len];
for (int i = 0; i < len; i++)
{
array[i] = bytes[len - 1 - i];
}
BN_bin2bn(array, len, _bn);
@@ -60,7 +64,9 @@ void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
#endif
}
else
{
BN_bin2bn(bytes, len, _bn);
}
}
bool BigNumber::SetHexStr(char const* str)
@@ -77,7 +83,9 @@ void BigNumber::SetRand(int32 numbits)
BigNumber& BigNumber::operator=(BigNumber const& bn)
{
if (this == &bn)
{
return *this;
}
BN_copy(_bn, bn._bn);
return *this;
@@ -195,13 +203,17 @@ void BigNumber::GetBytes(uint8* buf, size_t bufsize, bool littleEndian) const
// If we need more bytes than length of BigNumber set the rest to 0
if (numBytes < bufsize)
{
memset((void*)buf, 0, bufsize);
}
BN_bn2bin(_bn, buf + (bufsize - numBytes));
// openssl's BN stores data internally in big endian format, reverse if little endian desired
if (littleEndian)
{
std::reverse(buf, buf + bufsize);
}
#else
int res = littleEndian ? BN_bn2lebinpad(_bn, buf, bufsize) : BN_bn2binpad(_bn, buf, bufsize);
ASSERT(res > 0, "Buffer of size %zu is too small to hold bignum with %d bytes.\n", bufsize, BN_num_bytes(_bn));

View File

@@ -34,67 +34,69 @@ namespace Acore::Impl
template <GenericHashImpl::HashCreator HashCreator, size_t DigestLength>
class GenericHash
{
public:
static constexpr size_t DIGEST_LENGTH = DigestLength;
using Digest = std::array<uint8, DIGEST_LENGTH>;
public:
static constexpr size_t DIGEST_LENGTH = DigestLength;
using Digest = std::array<uint8, DIGEST_LENGTH>;
static Digest GetDigestOf(uint8 const* data, size_t len)
static Digest GetDigestOf(uint8 const* data, size_t len)
{
GenericHash hash;
hash.UpdateData(data, len);
hash.Finalize();
return hash.GetDigest();
}
template <typename... Ts>
static auto GetDigestOf(Ts&& ... pack) -> std::enable_if_t < !(std::is_integral_v<std::decay_t<Ts>> || ...), Digest >
{
GenericHash hash;
(hash.UpdateData(std::forward<Ts>(pack)), ...);
hash.Finalize();
return hash.GetDigest();
}
GenericHash() : _ctx(GenericHashImpl::MakeCTX())
{
int result = EVP_DigestInit_ex(_ctx, HashCreator(), nullptr);
ASSERT(result == 1);
}
~GenericHash()
{
if (!_ctx)
{
GenericHash hash;
hash.UpdateData(data, len);
hash.Finalize();
return hash.GetDigest();
return;
}
GenericHashImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
template <typename... Ts>
static auto GetDigestOf(Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
{
GenericHash hash;
(hash.UpdateData(std::forward<Ts>(pack)), ...);
hash.Finalize();
return hash.GetDigest();
}
void UpdateData(uint8 const* data, size_t len)
{
int result = EVP_DigestUpdate(_ctx, data, len);
ASSERT(result == 1);
}
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
template <typename Container>
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
GenericHash() : _ctx(GenericHashImpl::MakeCTX())
{
int result = EVP_DigestInit_ex(_ctx, HashCreator(), nullptr);
ASSERT(result == 1);
}
void Finalize()
{
uint32 length;
int result = EVP_DigestFinal_ex(_ctx, _digest.data(), &length);
ASSERT(result == 1);
ASSERT(length == DIGEST_LENGTH);
GenericHashImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
~GenericHash()
{
if (!_ctx)
return;
GenericHashImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
Digest const& GetDigest() const { return _digest; }
void UpdateData(uint8 const* data, size_t len)
{
int result = EVP_DigestUpdate(_ctx, data, len);
ASSERT(result == 1);
}
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
template <typename Container>
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
void Finalize()
{
uint32 length;
int result = EVP_DigestFinal_ex(_ctx, _digest.data(), &length);
ASSERT(result == 1);
ASSERT(length == DIGEST_LENGTH);
GenericHashImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
Digest const& GetDigest() const { return _digest; }
private:
EVP_MD_CTX* _ctx;
Digest _digest = { };
private:
EVP_MD_CTX* _ctx;
Digest _digest = { };
};
}

View File

@@ -44,69 +44,70 @@ namespace Acore::Impl
template <HMACImpl::HashCreator HashCreator, size_t DigestLength>
class GenericHMAC
{
public:
static constexpr size_t DIGEST_LENGTH = DigestLength;
using Digest = std::array<uint8, DIGEST_LENGTH>;
public:
static constexpr size_t DIGEST_LENGTH = DigestLength;
using Digest = std::array<uint8, DIGEST_LENGTH>;
template <typename Container>
static Digest GetDigestOf(Container const& seed, uint8 const* data, size_t len)
template <typename Container>
static Digest GetDigestOf(Container const& seed, uint8 const* data, size_t len)
{
GenericHMAC hash(seed);
hash.UpdateData(data, len);
hash.Finalize();
return hash.GetDigest();
}
template <typename Container, typename... Ts>
static auto GetDigestOf(Container const& seed, Ts&& ... pack) -> std::enable_if_t < !(std::is_integral_v<std::decay_t<Ts>> || ...), Digest >
{
GenericHMAC hash(seed);
(hash.UpdateData(std::forward<Ts>(pack)), ...);
hash.Finalize();
return hash.GetDigest();
}
GenericHMAC(uint8 const* seed, size_t len) : _ctx(HMACImpl::MakeCTX())
{
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
ASSERT(result == 1);
}
template <typename Container> GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
~GenericHMAC()
{
if (!_ctx)
{
GenericHMAC hash(seed);
hash.UpdateData(data, len);
hash.Finalize();
return hash.GetDigest();
return;
}
HMACImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
template <typename Container, typename... Ts>
static auto GetDigestOf(Container const& seed, Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
{
GenericHMAC hash(seed);
(hash.UpdateData(std::forward<Ts>(pack)), ...);
hash.Finalize();
return hash.GetDigest();
}
void UpdateData(uint8 const* data, size_t len)
{
int result = HMAC_Update(_ctx, data, len);
ASSERT(result == 1);
}
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
template <typename Container>
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
GenericHMAC(uint8 const* seed, size_t len) : _ctx(HMACImpl::MakeCTX())
{
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
ASSERT(result == 1);
}
template <typename Container>
GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
void Finalize()
{
uint32 length = 0;
int result = HMAC_Final(_ctx, _digest.data(), &length);
ASSERT(result == 1);
ASSERT(length == DIGEST_LENGTH);
HMACImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
~GenericHMAC()
{
if (!_ctx)
return;
HMACImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
void UpdateData(uint8 const* data, size_t len)
{
int result = HMAC_Update(_ctx, data, len);
ASSERT(result == 1);
}
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
template <typename Container>
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
void Finalize()
{
uint32 length = 0;
int result = HMAC_Final(_ctx, _digest.data(), &length);
ASSERT(result == 1);
ASSERT(length == DIGEST_LENGTH);
HMACImpl::DestroyCTX(_ctx);
_ctx = nullptr;
}
Digest const& GetDigest() const { return _digest; }
private:
HMAC_CTX* _ctx;
Digest _digest = { };
Digest const& GetDigest() const { return _digest; }
private:
HMAC_CTX* _ctx;
Digest _digest = { };
};
}

View File

@@ -15,9 +15,13 @@ std::vector<std::mutex*> cryptoLocks;
static void lockingCallback(int mode, int type, char const* /*file*/, int /*line*/)
{
if (mode & CRYPTO_LOCK)
{
cryptoLocks[type]->lock();
}
else
{
cryptoLocks[type]->unlock();
}
}
static void threadIdCallback(CRYPTO_THREADID* id)
{

View File

@@ -12,39 +12,38 @@
template <typename Hash>
class SessionKeyGenerator
{
public:
template <typename C>
SessionKeyGenerator(C const& buf) :
o0it(o0.begin())
{
uint8 const* data = std::data(buf);
size_t const len = std::size(buf);
size_t const halflen = (len / 2);
public:
template <typename C> SessionKeyGenerator(C const& buf) :
o0it(o0.begin())
{
uint8 const* data = std::data(buf);
size_t const len = std::size(buf);
size_t const halflen = (len / 2);
o1 = Hash::GetDigestOf(data, halflen);
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
o0 = Hash::GetDigestOf(o1, o0, o2);
}
o1 = Hash::GetDigestOf(data, halflen);
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
o0 = Hash::GetDigestOf(o1, o0, o2);
}
void Generate(uint8* buf, uint32 sz)
void Generate(uint8* buf, uint32 sz)
{
for (uint32 i = 0; i < sz; ++i)
{
for (uint32 i = 0; i < sz; ++i)
if (o0it == o0.end())
{
if (o0it == o0.end())
{
o0 = Hash::GetDigestOf(o1, o0, o2);
o0it = o0.begin();
}
buf[i] = *(o0it++);
o0 = Hash::GetDigestOf(o1, o0, o2);
o0it = o0.begin();
}
}
private:
typename Hash::Digest o0 = { };
typename Hash::Digest o1 = { };
typename Hash::Digest o2 = { };
typename Hash::Digest::const_iterator o0it;
};
buf[i] = *(o0it++);
}
}
private:
typename Hash::Digest o0 = { };
typename Hash::Digest o1 = { };
typename Hash::Digest o2 = { };
typename Hash::Digest::const_iterator o0it;
};
#endif

View File

@@ -18,7 +18,9 @@ static constexpr uint32 HMAC_RESULT_SIZE = 20;
unsigned char challenge[8];
for (int i = 8; i--; timestamp >>= 8)
{
challenge[i] = timestamp;
}
unsigned char digest[HMAC_RESULT_SIZE];
uint32 digestSize = HMAC_RESULT_SIZE;

View File

@@ -23,7 +23,9 @@ bool DBCFileLoader::Load(char const* filename, char const* fmt)
FILE* f = fopen(filename, "rb");
if (!f)
{
return false;
}
if (fread(&header, 4, 1, f) != 1) // Number of records
{
@@ -78,9 +80,13 @@ bool DBCFileLoader::Load(char const* filename, char const* fmt)
{
fieldsOffset[i] = fieldsOffset[i - 1];
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
{
fieldsOffset[i] += sizeof(uint8);
}
else // 4 byte fields (int32/float/strings)
{
fieldsOffset[i] += sizeof(uint32);
}
}
data = new unsigned char[recordSize * recordCount + stringSize];
@@ -151,7 +157,9 @@ uint32 DBCFileLoader::GetFormatRecordSize(char const* format, int32* index_pos)
}
if (index_pos)
{
*index_pos = i;
}
return recordsize;
}
@@ -171,7 +179,9 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
typedef char* ptr;
if (strlen(format) != fieldCount)
{
return nullptr;
}
//get struct size and index pos
int32 i;
@@ -185,7 +195,9 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
{
uint32 ind = getRecord(y).getUInt(i);
if (ind > maxi)
{
maxi = ind;
}
}
++maxi;
@@ -206,9 +218,13 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
for (uint32 y = 0; y < recordCount; ++y)
{
if (i >= 0)
{
indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
}
else
{
indexTable[y] = &dataTable[offset];
}
for (uint32 x = 0; x < fieldCount; ++x)
{
@@ -251,7 +267,9 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
char* DBCFileLoader::AutoProduceStrings(char const* format, char* dataTable)
{
if (strlen(format) != fieldCount)
{
return nullptr;
}
char* stringPool = new char[stringSize];
memcpy(stringPool, stringTable, stringSize);

View File

@@ -41,7 +41,9 @@ inline LPTSTR ErrorMessage(DWORD dw)
(LPTSTR) &lpMsgBuf,
0, nullptr);
if (formatResult != 0)
{
return (LPTSTR)lpMsgBuf;
}
else
{
LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30);
@@ -98,9 +100,13 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor
WheatyExceptionReport::~WheatyExceptionReport()
{
if (m_previousFilter)
{
SetUnhandledExceptionFilter(m_previousFilter);
}
if (m_previousCrtHandler)
{
_set_invalid_parameter_handler(m_previousCrtHandler);
}
ClearSymbols();
}
@@ -113,18 +119,24 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
std::unique_lock<std::mutex> guard(alreadyCrashedLock);
// Handle only 1 exception in the whole process lifetime
if (alreadyCrashed)
{
return EXCEPTION_EXECUTE_HANDLER;
}
alreadyCrashed = true;
if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
{
stackOverflowException = true;
}
TCHAR module_folder_name[MAX_PATH];
GetModuleFileName(0, module_folder_name, MAX_PATH);
TCHAR* pos = _tcsrchr(module_folder_name, '\\');
if (!pos)
{
return 0;
}
pos[0] = '\0';
++pos;
@@ -133,7 +145,9 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
if (!CreateDirectory(crash_folder_path, nullptr))
{
if (GetLastError() != ERROR_ALREADY_EXISTS)
{
return 0;
}
}
SYSTEMTIME systime;
@@ -197,9 +211,13 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
}
if (m_previousFilter)
{
return m_previousFilter(pExceptionInfo);
}
else
{
return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/;
}
}
void __cdecl WheatyExceptionReport::WheatyCrtHandler(wchar_t const* /*expression*/, wchar_t const* /*function*/, wchar_t const* /*file*/, unsigned int /*line*/, uintptr_t /*pReserved*/)
@@ -210,26 +228,34 @@ void __cdecl WheatyExceptionReport::WheatyCrtHandler(wchar_t const* /*expression
BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount)
{
if (!sProcessorName)
{
return FALSE;
}
HKEY hKey;
LONG lRet;
lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
0, KEY_QUERY_VALUE, &hKey);
if (lRet != ERROR_SUCCESS)
{
return FALSE;
}
TCHAR szTmp[2048];
DWORD cntBytes = sizeof(szTmp);
lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), nullptr, nullptr,
(LPBYTE)szTmp, &cntBytes);
if (lRet != ERROR_SUCCESS)
{
return FALSE;
}
::RegCloseKey(hKey);
sProcessorName[0] = '\0';
// Skip spaces
TCHAR* psz = szTmp;
while (iswspace(*psz))
{
++psz;
}
_tcsncpy(sProcessorName, psz, maxcount);
return TRUE;
}
@@ -257,7 +283,9 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
{
osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
if (!RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi))
{
return FALSE;
}
}
*szVersion = _T('\0');
@@ -282,40 +310,68 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
if (osvi.dwMajorVersion == 10)
{
if (productType == VER_NT_WORKSTATION)
{
_tcsncat(szVersion, _T("Windows 10 "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Windows Server 2016 "), cntMax);
}
}
else if (osvi.dwMajorVersion == 6)
{
if (productType == VER_NT_WORKSTATION)
{
if (osvi.dwMinorVersion == 3)
{
_tcsncat(szVersion, _T("Windows 8.1 "), cntMax);
}
else if (osvi.dwMinorVersion == 2)
{
_tcsncat(szVersion, _T("Windows 8 "), cntMax);
}
else if (osvi.dwMinorVersion == 1)
{
_tcsncat(szVersion, _T("Windows 7 "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Windows Vista "), cntMax);
}
}
else if (osvi.dwMinorVersion == 3)
{
_tcsncat(szVersion, _T("Windows Server 2012 R2 "), cntMax);
}
else if (osvi.dwMinorVersion == 2)
{
_tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
}
else if (osvi.dwMinorVersion == 1)
{
_tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
}
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
{
_tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax);
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
{
_tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax);
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
{
_tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax);
}
else if (osvi.dwMajorVersion <= 4)
{
_tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
}
// Test for specific product on Windows NT 4.0 SP6 and later.
if (bVersionEx >= 0)
@@ -324,13 +380,21 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
if (productType == VER_NT_WORKSTATION)
{
if (osvi.dwMajorVersion == 4)
{
_tcsncat(szVersion, _T("Workstation 4.0 "), cntMax);
}
else if (suiteMask & VER_SUITE_PERSONAL)
{
_tcsncat(szVersion, _T("Home Edition "), cntMax);
}
else if (suiteMask & VER_SUITE_EMBEDDEDNT)
{
_tcsncat(szVersion, _T("Embedded "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Professional "), cntMax);
}
}
// Test for the server type.
else if (productType == VER_NT_SERVER)
@@ -338,40 +402,66 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
{
if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
{
_tcsncat(szVersion, _T("Essentials "), cntMax);
}
else if (suiteMask & VER_SUITE_DATACENTER)
{
_tcsncat(szVersion, _T("Datacenter "), cntMax);
}
else if (suiteMask & VER_SUITE_ENTERPRISE)
{
_tcsncat(szVersion, _T("Enterprise "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Standard "), cntMax);
}
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
{
if (suiteMask & VER_SUITE_DATACENTER)
{
_tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
}
else if (suiteMask & VER_SUITE_ENTERPRISE)
{
_tcsncat(szVersion, _T("Enterprise Edition "), cntMax);
}
else if (suiteMask == VER_SUITE_BLADE)
{
_tcsncat(szVersion, _T("Web Edition "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Standard Edition "), cntMax);
}
}
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
{
if (suiteMask & VER_SUITE_DATACENTER)
{
_tcsncat(szVersion, _T("Datacenter Server "), cntMax);
}
else if (suiteMask & VER_SUITE_ENTERPRISE)
{
_tcsncat(szVersion, _T("Advanced Server "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Server "), cntMax);
}
}
else // Windows NT 4.0
{
if (suiteMask & VER_SUITE_ENTERPRISE)
{
_tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax);
}
else
{
_tcsncat(szVersion, _T("Server 4.0 "), cntMax);
}
}
}
}
@@ -438,9 +528,13 @@ void WheatyExceptionReport::PrintSystemInfo()
SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys / 0x400, MemoryStatus.dwAvailPhys / 0x400, MemoryStatus.dwTotalPageFile / 0x400);
if (_GetWindowsVersion(sString, countof(sString)))
{
Log(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
}
else
{
Log(_T("\r\n*** Operation System:\r\n<unknown>\r\n"));
}
}
//===========================================================================
@@ -453,7 +547,9 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)
// Take a snapshot of all running threads
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
{
return;
}
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);
@@ -480,7 +576,9 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)
if (threadHandle)
{
if (GetThreadContext(threadHandle, &context))
{
WriteStackDetails(&context, bWriteVariables, threadHandle);
}
CloseHandle(threadHandle);
}
}
@@ -663,15 +761,21 @@ BOOL WheatyExceptionReport::GetLogicalAddress(
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
{
return FALSE;
}
DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
if (!hMod)
{
return FALSE;
}
if (!GetModuleFileName((HMODULE)hMod, szModule, len))
{
return FALSE;
}
// Point to the DOS header in memory
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
@@ -771,9 +875,13 @@ void WheatyExceptionReport::WriteStackDetails(
SymFunctionTableAccess64,
SymGetModuleBase64,
0))
{
break;
}
if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure
break; // the frame is OK. Bail if not.
{
break; // the frame is OK. Bail if not.
}
#ifdef _M_IX86
Log(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
#endif
@@ -870,7 +978,9 @@ bool WheatyExceptionReport::FormatSymbolValue(
{
// If it's a function, don't do anything.
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
{
return false;
}
DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
@@ -890,7 +1000,9 @@ bool WheatyExceptionReport::FormatSymbolValue(
// return false;
}
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
return false; // Don't try to report register variable
{
return false; // Don't try to report register variable
}
else
{
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
@@ -900,9 +1012,13 @@ bool WheatyExceptionReport::FormatSymbolValue(
// Indicate if the variable is a local or parameter
if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
{
symbolDetails.top().Prefix = "Parameter ";
}
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
{
symbolDetails.top().Prefix = "Local ";
}
// Determine if the variable is a user defined type (UDT). IF so, bHandled
// will return true.
@@ -916,11 +1032,15 @@ bool WheatyExceptionReport::FormatSymbolValue(
// DWORD.
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
if (symbolDetails.top().Type.empty())
{
symbolDetails.top().Type = rgBaseType[basicType];
}
// Emit the variable name
if (pSym->Name[0] != '\0')
{
symbolDetails.top().Name = pSym->Name;
}
char buffer[50];
FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
@@ -949,11 +1069,15 @@ void WheatyExceptionReport::DumpTypeIndex(
bHandled = false;
if (newSymbol)
{
PushSymbolDetail();
}
DWORD typeTag;
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
{
return;
}
// Get the name of the symbol. This will either be a Type name (if a UDT),
// or the structure member name.
@@ -970,7 +1094,9 @@ void WheatyExceptionReport::DumpTypeIndex(
FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
symbolDetails.top().Value = buffer;
if (Name != nullptr && Name[0] != '\0')
{
symbolDetails.top().Name = Name;
}
bHandled = true;
return;
}
@@ -984,18 +1110,24 @@ void WheatyExceptionReport::DumpTypeIndex(
symbolDetails.top().Name = Name;
}
else if (buffer[0] != '\0')
{
symbolDetails.top().Name = buffer;
}
LocalFree(pwszTypeName);
}
else if (Name != nullptr && Name[0] != '\0')
{
symbolDetails.top().Name = Name;
}
if (!StoreSymbol(dwTypeIndex, offset))
{
// Skip printing address and base class if it has been printed already
if (typeTag == SymTagBaseClass)
{
bHandled = true;
}
return;
}
@@ -1006,7 +1138,9 @@ void WheatyExceptionReport::DumpTypeIndex(
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
{
if (Name != nullptr && Name[0] != '\0')
{
symbolDetails.top().Name = Name;
}
BOOL isReference;
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
@@ -1015,9 +1149,13 @@ void WheatyExceptionReport::DumpTypeIndex(
memset(addressStr, 0, sizeof(addressStr));
if (isReference)
{
symbolDetails.top().Suffix += "&";
}
else
{
symbolDetails.top().Suffix += "*";
}
// Try to dereference the pointer in a try/except block since it might be invalid
DWORD_PTR address = DereferenceUnsafePointer(offset);
@@ -1027,11 +1165,15 @@ void WheatyExceptionReport::DumpTypeIndex(
symbolDetails.top().Value = buffer;
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
{
logChildren = false;
}
// no need to log any children since the address is invalid anyway
if (address == NULL || address == DWORD_PTR(-1))
{
logChildren = false;
}
DumpTypeIndex(modBase, innerTypeID, address, bHandled, Name, addressStr, false, logChildren);
@@ -1039,12 +1181,18 @@ void WheatyExceptionReport::DumpTypeIndex(
{
BasicType basicType = GetBasicType(dwTypeIndex, modBase);
if (symbolDetails.top().Type.empty())
{
symbolDetails.top().Type = rgBaseType[basicType];
}
if (address == NULL)
{
symbolDetails.top().Value = "NULL";
}
else if (address == DWORD_PTR(-1))
{
symbolDetails.top().Value = "<Unable to read memory>";
}
else
{
// Get the size of the child member
@@ -1058,7 +1206,9 @@ void WheatyExceptionReport::DumpTypeIndex(
return;
}
else if (address == NULL)
{
symbolDetails.top().Value = "NULL";
}
else if (address == DWORD_PTR(-1))
{
symbolDetails.top().Value = "<Unable to read memory>";
@@ -1072,19 +1222,25 @@ void WheatyExceptionReport::DumpTypeIndex(
{
DWORD innerTypeTag;
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
{
break;
}
switch (innerTypeTag)
{
case SymTagUDT:
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
{
logChildren = false;
}
DumpTypeIndex(modBase, innerTypeID,
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
break;
case SymTagPointerType:
if (Name != nullptr && Name[0] != '\0')
{
symbolDetails.top().Name = Name;
}
DumpTypeIndex(modBase, innerTypeID,
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
break;
@@ -1112,15 +1268,21 @@ void WheatyExceptionReport::DumpTypeIndex(
DWORD elementsCount;
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
{
symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
}
else
{
symbolDetails.top().Suffix += "[<unknown count>]";
}
if (!bHandled)
{
basicType = GetBasicType(dwTypeIndex, modBase);
if (symbolDetails.top().Type.empty())
{
symbolDetails.top().Type = rgBaseType[basicType];
}
bHandled = true;
}
@@ -1184,7 +1346,9 @@ void WheatyExceptionReport::DumpTypeIndex(
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
if (!dwChildrenCount) // If no children, we're done
{
return;
}
// Prepare to get an array of "TypeIds", representing each of the children.
// SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
@@ -1215,7 +1379,9 @@ void WheatyExceptionReport::DumpTypeIndex(
symTag == SymTagEnum ||
symTag == SymTagTypedef ||
symTag == SymTagVTable)
{
continue;
}
// Ignore static fields
DWORD dataKind;
@@ -1223,7 +1389,9 @@ void WheatyExceptionReport::DumpTypeIndex(
if (dataKind == DataIsStaticLocal ||
dataKind == DataIsGlobal ||
dataKind == DataIsStaticMember)
{
continue;
}
symbolDetails.top().HasChildren = true;
if (!logChildren)
@@ -1252,7 +1420,9 @@ void WheatyExceptionReport::DumpTypeIndex(
if (!bHandled2)
{
if (symbolDetails.top().Type.empty())
{
symbolDetails.top().Type = rgBaseType[basicType];
}
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo(TI_GET_TYPEID) call below.
@@ -1291,36 +1461,56 @@ void WheatyExceptionReport::FormatOutputValue(char* pszCurrBuffer,
{
// Special case handling for char[] type
if (countOverride != 0)
{
length = countOverride;
}
else
{
length = strlen((char*)pAddress);
}
if (length > bufferSize - 6)
{
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), (char*)pAddress);
}
else
{
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", (DWORD)length, (char*)pAddress);
}
break;
}
case btStdString:
{
std::string* value = static_cast<std::string*>(pAddress);
if (value->length() > bufferSize - 6)
{
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), value->c_str());
}
else
{
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
}
break;
}
default:
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if (length == 1)
{
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
}
else if (length == 2)
{
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
}
else if (length == 4)
{
if (basicType == btFloat)
{
pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
}
else
{
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
}
}
else if (length == 8)
{
@@ -1401,9 +1591,13 @@ int __cdecl WheatyExceptionReport::Log(const TCHAR* format, ...)
va_start(argptr, format);
if (stackOverflowException)
{
retValue = HeapLog(format, argptr);
}
else
{
retValue = StackLog(format, argptr);
}
va_end(argptr);
@@ -1446,7 +1640,9 @@ void WheatyExceptionReport::ClearSymbols()
{
symbols.clear();
while (!symbolDetails.empty())
{
symbolDetails.pop();
}
}
void WheatyExceptionReport::PushSymbolDetail()
@@ -1465,15 +1661,21 @@ void WheatyExceptionReport::PopSymbolDetail()
void WheatyExceptionReport::PrintSymbolDetail()
{
if (symbolDetails.empty())
{
return;
}
// Don't log anything if has been logged already or if it's empty
if (symbolDetails.top().Logged || symbolDetails.top().empty())
{
return;
}
// Add appropriate indentation level (since this routine is recursive)
for (size_t i = 0; i < symbolDetails.size(); i++)
{
Log(_T("\t"));
}
Log(_T("%s\r\n"), symbolDetails.top().ToString().c_str());
@@ -1487,13 +1689,17 @@ std::string SymbolDetail::ToString()
if (!Name.empty())
{
if (!formatted.empty())
{
formatted += " ";
}
formatted += Name;
}
if (!Value.empty())
{
if (Name == "passwd" || Name == "password")
{
Value = "<sensitive data>";
}
formatted += " = " + Value;
}
return formatted;

View File

@@ -115,7 +115,9 @@ public:
return result;
}
else
{
return iSize;
}
}
void incSize() { ++iSize; }

View File

@@ -35,7 +35,9 @@ public:
{
ASSERT(fromObj); // fromObj MUST not be nullptr
if (isValid())
{
unlink();
}
if (toObj != nullptr)
{
iRefTo = toObj;

View File

@@ -41,7 +41,9 @@ public:
if ( iter != i_registeredObjects.end() )
{
if ( !override )
{
return false;
}
delete iter->second;
i_registeredObjects.erase(iter);
}
@@ -57,7 +59,9 @@ public:
if ( iter != i_registeredObjects.end() )
{
if ( delete_object )
{
delete iter->second;
}
i_registeredObjects.erase(iter);
}
}
@@ -74,7 +78,9 @@ public:
unsigned int sz = l.size();
l.resize(sz + i_registeredObjects.size());
for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
{
l[sz++] = iter->first;
}
return i_registeredObjects.size();
}
@@ -88,7 +94,9 @@ public:
~ObjectRegistry()
{
for (typename RegistryMapType::iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
{
delete iter->second;
}
i_registeredObjects.clear();
}
private:

View File

@@ -63,9 +63,13 @@ namespace Acore
{
auto i = elements._element.find(handle);
if (i == elements._element.end())
{
return nullptr;
}
else
{
return i->second;
}
}
template<class SPECIFIC_TYPE, class KEY_TYPE>

View File

@@ -90,7 +90,9 @@ namespace Acore
{
CountedPtr<SPECIFIC_TYPE>& t = Find(elements._elements, hdl, fake);
if (!t)
{
t = Find(elements._TailElement, hdl, fake);
}
return t;
}

View File

@@ -15,19 +15,19 @@ struct B32Impl
static constexpr char Encode(uint8 v)
{
ASSERT(v < 0x20);
if (v < 26) return 'A'+v;
else return '2' + (v-26);
if (v < 26) { return 'A' + v; }
else { return '2' + (v - 26); }
}
static constexpr uint8 DECODE_ERROR = 0xff;
static constexpr uint8 Decode(uint8 v)
{
if (v == '0') return Decode('O');
if (v == '1') return Decode('l');
if (v == '8') return Decode('B');
if (('A' <= v) && (v <= 'Z')) return (v-'A');
if (('a' <= v) && (v <= 'z')) return (v-'a');
if (('2' <= v) && (v <= '7')) return (v-'2')+26;
if (v == '0') { return Decode('O'); }
if (v == '1') { return Decode('l'); }
if (v == '8') { return Decode('B'); }
if (('A' <= v) && (v <= 'Z')) { return (v - 'A'); }
if (('a' <= v) && (v <= 'z')) { return (v - 'a'); }
if (('2' <= v) && (v <= '7')) { return (v - '2') + 26; }
return DECODE_ERROR;
}
};

View File

@@ -15,21 +15,21 @@ struct B64Impl
static constexpr char Encode(uint8 v)
{
ASSERT(v < 0x40);
if (v < 26) return 'A' + v;
if (v < 52) return 'a' + (v - 26);
if (v < 62) return '0' + (v - 52);
if (v == 62) return '+';
else return '/';
if (v < 26) { return 'A' + v; }
if (v < 52) { return 'a' + (v - 26); }
if (v < 62) { return '0' + (v - 52); }
if (v == 62) { return '+'; }
else { return '/'; }
}
static constexpr uint8 DECODE_ERROR = 0xff;
static constexpr uint8 Decode(uint8 v)
{
if (('A' <= v) && (v <= 'Z')) return (v - 'A');
if (('a' <= v) && (v <= 'z')) return (v - 'a') + 26;
if (('0' <= v) && (v <= '9')) return (v - '0') + 52;
if (v == '+') return 62;
if (v == '/') return 63;
if (('A' <= v) && (v <= 'Z')) { return (v - 'A'); }
if (('a' <= v) && (v <= 'z')) { return (v - 'a') + 26; }
if (('0' <= v) && (v <= '9')) { return (v - '0') + 52; }
if (v == '+') { return 62; }
if (v == '/') { return 63; }
return DECODE_ERROR;
}
};

View File

@@ -29,7 +29,9 @@ namespace Acore::Impl
{
size *= 8; // bits in input
if (size % PAD_TO) // pad to boundary
{
size += (PAD_TO - (size % PAD_TO));
}
return (size / BITS_PER_CHAR);
}
@@ -37,7 +39,9 @@ namespace Acore::Impl
{
size *= BITS_PER_CHAR; // bits in input
if (size % PAD_TO) // pad to boundary
{
size += (PAD_TO - (size % PAD_TO));
}
return (size / 8);
}
@@ -45,7 +49,9 @@ namespace Acore::Impl
{
auto it = data.begin(), end = data.end();
if (it == end)
{
return "";
}
std::string s;
s.reserve(EncodedSize(data.size()));
@@ -57,7 +63,7 @@ namespace Acore::Impl
if (bitsLeft >= BITS_PER_CHAR)
{
bitsLeft -= BITS_PER_CHAR;
thisC = ((*it >> bitsLeft) & ((1 << BITS_PER_CHAR)-1));
thisC = ((*it >> bitsLeft) & ((1 << BITS_PER_CHAR) - 1));
if (!bitsLeft)
{
++it;
@@ -69,7 +75,9 @@ namespace Acore::Impl
thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
bitsLeft += (8 - BITS_PER_CHAR);
if ((++it) != end)
{
thisC |= (*it >> bitsLeft);
}
}
s.append(1, Encoding::Encode(thisC));
} while (it != end);
@@ -77,9 +85,13 @@ namespace Acore::Impl
while (bitsLeft != 8)
{
if (bitsLeft > BITS_PER_CHAR)
{
bitsLeft -= BITS_PER_CHAR;
}
else
{
bitsLeft += (8 - BITS_PER_CHAR);
}
s.append(1, PADDING);
}
@@ -90,7 +102,9 @@ namespace Acore::Impl
{
auto it = data.begin(), end = data.end();
if (it == end)
{
return std::vector<uint8>();
}
std::vector<uint8> v;
v.reserve(DecodedSize(data.size()));
@@ -126,15 +140,21 @@ namespace Acore::Impl
while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
{
if (bitsLeft > BITS_PER_CHAR)
{
bitsLeft -= BITS_PER_CHAR;
}
else
{
bitsLeft += (8 - BITS_PER_CHAR);
}
++it;
}
// ok, all padding should be consumed, and we should be at end of string
if (it == end)
{
return v;
}
// anything else is an error
return {};

View File

@@ -9,7 +9,7 @@
#include <sstream>
Appender::Appender(uint8 _id, std::string const& _name, LogLevel _level /* = LOG_LEVEL_DISABLED */, AppenderFlags _flags /* = APPENDER_FLAGS_NONE */):
id(_id), name(_name), level(_level), flags(_flags) { }
id(_id), name(_name), level(_level), flags(_flags) { }
Appender::~Appender() { }
@@ -41,18 +41,26 @@ void Appender::setLogLevel(LogLevel _level)
void Appender::write(LogMessage* message)
{
if (!level || level < message->level)
{
return;
}
std::ostringstream ss;
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
{
ss << message->getTimeStr() << ' ';
}
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
{
ss << Acore::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
}
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
{
ss << '[' << message->type << "] ";
}
message->prefix = ss.str();
_write(message);

View File

@@ -20,10 +20,14 @@ AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel lev
: Appender(id, name, level, flags), _colored(false)
{
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
{
_colors[i] = ColorTypes(NUM_COLOR_TYPES);
}
if (3 < args.size())
{
InitColors(name, args[3]);
}
}
void AppenderConsole::InitColors(std::string const& name, std::string_view str)
@@ -44,7 +48,9 @@ void AppenderConsole::InitColors(std::string const& name, std::string_view str)
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
{
if (Optional<uint8> color = Acore::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color))
{
_colors[i] = static_cast<ColorTypes>(*color);
}
else
{
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Invalid color '%s' for log level %s on console appender %s",
@@ -138,8 +144,8 @@ void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
FG_WHITE // LWHITE
};
fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
#endif
fprintf((stdout_stream ? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
#endif
}
void AppenderConsole::ResetColor(bool stdout_stream)
@@ -163,23 +169,23 @@ void AppenderConsole::_write(LogMessage const* message)
switch (message->level)
{
case LOG_LEVEL_TRACE:
index = 5;
break;
index = 5;
break;
case LOG_LEVEL_DEBUG:
index = 4;
break;
index = 4;
break;
case LOG_LEVEL_INFO:
index = 3;
break;
index = 3;
break;
case LOG_LEVEL_WARN:
index = 2;
break;
index = 2;
break;
case LOG_LEVEL_FATAL:
index = 0;
break;
index = 0;
break;
default:
index = 1;
break;
index = 1;
break;
}
SetColor(stdout_stream, _colors[index]);
@@ -187,5 +193,7 @@ void AppenderConsole::_write(LogMessage const* message)
ResetColor(stdout_stream);
}
else
{
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
}
}

View File

@@ -18,36 +18,50 @@ AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, Ap
_fileSize(0)
{
if (args.size() < 4)
{
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s", name.c_str()));
}
_fileName.assign(args[3]);
std::string mode = "a";
if (4 < args.size())
{
mode.assign(args[4]);
}
if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
{
size_t dot_pos = _fileName.find_last_of('.');
if (dot_pos != std::string::npos)
{
_fileName.insert(dot_pos, sLog->GetLogsTimestamp());
}
else
{
_fileName += sLog->GetLogsTimestamp();
}
}
if (5 < args.size())
{
if (Optional<uint32> size = Acore::StringTo<uint32>(args[5]))
{
_maxFileSize = *size;
}
else
{
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Invalid size '%s' for appender %s", std::string(args[5]).c_str(), name.c_str()));
}
}
_dynamicName = std::string::npos != _fileName.find("%s");
_backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
if (!_dynamicName)
{
logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
}
}
AppenderFile::~AppenderFile()
@@ -67,7 +81,9 @@ void AppenderFile::_write(LogMessage const* message)
// always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
FILE* file = OpenFile(namebuf, "a", _backup || exceedMaxSize);
if (!file)
{
return;
}
fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(file);
@@ -77,10 +93,14 @@ void AppenderFile::_write(LogMessage const* message)
return;
}
else if (exceedMaxSize)
{
logfile = OpenFile(_fileName, "w", true);
}
if (!logfile)
{
return;
}
fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(logfile);

View File

@@ -39,7 +39,9 @@ Appender* Log::GetAppenderByName(std::string_view name)
{
auto it = appenders.begin();
while (it != appenders.end() && it->second && it->second->getName() != name)
{
++it;
}
return it == appenders.end() ? nullptr : it->second.get();
}
@@ -47,7 +49,9 @@ Appender* Log::GetAppenderByName(std::string_view name)
void Log::CreateAppenderFromConfig(std::string const& appenderName)
{
if (appenderName.empty())
{
return;
}
// Format = type, level, flags, optional1, optional2
// if type = File. optional1 = file and option2 = mode
@@ -85,7 +89,9 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName)
if (size > 2)
{
if (Optional<uint8> flagsVal = Acore::StringTo<uint8>(tokens[2]))
{
flags = AppenderFlags(*flagsVal);
}
else
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown flags '%s' for appender %s\n", std::string(tokens[2]).c_str(), name.c_str());
@@ -107,7 +113,9 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName)
void Log::CreateLoggerFromConfig(std::string const& appenderName)
{
if (appenderName.empty())
{
return;
}
LogLevel level = LOG_LEVEL_DISABLED;
@@ -143,7 +151,9 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
}
if (level > highestLogLevel)
{
highestLogLevel = level;
}
logger = std::make_unique<Logger>(name, level);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
@@ -156,7 +166,9 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
//fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
}
else
{
fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist\n", std::string(appenderName).c_str(), name.c_str());
}
}
}
@@ -164,14 +176,18 @@ void Log::ReadAppendersFromConfig()
{
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
for (std::string const& appenderName : keys)
{
CreateAppenderFromConfig(appenderName);
}
}
void Log::ReadLoggersFromConfig()
{
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
for (std::string const& loggerName : keys)
{
CreateLoggerFromConfig(loggerName);
}
// Bad config configuration, creating default config
if (loggers.find(LOGGER_ROOT) == loggers.end())
@@ -222,15 +238,21 @@ Logger const* Log::GetLoggerByType(std::string const& type) const
{
auto it = loggers.find(type);
if (it != loggers.end())
{
return it->second.get();
}
if (type == LOGGER_ROOT)
{
return nullptr;
}
std::string parentLogger = LOGGER_ROOT;
size_t found = type.find_last_of('.');
if (found != std::string::npos)
{
parentLogger = type.substr(0, found);
}
return GetLoggerByType(parentLogger);
}
@@ -255,7 +277,9 @@ std::string Log::GetTimestampStr()
bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /* = true */)
{
if (newLeveli < 0)
{
return false;
}
LogLevel newLevel = LogLevel(newLeveli);
@@ -263,21 +287,29 @@ bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /*
{
auto it = loggers.begin();
while (it != loggers.end() && it->second->getName() != name)
{
++it;
}
if (it == loggers.end())
{
return false;
}
it->second->setLogLevel(newLevel);
if (newLevel != LOG_LEVEL_DISABLED && newLevel > highestLogLevel)
{
highestLogLevel = newLevel;
}
}
else
{
Appender* appender = GetAppenderByName(name);
if (!appender)
{
return false;
}
appender->setLogLevel(newLevel);
}
@@ -288,7 +320,9 @@ bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /*
void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const* name)
{
if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO))
{
return;
}
std::ostringstream ss;
ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
@@ -306,7 +340,9 @@ void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const
void Log::SetRealmId(uint32 id)
{
for (std::pair<uint8 const, std::unique_ptr<Appender>>& appender : appenders)
{
appender.second->setRealmId(id);
}
}
void Log::Close()
@@ -323,11 +359,15 @@ bool Log::ShouldLog(std::string const& type, LogLevel level) const
// Don't even look for a logger if the LogLevel is higher than the highest log levels across all loggers
if (level > highestLogLevel)
{
return false;
}
Logger const* logger = GetLoggerByType(type);
if (!logger)
{
return false;
}
LogLevel logLevel = logger->getLogLevel();
return logLevel != LOG_LEVEL_DISABLED && logLevel >= level;
@@ -354,7 +394,9 @@ void Log::LoadFromConfig()
if (!m_logsDir.empty())
if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
{
m_logsDir.push_back('/');
}
ReadAppendersFromConfig();
ReadLoggersFromConfig();

View File

@@ -59,7 +59,9 @@ public:
void outCommand(uint32 account, Format&& fmt, Args&&... args)
{
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
{
return;
}
outCommand(Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...), std::to_string(account));
}
@@ -99,7 +101,9 @@ public:
void outErrorDb(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.sql", LOG_LEVEL_ERROR))
{
return;
}
outMessage("sql.sql", LOG_LEVEL_ERROR, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
@@ -120,7 +124,9 @@ public:
void outSQLDev(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.dev", LOG_LEVEL_INFO))
{
return;
}
outMessage("sql.dev", LOG_LEVEL_INFO, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
@@ -129,7 +135,9 @@ public:
void outSQLDriver(Format&& fmt, Args&& ... args)
{
if (!ShouldLog("sql.driver", LOG_LEVEL_INFO))
{
return;
}
outMessage("sql.driver", LOG_LEVEL_INFO, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}
@@ -144,10 +152,14 @@ public:
void outDebug(DebugLogFilters filter, Format&& fmt, Args&& ... args)
{
if (!(_debugLogMask & filter))
{
return;
}
if (!ShouldLog("server", LOG_LEVEL_DEBUG))
{
return;
}
outMessage("server", LOG_LEVEL_DEBUG, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
}

View File

@@ -44,5 +44,7 @@ void Logger::write(LogMessage* message) const
for (std::pair<uint8 const, Appender*> const& appender : appenders)
if (appender.second)
{
appender.second->write(message);
}
}

View File

@@ -11,12 +11,12 @@ float dtQueryFilterExt::getCost(const float* pa, const float* pb,
const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
{
float startX=pa[2], startY=pa[0], startZ=pa[1];
float destX=pb[2], destY=pb[0], destZ=pb[1];
float slopeAngle = getSlopeAngle(startX, startY, startZ, destX, destY, destZ);
float slopeAngleDegree = (slopeAngle * 180.0f / M_PI);
float cost = slopeAngleDegree > 0 ? 1.0f + (1.0f * (slopeAngleDegree/100)) : 1.0f;
float dist = dtVdist(pa, pb);
auto totalCost = dist * cost * getAreaCost(curPoly->getArea());
return totalCost;
float startX = pa[2], startY = pa[0], startZ = pa[1];
float destX = pb[2], destY = pb[0], destZ = pb[1];
float slopeAngle = getSlopeAngle(startX, startY, startZ, destX, destY, destZ);
float slopeAngleDegree = (slopeAngle * 180.0f / M_PI);
float cost = slopeAngleDegree > 0 ? 1.0f + (1.0f * (slopeAngleDegree / 100)) : 1.0f;
float dist = dtVdist(pa, pb);
auto totalCost = dist * cost * getAreaCost(curPoly->getArea());
return totalCost;
}

View File

@@ -123,7 +123,9 @@ bool WinServiceUninstall()
if (QueryServiceStatus(service, &serviceStatus2))
{
if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
{
DeleteService(service);
}
}
CloseServiceHandle(service);
}
@@ -163,10 +165,14 @@ void WINAPI ServiceControlHandler(DWORD controlCode)
default:
if ( controlCode >= 128 && controlCode <= 255 )
// user defined control code
{
break;
}
else
// unrecognized control code
{
break;
}
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
@@ -194,7 +200,7 @@ void WINAPI ServiceMain(DWORD argc, char* argv[])
for (i = 0; i < std::strlen(path); i++)
{
if (path[i] == '\\') last_slash = i;
if (path[i] == '\\') { last_slash = i; }
}
path[last_slash] = 0;

View File

@@ -10,7 +10,7 @@
#include <deque>
#include <mutex>
template <class T, typename StorageType = std::deque<T> >
template <class T, typename StorageType = std::deque<T>>
class LockedQueue
{
//! Lock access to the queue.
@@ -59,7 +59,9 @@ public:
std::lock_guard<std::mutex> lock(_lock);
if (_queue.empty())
{
return false;
}
result = _queue.front();
_queue.pop_front();
@@ -73,11 +75,15 @@ public:
std::lock_guard<std::mutex> lock(_lock);
if (_queue.empty())
{
return false;
}
result = _queue.front();
if (!check.Process(result))
{
return false;
}
_queue.pop_front();
return true;
@@ -91,7 +97,9 @@ public:
T& result = _queue.front();
if (autoUnlock)
{
unlock();
}
return result;
}

View File

@@ -45,7 +45,9 @@ public:
std::lock_guard<std::mutex> lock(_queueLock);
if (_queue.empty() || _shutdown)
{
return false;
}
value = _queue.front();
@@ -61,10 +63,14 @@ public:
// we could be using .wait(lock, predicate) overload here but it is broken
// https://connect.microsoft.com/VisualStudio/feedback/details/1098841
while (_queue.empty() && !_shutdown)
{
_condition.wait(lock);
}
if (_queue.empty() || _shutdown)
{
return;
}
value = _queue.front();

View File

@@ -31,20 +31,30 @@ void SetProcessPriority(std::string const& logChannel, uint32 affinity, bool hig
ULONG_PTR currentAffinity = affinity & appAff;
if (!currentAffinity)
{
LOG_ERROR(logChannel, "Processors marked in UseProcessors bitmask (hex) %x are not accessible. Accessible processors bitmask (hex): %x", affinity, appAff);
}
else if (SetProcessAffinityMask(hProcess, currentAffinity))
{
LOG_INFO(logChannel, "Using processors (bitmask, hex): %x", currentAffinity);
}
else
{
LOG_ERROR(logChannel, "Can't set used processors (hex): %x", currentAffinity);
}
}
}
if (highPriority)
{
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
{
LOG_INFO(logChannel, "Process priority class set to HIGH");
}
else
{
LOG_ERROR(logChannel, "Can't set process priority class.");
}
}
#elif defined(__linux__) // Linux
@@ -56,10 +66,14 @@ void SetProcessPriority(std::string const& logChannel, uint32 affinity, bool hig
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
if (affinity & (1 << i))
{
CPU_SET(i, &mask);
}
if (sched_setaffinity(0, sizeof(mask), &mask))
{
LOG_ERROR(logChannel, "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
}
else
{
CPU_ZERO(&mask);
@@ -71,9 +85,13 @@ void SetProcessPriority(std::string const& logChannel, uint32 affinity, bool hig
if (highPriority)
{
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
{
LOG_ERROR(logChannel, "Can't set process priority class, error: %s", strerror(errno));
}
else
{
LOG_INFO(logChannel, "Process priority class set to %i", getpriority(PRIO_PROCESS, 0));
}
}
#else

View File

@@ -25,7 +25,9 @@ Thread::Thread(Runnable* instance) : m_task(instance), m_ThreadImp(&Thread::Thre
// register reference to m_task to prevent it deeltion until destructor
if (m_task)
{
m_task->incReference();
}
}
Thread::~Thread()
@@ -34,13 +36,17 @@ Thread::~Thread()
// deleted runnable object (if no other references)
if (m_task)
{
m_task->decReference();
}
}
bool Thread::wait()
{
if (m_iThreadId == std::thread::id() || !m_task)
{
return false;
}
bool res = true;
@@ -61,7 +67,9 @@ bool Thread::wait()
void Thread::destroy()
{
if (m_iThreadId == std::thread::id() || !m_task)
{
return;
}
// FIXME: We need to make sure that all threads can be trusted to
// halt execution on their own as this is not an interrupt

View File

@@ -22,7 +22,9 @@ namespace Acore
void decReference()
{
if (!--m_refs)
{
delete this;
}
}
private:
std::atomic_long m_refs;

View File

@@ -14,7 +14,8 @@
#include <vector>
template <typename T>
class CircularBuffer {
class CircularBuffer
{
public:
explicit CircularBuffer(size_t size) :
buf_(std::unique_ptr<T[]>(new T[size])),
@@ -77,13 +78,15 @@ public:
// the implementation of this function is simplified by the fact that head_ will never be lower than tail_
// when compared to the original implementation of this class
std::vector<T> content() {
std::vector<T> content()
{
std::lock_guard<std::mutex> lock(mutex_);
return std::vector<T>(buf_.get(), buf_.get() + size());
}
T peak_back() {
T peak_back()
{
std::lock_guard<std::mutex> lock(mutex_);
return empty() ? T() : buf_[tail_];

View File

@@ -55,7 +55,9 @@ namespace Acore
void check() const
{
if (!(_buf < _end))
{
throw std::out_of_range("index");
}
}
};
}
@@ -70,7 +72,9 @@ namespace Acore::Containers
static_assert(std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<typename C::iterator>::iterator_category>::value, "Invalid container passed to Acore::Containers::RandomResize");
if (std::size(container) <= requestedSize)
{
return;
}
auto keepIt = std::begin(container), curIt = std::begin(container);
uint32 elementsToKeep = requestedSize, elementsToProcess = std::size(container);
@@ -81,7 +85,9 @@ namespace Acore::Containers
if (urand(1, elementsToProcess) <= elementsToKeep)
{
if (keepIt != curIt)
{
*keepIt = std::move(*curIt);
}
++keepIt;
--elementsToKeep;
@@ -102,7 +108,9 @@ namespace Acore::Containers
std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate);
if (requestedSize)
{
RandomResize(containerCopy, requestedSize);
}
container = std::move(containerCopy);
}
@@ -160,7 +168,9 @@ namespace Acore::Containers
}
if (weightSum <= 0.0)
{
weights.assign(std::size(container), 1.0);
}
return SelectRandomWeightedContainerElement(container, weights);
}
@@ -195,9 +205,13 @@ namespace Acore::Containers
for (auto itr = range.first; itr != range.second;)
{
if (itr->second == value)
{
itr = multimap.erase(itr);
}
else
{
++itr;
}
}
}

View File

@@ -30,11 +30,15 @@ public:
{
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
if (Container.empty())
{
return nullptr;
}
auto it = Container.find(k);
if (it != Container.end())
{
return dynamic_cast<T*>(it->second.get());
}
return nullptr;
}
@@ -47,7 +51,9 @@ public:
{
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
if (T* v = Get<T>(k))
{
return v;
}
T* v = new T();
Container.emplace(k, std::unique_ptr<T>(v));
return v;

View File

@@ -64,18 +64,22 @@ void EventProcessor::KillAllEvents(bool force)
delete i_old->second;
if (!force) // need per-element cleanup
{
m_events.erase (i_old);
}
}
}
// fast clear event list (in force case)
if (force)
{
m_events.clear();
}
}
void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)
{
if (set_addtime) Event->m_addTime = m_time;
if (set_addtime) { Event->m_addTime = m_time; }
Event->m_execTime = e_time;
m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event));
}

View File

@@ -28,7 +28,7 @@
[[nodiscard]] inline float getSlopeAngle(float startX, float startY, float startZ, float destX, float destY, float destZ)
{
float floorDist = sqrt(pow(startY - destY, 2.0f) + pow(startX - destX,2.0f));
float floorDist = sqrt(pow(startY - destY, 2.0f) + pow(startX - destX, 2.0f));
return atan(abs(destZ - startZ) / abs(floorDist));
}

View File

@@ -20,11 +20,15 @@ inline T standard_deviation(Container&& c)
auto mean = sum / size;
if (size == 1)
{
return (T) 0;
}
T accum = T();
for (const auto d : c)
{
accum += (d - mean) * (d - mean);
}
return std::sqrt(accum / (size - 1));
}
@@ -43,7 +47,8 @@ inline T median(std::vector<T> a)
{
size_t n = a.size();
// If size of the arr[] is even
if (n % 2 == 0) {
if (n % 2 == 0)
{
// Applying nth_element
// on n/2th index
@@ -65,7 +70,8 @@ inline T median(std::vector<T> a)
}
// If size of the arr[] is odd
else {
else
{
// Applying nth_element
// on n/2

View File

@@ -15,7 +15,9 @@ static RandomEngine engine;
static SFMTRand* GetRng()
{
if (!sfmtRand)
{
sfmtRand = std::make_unique<SFMTRand>();
}
return sfmtRand.get();
}
@@ -51,7 +53,7 @@ Milliseconds randtime(Milliseconds min, Milliseconds max)
{
long long diff = max.count() - min.count();
ASSERT(diff >= 0);
ASSERT(diff <= (uint32)-1);
ASSERT(diff <= (uint32) - 1);
return min + Milliseconds(urand(0, diff));
}

View File

@@ -26,7 +26,9 @@ namespace Acore
std::lock_guard lock(_mutex);
if (_handled.find(sig) != _handled.end())
{
return false;
}
_handled.insert(sig);
signal(sig, func);
@@ -36,7 +38,9 @@ namespace Acore
~SignalHandler()
{
for (auto const& sig : _handled)
{
signal(sig, nullptr);
}
}
};
}

View File

@@ -34,87 +34,88 @@ namespace Acore::Impl::EnumUtilsImpl
class EnumUtils
{
public:
template <typename Enum>
static size_t Count() { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::Count(); }
template <typename Enum>
static EnumText ToString(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToString(value); }
template <typename Enum>
static Enum FromIndex(size_t index) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::FromIndex(index); }
template <typename Enum>
static uint32 ToIndex(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);}
public:
template <typename Enum>
static size_t Count() { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::Count(); }
template <typename Enum>
static EnumText ToString(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToString(value); }
template <typename Enum>
static Enum FromIndex(size_t index) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::FromIndex(index); }
template <typename Enum>
static uint32 ToIndex(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);}
template<typename Enum>
static bool IsValid(Enum value)
template<typename Enum>
static bool IsValid(Enum value)
{
try
{
try
{
Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);
return true;
} catch (...)
{
return false;
}
Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);
return true;
}
template<typename Enum>
static bool IsValid(std::underlying_type_t<Enum> value) { return IsValid(static_cast<Enum>(value)); }
template <typename Enum>
class Iterator
catch (...)
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Enum;
using pointer = Enum*;
using reference = Enum&;
using difference_type = std::ptrdiff_t;
return false;
}
}
Iterator() : _index(EnumUtils::Count<Enum>()) {}
explicit Iterator(size_t index) : _index(index) { }
template<typename Enum>
static bool IsValid(std::underlying_type_t<Enum> value) { return IsValid(static_cast<Enum>(value)); }
bool operator==(const Iterator& other) const { return other._index == _index; }
bool operator!=(const Iterator& other) const { return !operator==(other); }
difference_type operator-(Iterator const& other) const { return _index - other._index; }
bool operator<(const Iterator& other) const { return _index < other._index; }
bool operator<=(const Iterator& other) const { return _index <= other._index; }
bool operator>(const Iterator& other) const { return _index > other._index; }
bool operator>=(const Iterator& other) const { return _index >= other._index; }
template <typename Enum>
class Iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = Enum;
using pointer = Enum*;
using reference = Enum&;
using difference_type = std::ptrdiff_t;
value_type operator[](difference_type d) const { return FromIndex<Enum>(_index + d); }
value_type operator*() const { return operator[](0); }
Iterator() : _index(EnumUtils::Count<Enum>()) {}
explicit Iterator(size_t index) : _index(index) { }
Iterator& operator+=(difference_type d) { _index += d; return *this; }
Iterator& operator++() { return operator+=(1); }
Iterator operator++(int) { Iterator i = *this; operator++(); return i; }
Iterator operator+(difference_type d) const { Iterator i = *this; i += d; return i; }
bool operator==(const Iterator& other) const { return other._index == _index; }
bool operator!=(const Iterator& other) const { return !operator==(other); }
difference_type operator-(Iterator const& other) const { return _index - other._index; }
bool operator<(const Iterator& other) const { return _index < other._index; }
bool operator<=(const Iterator& other) const { return _index <= other._index; }
bool operator>(const Iterator& other) const { return _index > other._index; }
bool operator>=(const Iterator& other) const { return _index >= other._index; }
Iterator& operator-=(difference_type d) { _index -= d; return *this; }
Iterator& operator--() { return operator-=(1); }
Iterator operator--(int) { Iterator i = *this; operator--(); return i; }
Iterator operator-(difference_type d) const { Iterator i = *this; i -= d; return i; }
value_type operator[](difference_type d) const { return FromIndex<Enum>(_index + d); }
value_type operator*() const { return operator[](0); }
private:
difference_type _index;
};
Iterator& operator+=(difference_type d) { _index += d; return *this; }
Iterator& operator++() { return operator+=(1); }
Iterator operator++(int) { Iterator i = *this; operator++(); return i; }
Iterator operator+(difference_type d) const { Iterator i = *this; i += d; return i; }
template <typename Enum>
static Iterator<Enum> Begin() { return Iterator<Enum>(0); }
Iterator& operator-=(difference_type d) { _index -= d; return *this; }
Iterator& operator--() { return operator-=(1); }
Iterator operator--(int) { Iterator i = *this; operator--(); return i; }
Iterator operator-(difference_type d) const { Iterator i = *this; i -= d; return i; }
template <typename Enum>
static Iterator<Enum> End() { return Iterator<Enum>(); }
private:
difference_type _index;
};
template <typename Enum>
static Acore::IteratorPair<Iterator<Enum>> Iterate() { return { Begin<Enum>(), End<Enum>() }; }
template <typename Enum>
static Iterator<Enum> Begin() { return Iterator<Enum>(0); }
template <typename Enum>
static char const* ToConstant(Enum value) { return ToString(value).Constant; }
template <typename Enum>
static Iterator<Enum> End() { return Iterator<Enum>(); }
template <typename Enum>
static char const* ToTitle(Enum value) { return ToString(value).Title; }
template <typename Enum>
static Acore::IteratorPair<Iterator<Enum>> Iterate() { return { Begin<Enum>(), End<Enum>() }; }
template <typename Enum>
static char const* ToDescription(Enum value) { return ToString(value).Description; }
template <typename Enum>
static char const* ToConstant(Enum value) { return ToString(value).Constant; }
template <typename Enum>
static char const* ToTitle(Enum value) { return ToString(value).Title; }
template <typename Enum>
static char const* ToDescription(Enum value) { return ToString(value).Description; }
};
#endif

View File

@@ -41,10 +41,14 @@ namespace Acore::Impl::StringConvertImpl
str.remove_prefix(2);
}
else
{
base = 10;
}
if (str.empty())
{
return std::nullopt;
}
}
char const* const start = str.data();
@@ -53,14 +57,18 @@ namespace Acore::Impl::StringConvertImpl
T val;
std::from_chars_result const res = std::from_chars(start, end, val, base);
if ((res.ptr == end) && (res.ec == std::errc()))
{
return val;
}
else
{
return std::nullopt;
}
}
static std::string ToString(T val)
{
std::string buf(20,'\0'); /* 2^64 is 20 decimal characters, -(2^63) is 20 including the sign */
std::string buf(20, '\0'); /* 2^64 is 20 decimal characters, -(2^63) is 20 including the sign */
char* const start = buf.data();
char* const end = (start + buf.length());
std::to_chars_result const res = std::to_chars(start, end, val);
@@ -84,13 +92,17 @@ namespace Acore::Impl::StringConvertImpl
static Optional<uint64> FromString(std::string_view str, int base = 10)
{
if (str.empty())
{
return std::nullopt;
}
try
{
size_t n;
uint64 val = std::stoull(std::string(str), &n, base);
if (n != str.length())
{
return std::nullopt;
}
return val;
}
catch (...) { return std::nullopt; }
@@ -107,13 +119,18 @@ namespace Acore::Impl::StringConvertImpl
{
static Optional<int64> FromString(std::string_view str, int base = 10)
{
try {
try
{
if (str.empty())
{
return std::nullopt;
}
size_t n;
int64 val = std::stoll(std::string(str), &n, base);
if (n != str.length())
{
return std::nullopt;
}
return val;
}
catch (...) { return std::nullopt; }
@@ -134,17 +151,25 @@ namespace Acore::Impl::StringConvertImpl
if (strict)
{
if (str == "1")
{
return true;
}
if (str == "0")
{
return false;
}
return std::nullopt;
}
else
{
if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true"))
{
return true;
}
if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false"))
{
return false;
}
return std::nullopt;
}
}
@@ -162,7 +187,9 @@ namespace Acore::Impl::StringConvertImpl
static Optional<T> FromString(std::string_view str, std::chars_format fmt = std::chars_format())
{
if (str.empty())
{
return std::nullopt;
}
if (fmt == std::chars_format())
{
@@ -172,10 +199,14 @@ namespace Acore::Impl::StringConvertImpl
str.remove_prefix(2);
}
else
{
fmt = std::chars_format::general;
}
if (str.empty())
{
return std::nullopt;
}
}
char const* const start = str.data();
@@ -184,20 +215,30 @@ namespace Acore::Impl::StringConvertImpl
T val;
std::from_chars_result const res = std::from_chars(start, end, val, fmt);
if ((res.ptr == end) && (res.ec == std::errc()))
{
return val;
}
else
{
return std::nullopt;
}
}
// this allows generic converters for all numeric types (easier templating!)
static Optional<T> FromString(std::string_view str, int base)
{
if (base == 16)
{
return FromString(str, std::chars_format::hex);
}
else if (base == 10)
{
return FromString(str, std::chars_format::general);
}
else
{
return FromString(str, std::chars_format());
}
}
static std::string ToString(T val)
@@ -212,22 +253,31 @@ namespace Acore::Impl::StringConvertImpl
{
static Optional<T> FromString(std::string_view str, int base = 0)
{
try {
try
{
if (str.empty())
{
return std::nullopt;
}
if ((base == 10) && StringEqualI(str.substr(0, 2), "0x"))
{
return std::nullopt;
}
std::string tmp;
if (base == 16)
{
tmp.append("0x");
}
tmp.append(str);
size_t n;
T val = static_cast<T>(std::stold(tmp, &n));
if (n != tmp.length())
{
return std::nullopt;
}
return val;
}
catch (...) { return std::nullopt; }

View File

@@ -13,19 +13,26 @@ Str Acore::String::Trim(const Str& s, const std::locale& loc /*= std::locale()*/
typename Str::const_iterator end = s.end();
while (first != end && std::isspace(*first, loc))
{
++first;
}
if (first == end)
{
return Str();
}
typename Str::const_iterator last = end;
do
{
--last;
while (std::isspace(*last, loc));
} while (std::isspace(*last, loc));
if (first != s.begin() || last + 1 != end)
{
return Str(first, last + 1);
}
return s;
}

View File

@@ -65,7 +65,9 @@ void TaskScheduler::Dispatch(success_t const& callback)
{
// If the validation failed abort the dispatching here.
if (!_predicate())
{
return;
}
// Process all asyncs
while (!_asyncHolder.empty())
@@ -75,13 +77,17 @@ void TaskScheduler::Dispatch(success_t const& callback)
// If the validation failed abort the dispatching here.
if (!_predicate())
{
return;
}
}
while (!_task_holder.IsEmpty())
{
if (_task_holder.First()->_end > _now)
{
break;
}
// Perfect forward the context to the handler
// Use weak references to catch destruction before callbacks.
@@ -92,7 +98,9 @@ void TaskScheduler::Dispatch(success_t const& callback)
// If the validation failed abort the dispatching here.
if (!_predicate())
{
return;
}
}
// On finish call the final callback
@@ -125,9 +133,13 @@ void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)
{
for (auto itr = container.begin(); itr != container.end();)
if (filter(*itr))
{
itr = container.erase(itr);
}
else
{
++itr;
}
}
void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
@@ -140,7 +152,9 @@ void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)
itr = container.erase(itr);
}
else
{
++itr;
}
container.insert(cache.begin(), cache.end());
}
@@ -153,7 +167,9 @@ bool TaskScheduler::TaskQueue::IsEmpty() const
TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
{
if (auto const owner = _owner.lock())
{
apply(*owner);
}
return *this;
}

View File

@@ -292,7 +292,9 @@ public:
return true;
}
else
{
return false;
}
});
return *this;
}
@@ -340,7 +342,9 @@ public:
return true;
}
else
{
return false;
}
});
return *this;
}

View File

@@ -30,9 +30,13 @@ inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
{
// getMSTime() have limited data range and this is case when it overflow in this tick
if (oldMSTime > newMSTime)
{
return (0xFFFFFFFF - oldMSTime) + newMSTime;
}
else
{
return newMSTime - oldMSTime;
}
}
inline uint32 getMSTimeDiff(uint32 oldMSTime, TimePoint newTime)
@@ -60,7 +64,9 @@ public:
{
_current += diff;
if (_current < 0)
{
_current = 0;
}
}
bool Passed()
@@ -71,7 +77,9 @@ public:
void Reset()
{
if (_current >= _interval)
{
_current %= _interval;
}
}
void SetCurrent(time_t current)
@@ -174,7 +182,9 @@ public:
bool Update(const uint32 diff)
{
if ((i_expireTime -= diff) > 0)
{
return false;
}
i_expireTime += i_period > int32(diff) ? i_period : diff;
return true;

View File

@@ -13,13 +13,17 @@ std::vector<std::string_view> Acore::Tokenize(std::string_view str, char sep, bo
for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start))
{
if (keepEmpty || (start < end))
{
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
}
if (keepEmpty || (start < str.length()))
{
tokens.push_back(str.substr(start));
}
return tokens;
}

View File

@@ -26,7 +26,9 @@ Tokenizer::Tokenizer(const std::string& src, const char sep, uint32 vectorReserv
memcpy(m_str, src.c_str(), src.length() + 1);
if (vectorReserve)
{
m_storage.reserve(vectorReserve);
}
char* posold = m_str;
char* posnew = m_str;
@@ -45,7 +47,9 @@ Tokenizer::Tokenizer(const std::string& src, const char sep, uint32 vectorReserv
// Hack like, but the old code accepted these kind of broken strings,
// so changing it would break other things
if (posold != posnew)
{
m_storage.push_back(posold);
}
break;
}
@@ -88,7 +92,9 @@ time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime)
time_t hourLocal = midnightLocal + hour * HOUR;
if (onlyAfterTime && hourLocal <= time)
{
hourLocal += DAY;
}
return hourLocal;
}
@@ -113,17 +119,25 @@ void stripLineInvisibleChars(std::string& str)
else
{
if (wpos != pos)
{
str[wpos++] = str[pos];
}
else
{
++wpos;
}
space = false;
}
}
if (wpos < str.size())
{
str.erase(wpos, str.size());
}
if (str.find("|TInterface") != std::string::npos)
{
str.clear();
}
}
std::string secsToTimeString(uint64 timeInSecs, bool shortText)
@@ -135,18 +149,28 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText)
std::ostringstream ss;
if (days)
{
ss << days << (shortText ? "d" : " day(s) ");
}
if (hours)
{
ss << hours << (shortText ? "h" : " hour(s) ");
}
if (minutes)
{
ss << minutes << (shortText ? "m" : " minute(s) ");
}
if (secs || (!days && !hours && !minutes) )
{
ss << secs << (shortText ? "s" : " second(s) ");
}
std::string str = ss.str();
if (!shortText && !str.empty() && str[str.size() - 1] == ' ')
{
str.resize(str.size() - 1);
}
return str;
}
@@ -158,7 +182,9 @@ int32 MoneyStringToMoney(const std::string& moneyString)
if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 ||
std::count(moneyString.begin(), moneyString.end(), 's') == 1 ||
std::count(moneyString.begin(), moneyString.end(), 'c') == 1))
return 0; // Bad format
{
return 0; // Bad format
}
Tokenizer tokens(moneyString, ' ');
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
@@ -168,15 +194,23 @@ int32 MoneyStringToMoney(const std::string& moneyString)
size_t sCount = std::count(tokenString.begin(), tokenString.end(), 's');
size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c');
if (gCount + sCount + cCount != 1)
{
return 0;
}
uint32 amount = atoi(*itr);
if (gCount == 1)
{
money += amount * 100 * 100;
}
else if (sCount == 1)
{
money += amount * 100;
}
else if (cCount == 1)
{
money += amount;
}
}
return money;
@@ -257,7 +291,9 @@ std::string TimeToHumanReadable(time_t t)
bool IsIPAddress(char const* ipaddress)
{
if (!ipaddress)
{
return false;
}
// Let the big boys do it.
// Drawback: all valid ip address formats are recognized e.g.: 12.23, 121234, 0xABCD)
@@ -275,7 +311,9 @@ bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_
{
uint32 mask = subnetMask.get_ip_address();
if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
{
return true;
}
return false;
}
@@ -284,7 +322,9 @@ uint32 CreatePIDFile(std::string const& filename)
{
FILE* pid_file = fopen(filename.c_str(), "w");
if (pid_file == nullptr)
{
return 0;
}
uint32 pid = GetPID();
@@ -324,7 +364,9 @@ void utf8truncate(std::string& utf8str, size_t len)
{
size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
if (wlen <= len)
{
return;
}
std::wstring wstr;
wstr.resize(wlen);
@@ -365,7 +407,9 @@ bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
wsize = 0;
}
else
{
wsize = 0;
}
return false;
}
@@ -451,7 +495,9 @@ std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension)
{
// supported only Cyrillic cases
if (wname.empty() || !isCyrillicCharacter(wname[0]) || declension > 5)
{
return wname;
}
// Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
static std::wstring const a_End = { wchar_t(0x0430), wchar_t(0x0000) };
@@ -488,10 +534,14 @@ std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension)
std::wstring const& ending = **itr;
std::size_t const endLen = ending.length();
if (!(endLen <= thisLen))
{
continue;
}
if (wname.substr(thisLen - endLen, thisLen) == ending)
{
return wname.substr(0, thisLen - endLen);
}
}
return wname;
@@ -502,7 +552,9 @@ bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
std::wstring wstr;
if (!Utf8toWStr(utf8str, wstr))
{
return false;
}
conStr.resize(wstr.size());
CharToOemBuffW(&wstr[0], &conStr[0], wstr.size());
@@ -534,13 +586,17 @@ bool Utf8FitTo(const std::string& str, std::wstring const& search)
std::wstring temp;
if (!Utf8toWStr(str, temp))
{
return false;
}
// converting to lower case
wstrToLower(temp);
if (temp.find(search) == std::wstring::npos)
{
return false;
}
return true;
}
@@ -562,7 +618,9 @@ void vutf8printf(FILE* out, const char* str, va_list* ap)
size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap);
//vsnprintf returns -1 if the buffer is too small
if (temp_len == size_t(-1))
{
temp_len = 32 * 1024 - 1;
}
size_t wtemp_len = 32 * 1024 - 1;
Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
@@ -578,7 +636,9 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String)
{
std::wstring wstr;
if (!Utf8toWStr(utf8String, wstr))
{
return false;
}
std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin);

View File

@@ -74,7 +74,9 @@ std::string TimeToHumanReadable(time_t t);
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
{
if (val == -100.0f) // prevent set var to zero
{
val = -99.99f;
}
var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
}
@@ -125,60 +127,100 @@ void utf8truncate(std::string& utf8str, size_t len);
inline bool isBasicLatinCharacter(wchar_t wchar)
{
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
{
return true;
}
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
{
return true;
}
return false;
}
inline bool isExtendedLatinCharacter(wchar_t wchar)
{
if (isBasicLatinCharacter(wchar))
{
return true;
}
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
{
return true;
}
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
{
return true;
}
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
{
return true;
}
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
{
return true;
}
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
{
return true;
}
if (wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
{
return true;
}
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
{
return true;
}
return false;
}
inline bool isCyrillicCharacter(wchar_t wchar)
{
if (wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
{
return true;
}
if (wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
{
return true;
}
return false;
}
inline bool isEastAsianCharacter(wchar_t wchar)
{
if (wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo
{
return true;
}
if (wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana
{
return true;
}
if (wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo
{
return true;
}
if (wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext.
{
return true;
}
if (wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A
{
return true;
}
if (wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs
{
return true;
}
if (wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables
{
return true;
}
if (wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms
{
return true;
}
return false;
}
@@ -196,7 +238,9 @@ inline bool isNumeric(char const* str)
{
for (char const* c = str; *c; ++c)
if (!isNumeric(*c))
{
return false;
}
return true;
}
@@ -210,7 +254,9 @@ inline bool isBasicLatinString(const std::wstring& wstr, bool numericOrSpace)
{
for (wchar_t i : wstr)
if (!isBasicLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
{
return false;
}
return true;
}
@@ -218,7 +264,9 @@ inline bool isExtendedLatinString(const std::wstring& wstr, bool numericOrSpace)
{
for (wchar_t i : wstr)
if (!isExtendedLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
{
return false;
}
return true;
}
@@ -226,7 +274,9 @@ inline bool isCyrillicString(const std::wstring& wstr, bool numericOrSpace)
{
for (wchar_t i : wstr)
if (!isCyrillicCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
{
return false;
}
return true;
}
@@ -234,29 +284,45 @@ inline bool isEastAsianString(const std::wstring& wstr, bool numericOrSpace)
{
for (wchar_t i : wstr)
if (!isEastAsianCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
{
return false;
}
return true;
}
inline wchar_t wcharToUpper(wchar_t wchar)
{
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
{
return wchar_t(uint16(wchar) - 0x0020);
}
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
{
return wchar_t(0x1E9E);
}
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
{
return wchar_t(uint16(wchar) - 0x0020);
}
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
{
return wchar_t(uint16(wchar) - 0x0020);
}
if (wchar >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
{
if (wchar % 2 == 1)
{
return wchar_t(uint16(wchar) - 0x0001);
}
}
if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
{
return wchar_t(uint16(wchar) - 0x0020);
}
if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
{
return wchar_t(0x0401);
}
return wchar;
}
@@ -269,22 +335,36 @@ inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
inline wchar_t wcharToLower(wchar_t wchar)
{
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
{
return wchar_t(uint16(wchar) + 0x0020);
}
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
{
return wchar_t(uint16(wchar) + 0x0020);
}
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
{
return wchar_t(uint16(wchar) + 0x0020);
}
if (wchar >= 0x0100 && wchar <= 0x012E) // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0)
{
if (wchar % 2 == 0)
{
return wchar_t(uint16(wchar) + 0x0001);
}
}
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
{
return wchar_t(0x00DF);
}
if (wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO
{
return wchar_t(0x0451);
}
if (wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
{
return wchar_t(uint16(wchar) + 0x0020);
}
return wchar;
}
@@ -418,9 +498,13 @@ public:
for (uint8 i = 3; i > 0; --i)
{
if (part[i - 1] < right.part[i - 1])
{
return true;
}
else if (part[i - 1] > right.part[i - 1])
{
return false;
}
}
return false;
}