mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
refactor(Core/Misc): add braces and impove codestyle (#6402)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace VMAP
|
||||
VMapManager2* VMapFactory::createOrGetVMapManager()
|
||||
{
|
||||
if (!gVMapManager)
|
||||
{
|
||||
gVMapManager = new VMapManager2();
|
||||
}
|
||||
|
||||
return gVMapManager;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) { }
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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); }
|
||||
}
|
||||
|
||||
@@ -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", " ");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
);
|
||||
|
||||
if (status == ARGON2_OK)
|
||||
{
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 = { };
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = { };
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -115,7 +115,9 @@ public:
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return iSize;
|
||||
}
|
||||
}
|
||||
|
||||
void incSize() { ++iSize; }
|
||||
|
||||
@@ -35,7 +35,9 @@ public:
|
||||
{
|
||||
ASSERT(fromObj); // fromObj MUST not be nullptr
|
||||
if (isValid())
|
||||
{
|
||||
unlink();
|
||||
}
|
||||
if (toObj != nullptr)
|
||||
{
|
||||
iRefTo = toObj;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)...));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -22,7 +22,9 @@ namespace Acore
|
||||
void decReference()
|
||||
{
|
||||
if (!--m_refs)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::atomic_long m_refs;
|
||||
|
||||
@@ -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_];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
@@ -340,7 +342,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user