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)
|
inline boost::asio::ip::address_v4 GetDefaultNetmaskV4(boost::asio::ip::address_v4 const& networkAddress)
|
||||||
{
|
{
|
||||||
if ((address_to_uint(networkAddress) & 0x80000000) == 0)
|
if ((address_to_uint(networkAddress) & 0x80000000) == 0)
|
||||||
|
{
|
||||||
return boost::asio::ip::address_v4(0xFF000000);
|
return boost::asio::ip::address_v4(0xFF000000);
|
||||||
|
}
|
||||||
if ((address_to_uint(networkAddress) & 0xC0000000) == 0x80000000)
|
if ((address_to_uint(networkAddress) & 0xC0000000) == 0x80000000)
|
||||||
|
{
|
||||||
return boost::asio::ip::address_v4(0xFFFF0000);
|
return boost::asio::ip::address_v4(0xFFFF0000);
|
||||||
|
}
|
||||||
if ((address_to_uint(networkAddress) & 0xE0000000) == 0xC0000000)
|
if ((address_to_uint(networkAddress) & 0xE0000000) == 0xC0000000)
|
||||||
|
{
|
||||||
return boost::asio::ip::address_v4(0xFFFFFF00);
|
return boost::asio::ip::address_v4(0xFFFFFF00);
|
||||||
|
}
|
||||||
return boost::asio::ip::address_v4(0xFFFFFFFF);
|
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
|
// perform quick consistency checks
|
||||||
G3D::Vector3 d( gridBox.hi - gridBox.lo );
|
G3D::Vector3 d( gridBox.hi - gridBox.lo );
|
||||||
if (d.x < 0 || d.y < 0 || d.z < 0)
|
if (d.x < 0 || d.y < 0 || d.z < 0)
|
||||||
|
{
|
||||||
throw std::logic_error("negative node extents");
|
throw std::logic_error("negative node extents");
|
||||||
|
}
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[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
|
// stay left
|
||||||
i++;
|
i++;
|
||||||
if (clipL < maxb)
|
if (clipL < maxb)
|
||||||
|
{
|
||||||
clipL = maxb;
|
clipL = maxb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -86,7 +90,9 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
|
|||||||
dat.indices[right] = t;
|
dat.indices[right] = t;
|
||||||
right--;
|
right--;
|
||||||
if (clipR > minb)
|
if (clipR > minb)
|
||||||
|
{
|
||||||
clipR = minb;
|
clipR = minb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nodeL = std::min(nodeL, minb);
|
nodeL = std::min(nodeL, minb);
|
||||||
nodeR = std::max(nodeR, maxb);
|
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);
|
tempTree.push_back(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
nextIndex -= 3;
|
nextIndex -= 3;
|
||||||
|
}
|
||||||
// allocate right node
|
// allocate right node
|
||||||
if (nr > 0)
|
if (nr > 0)
|
||||||
{
|
{
|
||||||
@@ -233,13 +241,21 @@ void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildDat
|
|||||||
nodeBoxR.lo[axis] = clipR;
|
nodeBoxR.lo[axis] = clipR;
|
||||||
// recurse
|
// recurse
|
||||||
if (nl > 0)
|
if (nl > 0)
|
||||||
|
{
|
||||||
subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
|
subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
stats.updateLeaf(depth + 1, 0);
|
stats.updateLeaf(depth + 1, 0);
|
||||||
|
}
|
||||||
if (nr > 0)
|
if (nr > 0)
|
||||||
|
{
|
||||||
subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
|
subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
stats.updateLeaf(depth + 1, 0);
|
stats.updateLeaf(depth + 1, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BIH::writeToFile(FILE* wf) const
|
bool BIH::writeToFile(FILE* wf) const
|
||||||
|
|||||||
@@ -90,11 +90,15 @@ public:
|
|||||||
BuildStats stats;
|
BuildStats stats;
|
||||||
buildHierarchy(tempTree, dat, stats);
|
buildHierarchy(tempTree, dat, stats);
|
||||||
if (printStats)
|
if (printStats)
|
||||||
|
{
|
||||||
stats.printStats();
|
stats.printStats();
|
||||||
|
}
|
||||||
|
|
||||||
objects.resize(dat.numPrims);
|
objects.resize(dat.numPrims);
|
||||||
for (uint32 i = 0; i < dat.numPrims; ++i)
|
for (uint32 i = 0; i < dat.numPrims; ++i)
|
||||||
|
{
|
||||||
objects[i] = dat.indices[i];
|
objects[i] = dat.indices[i];
|
||||||
|
}
|
||||||
//nObjects = dat.numPrims;
|
//nObjects = dat.numPrims;
|
||||||
tree = tempTree;
|
tree = tempTree;
|
||||||
delete[] dat.primBound;
|
delete[] dat.primBound;
|
||||||
@@ -118,20 +122,30 @@ public:
|
|||||||
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
|
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
|
||||||
float t2 = (bounds.high()[i] - org[i]) * invDir[i];
|
float t2 = (bounds.high()[i] - org[i]) * invDir[i];
|
||||||
if (t1 > t2)
|
if (t1 > t2)
|
||||||
|
{
|
||||||
std::swap(t1, t2);
|
std::swap(t1, t2);
|
||||||
|
}
|
||||||
if (t1 > intervalMin)
|
if (t1 > intervalMin)
|
||||||
|
{
|
||||||
intervalMin = t1;
|
intervalMin = t1;
|
||||||
|
}
|
||||||
if (t2 < intervalMax || intervalMax < 0.f)
|
if (t2 < intervalMax || intervalMax < 0.f)
|
||||||
|
{
|
||||||
intervalMax = t2;
|
intervalMax = t2;
|
||||||
|
}
|
||||||
// intervalMax can only become smaller for other axis,
|
// intervalMax can only become smaller for other axis,
|
||||||
// and intervalMin only larger respectively, so stop early
|
// and intervalMin only larger respectively, so stop early
|
||||||
if (intervalMax <= 0 || intervalMin >= maxDist)
|
if (intervalMax <= 0 || intervalMin >= maxDist)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intervalMin > intervalMax)
|
if (intervalMin > intervalMax)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
intervalMin = std::max(intervalMin, 0.f);
|
intervalMin = std::max(intervalMin, 0.f);
|
||||||
intervalMax = std::min(intervalMax, maxDist);
|
intervalMax = std::min(intervalMax, maxDist);
|
||||||
|
|
||||||
@@ -174,7 +188,9 @@ public:
|
|||||||
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||||
// ray passes between clip zones
|
// ray passes between clip zones
|
||||||
if (tf < intervalMin && tb > intervalMax)
|
if (tf < intervalMin && tb > intervalMax)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
int back = offset + offsetBack3[axis];
|
int back = offset + offsetBack3[axis];
|
||||||
node = back;
|
node = back;
|
||||||
// ray passes through far node only
|
// ray passes through far node only
|
||||||
@@ -207,7 +223,7 @@ public:
|
|||||||
while (n > 0)
|
while (n > 0)
|
||||||
{
|
{
|
||||||
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirstHit);
|
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirstHit);
|
||||||
if (stopAtFirstHit && hit) return;
|
if (stopAtFirstHit && hit) { return; }
|
||||||
--n;
|
--n;
|
||||||
++offset;
|
++offset;
|
||||||
}
|
}
|
||||||
@@ -217,14 +233,18 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (axis > 2)
|
if (axis > 2)
|
||||||
return; // should not happen
|
{
|
||||||
|
return; // should not happen
|
||||||
|
}
|
||||||
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
|
||||||
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
|
||||||
node = offset;
|
node = offset;
|
||||||
intervalMin = (tf >= intervalMin) ? tf : intervalMin;
|
intervalMin = (tf >= intervalMin) ? tf : intervalMin;
|
||||||
intervalMax = (tb <= intervalMax) ? tb : intervalMax;
|
intervalMax = (tb <= intervalMax) ? tb : intervalMax;
|
||||||
if (intervalMin > intervalMax)
|
if (intervalMin > intervalMax)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} // traversal loop
|
} // traversal loop
|
||||||
@@ -232,12 +252,16 @@ public:
|
|||||||
{
|
{
|
||||||
// stack is empty?
|
// stack is empty?
|
||||||
if (stackPos == 0)
|
if (stackPos == 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// move back up the stack
|
// move back up the stack
|
||||||
stackPos--;
|
stackPos--;
|
||||||
intervalMin = stack[stackPos].tnear;
|
intervalMin = stack[stackPos].tnear;
|
||||||
if (maxDist < intervalMin)
|
if (maxDist < intervalMin)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
node = stack[stackPos].node;
|
node = stack[stackPos].node;
|
||||||
intervalMax = stack[stackPos].tfar;
|
intervalMax = stack[stackPos].tfar;
|
||||||
break;
|
break;
|
||||||
@@ -249,7 +273,9 @@ public:
|
|||||||
void intersectPoint(const G3D::Vector3& p, IsectCallback& intersectCallback) const
|
void intersectPoint(const G3D::Vector3& p, IsectCallback& intersectCallback) const
|
||||||
{
|
{
|
||||||
if (!bounds.contains(p))
|
if (!bounds.contains(p))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StackNode stack[MAX_STACK_SIZE];
|
StackNode stack[MAX_STACK_SIZE];
|
||||||
int stackPos = 0;
|
int stackPos = 0;
|
||||||
@@ -272,7 +298,9 @@ public:
|
|||||||
float tr = intBitsToFloat(tree[node + 2]);
|
float tr = intBitsToFloat(tree[node + 2]);
|
||||||
// point is between clip zones
|
// point is between clip zones
|
||||||
if (tl < p[axis] && tr > p[axis])
|
if (tl < p[axis] && tr > p[axis])
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
int right = offset + 3;
|
int right = offset + 3;
|
||||||
node = right;
|
node = right;
|
||||||
// point is in right node only
|
// point is in right node only
|
||||||
@@ -308,19 +336,25 @@ public:
|
|||||||
else // BVH2 node (empty space cut off left and right)
|
else // BVH2 node (empty space cut off left and right)
|
||||||
{
|
{
|
||||||
if (axis > 2)
|
if (axis > 2)
|
||||||
return; // should not happen
|
{
|
||||||
|
return; // should not happen
|
||||||
|
}
|
||||||
float tl = intBitsToFloat(tree[node + 1]);
|
float tl = intBitsToFloat(tree[node + 1]);
|
||||||
float tr = intBitsToFloat(tree[node + 2]);
|
float tr = intBitsToFloat(tree[node + 2]);
|
||||||
node = offset;
|
node = offset;
|
||||||
if (tl > p[axis] || tr < p[axis])
|
if (tl > p[axis] || tr < p[axis])
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} // traversal loop
|
} // traversal loop
|
||||||
|
|
||||||
// stack is empty?
|
// stack is empty?
|
||||||
if (stackPos == 0)
|
if (stackPos == 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// move back up the stack
|
// move back up the stack
|
||||||
stackPos--;
|
stackPos--;
|
||||||
node = stack[stackPos].node;
|
node = stack[stackPos].node;
|
||||||
@@ -366,7 +400,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
BuildStats()
|
BuildStats()
|
||||||
{
|
{
|
||||||
for (int & i : numLeavesN) i = 0;
|
for (int& i : numLeavesN) { i = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateInner() { numNodes++; }
|
void updateInner() { numNodes++; }
|
||||||
|
|||||||
@@ -28,9 +28,13 @@ class BIHWrap
|
|||||||
bool operator() (const G3D::Ray& ray, uint32 idx, float& maxDist, bool stopAtFirstHit)
|
bool operator() (const G3D::Ray& ray, uint32 idx, float& maxDist, bool stopAtFirstHit)
|
||||||
{
|
{
|
||||||
if (idx >= objects_size)
|
if (idx >= objects_size)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (const T* obj = objects[idx])
|
if (const T* obj = objects[idx])
|
||||||
|
{
|
||||||
return _callback(ray, *obj, maxDist, stopAtFirstHit);
|
return _callback(ray, *obj, maxDist, stopAtFirstHit);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,9 +42,13 @@ class BIHWrap
|
|||||||
void operator() (const G3D::Vector3& p, uint32 idx)
|
void operator() (const G3D::Vector3& p, uint32 idx)
|
||||||
{
|
{
|
||||||
if (idx >= objects_size)
|
if (idx >= objects_size)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (const T* obj = objects[idx])
|
if (const T* obj = objects[idx])
|
||||||
|
{
|
||||||
_callback(p, *obj);
|
_callback(p, *obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,15 +75,21 @@ public:
|
|||||||
uint32 Idx = 0;
|
uint32 Idx = 0;
|
||||||
const T* temp;
|
const T* temp;
|
||||||
if (m_obj2Idx.getRemove(&obj, temp, Idx))
|
if (m_obj2Idx.getRemove(&obj, temp, Idx))
|
||||||
|
{
|
||||||
m_objects[Idx] = nullptr;
|
m_objects[Idx] = nullptr;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
m_objects_to_push.remove(&obj);
|
m_objects_to_push.remove(&obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void balance()
|
void balance()
|
||||||
{
|
{
|
||||||
if (unbalanced_times == 0)
|
if (unbalanced_times == 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unbalanced_times = 0;
|
unbalanced_times = 0;
|
||||||
m_objects.fastClear();
|
m_objects.fastClear();
|
||||||
|
|||||||
@@ -72,14 +72,18 @@ struct DynTreeImpl : public ParentTree
|
|||||||
void update(uint32 difftime)
|
void update(uint32 difftime)
|
||||||
{
|
{
|
||||||
if (!size())
|
if (!size())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rebalance_timer.Update(difftime);
|
rebalance_timer.Update(difftime);
|
||||||
if (rebalance_timer.Passed())
|
if (rebalance_timer.Passed())
|
||||||
{
|
{
|
||||||
rebalance_timer.Reset(CHECK_TREE_PERIOD);
|
rebalance_timer.Reset(CHECK_TREE_PERIOD);
|
||||||
if (unbalanced_times > 0)
|
if (unbalanced_times > 0)
|
||||||
|
{
|
||||||
balance();
|
balance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +137,9 @@ struct DynamicTreeIntersectionCallback
|
|||||||
{
|
{
|
||||||
bool result = obj.intersectRay(r, distance, stopAtFirstHit, phase_mask);
|
bool result = obj.intersectRay(r, distance, stopAtFirstHit, phase_mask);
|
||||||
if (result)
|
if (result)
|
||||||
|
{
|
||||||
did_hit = result;
|
did_hit = result;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool didHit() const { return did_hit;}
|
bool didHit() const { return did_hit;}
|
||||||
@@ -146,7 +152,9 @@ bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray&
|
|||||||
DynamicTreeIntersectionCallback callback(phasemask);
|
DynamicTreeIntersectionCallback callback(phasemask);
|
||||||
impl->intersectRay(ray, callback, distance, endPos, false);
|
impl->intersectRay(ray, callback, distance, endPos, false);
|
||||||
if (callback.didHit())
|
if (callback.didHit())
|
||||||
|
{
|
||||||
maxDist = distance;
|
maxDist = distance;
|
||||||
|
}
|
||||||
return callback.didHit();
|
return callback.didHit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,12 +181,18 @@ bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const G3D::Vector3&
|
|||||||
if (modifyDist < 0)
|
if (modifyDist < 0)
|
||||||
{
|
{
|
||||||
if ((resultHit - startPos).magnitude() > -modifyDist)
|
if ((resultHit - startPos).magnitude() > -modifyDist)
|
||||||
|
{
|
||||||
resultHit = resultHit + dir * modifyDist;
|
resultHit = resultHit + dir * modifyDist;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
resultHit = startPos;
|
resultHit = startPos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
resultHit = resultHit + dir * modifyDist;
|
resultHit = resultHit + dir * modifyDist;
|
||||||
|
}
|
||||||
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
@@ -197,7 +211,9 @@ bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, flo
|
|||||||
float maxDist = (v2 - v1).magnitude();
|
float maxDist = (v2 - v1).magnitude();
|
||||||
|
|
||||||
if (!G3D::fuzzyGt(maxDist, 0) )
|
if (!G3D::fuzzyGt(maxDist, 0) )
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
G3D::Ray r(v1, (v2 - v1) / maxDist);
|
G3D::Ray r(v1, (v2 - v1) / maxDist);
|
||||||
DynamicTreeIntersectionCallback callback(phasemask);
|
DynamicTreeIntersectionCallback callback(phasemask);
|
||||||
@@ -214,7 +230,11 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
|
|||||||
impl->intersectZAllignedRay(r, callback, maxSearchDist);
|
impl->intersectZAllignedRay(r, callback, maxSearchDist);
|
||||||
|
|
||||||
if (callback.didHit())
|
if (callback.didHit())
|
||||||
|
{
|
||||||
return v.z - maxSearchDist;
|
return v.z - maxSearchDist;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return -G3D::finf();
|
return -G3D::finf();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public:
|
|||||||
~DynamicMapTree();
|
~DynamicMapTree();
|
||||||
|
|
||||||
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2,
|
[[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,
|
bool getIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
|
||||||
const G3D::Vector3& endPos, float& maxDist) const;
|
const G3D::Vector3& endPos, float& maxDist) const;
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ namespace MMAP
|
|||||||
MMapManager* MMapFactory::createOrGetMMapManager()
|
MMapManager* MMapFactory::createOrGetMMapManager()
|
||||||
{
|
{
|
||||||
if (g_MMapManager == nullptr)
|
if (g_MMapManager == nullptr)
|
||||||
|
{
|
||||||
g_MMapManager = new MMapManager();
|
g_MMapManager = new MMapManager();
|
||||||
|
}
|
||||||
|
|
||||||
return g_MMapManager;
|
return g_MMapManager;
|
||||||
}
|
}
|
||||||
@@ -29,7 +31,9 @@ namespace MMAP
|
|||||||
int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1};
|
int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1};
|
||||||
uint32 i = 0;
|
uint32 i = 0;
|
||||||
while (f[i] >= 0)
|
while (f[i] >= 0)
|
||||||
|
{
|
||||||
forbiddenMaps[f[i++]] = true;
|
forbiddenMaps[f[i++]] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MMapFactory::clear()
|
void MMapFactory::clear()
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ namespace MMAP
|
|||||||
MMapManager::~MMapManager()
|
MMapManager::~MMapManager()
|
||||||
{
|
{
|
||||||
for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
|
for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
|
||||||
|
{
|
||||||
delete i->second;
|
delete i->second;
|
||||||
|
}
|
||||||
|
|
||||||
// by now we should not have maps loaded
|
// by now we should not have maps loaded
|
||||||
// if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
|
// 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
|
// the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
|
||||||
for (const uint32& mapId : mapIds)
|
for (const uint32& mapId : mapIds)
|
||||||
|
{
|
||||||
loadedMMaps.emplace(mapId, nullptr);
|
loadedMMaps.emplace(mapId, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
thread_safe_environment = false;
|
thread_safe_environment = false;
|
||||||
}
|
}
|
||||||
@@ -40,7 +44,9 @@ namespace MMAP
|
|||||||
// return the iterator if found or end() if not found/NULL
|
// return the iterator if found or end() if not found/NULL
|
||||||
MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
|
MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
|
||||||
if (itr != loadedMMaps.cend() && !itr->second)
|
if (itr != loadedMMaps.cend() && !itr->second)
|
||||||
|
{
|
||||||
itr = loadedMMaps.cend();
|
itr = loadedMMaps.cend();
|
||||||
|
}
|
||||||
|
|
||||||
return itr;
|
return itr;
|
||||||
}
|
}
|
||||||
@@ -52,14 +58,20 @@ namespace MMAP
|
|||||||
if (itr != loadedMMaps.end())
|
if (itr != loadedMMaps.end())
|
||||||
{
|
{
|
||||||
if (itr->second)
|
if (itr->second)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (thread_safe_environment)
|
if (thread_safe_environment)
|
||||||
|
{
|
||||||
itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
|
itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
|
ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load and init dtNavMesh - read parameters from file
|
// 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
|
// make sure the mmap is loaded and ready to load tiles
|
||||||
if (!loadMapData(mapId))
|
if (!loadMapData(mapId))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// get this mmap data
|
// get this mmap data
|
||||||
MMapData* mmap = loadedMMaps[mapId];
|
MMapData* mmap = loadedMMaps[mapId];
|
||||||
@@ -243,7 +257,9 @@ namespace MMAP
|
|||||||
uint32 y = (i.first & 0x0000FFFF);
|
uint32 y = (i.first & 0x0000FFFF);
|
||||||
|
|
||||||
if (dtStatusFailed(mmap->navMesh->removeTile(i.second, nullptr, nullptr)))
|
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);
|
LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
--loadedTiles;
|
--loadedTiles;
|
||||||
@@ -289,7 +305,9 @@ namespace MMAP
|
|||||||
{
|
{
|
||||||
MMapDataSet::const_iterator itr = GetMMapData(mapId);
|
MMapDataSet::const_iterator itr = GetMMapData(mapId);
|
||||||
if (itr == loadedMMaps.end())
|
if (itr == loadedMMaps.end())
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return itr->second->navMesh;
|
return itr->second->navMesh;
|
||||||
}
|
}
|
||||||
@@ -298,7 +316,9 @@ namespace MMAP
|
|||||||
{
|
{
|
||||||
MMapDataSet::const_iterator itr = GetMMapData(mapId);
|
MMapDataSet::const_iterator itr = GetMMapData(mapId);
|
||||||
if (itr == loadedMMaps.end())
|
if (itr == loadedMMaps.end())
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
MMapData* mmap = itr->second;
|
MMapData* mmap = itr->second;
|
||||||
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
|
if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
|
||||||
|
|||||||
@@ -40,10 +40,14 @@ namespace MMAP
|
|||||||
~MMapData()
|
~MMapData()
|
||||||
{
|
{
|
||||||
for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
|
for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
|
||||||
|
{
|
||||||
dtFreeNavMeshQuery(i->second);
|
dtFreeNavMeshQuery(i->second);
|
||||||
|
}
|
||||||
|
|
||||||
if (navMesh)
|
if (navMesh)
|
||||||
|
{
|
||||||
dtFreeNavMesh(navMesh);
|
dtFreeNavMesh(navMesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe
|
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ namespace VMAP
|
|||||||
VMapManager2* VMapFactory::createOrGetVMapManager()
|
VMapManager2* VMapFactory::createOrGetVMapManager()
|
||||||
{
|
{
|
||||||
if (!gVMapManager)
|
if (!gVMapManager)
|
||||||
|
{
|
||||||
gVMapManager = new VMapManager2();
|
gVMapManager = new VMapManager2();
|
||||||
|
}
|
||||||
|
|
||||||
return gVMapManager;
|
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
|
// the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
|
||||||
for (const uint32& mapId : mapIds)
|
for (const uint32& mapId : mapIds)
|
||||||
|
{
|
||||||
iInstanceMapTrees.emplace(mapId, nullptr);
|
iInstanceMapTrees.emplace(mapId, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
thread_safe_environment = false;
|
thread_safe_environment = false;
|
||||||
}
|
}
|
||||||
@@ -78,7 +80,9 @@ namespace VMAP
|
|||||||
// return the iterator if found or end() if not found/NULL
|
// return the iterator if found or end() if not found/NULL
|
||||||
InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId);
|
InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId);
|
||||||
if (itr != iInstanceMapTrees.cend() && !itr->second)
|
if (itr != iInstanceMapTrees.cend() && !itr->second)
|
||||||
|
{
|
||||||
itr = iInstanceMapTrees.cend();
|
itr = iInstanceMapTrees.cend();
|
||||||
|
}
|
||||||
|
|
||||||
return itr;
|
return itr;
|
||||||
}
|
}
|
||||||
@@ -99,9 +103,13 @@ namespace VMAP
|
|||||||
if (isMapLoadingEnabled())
|
if (isMapLoadingEnabled())
|
||||||
{
|
{
|
||||||
if (_loadMap(mapId, basePath, x, y))
|
if (_loadMap(mapId, basePath, x, y))
|
||||||
|
{
|
||||||
result = VMAP_LOAD_RESULT_OK;
|
result = VMAP_LOAD_RESULT_OK;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
result = VMAP_LOAD_RESULT_ERROR;
|
result = VMAP_LOAD_RESULT_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -114,10 +122,12 @@ namespace VMAP
|
|||||||
if (instanceTree == iInstanceMapTrees.end())
|
if (instanceTree == iInstanceMapTrees.end())
|
||||||
{
|
{
|
||||||
if (thread_safe_environment)
|
if (thread_safe_environment)
|
||||||
|
{
|
||||||
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first;
|
instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ASSERT(false, "Invalid mapId %u tile [%u, %u] passed to VMapManager2 after startup in thread unsafe environment",
|
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)
|
if (!instanceTree->second)
|
||||||
@@ -167,7 +177,9 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
#if defined(ENABLE_VMAP_CHECKS)
|
#if defined(ENABLE_VMAP_CHECKS)
|
||||||
if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
|
if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
|
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
|
||||||
@@ -232,7 +244,9 @@ namespace VMAP
|
|||||||
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||||
float height = instanceTree->second->getHeight(pos, maxSearchDist);
|
float height = instanceTree->second->getHeight(pos, maxSearchDist);
|
||||||
if (!(height < G3D::finf()))
|
if (!(height < G3D::finf()))
|
||||||
return height = VMAP_INVALID_HEIGHT_VALUE; // No height
|
{
|
||||||
|
return height = VMAP_INVALID_HEIGHT_VALUE; // No height
|
||||||
|
}
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
@@ -278,9 +292,13 @@ namespace VMAP
|
|||||||
ASSERT(floor < std::numeric_limits<float>::max());
|
ASSERT(floor < std::numeric_limits<float>::max());
|
||||||
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
||||||
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (info.hitInstance->GetLiquidLevel(pos, info, level))
|
if (info.hitInstance->GetLiquidLevel(pos, info, level))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct MmapTileHeader
|
|||||||
uint32 mmapVersion{MMAP_VERSION};
|
uint32 mmapVersion{MMAP_VERSION};
|
||||||
uint32 size{0};
|
uint32 size{0};
|
||||||
char usesLiquids{true};
|
char usesLiquids{true};
|
||||||
char padding[3]{};
|
char padding[3] {};
|
||||||
|
|
||||||
MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) { }
|
MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) { }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
bool result = prims[entry].intersectRay(ray, distance, StopAtFirstHit);
|
bool result = prims[entry].intersectRay(ray, distance, StopAtFirstHit);
|
||||||
if (result)
|
if (result)
|
||||||
|
{
|
||||||
hit = true;
|
hit = true;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool didHit() { return hit; }
|
bool didHit() { return hit; }
|
||||||
@@ -62,7 +64,9 @@ namespace VMAP
|
|||||||
LOG_DEBUG("maps", "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
|
LOG_DEBUG("maps", "LocationInfoCallback: trying to intersect '%s'", prims[entry].name.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (prims[entry].GetLocationInfo(point, locInfo))
|
if (prims[entry].GetLocationInfo(point, locInfo))
|
||||||
|
{
|
||||||
result = true;
|
result = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelInstance* prims;
|
ModelInstance* prims;
|
||||||
@@ -133,7 +137,9 @@ namespace VMAP
|
|||||||
MapRayCallback intersectionCallBack(iTreeValues);
|
MapRayCallback intersectionCallBack(iTreeValues);
|
||||||
iTree.intersectRay(pRay, intersectionCallBack, distance, StopAtFirstHit);
|
iTree.intersectRay(pRay, intersectionCallBack, distance, StopAtFirstHit);
|
||||||
if (intersectionCallBack.didHit())
|
if (intersectionCallBack.didHit())
|
||||||
|
{
|
||||||
pMaxDist = distance;
|
pMaxDist = distance;
|
||||||
|
}
|
||||||
return intersectionCallBack.didHit();
|
return intersectionCallBack.didHit();
|
||||||
}
|
}
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -143,17 +149,23 @@ namespace VMAP
|
|||||||
float maxDist = (pos2 - pos1).magnitude();
|
float maxDist = (pos2 - pos1).magnitude();
|
||||||
// return false if distance is over max float, in case of cheater teleporting to the end of the universe
|
// 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))
|
if (maxDist == std::numeric_limits<float>::max() || !std::isfinite(maxDist))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
|
// valid map coords should *never ever* produce float overflow, but this would produce NaNs too
|
||||||
ASSERT(maxDist < std::numeric_limits<float>::max());
|
ASSERT(maxDist < std::numeric_limits<float>::max());
|
||||||
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
// prevent NaN values which can cause BIH intersection to enter infinite loop
|
||||||
if (maxDist < 1e-10f)
|
if (maxDist < 1e-10f)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
// direction with length of 1
|
// direction with length of 1
|
||||||
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1) / maxDist);
|
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1) / maxDist);
|
||||||
if (getIntersectionTime(ray, maxDist, true))
|
if (getIntersectionTime(ray, maxDist, true))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -227,12 +239,16 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
std::string basePath = vmapPath;
|
std::string basePath = vmapPath;
|
||||||
if (basePath.length() > 0 && basePath[basePath.length() - 1] != '/' && basePath[basePath.length() - 1] != '\\')
|
if (basePath.length() > 0 && basePath[basePath.length() - 1] != '/' && basePath[basePath.length() - 1] != '\\')
|
||||||
|
{
|
||||||
basePath.push_back('/');
|
basePath.push_back('/');
|
||||||
|
}
|
||||||
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
|
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
FILE* rf = fopen(fullname.c_str(), "rb");
|
FILE* rf = fopen(fullname.c_str(), "rb");
|
||||||
if (!rf)
|
if (!rf)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// TODO: check magic number when implemented...
|
// TODO: check magic number when implemented...
|
||||||
char tiled;
|
char tiled;
|
||||||
char chunk[8];
|
char chunk[8];
|
||||||
@@ -246,11 +262,15 @@ namespace VMAP
|
|||||||
std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
|
std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
|
||||||
FILE* tf = fopen(tilefile.c_str(), "rb");
|
FILE* tf = fopen(tilefile.c_str(), "rb");
|
||||||
if (!tf)
|
if (!tf)
|
||||||
|
{
|
||||||
success = false;
|
success = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
{
|
||||||
success = false;
|
success = false;
|
||||||
|
}
|
||||||
fclose(tf);
|
fclose(tf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +287,9 @@ namespace VMAP
|
|||||||
std::string fullname = iBasePath + fname;
|
std::string fullname = iBasePath + fname;
|
||||||
FILE* rf = fopen(fullname.c_str(), "rb");
|
FILE* rf = fopen(fullname.c_str(), "rb");
|
||||||
if (!rf)
|
if (!rf)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
char chunk[8];
|
char chunk[8];
|
||||||
char tiled = '\0';
|
char tiled = '\0';
|
||||||
@@ -317,7 +339,9 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
iTreeValues[i->first].setUnloaded();
|
iTreeValues[i->first].setUnloaded();
|
||||||
for (uint32 refCount = 0; refCount < i->second; ++refCount)
|
for (uint32 refCount = 0; refCount < i->second; ++refCount)
|
||||||
|
{
|
||||||
vm->releaseModelInstance(iTreeValues[i->first].name);
|
vm->releaseModelInstance(iTreeValues[i->first].name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iLoadedSpawns.clear();
|
iLoadedSpawns.clear();
|
||||||
iLoadedTiles.clear();
|
iLoadedTiles.clear();
|
||||||
@@ -348,10 +372,14 @@ namespace VMAP
|
|||||||
char chunk[8];
|
char chunk[8];
|
||||||
|
|
||||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
uint32 numSpawns = 0;
|
uint32 numSpawns = 0;
|
||||||
if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
for (uint32 i = 0; i < numSpawns && result; ++i)
|
for (uint32 i = 0; i < numSpawns && result; ++i)
|
||||||
{
|
{
|
||||||
// read model spawns
|
// read model spawns
|
||||||
@@ -362,7 +390,9 @@ namespace VMAP
|
|||||||
// acquire model instance
|
// acquire model instance
|
||||||
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
|
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
|
||||||
if (!model)
|
if (!model)
|
||||||
|
{
|
||||||
LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
|
LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
|
||||||
|
}
|
||||||
|
|
||||||
// update tree
|
// update tree
|
||||||
uint32 referencedVal;
|
uint32 referencedVal;
|
||||||
@@ -386,21 +416,29 @@ namespace VMAP
|
|||||||
++iLoadedSpawns[referencedVal];
|
++iLoadedSpawns[referencedVal];
|
||||||
#if defined(VMAP_DEBUG)
|
#if defined(VMAP_DEBUG)
|
||||||
if (iTreeValues[referencedVal].ID != spawn.ID)
|
if (iTreeValues[referencedVal].ID != spawn.ID)
|
||||||
|
{
|
||||||
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
|
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
|
||||||
|
}
|
||||||
else if (iTreeValues[referencedVal].name != spawn.name)
|
else if (iTreeValues[referencedVal].name != spawn.name)
|
||||||
|
{
|
||||||
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
|
LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID=%u", spawn.ID);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iLoadedTiles[packTileID(tileX, tileY)] = true;
|
iLoadedTiles[packTileID(tileX, tileY)] = true;
|
||||||
fclose(tf);
|
fclose(tf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
iLoadedTiles[packTileID(tileX, tileY)] = false;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,10 +462,14 @@ namespace VMAP
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
char chunk[8];
|
char chunk[8];
|
||||||
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
uint32 numSpawns;
|
uint32 numSpawns;
|
||||||
if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
for (uint32 i = 0; i < numSpawns && result; ++i)
|
for (uint32 i = 0; i < numSpawns && result; ++i)
|
||||||
{
|
{
|
||||||
// read model spawns
|
// read model spawns
|
||||||
@@ -442,11 +484,15 @@ namespace VMAP
|
|||||||
uint32 referencedNode;
|
uint32 referencedNode;
|
||||||
|
|
||||||
if (fread(&referencedNode, sizeof(uint32), 1, tf) != 1)
|
if (fread(&referencedNode, sizeof(uint32), 1, tf) != 1)
|
||||||
|
{
|
||||||
result = false;
|
result = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!iLoadedSpawns.count(referencedNode))
|
if (!iLoadedSpawns.count(referencedNode))
|
||||||
|
{
|
||||||
LOG_ERROR("maps", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
|
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)
|
else if (--iLoadedSpawns[referencedNode] == 0)
|
||||||
{
|
{
|
||||||
iTreeValues[referencedNode].setUnloaded();
|
iTreeValues[referencedNode].setUnloaded();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
bool readChunk(FILE* rf, char* dest, const char* compare, uint32 len)
|
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;
|
return memcmp(dest, compare, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,9 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
bool success = readMapSpawns();
|
bool success = readMapSpawns();
|
||||||
if (!success)
|
if (!success)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// export Map data
|
// export Map data
|
||||||
for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter)
|
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 (entry->second.flags & MOD_M2)
|
||||||
{
|
{
|
||||||
if (!calculateTransformedBound(entry->second))
|
if (!calculateTransformedBound(entry->second))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/
|
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
|
// ===> possibly move this code to StaticMapTree class
|
||||||
std::map<uint32, uint32> modelNodeIdx;
|
std::map<uint32, uint32> modelNodeIdx;
|
||||||
for (uint32 i = 0; i < mapSpawns.size(); ++i)
|
for (uint32 i = 0; i < mapSpawns.size(); ++i)
|
||||||
|
{
|
||||||
modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
|
modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i));
|
||||||
|
}
|
||||||
|
|
||||||
// write map tree file
|
// write map tree file
|
||||||
std::stringstream mapfilename;
|
std::stringstream mapfilename;
|
||||||
@@ -113,16 +119,16 @@ namespace VMAP
|
|||||||
}
|
}
|
||||||
|
|
||||||
//general info
|
//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);
|
uint32 globalTileID = StaticMapTree::packTileID(65, 65);
|
||||||
pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID);
|
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
|
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
|
// Nodes
|
||||||
if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false;
|
if (success && fwrite("NODE", 4, 1, mapfile) != 1) { success = false; }
|
||||||
if (success) success = pTree.writeToFile(mapfile);
|
if (success) { success = pTree.writeToFile(mapfile); }
|
||||||
// global map spawns (WDT), if any (most instances)
|
// 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)
|
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];
|
const ModelSpawn& spawn = map_iter->second->UniqueEntries[tile->second];
|
||||||
if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
|
if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently...
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
uint32 nSpawns = tileEntries.count(tile->first);
|
uint32 nSpawns = tileEntries.count(tile->first);
|
||||||
std::stringstream tilefilename;
|
std::stringstream tilefilename;
|
||||||
tilefilename.fill('0');
|
tilefilename.fill('0');
|
||||||
@@ -151,19 +159,21 @@ namespace VMAP
|
|||||||
if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
|
if (FILE* tilefile = fopen(tilefilename.str().c_str(), "wb"))
|
||||||
{
|
{
|
||||||
// file header
|
// 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
|
// 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
|
// write tile spawns
|
||||||
for (uint32 s = 0; s < nSpawns; ++s)
|
for (uint32 s = 0; s < nSpawns; ++s)
|
||||||
{
|
{
|
||||||
if (s)
|
if (s)
|
||||||
|
{
|
||||||
++tile;
|
++tile;
|
||||||
|
}
|
||||||
const ModelSpawn& spawn2 = map_iter->second->UniqueEntries[tile->second];
|
const ModelSpawn& spawn2 = map_iter->second->UniqueEntries[tile->second];
|
||||||
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
|
success = success && ModelSpawn::writeToFile(tilefile, spawn2);
|
||||||
// MapTree nodes to update when loading tile:
|
// MapTree nodes to update when loading tile:
|
||||||
std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID);
|
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);
|
fclose(tilefile);
|
||||||
}
|
}
|
||||||
@@ -212,11 +222,15 @@ namespace VMAP
|
|||||||
// read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
// read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||||
check = fread(&mapID, sizeof(uint32), 1, dirf);
|
check = fread(&mapID, sizeof(uint32), 1, dirf);
|
||||||
if (check == 0) // EoF...
|
if (check == 0) // EoF...
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
check += fread(&tileX, sizeof(uint32), 1, dirf);
|
check += fread(&tileX, sizeof(uint32), 1, dirf);
|
||||||
check += fread(&tileY, sizeof(uint32), 1, dirf);
|
check += fread(&tileY, sizeof(uint32), 1, dirf);
|
||||||
if (!ModelSpawn::readFromFile(dirf, spawn))
|
if (!ModelSpawn::readFromFile(dirf, spawn))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
MapSpawns* current;
|
MapSpawns* current;
|
||||||
MapData::iterator map_iter = mapData.find(mapID);
|
MapData::iterator map_iter = mapData.find(mapID);
|
||||||
@@ -226,7 +240,9 @@ namespace VMAP
|
|||||||
mapData[mapID] = current = new MapSpawns();
|
mapData[mapID] = current = new MapSpawns();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
current = map_iter->second;
|
current = map_iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
current->UniqueEntries.emplace(spawn.ID, spawn);
|
current->UniqueEntries.emplace(spawn.ID, spawn);
|
||||||
current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
|
current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID));
|
||||||
@@ -249,11 +265,15 @@ namespace VMAP
|
|||||||
|
|
||||||
WorldModel_Raw raw_model;
|
WorldModel_Raw raw_model;
|
||||||
if (!raw_model.Read(modelFilename.c_str()))
|
if (!raw_model.Read(modelFilename.c_str()))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 groups = raw_model.groupsArray.size();
|
uint32 groups = raw_model.groupsArray.size();
|
||||||
if (groups != 1)
|
if (groups != 1)
|
||||||
|
{
|
||||||
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
|
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
AABox modelBound;
|
AABox modelBound;
|
||||||
bool boundEmpty = true;
|
bool boundEmpty = true;
|
||||||
@@ -274,9 +294,13 @@ namespace VMAP
|
|||||||
Vector3 v = modelPosition.transform(vertices[i]);
|
Vector3 v = modelPosition.transform(vertices[i]);
|
||||||
|
|
||||||
if (boundEmpty)
|
if (boundEmpty)
|
||||||
|
{
|
||||||
modelBound = AABox(v, v), boundEmpty = false;
|
modelBound = AABox(v, v), boundEmpty = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
modelBound.merge(v);
|
modelBound.merge(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spawn.iBound = modelBound + spawn.iPos;
|
spawn.iBound = modelBound + spawn.iPos;
|
||||||
@@ -300,12 +324,16 @@ namespace VMAP
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
std::string filename = iSrcDir;
|
std::string filename = iSrcDir;
|
||||||
if (filename.length() > 0)
|
if (filename.length() > 0)
|
||||||
|
{
|
||||||
filename.push_back('/');
|
filename.push_back('/');
|
||||||
|
}
|
||||||
filename.append(pModelFilename);
|
filename.append(pModelFilename);
|
||||||
|
|
||||||
WorldModel_Raw raw_model;
|
WorldModel_Raw raw_model;
|
||||||
if (!raw_model.Read(filename.c_str()))
|
if (!raw_model.Read(filename.c_str()))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// write WorldModel
|
// write WorldModel
|
||||||
WorldModel model;
|
WorldModel model;
|
||||||
@@ -335,11 +363,15 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
|
FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
|
||||||
if (!model_list)
|
if (!model_list)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char ident[8];
|
char ident[8];
|
||||||
if (fread(ident, 1, 8, model_list) != 8 || memcmp(ident, VMAP::RAW_VMAP_MAGIC, 8) != 0)
|
if (fread(ident, 1, 8, model_list) != 8 || memcmp(ident, VMAP::RAW_VMAP_MAGIC, 8) != 0)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
|
FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
|
||||||
if (!model_list_copy)
|
if (!model_list_copy)
|
||||||
@@ -357,12 +389,14 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
if (fread(&displayId, sizeof(uint32), 1, model_list) != 1)
|
if (fread(&displayId, sizeof(uint32), 1, model_list) != 1)
|
||||||
if (feof(model_list)) // EOF flag is only set after failed reading attempt
|
if (feof(model_list)) // EOF flag is only set after failed reading attempt
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (fread(&isWmo, sizeof(uint8), 1, model_list) != 1
|
if (fread(&isWmo, sizeof(uint8), 1, model_list) != 1
|
||||||
|| fread(&name_length, sizeof(uint32), 1, model_list) != 1
|
|| fread(&name_length, sizeof(uint32), 1, model_list) != 1
|
||||||
|| name_length >= sizeof(buff)
|
|| name_length >= sizeof(buff)
|
||||||
|| fread(&buff, sizeof(char), name_length, model_list) != name_length)
|
|| fread(&buff, sizeof(char), name_length, model_list) != name_length)
|
||||||
{
|
{
|
||||||
std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
|
std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
|
||||||
break;
|
break;
|
||||||
@@ -372,7 +406,9 @@ namespace VMAP
|
|||||||
|
|
||||||
WorldModel_Raw raw_model;
|
WorldModel_Raw raw_model;
|
||||||
if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
|
if ( !raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
spawnedModelFiles.insert(model_name);
|
spawnedModelFiles.insert(model_name);
|
||||||
AABox bounds;
|
AABox bounds;
|
||||||
@@ -386,9 +422,13 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
Vector3& v = vertices[i];
|
Vector3& v = vertices[i];
|
||||||
if (boundEmpty)
|
if (boundEmpty)
|
||||||
|
{
|
||||||
bounds = AABox(v, v), boundEmpty = false;
|
bounds = AABox(v, v), boundEmpty = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bounds.merge(v);
|
bounds.merge(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +494,9 @@ namespace VMAP
|
|||||||
READ_OR_RETURN_WITH_DELETE(indexarray, nindexes * sizeof(uint16));
|
READ_OR_RETURN_WITH_DELETE(indexarray, nindexes * sizeof(uint16));
|
||||||
triangles.reserve(nindexes / 3);
|
triangles.reserve(nindexes / 3);
|
||||||
for (uint32 i = 0; i < nindexes; i += 3)
|
for (uint32 i = 0; i < nindexes; i += 3)
|
||||||
|
{
|
||||||
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i + 1], indexarray[i + 2]));
|
triangles.push_back(MeshTriangle(indexarray[i], indexarray[i + 1], indexarray[i + 2]));
|
||||||
|
}
|
||||||
|
|
||||||
delete[] indexarray;
|
delete[] indexarray;
|
||||||
}
|
}
|
||||||
@@ -471,7 +513,9 @@ namespace VMAP
|
|||||||
float* vectorarray = new float[nvectors * 3];
|
float* vectorarray = new float[nvectors * 3];
|
||||||
READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors * sizeof(float) * 3);
|
READ_OR_RETURN_WITH_DELETE(vectorarray, nvectors * sizeof(float) * 3);
|
||||||
for (uint32 i = 0; i < nvectors; ++i)
|
for (uint32 i = 0; i < nvectors; ++i)
|
||||||
|
{
|
||||||
vertexArray.push_back( Vector3(vectorarray + 3 * i) );
|
vertexArray.push_back( Vector3(vectorarray + 3 * i) );
|
||||||
|
}
|
||||||
|
|
||||||
delete[] vectorarray;
|
delete[] vectorarray;
|
||||||
}
|
}
|
||||||
@@ -526,10 +570,14 @@ namespace VMAP
|
|||||||
groupsArray.resize(groups);
|
groupsArray.resize(groups);
|
||||||
bool succeed = true;
|
bool succeed = true;
|
||||||
for (uint32 g = 0; g < groups && succeed; ++g)
|
for (uint32 g = 0; g < groups && succeed; ++g)
|
||||||
|
{
|
||||||
succeed = groupsArray[g].Read(rf);
|
succeed = groupsArray[g].Read(rf);
|
||||||
|
}
|
||||||
|
|
||||||
if (succeed) /// rf will be freed inside Read if the function had any errors.
|
if (succeed) /// rf will be freed inside Read if the function had any errors.
|
||||||
|
{
|
||||||
fclose(rf);
|
fclose(rf);
|
||||||
|
}
|
||||||
return succeed;
|
return succeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,23 +80,23 @@ namespace VMAP
|
|||||||
|
|
||||||
class TileAssembler
|
class TileAssembler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string iDestDir;
|
std::string iDestDir;
|
||||||
std::string iSrcDir;
|
std::string iSrcDir;
|
||||||
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
G3D::Table<std::string, unsigned int > iUniqueNameIds;
|
||||||
MapData mapData;
|
MapData mapData;
|
||||||
std::set<std::string> spawnedModelFiles;
|
std::set<std::string> spawnedModelFiles;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName);
|
||||||
virtual ~TileAssembler();
|
virtual ~TileAssembler();
|
||||||
|
|
||||||
bool convertWorld2();
|
bool convertWorld2();
|
||||||
bool readMapSpawns();
|
bool readMapSpawns();
|
||||||
bool calculateTransformedBound(ModelSpawn &spawn);
|
bool calculateTransformedBound(ModelSpawn& spawn);
|
||||||
void exportGameobjectModels();
|
void exportGameobjectModels();
|
||||||
|
|
||||||
bool convertRawFile(const std::string& pModelFilename);
|
bool convertRawFile(const std::string& pModelFilename);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // VMAP
|
} // VMAP
|
||||||
|
|||||||
@@ -55,14 +55,16 @@ void LoadGameObjectModelList(std::string const& dataPath)
|
|||||||
Vector3 v1, v2;
|
Vector3 v1, v2;
|
||||||
if (fread(&displayId, sizeof(uint32), 1, model_list_file) != 1)
|
if (fread(&displayId, sizeof(uint32), 1, model_list_file) != 1)
|
||||||
if (feof(model_list_file)) // EOF flag is only set after failed reading attempt
|
if (feof(model_list_file)) // EOF flag is only set after failed reading attempt
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (fread(&isWmo, sizeof(uint8), 1, model_list_file) != 1
|
if (fread(&isWmo, sizeof(uint8), 1, model_list_file) != 1
|
||||||
|| fread(&name_length, sizeof(uint32), 1, model_list_file) != 1
|
|| fread(&name_length, sizeof(uint32), 1, model_list_file) != 1
|
||||||
|| name_length >= sizeof(buff)
|
|| name_length >= sizeof(buff)
|
||||||
|| fread(&buff, sizeof(char), name_length, model_list_file) != name_length
|
|| fread(&buff, sizeof(char), name_length, model_list_file) != name_length
|
||||||
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|
||||||
|| fread(&v2, 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);
|
LOG_ERROR("maps", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
|
||||||
fclose(model_list_file);
|
fclose(model_list_file);
|
||||||
@@ -72,7 +74,7 @@ void LoadGameObjectModelList(std::string const& dataPath)
|
|||||||
if (v1.isNaN() || v2.isNaN())
|
if (v1.isNaN() || v2.isNaN())
|
||||||
{
|
{
|
||||||
LOG_ERROR("maps", "File '%s' Model '%s' has invalid v1%s v2%s values!",
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +90,18 @@ void LoadGameObjectModelList(std::string const& dataPath)
|
|||||||
GameObjectModel::~GameObjectModel()
|
GameObjectModel::~GameObjectModel()
|
||||||
{
|
{
|
||||||
if (iModel)
|
if (iModel)
|
||||||
|
{
|
||||||
VMAP::VMapFactory::createOrGetVMapManager()->releaseModelInstance(name);
|
VMAP::VMapFactory::createOrGetVMapManager()->releaseModelInstance(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath)
|
bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath)
|
||||||
{
|
{
|
||||||
ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId());
|
ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId());
|
||||||
if (it == model_list.end())
|
if (it == model_list.end())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
G3D::AABox mdl_box(it->second.bound);
|
G3D::AABox mdl_box(it->second.bound);
|
||||||
// ignore models with no bounds
|
// 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);
|
iModel = VMAP::VMapFactory::createOrGetVMapManager()->acquireModelInstance(dataPath + "vmaps/", it->second.name);
|
||||||
|
|
||||||
if (!iModel)
|
if (!iModel)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
name = it->second.name;
|
name = it->second.name;
|
||||||
iPos = modelOwner->GetPosition();
|
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);
|
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
|
||||||
AABox rotated_bounds;
|
AABox rotated_bounds;
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
||||||
|
}
|
||||||
|
|
||||||
iBound = rotated_bounds + iPos;
|
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
|
bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const
|
||||||
{
|
{
|
||||||
if (!(phasemask & ph_mask) || !owner->IsSpawned())
|
if (!(phasemask & ph_mask) || !owner->IsSpawned())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
float time = ray.intersectionTime(iBound);
|
float time = ray.intersectionTime(iBound);
|
||||||
if (time == G3D::inf())
|
if (time == G3D::inf())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// child bounds are defined in object space:
|
// child bounds are defined in object space:
|
||||||
Vector3 p = iInvRot * (ray.origin() - iPos) * iInvScale;
|
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()
|
bool GameObjectModel::UpdatePosition()
|
||||||
{
|
{
|
||||||
if (!iModel)
|
if (!iModel)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ModelList::const_iterator it = model_list.find(owner->GetDisplayId());
|
ModelList::const_iterator it = model_list.find(owner->GetDisplayId());
|
||||||
if (it == model_list.end())
|
if (it == model_list.end())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
G3D::AABox mdl_box(it->second.bound);
|
G3D::AABox mdl_box(it->second.bound);
|
||||||
|
|
||||||
@@ -200,7 +218,9 @@ bool GameObjectModel::UpdatePosition()
|
|||||||
AABox rotated_bounds;
|
AABox rotated_bounds;
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
rotated_bounds.merge(iRotation * mdl_box.corner(i));
|
||||||
|
}
|
||||||
|
|
||||||
iBound = rotated_bounds + iPos;
|
iBound = rotated_bounds + iPos;
|
||||||
#ifdef SPAWN_CORNERS
|
#ifdef SPAWN_CORNERS
|
||||||
|
|||||||
@@ -65,9 +65,13 @@ namespace VMAP
|
|||||||
|
|
||||||
// M2 files don't contain area info, only WMO files
|
// M2 files don't contain area info, only WMO files
|
||||||
if (flags & MOD_M2)
|
if (flags & MOD_M2)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (!iBound.contains(p))
|
if (!iBound.contains(p))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
// child bounds are defined in object space:
|
// child bounds are defined in object space:
|
||||||
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||||
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
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
|
// M2 files don't contain area info, only WMO files
|
||||||
if (flags & MOD_M2)
|
if (flags & MOD_M2)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (!iBound.contains(p))
|
if (!iBound.contains(p))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// child bounds are defined in object space:
|
// child bounds are defined in object space:
|
||||||
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
|
||||||
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
@@ -147,7 +155,9 @@ namespace VMAP
|
|||||||
if (!check)
|
if (!check)
|
||||||
{
|
{
|
||||||
if (ferror(rf))
|
if (ferror(rf))
|
||||||
|
{
|
||||||
std::cout << "Error reading ModelSpawn!\n";
|
std::cout << "Error reading ModelSpawn!\n";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
|
check += fread(&spawn.adtId, sizeof(uint16), 1, rf);
|
||||||
@@ -202,9 +212,9 @@ namespace VMAP
|
|||||||
}
|
}
|
||||||
uint32 nameLen = spawn.name.length();
|
uint32 nameLen = spawn.name.length();
|
||||||
check += fwrite(&nameLen, sizeof(uint32), 1, wf);
|
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);
|
check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf);
|
||||||
if (check != nameLen) return false;
|
if (check != nameLen) { return false; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ namespace VMAP
|
|||||||
WmoLiquid& WmoLiquid::operator=(const WmoLiquid& other)
|
WmoLiquid& WmoLiquid::operator=(const WmoLiquid& other)
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
}
|
||||||
iTilesX = other.iTilesX;
|
iTilesX = other.iTilesX;
|
||||||
iTilesY = other.iTilesY;
|
iTilesY = other.iTilesY;
|
||||||
iCorner = other.iCorner;
|
iCorner = other.iCorner;
|
||||||
@@ -126,14 +128,18 @@ namespace VMAP
|
|||||||
memcpy(iHeight, other.iHeight, (iTilesX + 1) * (iTilesY + 1)*sizeof(float));
|
memcpy(iHeight, other.iHeight, (iTilesX + 1) * (iTilesY + 1)*sizeof(float));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
iHeight = 0;
|
iHeight = 0;
|
||||||
|
}
|
||||||
if (other.iFlags)
|
if (other.iFlags)
|
||||||
{
|
{
|
||||||
iFlags = new uint8[iTilesX * iTilesY];
|
iFlags = new uint8[iTilesX * iTilesY];
|
||||||
memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
|
memcpy(iFlags, other.iFlags, iTilesX * iTilesY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
iFlags = 0;
|
iFlags = 0;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,16 +148,22 @@ namespace VMAP
|
|||||||
float tx_f = (pos.x - iCorner.x) / LIQUID_TILE_SIZE;
|
float tx_f = (pos.x - iCorner.x) / LIQUID_TILE_SIZE;
|
||||||
uint32 tx = uint32(tx_f);
|
uint32 tx = uint32(tx_f);
|
||||||
if (tx_f < 0.0f || tx >= iTilesX)
|
if (tx_f < 0.0f || tx >= iTilesX)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
float ty_f = (pos.y - iCorner.y) / LIQUID_TILE_SIZE;
|
float ty_f = (pos.y - iCorner.y) / LIQUID_TILE_SIZE;
|
||||||
uint32 ty = uint32(ty_f);
|
uint32 ty = uint32(ty_f);
|
||||||
if (ty_f < 0.0f || ty >= iTilesY)
|
if (ty_f < 0.0f || ty >= iTilesY)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// check if tile shall be used for liquid level
|
// check if tile shall be used for liquid level
|
||||||
// checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
|
// checking for 0x08 *might* be enough, but disabled tiles always are 0x?F:
|
||||||
if ((iFlags[tx + ty * iTilesX] & 0x0F) == 0x0F)
|
if ((iFlags[tx + ty * iTilesX] & 0x0F) == 0x0F)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// (dx, dy) coordinates inside tile, in [0, 1]^2
|
// (dx, dy) coordinates inside tile, in [0, 1]^2
|
||||||
float dx = tx_f - (float)tx;
|
float dx = tx_f - (float)tx;
|
||||||
@@ -234,9 +246,13 @@ namespace VMAP
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
|
{
|
||||||
delete liquid;
|
delete liquid;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
out = liquid;
|
out = liquid;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -255,7 +271,9 @@ namespace VMAP
|
|||||||
vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0)
|
vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0)
|
||||||
{
|
{
|
||||||
if (other.iLiquid)
|
if (other.iLiquid)
|
||||||
|
{
|
||||||
iLiquid = new WmoLiquid(*other.iLiquid);
|
iLiquid = new WmoLiquid(*other.iLiquid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupModel::setMeshData(std::vector<Vector3>& vert, std::vector<MeshTriangle>& tri)
|
void GroupModel::setMeshData(std::vector<Vector3>& vert, std::vector<MeshTriangle>& tri)
|
||||||
@@ -271,43 +289,45 @@ namespace VMAP
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
uint32 chunkSize, count;
|
uint32 chunkSize, count;
|
||||||
|
|
||||||
if (result && fwrite(&iBound, sizeof(G3D::AABox), 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(&iMogpFlags, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false;
|
if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
|
|
||||||
// write vertices
|
// 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();
|
count = vertices.size();
|
||||||
chunkSize = sizeof(uint32) + sizeof(Vector3) * count;
|
chunkSize = sizeof(uint32) + sizeof(Vector3) * count;
|
||||||
if (result && fwrite(&chunkSize, 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 (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||||
|
{
|
||||||
return result;
|
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
|
// 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();
|
count = triangles.size();
|
||||||
chunkSize = sizeof(uint32) + sizeof(MeshTriangle) * count;
|
chunkSize = sizeof(uint32) + sizeof(MeshTriangle) * count;
|
||||||
if (result && fwrite(&chunkSize, 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 (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(&triangles[0], sizeof(MeshTriangle), count, wf) != count) { result = false; }
|
||||||
|
|
||||||
// write mesh BIH
|
// write mesh BIH
|
||||||
if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false;
|
if (result && fwrite("MBIH", 1, 4, wf) != 4) { result = false; }
|
||||||
if (result) result = meshTree.writeToFile(wf);
|
if (result) { result = meshTree.writeToFile(wf); }
|
||||||
|
|
||||||
// write liquid data
|
// 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)
|
if (!iLiquid)
|
||||||
{
|
{
|
||||||
chunkSize = 0;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
chunkSize = iLiquid->GetFileSize();
|
chunkSize = iLiquid->GetFileSize();
|
||||||
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false;
|
if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
if (result) result = iLiquid->writeToFile(wf);
|
if (result) { result = iLiquid->writeToFile(wf); }
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -323,35 +343,39 @@ namespace VMAP
|
|||||||
delete iLiquid;
|
delete iLiquid;
|
||||||
iLiquid = nullptr;
|
iLiquid = nullptr;
|
||||||
|
|
||||||
if (result && fread(&iBound, sizeof(G3D::AABox), 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(&iMogpFlags, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false;
|
if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
|
|
||||||
// read vertices
|
// read vertices
|
||||||
if (result && !readChunk(rf, chunk, "VERT", 4)) 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(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
if (result && fread(&count, 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
|
if (!count) // models without (collision) geometry end here, unsure if they are useful
|
||||||
|
{
|
||||||
return result;
|
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
|
// read triangle mesh
|
||||||
if (result && !readChunk(rf, chunk, "TRIM", 4)) 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(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
if (result && fread(&count, 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) { triangles.resize(count); }
|
||||||
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false;
|
if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) { result = false; }
|
||||||
|
|
||||||
// read mesh BIH
|
// read mesh BIH
|
||||||
if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false;
|
if (result && !readChunk(rf, chunk, "MBIH", 4)) { result = false; }
|
||||||
if (result) result = meshTree.readFromFile(rf);
|
if (result) { result = meshTree.readFromFile(rf); }
|
||||||
|
|
||||||
// write liquid data
|
// write liquid data
|
||||||
if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false;
|
if (result && !readChunk(rf, chunk, "LIQU", 4)) { result = false; }
|
||||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
if (result && chunkSize > 0)
|
if (result && chunkSize > 0)
|
||||||
|
{
|
||||||
result = WmoLiquid::readFromFile(rf, iLiquid);
|
result = WmoLiquid::readFromFile(rf, iLiquid);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +386,7 @@ namespace VMAP
|
|||||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool /*StopAtFirstHit*/)
|
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool /*StopAtFirstHit*/)
|
||||||
{
|
{
|
||||||
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
|
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
|
||||||
if (result) hit = true;
|
if (result) { hit = true; }
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
std::vector<Vector3>::const_iterator vertices;
|
std::vector<Vector3>::const_iterator vertices;
|
||||||
@@ -373,7 +397,9 @@ namespace VMAP
|
|||||||
bool GroupModel::IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const
|
bool GroupModel::IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const
|
||||||
{
|
{
|
||||||
if (triangles.empty())
|
if (triangles.empty())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GModelRayCallback callback(triangles, vertices);
|
GModelRayCallback callback(triangles, vertices);
|
||||||
meshTree.intersectRay(ray, callback, distance, stopAtFirstHit);
|
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
|
bool GroupModel::IsInsideObject(const Vector3& pos, const Vector3& down, float& z_dist) const
|
||||||
{
|
{
|
||||||
if (triangles.empty() || !iBound.contains(pos))
|
if (triangles.empty() || !iBound.contains(pos))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
GModelRayCallback callback(triangles, vertices);
|
GModelRayCallback callback(triangles, vertices);
|
||||||
Vector3 rPos = pos - 0.1f * down;
|
Vector3 rPos = pos - 0.1f * down;
|
||||||
float dist = G3D::inf();
|
float dist = G3D::inf();
|
||||||
G3D::Ray ray(rPos, down);
|
G3D::Ray ray(rPos, down);
|
||||||
bool hit = IntersectRay(ray, dist, false);
|
bool hit = IntersectRay(ray, dist, false);
|
||||||
if (hit)
|
if (hit)
|
||||||
|
{
|
||||||
z_dist = dist - 0.1f;
|
z_dist = dist - 0.1f;
|
||||||
|
}
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const
|
bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const
|
||||||
{
|
{
|
||||||
if (iLiquid)
|
if (iLiquid)
|
||||||
|
{
|
||||||
return iLiquid->GetLiquidHeight(pos, liqHeight);
|
return iLiquid->GetLiquidHeight(pos, liqHeight);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 GroupModel::GetLiquidType() const
|
uint32 GroupModel::GetLiquidType() const
|
||||||
{
|
{
|
||||||
if (iLiquid)
|
if (iLiquid)
|
||||||
|
{
|
||||||
return iLiquid->GetType();
|
return iLiquid->GetType();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +463,7 @@ namespace VMAP
|
|||||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool StopAtFirstHit)
|
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool StopAtFirstHit)
|
||||||
{
|
{
|
||||||
bool result = models[entry].IntersectRay(ray, distance, StopAtFirstHit);
|
bool result = models[entry].IntersectRay(ray, distance, StopAtFirstHit);
|
||||||
if (result) hit = true;
|
if (result) { hit = true; }
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
std::vector<GroupModel>::const_iterator models;
|
std::vector<GroupModel>::const_iterator models;
|
||||||
@@ -441,7 +475,9 @@ namespace VMAP
|
|||||||
// small M2 workaround, maybe better make separate class with virtual intersection funcs
|
// 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
|
// in any case, there's no need to use a bound tree if we only have one submodel
|
||||||
if (groupModels.size() == 1)
|
if (groupModels.size() == 1)
|
||||||
|
{
|
||||||
return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
|
return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit);
|
||||||
|
}
|
||||||
|
|
||||||
WModelRayCallBack isc(groupModels);
|
WModelRayCallBack isc(groupModels);
|
||||||
groupTree.intersectRay(ray, isc, distance, stopAtFirstHit);
|
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
|
bool WorldModel::IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const
|
||||||
{
|
{
|
||||||
if (groupModels.empty())
|
if (groupModels.empty())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
WModelAreaCallback callback(groupModels, down);
|
WModelAreaCallback callback(groupModels, down);
|
||||||
groupTree.intersectPoint(p, callback);
|
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
|
bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const
|
||||||
{
|
{
|
||||||
if (groupModels.empty())
|
if (groupModels.empty())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
WModelAreaCallback callback(groupModels, down);
|
WModelAreaCallback callback(groupModels, down);
|
||||||
groupTree.intersectPoint(p, callback);
|
groupTree.intersectPoint(p, callback);
|
||||||
@@ -525,29 +565,33 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
FILE* wf = fopen(filename.c_str(), "wb");
|
FILE* wf = fopen(filename.c_str(), "wb");
|
||||||
if (!wf)
|
if (!wf)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 chunkSize, count;
|
uint32 chunkSize, count;
|
||||||
bool result = fwrite(VMAP_MAGIC, 1, 8, wf) == 8;
|
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);
|
chunkSize = sizeof(uint32) + sizeof(uint32);
|
||||||
if (result && fwrite(&chunkSize, 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;
|
if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
|
|
||||||
// write group models
|
// write group models
|
||||||
count = groupModels.size();
|
count = groupModels.size();
|
||||||
if (count)
|
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;
|
//chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count;
|
||||||
//if (result && fwrite(&chunkSize, 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 (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) { result = false; }
|
||||||
for (uint32 i = 0; i < groupModels.size() && result; ++i)
|
for (uint32 i = 0; i < groupModels.size() && result; ++i)
|
||||||
|
{
|
||||||
result = groupModels[i].writeToFile(wf);
|
result = groupModels[i].writeToFile(wf);
|
||||||
|
}
|
||||||
|
|
||||||
// write group BIH
|
// write group BIH
|
||||||
if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false;
|
if (result && fwrite("GBIH", 1, 4, wf) != 4) { result = false; }
|
||||||
if (result) result = groupTree.writeToFile(wf);
|
if (result) { result = groupTree.writeToFile(wf); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(wf);
|
fclose(wf);
|
||||||
@@ -558,32 +602,36 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
FILE* rf = fopen(filename.c_str(), "rb");
|
FILE* rf = fopen(filename.c_str(), "rb");
|
||||||
if (!rf)
|
if (!rf)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
uint32 chunkSize = 0;
|
uint32 chunkSize = 0;
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
char chunk[8]; // Ignore the added magic header
|
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 && !readChunk(rf, chunk, "WMOD", 4)) { result = false; }
|
||||||
if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) 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 && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) { result = false; }
|
||||||
|
|
||||||
// read group models
|
// read group models
|
||||||
if (result && readChunk(rf, chunk, "GMOD", 4))
|
if (result && readChunk(rf, chunk, "GMOD", 4))
|
||||||
{
|
{
|
||||||
//if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
//if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false;
|
||||||
|
|
||||||
if (result && fread(&count, 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) { groupModels.resize(count); }
|
||||||
//if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
|
//if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false;
|
||||||
for (uint32 i = 0; i < count && result; ++i)
|
for (uint32 i = 0; i < count && result; ++i)
|
||||||
|
{
|
||||||
result = groupModels[i].readFromFile(rf);
|
result = groupModels[i].readFromFile(rf);
|
||||||
|
}
|
||||||
|
|
||||||
// read group BIH
|
// read group BIH
|
||||||
if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false;
|
if (result && !readChunk(rf, chunk, "GBIH", 4)) { result = false; }
|
||||||
if (result) result = groupTree.readFromFile(rf);
|
if (result) { result = groupTree.readFromFile(rf); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(rf);
|
fclose(rf);
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (_nodes[i] == n)
|
else if (_nodes[i] == n)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Node* _nodes[9];
|
Node* _nodes[9];
|
||||||
};
|
};
|
||||||
@@ -64,7 +66,9 @@ public:
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||||
|
{
|
||||||
delete nodes[x][y];
|
delete nodes[x][y];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(const T& value)
|
void insert(const T& value)
|
||||||
@@ -85,7 +89,9 @@ public:
|
|||||||
{
|
{
|
||||||
Cell c = Cell::ComputeCell(pos[i].x, pos[i].y);
|
Cell c = Cell::ComputeCell(pos[i].x, pos[i].y);
|
||||||
if (!c.isValid())
|
if (!c.isValid())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
Node& node = getGridFor(pos[i].x, pos[i].y);
|
Node& node = getGridFor(pos[i].x, pos[i].y);
|
||||||
na.AddNode(&node);
|
na.AddNode(&node);
|
||||||
}
|
}
|
||||||
@@ -93,9 +99,13 @@ public:
|
|||||||
for (uint8 i = 0; i < 9; ++i)
|
for (uint8 i = 0; i < 9; ++i)
|
||||||
{
|
{
|
||||||
if (na._nodes[i])
|
if (na._nodes[i])
|
||||||
|
{
|
||||||
na._nodes[i]->insert(value);
|
na._nodes[i]->insert(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memberTable.set(&value, na);
|
memberTable.set(&value, na);
|
||||||
@@ -107,9 +117,13 @@ public:
|
|||||||
for (uint8 i = 0; i < 9; ++i)
|
for (uint8 i = 0; i < 9; ++i)
|
||||||
{
|
{
|
||||||
if (na._nodes[i])
|
if (na._nodes[i])
|
||||||
|
{
|
||||||
na._nodes[i]->remove(value);
|
na._nodes[i]->remove(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the member
|
// Remove the member
|
||||||
@@ -121,7 +135,9 @@ public:
|
|||||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||||
if (Node* n = nodes[x][y])
|
if (Node* n = nodes[x][y])
|
||||||
|
{
|
||||||
n->balance();
|
n->balance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const T& value) const { return memberTable.containsKey(&value); }
|
bool contains(const T& value) const { return memberTable.containsKey(&value); }
|
||||||
@@ -151,7 +167,9 @@ public:
|
|||||||
{
|
{
|
||||||
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
|
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
|
||||||
if (!nodes[x][y])
|
if (!nodes[x][y])
|
||||||
|
{
|
||||||
nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
|
nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
|
||||||
|
}
|
||||||
return *nodes[x][y];
|
return *nodes[x][y];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,14 +184,18 @@ public:
|
|||||||
{
|
{
|
||||||
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||||
if (!cell.isValid())
|
if (!cell.isValid())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Cell last_cell = Cell::ComputeCell(end.x, end.y);
|
Cell last_cell = Cell::ComputeCell(end.x, end.y);
|
||||||
|
|
||||||
if (cell == last_cell)
|
if (cell == last_cell)
|
||||||
{
|
{
|
||||||
if (Node* node = nodes[cell.x][cell.y])
|
if (Node* node = nodes[cell.x][cell.y])
|
||||||
|
{
|
||||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +244,9 @@ public:
|
|||||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||||
}
|
}
|
||||||
if (cell == last_cell)
|
if (cell == last_cell)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (tMaxX < tMaxY)
|
if (tMaxX < tMaxY)
|
||||||
{
|
{
|
||||||
tMaxX += tDeltaX;
|
tMaxX += tDeltaX;
|
||||||
@@ -242,9 +266,13 @@ public:
|
|||||||
{
|
{
|
||||||
Cell cell = Cell::ComputeCell(point.x, point.y);
|
Cell cell = Cell::ComputeCell(point.x, point.y);
|
||||||
if (!cell.isValid())
|
if (!cell.isValid())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (Node* node = nodes[cell.x][cell.y])
|
if (Node* node = nodes[cell.x][cell.y])
|
||||||
|
{
|
||||||
node->intersectPoint(point, intersectCallback);
|
node->intersectPoint(point, intersectCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized verson of intersectRay function for rays with vertical directions
|
// 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);
|
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||||
if (!cell.isValid())
|
if (!cell.isValid())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (Node* node = nodes[cell.x][cell.y])
|
if (Node* node = nodes[cell.x][cell.y])
|
||||||
|
{
|
||||||
node->intersectRay(ray, intersectCallback, max_dist, false);
|
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)
|
for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
|
||||||
if (name == localeNames[i])
|
if (name == localeNames[i])
|
||||||
|
{
|
||||||
return LocaleConstant(i);
|
return LocaleConstant(i);
|
||||||
|
}
|
||||||
|
|
||||||
return LOCALE_enUS; // including enGB case
|
return LOCALE_enUS; // including enGB case
|
||||||
}
|
}
|
||||||
@@ -31,7 +33,7 @@ LocaleConstant GetLocaleByName(const std::string& name)
|
|||||||
void CleanStringForMysqlQuery(std::string& str)
|
void CleanStringForMysqlQuery(std::string& str)
|
||||||
{
|
{
|
||||||
std::string::size_type n = 0;
|
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
|
// No lines read
|
||||||
if (!count)
|
if (!count)
|
||||||
|
{
|
||||||
throw ConfigException(Acore::StringFormat("Config::LoadFile: Empty file '%s'", file.c_str()));
|
throw ConfigException(Acore::StringFormat("Config::LoadFile: Empty file '%s'", file.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
// Add correct keys if file load without errors
|
// Add correct keys if file load without errors
|
||||||
for (auto const& [entry, key] : fileConfigs)
|
for (auto const& [entry, key] : fileConfigs)
|
||||||
@@ -200,7 +202,9 @@ ConfigMgr* ConfigMgr::instance()
|
|||||||
bool ConfigMgr::Reload()
|
bool ConfigMgr::Reload()
|
||||||
{
|
{
|
||||||
if (!LoadAppConfigs())
|
if (!LoadAppConfigs())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return LoadModulesConfigs();
|
return LoadModulesConfigs();
|
||||||
}
|
}
|
||||||
@@ -287,7 +291,9 @@ std::vector<std::string> ConfigMgr::GetKeysByString(std::string const& name)
|
|||||||
|
|
||||||
for (auto const& [optionName, key] : _configOptions)
|
for (auto const& [optionName, key] : _configOptions)
|
||||||
if (!optionName.compare(0, name.length(), name))
|
if (!optionName.compare(0, name.length(), name))
|
||||||
|
{
|
||||||
keys.emplace_back(optionName);
|
keys.emplace_back(optionName);
|
||||||
|
}
|
||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
@@ -324,7 +330,9 @@ void ConfigMgr::Configure(std::string const& initFileName, std::vector<std::stri
|
|||||||
{
|
{
|
||||||
Tokenizer configFileList(modulesConfigList, ',');
|
Tokenizer configFileList(modulesConfigList, ',');
|
||||||
for (auto const& itr : configFileList)
|
for (auto const& itr : configFileList)
|
||||||
|
{
|
||||||
_additonalFiles.emplace_back(std::string(itr));
|
_additonalFiles.emplace_back(std::string(itr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,11 +340,15 @@ bool ConfigMgr::LoadAppConfigs()
|
|||||||
{
|
{
|
||||||
// #1 - Load init config file .conf.dist
|
// #1 - Load init config file .conf.dist
|
||||||
if (!LoadInitial(_filename + ".dist"))
|
if (!LoadInitial(_filename + ".dist"))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// #2 - Load .conf file
|
// #2 - Load .conf file
|
||||||
if (!LoadAdditionalFile(_filename))
|
if (!LoadAdditionalFile(_filename))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -344,7 +356,9 @@ bool ConfigMgr::LoadAppConfigs()
|
|||||||
bool ConfigMgr::LoadModulesConfigs()
|
bool ConfigMgr::LoadModulesConfigs()
|
||||||
{
|
{
|
||||||
if (_additonalFiles.empty())
|
if (_additonalFiles.empty())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Start loading module configs
|
// Start loading module configs
|
||||||
std::string const& moduleConfigPath = GetConfigPath() + "modules/";
|
std::string const& moduleConfigPath = GetConfigPath() + "modules/";
|
||||||
@@ -356,20 +370,30 @@ bool ConfigMgr::LoadModulesConfigs()
|
|||||||
std::string defaultFileName = distFileName;
|
std::string defaultFileName = distFileName;
|
||||||
|
|
||||||
if (!defaultFileName.empty())
|
if (!defaultFileName.empty())
|
||||||
|
{
|
||||||
defaultFileName.erase(defaultFileName.end() - 5, defaultFileName.end());
|
defaultFileName.erase(defaultFileName.end() - 5, defaultFileName.end());
|
||||||
|
}
|
||||||
|
|
||||||
// Load .conf.dist config
|
// Load .conf.dist config
|
||||||
if (!LoadAdditionalFile(moduleConfigPath + distFileName))
|
if (!LoadAdditionalFile(moduleConfigPath + distFileName))
|
||||||
|
{
|
||||||
isExistDistConfig = false;
|
isExistDistConfig = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Load .conf config
|
// Load .conf config
|
||||||
if (!LoadAdditionalFile(moduleConfigPath + defaultFileName))
|
if (!LoadAdditionalFile(moduleConfigPath + defaultFileName))
|
||||||
|
{
|
||||||
isExistDefaultConfig = false;
|
isExistDefaultConfig = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isExistDefaultConfig && isExistDistConfig)
|
if (isExistDefaultConfig && isExistDistConfig)
|
||||||
|
{
|
||||||
_moduleConfigFiles.emplace_back(defaultFileName);
|
_moduleConfigFiles.emplace_back(defaultFileName);
|
||||||
|
}
|
||||||
else if (!isExistDefaultConfig && isExistDistConfig)
|
else if (!isExistDefaultConfig && isExistDistConfig)
|
||||||
|
{
|
||||||
_moduleConfigFiles.emplace_back(distFileName);
|
_moduleConfigFiles.emplace_back(distFileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If module configs not exist - no load
|
// If module configs not exist - no load
|
||||||
@@ -383,7 +407,9 @@ void ConfigMgr::PrintLoadedModulesConfigs()
|
|||||||
LOG_INFO("server.loading", "Using modules configuration:");
|
LOG_INFO("server.loading", "Using modules configuration:");
|
||||||
|
|
||||||
for (auto const& itr : _moduleConfigFiles)
|
for (auto const& itr : _moduleConfigFiles)
|
||||||
|
{
|
||||||
LOG_INFO("server.loading", "> %s", itr.c_str());
|
LOG_INFO("server.loading", "> %s", itr.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO("server.loading", " ");
|
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()));
|
ASSERT(length <= static_cast<size_t>(std::numeric_limits<int>::max()));
|
||||||
int len = static_cast<int>(length);
|
int len = static_cast<int>(length);
|
||||||
if (!EVP_CipherInit_ex(_ctx, nullptr, nullptr, nullptr, iv.data(), -1))
|
if (!EVP_CipherInit_ex(_ctx, nullptr, nullptr, nullptr, iv.data(), -1))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int outLen;
|
int outLen;
|
||||||
if (!EVP_CipherUpdate(_ctx, data, &outLen, data, len))
|
if (!EVP_CipherUpdate(_ctx, data, &outLen, data, len))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
len -= outLen;
|
len -= outLen;
|
||||||
|
|
||||||
if (!_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_TAG, sizeof(tag), tag))
|
if (!_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_TAG, sizeof(tag), tag))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!EVP_CipherFinal_ex(_ctx, data + outLen, &outLen))
|
if (!EVP_CipherFinal_ex(_ctx, data + outLen, &outLen))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(len == outLen);
|
ASSERT(len == outLen);
|
||||||
|
|
||||||
if (_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_GET_TAG, sizeof(tag), tag))
|
if (_encrypting && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_GET_TAG, sizeof(tag), tag))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (status == ARGON2_OK)
|
if (status == ARGON2_OK)
|
||||||
|
{
|
||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ void AuthCrypt::Init(SessionKey const& K)
|
|||||||
|
|
||||||
void AuthCrypt::DecryptRecv(uint8* data, size_t len)
|
void AuthCrypt::DecryptRecv(uint8* data, size_t len)
|
||||||
{
|
{
|
||||||
ASSERT(_initialized);
|
ASSERT(_initialized);
|
||||||
_clientDecrypt.UpdateData(data, len);
|
_clientDecrypt.UpdateData(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,13 +48,13 @@ using SRP6 = Acore::Crypto::SRP6;
|
|||||||
|
|
||||||
// find position of first nonzero byte
|
// find position of first nonzero byte
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) ++p;
|
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) { ++p; }
|
||||||
if (p & 1) ++p; // skip one extra byte if p is odd
|
if (p & 1) { ++p; } // skip one extra byte if p is odd
|
||||||
p /= 2; // offset into buffers
|
p /= 2; // offset into buffers
|
||||||
|
|
||||||
// hash each of the halves, starting at the first nonzero byte
|
// 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 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 hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH / 2 - p);
|
||||||
|
|
||||||
// stick the two hashes back together
|
// stick the two hashes back together
|
||||||
SessionKey K;
|
SessionKey K;
|
||||||
@@ -76,7 +76,9 @@ std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, S
|
|||||||
|
|
||||||
BigNumber const _A(A);
|
BigNumber const _A(A);
|
||||||
if ((_A % _N).IsZero())
|
if ((_A % _N).IsZero())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
BigNumber const u(SHA1::GetDigestOf(A, B));
|
BigNumber const u(SHA1::GetDigestOf(A, B));
|
||||||
EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
|
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);
|
SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
|
||||||
if (ourM == clientM)
|
if (ourM == clientM)
|
||||||
|
{
|
||||||
return K;
|
return K;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,53 +18,53 @@ namespace Acore::Crypto
|
|||||||
{
|
{
|
||||||
class SRP6
|
class SRP6
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr size_t SALT_LENGTH = 32;
|
static constexpr size_t SALT_LENGTH = 32;
|
||||||
using Salt = std::array<uint8, SALT_LENGTH>;
|
using Salt = std::array<uint8, SALT_LENGTH>;
|
||||||
static constexpr size_t VERIFIER_LENGTH = 32;
|
static constexpr size_t VERIFIER_LENGTH = 32;
|
||||||
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
|
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
|
||||||
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
|
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
|
||||||
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
|
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
|
||||||
|
|
||||||
static std::array<uint8, 1> const g;
|
static std::array<uint8, 1> const g;
|
||||||
static std::array<uint8, 32> const N;
|
static std::array<uint8, 32> const N;
|
||||||
|
|
||||||
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
|
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
|
||||||
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
|
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
|
||||||
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
|
// 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)
|
static bool CheckLogin(std::string const& username, std::string const& password, Salt const& salt, Verifier const& verifier)
|
||||||
{
|
{
|
||||||
return (verifier == CalculateVerifier(username, password, salt));
|
return (verifier == CalculateVerifier(username, password, salt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
|
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
|
||||||
{
|
{
|
||||||
return SHA1::GetDigestOf(A, clientM, K);
|
return SHA1::GetDigestOf(A, clientM, K);
|
||||||
}
|
}
|
||||||
|
|
||||||
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
|
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
|
||||||
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
|
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _used = false; // a single instance can only be used to verify once
|
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 Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt);
|
||||||
static SessionKey SHA1Interleave(EphemeralKey const& S);
|
static SessionKey SHA1Interleave(EphemeralKey const& S);
|
||||||
|
|
||||||
/* global algorithm parameters */
|
/* global algorithm parameters */
|
||||||
static BigNumber const _g; // a [g]enerator for the ring of integers mod N, algorithm parameter
|
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 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 */
|
/* per-instantiation parameters, set on construction */
|
||||||
SHA1::Digest const _I; // H(I) - the username, all uppercase
|
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 _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)
|
BigNumber const _v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Salt const s; // s - the user's password salt, random, used to calculate v on registration
|
Salt const s; // s - the user's password salt, random, used to calculate v on registration
|
||||||
EphemeralKey const B; // B = 3v + g^b
|
EphemeralKey const B; // B = 3v + g^b
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ void BigNumber::SetDword(int32 val)
|
|||||||
{
|
{
|
||||||
SetDword(uint32(abs(val)));
|
SetDword(uint32(abs(val)));
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
|
{
|
||||||
BN_set_negative(_bn, 1);
|
BN_set_negative(_bn, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigNumber::SetDword(uint32 val)
|
void BigNumber::SetDword(uint32 val)
|
||||||
@@ -50,7 +52,9 @@ void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
|
|||||||
uint8* array = new uint8[len];
|
uint8* array = new uint8[len];
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
array[i] = bytes[len - 1 - i];
|
array[i] = bytes[len - 1 - i];
|
||||||
|
}
|
||||||
|
|
||||||
BN_bin2bn(array, len, _bn);
|
BN_bin2bn(array, len, _bn);
|
||||||
|
|
||||||
@@ -60,7 +64,9 @@ void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
BN_bin2bn(bytes, len, _bn);
|
BN_bin2bn(bytes, len, _bn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BigNumber::SetHexStr(char const* str)
|
bool BigNumber::SetHexStr(char const* str)
|
||||||
@@ -77,7 +83,9 @@ void BigNumber::SetRand(int32 numbits)
|
|||||||
BigNumber& BigNumber::operator=(BigNumber const& bn)
|
BigNumber& BigNumber::operator=(BigNumber const& bn)
|
||||||
{
|
{
|
||||||
if (this == &bn)
|
if (this == &bn)
|
||||||
|
{
|
||||||
return *this;
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
BN_copy(_bn, bn._bn);
|
BN_copy(_bn, bn._bn);
|
||||||
return *this;
|
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 we need more bytes than length of BigNumber set the rest to 0
|
||||||
if (numBytes < bufsize)
|
if (numBytes < bufsize)
|
||||||
|
{
|
||||||
memset((void*)buf, 0, bufsize);
|
memset((void*)buf, 0, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
BN_bn2bin(_bn, buf + (bufsize - numBytes));
|
BN_bn2bin(_bn, buf + (bufsize - numBytes));
|
||||||
|
|
||||||
// openssl's BN stores data internally in big endian format, reverse if little endian desired
|
// openssl's BN stores data internally in big endian format, reverse if little endian desired
|
||||||
if (littleEndian)
|
if (littleEndian)
|
||||||
|
{
|
||||||
std::reverse(buf, buf + bufsize);
|
std::reverse(buf, buf + bufsize);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
int res = littleEndian ? BN_bn2lebinpad(_bn, buf, bufsize) : BN_bn2binpad(_bn, buf, bufsize);
|
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));
|
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>
|
template <GenericHashImpl::HashCreator HashCreator, size_t DigestLength>
|
||||||
class GenericHash
|
class GenericHash
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
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;
|
return;
|
||||||
hash.UpdateData(data, len);
|
|
||||||
hash.Finalize();
|
|
||||||
return hash.GetDigest();
|
|
||||||
}
|
}
|
||||||
|
GenericHashImpl::DestroyCTX(_ctx);
|
||||||
|
_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Ts>
|
void UpdateData(uint8 const* data, size_t len)
|
||||||
static auto GetDigestOf(Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
{
|
||||||
{
|
int result = EVP_DigestUpdate(_ctx, data, len);
|
||||||
GenericHash hash;
|
ASSERT(result == 1);
|
||||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
}
|
||||||
hash.Finalize();
|
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||||
return hash.GetDigest();
|
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())
|
void Finalize()
|
||||||
{
|
{
|
||||||
int result = EVP_DigestInit_ex(_ctx, HashCreator(), nullptr);
|
uint32 length;
|
||||||
ASSERT(result == 1);
|
int result = EVP_DigestFinal_ex(_ctx, _digest.data(), &length);
|
||||||
}
|
ASSERT(result == 1);
|
||||||
|
ASSERT(length == DIGEST_LENGTH);
|
||||||
|
GenericHashImpl::DestroyCTX(_ctx);
|
||||||
|
_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
~GenericHash()
|
Digest const& GetDigest() const { return _digest; }
|
||||||
{
|
|
||||||
if (!_ctx)
|
|
||||||
return;
|
|
||||||
GenericHashImpl::DestroyCTX(_ctx);
|
|
||||||
_ctx = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateData(uint8 const* data, size_t len)
|
private:
|
||||||
{
|
EVP_MD_CTX* _ctx;
|
||||||
int result = EVP_DigestUpdate(_ctx, data, len);
|
Digest _digest = { };
|
||||||
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 = { };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,69 +44,70 @@ namespace Acore::Impl
|
|||||||
template <HMACImpl::HashCreator HashCreator, size_t DigestLength>
|
template <HMACImpl::HashCreator HashCreator, size_t DigestLength>
|
||||||
class GenericHMAC
|
class GenericHMAC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||||
|
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
static Digest GetDigestOf(Container const& seed, uint8 const* data, size_t len)
|
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);
|
return;
|
||||||
hash.UpdateData(data, len);
|
|
||||||
hash.Finalize();
|
|
||||||
return hash.GetDigest();
|
|
||||||
}
|
}
|
||||||
|
HMACImpl::DestroyCTX(_ctx);
|
||||||
|
_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Container, typename... Ts>
|
void UpdateData(uint8 const* data, size_t len)
|
||||||
static auto GetDigestOf(Container const& seed, Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
{
|
||||||
{
|
int result = HMAC_Update(_ctx, data, len);
|
||||||
GenericHMAC hash(seed);
|
ASSERT(result == 1);
|
||||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
}
|
||||||
hash.Finalize();
|
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||||
return hash.GetDigest();
|
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())
|
void Finalize()
|
||||||
{
|
{
|
||||||
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
|
uint32 length = 0;
|
||||||
ASSERT(result == 1);
|
int result = HMAC_Final(_ctx, _digest.data(), &length);
|
||||||
}
|
ASSERT(result == 1);
|
||||||
template <typename Container>
|
ASSERT(length == DIGEST_LENGTH);
|
||||||
GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
|
HMACImpl::DestroyCTX(_ctx);
|
||||||
|
_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
~GenericHMAC()
|
Digest const& GetDigest() const { return _digest; }
|
||||||
{
|
private:
|
||||||
if (!_ctx)
|
HMAC_CTX* _ctx;
|
||||||
return;
|
Digest _digest = { };
|
||||||
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 = { };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ std::vector<std::mutex*> cryptoLocks;
|
|||||||
static void lockingCallback(int mode, int type, char const* /*file*/, int /*line*/)
|
static void lockingCallback(int mode, int type, char const* /*file*/, int /*line*/)
|
||||||
{
|
{
|
||||||
if (mode & CRYPTO_LOCK)
|
if (mode & CRYPTO_LOCK)
|
||||||
|
{
|
||||||
cryptoLocks[type]->lock();
|
cryptoLocks[type]->lock();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
cryptoLocks[type]->unlock();
|
cryptoLocks[type]->unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void threadIdCallback(CRYPTO_THREADID* id)
|
static void threadIdCallback(CRYPTO_THREADID* id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,39 +12,38 @@
|
|||||||
template <typename Hash>
|
template <typename Hash>
|
||||||
class SessionKeyGenerator
|
class SessionKeyGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename C>
|
template <typename C> SessionKeyGenerator(C const& buf) :
|
||||||
SessionKeyGenerator(C const& buf) :
|
o0it(o0.begin())
|
||||||
o0it(o0.begin())
|
{
|
||||||
{
|
uint8 const* data = std::data(buf);
|
||||||
uint8 const* data = std::data(buf);
|
size_t const len = std::size(buf);
|
||||||
size_t const len = std::size(buf);
|
size_t const halflen = (len / 2);
|
||||||
size_t const halflen = (len / 2);
|
|
||||||
|
|
||||||
o1 = Hash::GetDigestOf(data, halflen);
|
o1 = Hash::GetDigestOf(data, halflen);
|
||||||
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
|
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
|
||||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
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();
|
||||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
|
||||||
o0it = o0.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[i] = *(o0it++);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
buf[i] = *(o0it++);
|
||||||
typename Hash::Digest o0 = { };
|
}
|
||||||
typename Hash::Digest o1 = { };
|
}
|
||||||
typename Hash::Digest o2 = { };
|
|
||||||
typename Hash::Digest::const_iterator o0it;
|
private:
|
||||||
};
|
typename Hash::Digest o0 = { };
|
||||||
|
typename Hash::Digest o1 = { };
|
||||||
|
typename Hash::Digest o2 = { };
|
||||||
|
typename Hash::Digest::const_iterator o0it;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ static constexpr uint32 HMAC_RESULT_SIZE = 20;
|
|||||||
unsigned char challenge[8];
|
unsigned char challenge[8];
|
||||||
|
|
||||||
for (int i = 8; i--; timestamp >>= 8)
|
for (int i = 8; i--; timestamp >>= 8)
|
||||||
|
{
|
||||||
challenge[i] = timestamp;
|
challenge[i] = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char digest[HMAC_RESULT_SIZE];
|
unsigned char digest[HMAC_RESULT_SIZE];
|
||||||
uint32 digestSize = 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");
|
FILE* f = fopen(filename, "rb");
|
||||||
if (!f)
|
if (!f)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (fread(&header, 4, 1, f) != 1) // Number of records
|
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];
|
fieldsOffset[i] = fieldsOffset[i - 1];
|
||||||
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
|
if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
|
||||||
|
{
|
||||||
fieldsOffset[i] += sizeof(uint8);
|
fieldsOffset[i] += sizeof(uint8);
|
||||||
|
}
|
||||||
else // 4 byte fields (int32/float/strings)
|
else // 4 byte fields (int32/float/strings)
|
||||||
|
{
|
||||||
fieldsOffset[i] += sizeof(uint32);
|
fieldsOffset[i] += sizeof(uint32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data = new unsigned char[recordSize * recordCount + stringSize];
|
data = new unsigned char[recordSize * recordCount + stringSize];
|
||||||
@@ -151,7 +157,9 @@ uint32 DBCFileLoader::GetFormatRecordSize(char const* format, int32* index_pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (index_pos)
|
if (index_pos)
|
||||||
|
{
|
||||||
*index_pos = i;
|
*index_pos = i;
|
||||||
|
}
|
||||||
|
|
||||||
return recordsize;
|
return recordsize;
|
||||||
}
|
}
|
||||||
@@ -171,7 +179,9 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
|
|||||||
|
|
||||||
typedef char* ptr;
|
typedef char* ptr;
|
||||||
if (strlen(format) != fieldCount)
|
if (strlen(format) != fieldCount)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
//get struct size and index pos
|
//get struct size and index pos
|
||||||
int32 i;
|
int32 i;
|
||||||
@@ -185,7 +195,9 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
|
|||||||
{
|
{
|
||||||
uint32 ind = getRecord(y).getUInt(i);
|
uint32 ind = getRecord(y).getUInt(i);
|
||||||
if (ind > maxi)
|
if (ind > maxi)
|
||||||
|
{
|
||||||
maxi = ind;
|
maxi = ind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++maxi;
|
++maxi;
|
||||||
@@ -206,9 +218,13 @@ char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**
|
|||||||
for (uint32 y = 0; y < recordCount; ++y)
|
for (uint32 y = 0; y < recordCount; ++y)
|
||||||
{
|
{
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
|
{
|
||||||
indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
|
indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
indexTable[y] = &dataTable[offset];
|
indexTable[y] = &dataTable[offset];
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32 x = 0; x < fieldCount; ++x)
|
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)
|
char* DBCFileLoader::AutoProduceStrings(char const* format, char* dataTable)
|
||||||
{
|
{
|
||||||
if (strlen(format) != fieldCount)
|
if (strlen(format) != fieldCount)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
char* stringPool = new char[stringSize];
|
char* stringPool = new char[stringSize];
|
||||||
memcpy(stringPool, stringTable, stringSize);
|
memcpy(stringPool, stringTable, stringSize);
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ inline LPTSTR ErrorMessage(DWORD dw)
|
|||||||
(LPTSTR) &lpMsgBuf,
|
(LPTSTR) &lpMsgBuf,
|
||||||
0, nullptr);
|
0, nullptr);
|
||||||
if (formatResult != 0)
|
if (formatResult != 0)
|
||||||
|
{
|
||||||
return (LPTSTR)lpMsgBuf;
|
return (LPTSTR)lpMsgBuf;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30);
|
LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30);
|
||||||
@@ -98,9 +100,13 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor
|
|||||||
WheatyExceptionReport::~WheatyExceptionReport()
|
WheatyExceptionReport::~WheatyExceptionReport()
|
||||||
{
|
{
|
||||||
if (m_previousFilter)
|
if (m_previousFilter)
|
||||||
|
{
|
||||||
SetUnhandledExceptionFilter(m_previousFilter);
|
SetUnhandledExceptionFilter(m_previousFilter);
|
||||||
|
}
|
||||||
if (m_previousCrtHandler)
|
if (m_previousCrtHandler)
|
||||||
|
{
|
||||||
_set_invalid_parameter_handler(m_previousCrtHandler);
|
_set_invalid_parameter_handler(m_previousCrtHandler);
|
||||||
|
}
|
||||||
ClearSymbols();
|
ClearSymbols();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,18 +119,24 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
|
|||||||
std::unique_lock<std::mutex> guard(alreadyCrashedLock);
|
std::unique_lock<std::mutex> guard(alreadyCrashedLock);
|
||||||
// Handle only 1 exception in the whole process lifetime
|
// Handle only 1 exception in the whole process lifetime
|
||||||
if (alreadyCrashed)
|
if (alreadyCrashed)
|
||||||
|
{
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
alreadyCrashed = true;
|
alreadyCrashed = true;
|
||||||
|
|
||||||
if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
|
if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
|
||||||
|
{
|
||||||
stackOverflowException = true;
|
stackOverflowException = true;
|
||||||
|
}
|
||||||
|
|
||||||
TCHAR module_folder_name[MAX_PATH];
|
TCHAR module_folder_name[MAX_PATH];
|
||||||
GetModuleFileName(0, module_folder_name, MAX_PATH);
|
GetModuleFileName(0, module_folder_name, MAX_PATH);
|
||||||
TCHAR* pos = _tcsrchr(module_folder_name, '\\');
|
TCHAR* pos = _tcsrchr(module_folder_name, '\\');
|
||||||
if (!pos)
|
if (!pos)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
pos[0] = '\0';
|
pos[0] = '\0';
|
||||||
++pos;
|
++pos;
|
||||||
|
|
||||||
@@ -133,7 +145,9 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
|
|||||||
if (!CreateDirectory(crash_folder_path, nullptr))
|
if (!CreateDirectory(crash_folder_path, nullptr))
|
||||||
{
|
{
|
||||||
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSTEMTIME systime;
|
SYSTEMTIME systime;
|
||||||
@@ -197,9 +211,13 @@ LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_previousFilter)
|
if (m_previousFilter)
|
||||||
|
{
|
||||||
return m_previousFilter(pExceptionInfo);
|
return m_previousFilter(pExceptionInfo);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/;
|
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*/)
|
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)
|
BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount)
|
||||||
{
|
{
|
||||||
if (!sProcessorName)
|
if (!sProcessorName)
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
HKEY hKey;
|
HKEY hKey;
|
||||||
LONG lRet;
|
LONG lRet;
|
||||||
lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
|
lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
|
||||||
0, KEY_QUERY_VALUE, &hKey);
|
0, KEY_QUERY_VALUE, &hKey);
|
||||||
if (lRet != ERROR_SUCCESS)
|
if (lRet != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
TCHAR szTmp[2048];
|
TCHAR szTmp[2048];
|
||||||
DWORD cntBytes = sizeof(szTmp);
|
DWORD cntBytes = sizeof(szTmp);
|
||||||
lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), nullptr, nullptr,
|
lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), nullptr, nullptr,
|
||||||
(LPBYTE)szTmp, &cntBytes);
|
(LPBYTE)szTmp, &cntBytes);
|
||||||
if (lRet != ERROR_SUCCESS)
|
if (lRet != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
::RegCloseKey(hKey);
|
::RegCloseKey(hKey);
|
||||||
sProcessorName[0] = '\0';
|
sProcessorName[0] = '\0';
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
TCHAR* psz = szTmp;
|
TCHAR* psz = szTmp;
|
||||||
while (iswspace(*psz))
|
while (iswspace(*psz))
|
||||||
|
{
|
||||||
++psz;
|
++psz;
|
||||||
|
}
|
||||||
_tcsncpy(sProcessorName, psz, maxcount);
|
_tcsncpy(sProcessorName, psz, maxcount);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -257,7 +283,9 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
|
|||||||
{
|
{
|
||||||
osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
|
osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
|
||||||
if (!RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi))
|
if (!RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi))
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*szVersion = _T('\0');
|
*szVersion = _T('\0');
|
||||||
|
|
||||||
@@ -282,40 +310,68 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
|
|||||||
if (osvi.dwMajorVersion == 10)
|
if (osvi.dwMajorVersion == 10)
|
||||||
{
|
{
|
||||||
if (productType == VER_NT_WORKSTATION)
|
if (productType == VER_NT_WORKSTATION)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows 10 "), cntMax);
|
_tcsncat(szVersion, _T("Windows 10 "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Server 2016 "), cntMax);
|
_tcsncat(szVersion, _T("Windows Server 2016 "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (osvi.dwMajorVersion == 6)
|
else if (osvi.dwMajorVersion == 6)
|
||||||
{
|
{
|
||||||
if (productType == VER_NT_WORKSTATION)
|
if (productType == VER_NT_WORKSTATION)
|
||||||
{
|
{
|
||||||
if (osvi.dwMinorVersion == 3)
|
if (osvi.dwMinorVersion == 3)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows 8.1 "), cntMax);
|
_tcsncat(szVersion, _T("Windows 8.1 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMinorVersion == 2)
|
else if (osvi.dwMinorVersion == 2)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows 8 "), cntMax);
|
_tcsncat(szVersion, _T("Windows 8 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMinorVersion == 1)
|
else if (osvi.dwMinorVersion == 1)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows 7 "), cntMax);
|
_tcsncat(szVersion, _T("Windows 7 "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Vista "), cntMax);
|
_tcsncat(szVersion, _T("Windows Vista "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (osvi.dwMinorVersion == 3)
|
else if (osvi.dwMinorVersion == 3)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Server 2012 R2 "), cntMax);
|
_tcsncat(szVersion, _T("Windows Server 2012 R2 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMinorVersion == 2)
|
else if (osvi.dwMinorVersion == 2)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
|
_tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMinorVersion == 1)
|
else if (osvi.dwMinorVersion == 1)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
|
_tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
|
_tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
|
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax);
|
_tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
|
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax);
|
_tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
|
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax);
|
_tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax);
|
||||||
|
}
|
||||||
else if (osvi.dwMajorVersion <= 4)
|
else if (osvi.dwMajorVersion <= 4)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
|
_tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
|
||||||
|
}
|
||||||
|
|
||||||
// Test for specific product on Windows NT 4.0 SP6 and later.
|
// Test for specific product on Windows NT 4.0 SP6 and later.
|
||||||
if (bVersionEx >= 0)
|
if (bVersionEx >= 0)
|
||||||
@@ -324,13 +380,21 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
|
|||||||
if (productType == VER_NT_WORKSTATION)
|
if (productType == VER_NT_WORKSTATION)
|
||||||
{
|
{
|
||||||
if (osvi.dwMajorVersion == 4)
|
if (osvi.dwMajorVersion == 4)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Workstation 4.0 "), cntMax);
|
_tcsncat(szVersion, _T("Workstation 4.0 "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_PERSONAL)
|
else if (suiteMask & VER_SUITE_PERSONAL)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Home Edition "), cntMax);
|
_tcsncat(szVersion, _T("Home Edition "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_EMBEDDEDNT)
|
else if (suiteMask & VER_SUITE_EMBEDDEDNT)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Embedded "), cntMax);
|
_tcsncat(szVersion, _T("Embedded "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Professional "), cntMax);
|
_tcsncat(szVersion, _T("Professional "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Test for the server type.
|
// Test for the server type.
|
||||||
else if (productType == VER_NT_SERVER)
|
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 (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
|
||||||
{
|
{
|
||||||
if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
|
if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Essentials "), cntMax);
|
_tcsncat(szVersion, _T("Essentials "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_DATACENTER)
|
else if (suiteMask & VER_SUITE_DATACENTER)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Datacenter "), cntMax);
|
_tcsncat(szVersion, _T("Datacenter "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Enterprise "), cntMax);
|
_tcsncat(szVersion, _T("Enterprise "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Standard "), cntMax);
|
_tcsncat(szVersion, _T("Standard "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
|
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
|
||||||
{
|
{
|
||||||
if (suiteMask & VER_SUITE_DATACENTER)
|
if (suiteMask & VER_SUITE_DATACENTER)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
|
_tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Enterprise Edition "), cntMax);
|
_tcsncat(szVersion, _T("Enterprise Edition "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask == VER_SUITE_BLADE)
|
else if (suiteMask == VER_SUITE_BLADE)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Web Edition "), cntMax);
|
_tcsncat(szVersion, _T("Web Edition "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Standard Edition "), cntMax);
|
_tcsncat(szVersion, _T("Standard Edition "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
|
else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
|
||||||
{
|
{
|
||||||
if (suiteMask & VER_SUITE_DATACENTER)
|
if (suiteMask & VER_SUITE_DATACENTER)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Datacenter Server "), cntMax);
|
_tcsncat(szVersion, _T("Datacenter Server "), cntMax);
|
||||||
|
}
|
||||||
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
else if (suiteMask & VER_SUITE_ENTERPRISE)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Advanced Server "), cntMax);
|
_tcsncat(szVersion, _T("Advanced Server "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Server "), cntMax);
|
_tcsncat(szVersion, _T("Server "), cntMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // Windows NT 4.0
|
else // Windows NT 4.0
|
||||||
{
|
{
|
||||||
if (suiteMask & VER_SUITE_ENTERPRISE)
|
if (suiteMask & VER_SUITE_ENTERPRISE)
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax);
|
_tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_tcsncat(szVersion, _T("Server 4.0 "), cntMax);
|
_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);
|
SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys / 0x400, MemoryStatus.dwAvailPhys / 0x400, MemoryStatus.dwTotalPageFile / 0x400);
|
||||||
|
|
||||||
if (_GetWindowsVersion(sString, countof(sString)))
|
if (_GetWindowsVersion(sString, countof(sString)))
|
||||||
|
{
|
||||||
Log(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
|
Log(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Log(_T("\r\n*** Operation System:\r\n<unknown>\r\n"));
|
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
|
// Take a snapshot of all running threads
|
||||||
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||||
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Fill in the size of the structure before using it.
|
// Fill in the size of the structure before using it.
|
||||||
te32.dwSize = sizeof(THREADENTRY32);
|
te32.dwSize = sizeof(THREADENTRY32);
|
||||||
@@ -480,7 +576,9 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)
|
|||||||
if (threadHandle)
|
if (threadHandle)
|
||||||
{
|
{
|
||||||
if (GetThreadContext(threadHandle, &context))
|
if (GetThreadContext(threadHandle, &context))
|
||||||
|
{
|
||||||
WriteStackDetails(&context, bWriteVariables, threadHandle);
|
WriteStackDetails(&context, bWriteVariables, threadHandle);
|
||||||
|
}
|
||||||
CloseHandle(threadHandle);
|
CloseHandle(threadHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -663,15 +761,21 @@ BOOL WheatyExceptionReport::GetLogicalAddress(
|
|||||||
MEMORY_BASIC_INFORMATION mbi;
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
|
||||||
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
|
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
|
DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
|
||||||
|
|
||||||
if (!hMod)
|
if (!hMod)
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!GetModuleFileName((HMODULE)hMod, szModule, len))
|
if (!GetModuleFileName((HMODULE)hMod, szModule, len))
|
||||||
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// Point to the DOS header in memory
|
// Point to the DOS header in memory
|
||||||
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
|
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
|
||||||
@@ -771,9 +875,13 @@ void WheatyExceptionReport::WriteStackDetails(
|
|||||||
SymFunctionTableAccess64,
|
SymFunctionTableAccess64,
|
||||||
SymGetModuleBase64,
|
SymGetModuleBase64,
|
||||||
0))
|
0))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure
|
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
|
#ifdef _M_IX86
|
||||||
Log(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
|
Log(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
|
||||||
#endif
|
#endif
|
||||||
@@ -870,7 +978,9 @@ bool WheatyExceptionReport::FormatSymbolValue(
|
|||||||
{
|
{
|
||||||
// If it's a function, don't do anything.
|
// If it's a function, don't do anything.
|
||||||
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
|
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
|
DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
|
||||||
|
|
||||||
@@ -890,7 +1000,9 @@ bool WheatyExceptionReport::FormatSymbolValue(
|
|||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
|
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
|
else
|
||||||
{
|
{
|
||||||
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
|
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
|
// Indicate if the variable is a local or parameter
|
||||||
if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
|
if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
|
||||||
|
{
|
||||||
symbolDetails.top().Prefix = "Parameter ";
|
symbolDetails.top().Prefix = "Parameter ";
|
||||||
|
}
|
||||||
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
|
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
|
||||||
|
{
|
||||||
symbolDetails.top().Prefix = "Local ";
|
symbolDetails.top().Prefix = "Local ";
|
||||||
|
}
|
||||||
|
|
||||||
// Determine if the variable is a user defined type (UDT). IF so, bHandled
|
// Determine if the variable is a user defined type (UDT). IF so, bHandled
|
||||||
// will return true.
|
// will return true.
|
||||||
@@ -916,11 +1032,15 @@ bool WheatyExceptionReport::FormatSymbolValue(
|
|||||||
// DWORD.
|
// DWORD.
|
||||||
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
|
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
|
||||||
if (symbolDetails.top().Type.empty())
|
if (symbolDetails.top().Type.empty())
|
||||||
|
{
|
||||||
symbolDetails.top().Type = rgBaseType[basicType];
|
symbolDetails.top().Type = rgBaseType[basicType];
|
||||||
|
}
|
||||||
|
|
||||||
// Emit the variable name
|
// Emit the variable name
|
||||||
if (pSym->Name[0] != '\0')
|
if (pSym->Name[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = pSym->Name;
|
symbolDetails.top().Name = pSym->Name;
|
||||||
|
}
|
||||||
|
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
|
FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
|
||||||
@@ -949,11 +1069,15 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
bHandled = false;
|
bHandled = false;
|
||||||
|
|
||||||
if (newSymbol)
|
if (newSymbol)
|
||||||
|
{
|
||||||
PushSymbolDetail();
|
PushSymbolDetail();
|
||||||
|
}
|
||||||
|
|
||||||
DWORD typeTag;
|
DWORD typeTag;
|
||||||
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
|
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the name of the symbol. This will either be a Type name (if a UDT),
|
// Get the name of the symbol. This will either be a Type name (if a UDT),
|
||||||
// or the structure member name.
|
// or the structure member name.
|
||||||
@@ -970,7 +1094,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
|
FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
|
||||||
symbolDetails.top().Value = buffer;
|
symbolDetails.top().Value = buffer;
|
||||||
if (Name != nullptr && Name[0] != '\0')
|
if (Name != nullptr && Name[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = Name;
|
symbolDetails.top().Name = Name;
|
||||||
|
}
|
||||||
bHandled = true;
|
bHandled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -984,18 +1110,24 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
symbolDetails.top().Name = Name;
|
symbolDetails.top().Name = Name;
|
||||||
}
|
}
|
||||||
else if (buffer[0] != '\0')
|
else if (buffer[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = buffer;
|
symbolDetails.top().Name = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
LocalFree(pwszTypeName);
|
LocalFree(pwszTypeName);
|
||||||
}
|
}
|
||||||
else if (Name != nullptr && Name[0] != '\0')
|
else if (Name != nullptr && Name[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = Name;
|
symbolDetails.top().Name = Name;
|
||||||
|
}
|
||||||
|
|
||||||
if (!StoreSymbol(dwTypeIndex, offset))
|
if (!StoreSymbol(dwTypeIndex, offset))
|
||||||
{
|
{
|
||||||
// Skip printing address and base class if it has been printed already
|
// Skip printing address and base class if it has been printed already
|
||||||
if (typeTag == SymTagBaseClass)
|
if (typeTag == SymTagBaseClass)
|
||||||
|
{
|
||||||
bHandled = true;
|
bHandled = true;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,7 +1138,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
|
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
|
||||||
{
|
{
|
||||||
if (Name != nullptr && Name[0] != '\0')
|
if (Name != nullptr && Name[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = Name;
|
symbolDetails.top().Name = Name;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL isReference;
|
BOOL isReference;
|
||||||
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
|
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
|
||||||
@@ -1015,9 +1149,13 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
memset(addressStr, 0, sizeof(addressStr));
|
memset(addressStr, 0, sizeof(addressStr));
|
||||||
|
|
||||||
if (isReference)
|
if (isReference)
|
||||||
|
{
|
||||||
symbolDetails.top().Suffix += "&";
|
symbolDetails.top().Suffix += "&";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
symbolDetails.top().Suffix += "*";
|
symbolDetails.top().Suffix += "*";
|
||||||
|
}
|
||||||
|
|
||||||
// Try to dereference the pointer in a try/except block since it might be invalid
|
// Try to dereference the pointer in a try/except block since it might be invalid
|
||||||
DWORD_PTR address = DereferenceUnsafePointer(offset);
|
DWORD_PTR address = DereferenceUnsafePointer(offset);
|
||||||
@@ -1027,11 +1165,15 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
symbolDetails.top().Value = buffer;
|
symbolDetails.top().Value = buffer;
|
||||||
|
|
||||||
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
|
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
|
||||||
|
{
|
||||||
logChildren = false;
|
logChildren = false;
|
||||||
|
}
|
||||||
|
|
||||||
// no need to log any children since the address is invalid anyway
|
// no need to log any children since the address is invalid anyway
|
||||||
if (address == NULL || address == DWORD_PTR(-1))
|
if (address == NULL || address == DWORD_PTR(-1))
|
||||||
|
{
|
||||||
logChildren = false;
|
logChildren = false;
|
||||||
|
}
|
||||||
|
|
||||||
DumpTypeIndex(modBase, innerTypeID, address, bHandled, Name, addressStr, false, logChildren);
|
DumpTypeIndex(modBase, innerTypeID, address, bHandled, Name, addressStr, false, logChildren);
|
||||||
|
|
||||||
@@ -1039,12 +1181,18 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
{
|
{
|
||||||
BasicType basicType = GetBasicType(dwTypeIndex, modBase);
|
BasicType basicType = GetBasicType(dwTypeIndex, modBase);
|
||||||
if (symbolDetails.top().Type.empty())
|
if (symbolDetails.top().Type.empty())
|
||||||
|
{
|
||||||
symbolDetails.top().Type = rgBaseType[basicType];
|
symbolDetails.top().Type = rgBaseType[basicType];
|
||||||
|
}
|
||||||
|
|
||||||
if (address == NULL)
|
if (address == NULL)
|
||||||
|
{
|
||||||
symbolDetails.top().Value = "NULL";
|
symbolDetails.top().Value = "NULL";
|
||||||
|
}
|
||||||
else if (address == DWORD_PTR(-1))
|
else if (address == DWORD_PTR(-1))
|
||||||
|
{
|
||||||
symbolDetails.top().Value = "<Unable to read memory>";
|
symbolDetails.top().Value = "<Unable to read memory>";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get the size of the child member
|
// Get the size of the child member
|
||||||
@@ -1058,7 +1206,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (address == NULL)
|
else if (address == NULL)
|
||||||
|
{
|
||||||
symbolDetails.top().Value = "NULL";
|
symbolDetails.top().Value = "NULL";
|
||||||
|
}
|
||||||
else if (address == DWORD_PTR(-1))
|
else if (address == DWORD_PTR(-1))
|
||||||
{
|
{
|
||||||
symbolDetails.top().Value = "<Unable to read memory>";
|
symbolDetails.top().Value = "<Unable to read memory>";
|
||||||
@@ -1072,19 +1222,25 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
{
|
{
|
||||||
DWORD innerTypeTag;
|
DWORD innerTypeTag;
|
||||||
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
|
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (innerTypeTag)
|
switch (innerTypeTag)
|
||||||
{
|
{
|
||||||
case SymTagUDT:
|
case SymTagUDT:
|
||||||
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
|
if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL)
|
||||||
|
{
|
||||||
logChildren = false;
|
logChildren = false;
|
||||||
|
}
|
||||||
DumpTypeIndex(modBase, innerTypeID,
|
DumpTypeIndex(modBase, innerTypeID,
|
||||||
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
|
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
|
||||||
break;
|
break;
|
||||||
case SymTagPointerType:
|
case SymTagPointerType:
|
||||||
if (Name != nullptr && Name[0] != '\0')
|
if (Name != nullptr && Name[0] != '\0')
|
||||||
|
{
|
||||||
symbolDetails.top().Name = Name;
|
symbolDetails.top().Name = Name;
|
||||||
|
}
|
||||||
DumpTypeIndex(modBase, innerTypeID,
|
DumpTypeIndex(modBase, innerTypeID,
|
||||||
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
|
offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
|
||||||
break;
|
break;
|
||||||
@@ -1112,15 +1268,21 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
|
|
||||||
DWORD elementsCount;
|
DWORD elementsCount;
|
||||||
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
|
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
|
||||||
|
{
|
||||||
symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
|
symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
symbolDetails.top().Suffix += "[<unknown count>]";
|
symbolDetails.top().Suffix += "[<unknown count>]";
|
||||||
|
}
|
||||||
|
|
||||||
if (!bHandled)
|
if (!bHandled)
|
||||||
{
|
{
|
||||||
basicType = GetBasicType(dwTypeIndex, modBase);
|
basicType = GetBasicType(dwTypeIndex, modBase);
|
||||||
if (symbolDetails.top().Type.empty())
|
if (symbolDetails.top().Type.empty())
|
||||||
|
{
|
||||||
symbolDetails.top().Type = rgBaseType[basicType];
|
symbolDetails.top().Type = rgBaseType[basicType];
|
||||||
|
}
|
||||||
bHandled = true;
|
bHandled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1184,7 +1346,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
|
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
|
||||||
|
|
||||||
if (!dwChildrenCount) // If no children, we're done
|
if (!dwChildrenCount) // If no children, we're done
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare to get an array of "TypeIds", representing each of the children.
|
// Prepare to get an array of "TypeIds", representing each of the children.
|
||||||
// SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
|
// SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
|
||||||
@@ -1215,7 +1379,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
symTag == SymTagEnum ||
|
symTag == SymTagEnum ||
|
||||||
symTag == SymTagTypedef ||
|
symTag == SymTagTypedef ||
|
||||||
symTag == SymTagVTable)
|
symTag == SymTagVTable)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore static fields
|
// Ignore static fields
|
||||||
DWORD dataKind;
|
DWORD dataKind;
|
||||||
@@ -1223,7 +1389,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
if (dataKind == DataIsStaticLocal ||
|
if (dataKind == DataIsStaticLocal ||
|
||||||
dataKind == DataIsGlobal ||
|
dataKind == DataIsGlobal ||
|
||||||
dataKind == DataIsStaticMember)
|
dataKind == DataIsStaticMember)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
symbolDetails.top().HasChildren = true;
|
symbolDetails.top().HasChildren = true;
|
||||||
if (!logChildren)
|
if (!logChildren)
|
||||||
@@ -1252,7 +1420,9 @@ void WheatyExceptionReport::DumpTypeIndex(
|
|||||||
if (!bHandled2)
|
if (!bHandled2)
|
||||||
{
|
{
|
||||||
if (symbolDetails.top().Type.empty())
|
if (symbolDetails.top().Type.empty())
|
||||||
|
{
|
||||||
symbolDetails.top().Type = rgBaseType[basicType];
|
symbolDetails.top().Type = rgBaseType[basicType];
|
||||||
|
}
|
||||||
|
|
||||||
// Get the real "TypeId" of the child. We need this for the
|
// Get the real "TypeId" of the child. We need this for the
|
||||||
// SymGetTypeInfo(TI_GET_TYPEID) call below.
|
// SymGetTypeInfo(TI_GET_TYPEID) call below.
|
||||||
@@ -1291,36 +1461,56 @@ void WheatyExceptionReport::FormatOutputValue(char* pszCurrBuffer,
|
|||||||
{
|
{
|
||||||
// Special case handling for char[] type
|
// Special case handling for char[] type
|
||||||
if (countOverride != 0)
|
if (countOverride != 0)
|
||||||
|
{
|
||||||
length = countOverride;
|
length = countOverride;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
length = strlen((char*)pAddress);
|
length = strlen((char*)pAddress);
|
||||||
|
}
|
||||||
if (length > bufferSize - 6)
|
if (length > bufferSize - 6)
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), (char*)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), (char*)pAddress);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", (DWORD)length, (char*)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", (DWORD)length, (char*)pAddress);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case btStdString:
|
case btStdString:
|
||||||
{
|
{
|
||||||
std::string* value = static_cast<std::string*>(pAddress);
|
std::string* value = static_cast<std::string*>(pAddress);
|
||||||
if (value->length() > bufferSize - 6)
|
if (value->length() > bufferSize - 6)
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), value->c_str());
|
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), value->c_str());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
|
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
|
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
|
||||||
if (length == 1)
|
if (length == 1)
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
|
||||||
|
}
|
||||||
else if (length == 2)
|
else if (length == 2)
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
|
||||||
|
}
|
||||||
else if (length == 4)
|
else if (length == 4)
|
||||||
{
|
{
|
||||||
if (basicType == btFloat)
|
if (basicType == btFloat)
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
|
pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (length == 8)
|
else if (length == 8)
|
||||||
{
|
{
|
||||||
@@ -1401,9 +1591,13 @@ int __cdecl WheatyExceptionReport::Log(const TCHAR* format, ...)
|
|||||||
va_start(argptr, format);
|
va_start(argptr, format);
|
||||||
|
|
||||||
if (stackOverflowException)
|
if (stackOverflowException)
|
||||||
|
{
|
||||||
retValue = HeapLog(format, argptr);
|
retValue = HeapLog(format, argptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
retValue = StackLog(format, argptr);
|
retValue = StackLog(format, argptr);
|
||||||
|
}
|
||||||
|
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
|
|
||||||
@@ -1446,7 +1640,9 @@ void WheatyExceptionReport::ClearSymbols()
|
|||||||
{
|
{
|
||||||
symbols.clear();
|
symbols.clear();
|
||||||
while (!symbolDetails.empty())
|
while (!symbolDetails.empty())
|
||||||
|
{
|
||||||
symbolDetails.pop();
|
symbolDetails.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WheatyExceptionReport::PushSymbolDetail()
|
void WheatyExceptionReport::PushSymbolDetail()
|
||||||
@@ -1465,15 +1661,21 @@ void WheatyExceptionReport::PopSymbolDetail()
|
|||||||
void WheatyExceptionReport::PrintSymbolDetail()
|
void WheatyExceptionReport::PrintSymbolDetail()
|
||||||
{
|
{
|
||||||
if (symbolDetails.empty())
|
if (symbolDetails.empty())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't log anything if has been logged already or if it's empty
|
// Don't log anything if has been logged already or if it's empty
|
||||||
if (symbolDetails.top().Logged || symbolDetails.top().empty())
|
if (symbolDetails.top().Logged || symbolDetails.top().empty())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add appropriate indentation level (since this routine is recursive)
|
// Add appropriate indentation level (since this routine is recursive)
|
||||||
for (size_t i = 0; i < symbolDetails.size(); i++)
|
for (size_t i = 0; i < symbolDetails.size(); i++)
|
||||||
|
{
|
||||||
Log(_T("\t"));
|
Log(_T("\t"));
|
||||||
|
}
|
||||||
|
|
||||||
Log(_T("%s\r\n"), symbolDetails.top().ToString().c_str());
|
Log(_T("%s\r\n"), symbolDetails.top().ToString().c_str());
|
||||||
|
|
||||||
@@ -1487,13 +1689,17 @@ std::string SymbolDetail::ToString()
|
|||||||
if (!Name.empty())
|
if (!Name.empty())
|
||||||
{
|
{
|
||||||
if (!formatted.empty())
|
if (!formatted.empty())
|
||||||
|
{
|
||||||
formatted += " ";
|
formatted += " ";
|
||||||
|
}
|
||||||
formatted += Name;
|
formatted += Name;
|
||||||
}
|
}
|
||||||
if (!Value.empty())
|
if (!Value.empty())
|
||||||
{
|
{
|
||||||
if (Name == "passwd" || Name == "password")
|
if (Name == "passwd" || Name == "password")
|
||||||
|
{
|
||||||
Value = "<sensitive data>";
|
Value = "<sensitive data>";
|
||||||
|
}
|
||||||
formatted += " = " + Value;
|
formatted += " = " + Value;
|
||||||
}
|
}
|
||||||
return formatted;
|
return formatted;
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return iSize;
|
return iSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void incSize() { ++iSize; }
|
void incSize() { ++iSize; }
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ public:
|
|||||||
{
|
{
|
||||||
ASSERT(fromObj); // fromObj MUST not be nullptr
|
ASSERT(fromObj); // fromObj MUST not be nullptr
|
||||||
if (isValid())
|
if (isValid())
|
||||||
|
{
|
||||||
unlink();
|
unlink();
|
||||||
|
}
|
||||||
if (toObj != nullptr)
|
if (toObj != nullptr)
|
||||||
{
|
{
|
||||||
iRefTo = toObj;
|
iRefTo = toObj;
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ public:
|
|||||||
if ( iter != i_registeredObjects.end() )
|
if ( iter != i_registeredObjects.end() )
|
||||||
{
|
{
|
||||||
if ( !override )
|
if ( !override )
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
i_registeredObjects.erase(iter);
|
i_registeredObjects.erase(iter);
|
||||||
}
|
}
|
||||||
@@ -57,7 +59,9 @@ public:
|
|||||||
if ( iter != i_registeredObjects.end() )
|
if ( iter != i_registeredObjects.end() )
|
||||||
{
|
{
|
||||||
if ( delete_object )
|
if ( delete_object )
|
||||||
|
{
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
|
}
|
||||||
i_registeredObjects.erase(iter);
|
i_registeredObjects.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +78,9 @@ public:
|
|||||||
unsigned int sz = l.size();
|
unsigned int sz = l.size();
|
||||||
l.resize(sz + i_registeredObjects.size());
|
l.resize(sz + i_registeredObjects.size());
|
||||||
for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
|
for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
|
||||||
|
{
|
||||||
l[sz++] = iter->first;
|
l[sz++] = iter->first;
|
||||||
|
}
|
||||||
return i_registeredObjects.size();
|
return i_registeredObjects.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +94,9 @@ public:
|
|||||||
~ObjectRegistry()
|
~ObjectRegistry()
|
||||||
{
|
{
|
||||||
for (typename RegistryMapType::iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
|
for (typename RegistryMapType::iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
|
||||||
|
{
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
|
}
|
||||||
i_registeredObjects.clear();
|
i_registeredObjects.clear();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -63,9 +63,13 @@ namespace Acore
|
|||||||
{
|
{
|
||||||
auto i = elements._element.find(handle);
|
auto i = elements._element.find(handle);
|
||||||
if (i == elements._element.end())
|
if (i == elements._element.end())
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return i->second;
|
return i->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class SPECIFIC_TYPE, class KEY_TYPE>
|
template<class SPECIFIC_TYPE, class KEY_TYPE>
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ namespace Acore
|
|||||||
{
|
{
|
||||||
CountedPtr<SPECIFIC_TYPE>& t = Find(elements._elements, hdl, fake);
|
CountedPtr<SPECIFIC_TYPE>& t = Find(elements._elements, hdl, fake);
|
||||||
if (!t)
|
if (!t)
|
||||||
|
{
|
||||||
t = Find(elements._TailElement, hdl, fake);
|
t = Find(elements._TailElement, hdl, fake);
|
||||||
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ struct B32Impl
|
|||||||
static constexpr char Encode(uint8 v)
|
static constexpr char Encode(uint8 v)
|
||||||
{
|
{
|
||||||
ASSERT(v < 0x20);
|
ASSERT(v < 0x20);
|
||||||
if (v < 26) return 'A'+v;
|
if (v < 26) { return 'A' + v; }
|
||||||
else return '2' + (v-26);
|
else { return '2' + (v - 26); }
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr uint8 DECODE_ERROR = 0xff;
|
static constexpr uint8 DECODE_ERROR = 0xff;
|
||||||
static constexpr uint8 Decode(uint8 v)
|
static constexpr uint8 Decode(uint8 v)
|
||||||
{
|
{
|
||||||
if (v == '0') return Decode('O');
|
if (v == '0') { return Decode('O'); }
|
||||||
if (v == '1') return Decode('l');
|
if (v == '1') { return Decode('l'); }
|
||||||
if (v == '8') return Decode('B');
|
if (v == '8') { return Decode('B'); }
|
||||||
if (('A' <= v) && (v <= 'Z')) return (v-'A');
|
if (('A' <= v) && (v <= 'Z')) { return (v - 'A'); }
|
||||||
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 (('2' <= v) && (v <= '7')) { return (v - '2') + 26; }
|
||||||
return DECODE_ERROR;
|
return DECODE_ERROR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ struct B64Impl
|
|||||||
static constexpr char Encode(uint8 v)
|
static constexpr char Encode(uint8 v)
|
||||||
{
|
{
|
||||||
ASSERT(v < 0x40);
|
ASSERT(v < 0x40);
|
||||||
if (v < 26) return 'A' + v;
|
if (v < 26) { return 'A' + v; }
|
||||||
if (v < 52) return 'a' + (v - 26);
|
if (v < 52) { return 'a' + (v - 26); }
|
||||||
if (v < 62) return '0' + (v - 52);
|
if (v < 62) { return '0' + (v - 52); }
|
||||||
if (v == 62) return '+';
|
if (v == 62) { return '+'; }
|
||||||
else return '/';
|
else { return '/'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr uint8 DECODE_ERROR = 0xff;
|
static constexpr uint8 DECODE_ERROR = 0xff;
|
||||||
static constexpr uint8 Decode(uint8 v)
|
static constexpr uint8 Decode(uint8 v)
|
||||||
{
|
{
|
||||||
if (('A' <= v) && (v <= 'Z')) return (v - 'A');
|
if (('A' <= v) && (v <= 'Z')) { return (v - 'A'); }
|
||||||
if (('a' <= v) && (v <= 'z')) return (v - 'a') + 26;
|
if (('a' <= v) && (v <= 'z')) { return (v - 'a') + 26; }
|
||||||
if (('0' <= v) && (v <= '9')) return (v - '0') + 52;
|
if (('0' <= v) && (v <= '9')) { return (v - '0') + 52; }
|
||||||
if (v == '+') return 62;
|
if (v == '+') { return 62; }
|
||||||
if (v == '/') return 63;
|
if (v == '/') { return 63; }
|
||||||
return DECODE_ERROR;
|
return DECODE_ERROR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ namespace Acore::Impl
|
|||||||
{
|
{
|
||||||
size *= 8; // bits in input
|
size *= 8; // bits in input
|
||||||
if (size % PAD_TO) // pad to boundary
|
if (size % PAD_TO) // pad to boundary
|
||||||
|
{
|
||||||
size += (PAD_TO - (size % PAD_TO));
|
size += (PAD_TO - (size % PAD_TO));
|
||||||
|
}
|
||||||
return (size / BITS_PER_CHAR);
|
return (size / BITS_PER_CHAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +39,9 @@ namespace Acore::Impl
|
|||||||
{
|
{
|
||||||
size *= BITS_PER_CHAR; // bits in input
|
size *= BITS_PER_CHAR; // bits in input
|
||||||
if (size % PAD_TO) // pad to boundary
|
if (size % PAD_TO) // pad to boundary
|
||||||
|
{
|
||||||
size += (PAD_TO - (size % PAD_TO));
|
size += (PAD_TO - (size % PAD_TO));
|
||||||
|
}
|
||||||
return (size / 8);
|
return (size / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +49,9 @@ namespace Acore::Impl
|
|||||||
{
|
{
|
||||||
auto it = data.begin(), end = data.end();
|
auto it = data.begin(), end = data.end();
|
||||||
if (it == end)
|
if (it == end)
|
||||||
|
{
|
||||||
return "";
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
s.reserve(EncodedSize(data.size()));
|
s.reserve(EncodedSize(data.size()));
|
||||||
@@ -57,7 +63,7 @@ namespace Acore::Impl
|
|||||||
if (bitsLeft >= BITS_PER_CHAR)
|
if (bitsLeft >= BITS_PER_CHAR)
|
||||||
{
|
{
|
||||||
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)
|
if (!bitsLeft)
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
@@ -69,7 +75,9 @@ namespace Acore::Impl
|
|||||||
thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
|
thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
|
||||||
bitsLeft += (8 - BITS_PER_CHAR);
|
bitsLeft += (8 - BITS_PER_CHAR);
|
||||||
if ((++it) != end)
|
if ((++it) != end)
|
||||||
|
{
|
||||||
thisC |= (*it >> bitsLeft);
|
thisC |= (*it >> bitsLeft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.append(1, Encoding::Encode(thisC));
|
s.append(1, Encoding::Encode(thisC));
|
||||||
} while (it != end);
|
} while (it != end);
|
||||||
@@ -77,9 +85,13 @@ namespace Acore::Impl
|
|||||||
while (bitsLeft != 8)
|
while (bitsLeft != 8)
|
||||||
{
|
{
|
||||||
if (bitsLeft > BITS_PER_CHAR)
|
if (bitsLeft > BITS_PER_CHAR)
|
||||||
|
{
|
||||||
bitsLeft -= BITS_PER_CHAR;
|
bitsLeft -= BITS_PER_CHAR;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bitsLeft += (8 - BITS_PER_CHAR);
|
bitsLeft += (8 - BITS_PER_CHAR);
|
||||||
|
}
|
||||||
s.append(1, PADDING);
|
s.append(1, PADDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +102,9 @@ namespace Acore::Impl
|
|||||||
{
|
{
|
||||||
auto it = data.begin(), end = data.end();
|
auto it = data.begin(), end = data.end();
|
||||||
if (it == end)
|
if (it == end)
|
||||||
|
{
|
||||||
return std::vector<uint8>();
|
return std::vector<uint8>();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8> v;
|
std::vector<uint8> v;
|
||||||
v.reserve(DecodedSize(data.size()));
|
v.reserve(DecodedSize(data.size()));
|
||||||
@@ -126,15 +140,21 @@ namespace Acore::Impl
|
|||||||
while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
|
while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
|
||||||
{
|
{
|
||||||
if (bitsLeft > BITS_PER_CHAR)
|
if (bitsLeft > BITS_PER_CHAR)
|
||||||
|
{
|
||||||
bitsLeft -= BITS_PER_CHAR;
|
bitsLeft -= BITS_PER_CHAR;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bitsLeft += (8 - BITS_PER_CHAR);
|
bitsLeft += (8 - BITS_PER_CHAR);
|
||||||
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok, all padding should be consumed, and we should be at end of string
|
// ok, all padding should be consumed, and we should be at end of string
|
||||||
if (it == end)
|
if (it == end)
|
||||||
|
{
|
||||||
return v;
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
// anything else is an error
|
// anything else is an error
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
Appender::Appender(uint8 _id, std::string const& _name, LogLevel _level /* = LOG_LEVEL_DISABLED */, AppenderFlags _flags /* = APPENDER_FLAGS_NONE */):
|
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() { }
|
Appender::~Appender() { }
|
||||||
|
|
||||||
@@ -41,18 +41,26 @@ void Appender::setLogLevel(LogLevel _level)
|
|||||||
void Appender::write(LogMessage* message)
|
void Appender::write(LogMessage* message)
|
||||||
{
|
{
|
||||||
if (!level || level < message->level)
|
if (!level || level < message->level)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
|
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
|
||||||
|
{
|
||||||
ss << message->getTimeStr() << ' ';
|
ss << message->getTimeStr() << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
|
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
|
||||||
|
{
|
||||||
ss << Acore::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
|
ss << Acore::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
|
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
|
||||||
|
{
|
||||||
ss << '[' << message->type << "] ";
|
ss << '[' << message->type << "] ";
|
||||||
|
}
|
||||||
|
|
||||||
message->prefix = ss.str();
|
message->prefix = ss.str();
|
||||||
_write(message);
|
_write(message);
|
||||||
|
|||||||
@@ -20,10 +20,14 @@ AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel lev
|
|||||||
: Appender(id, name, level, flags), _colored(false)
|
: Appender(id, name, level, flags), _colored(false)
|
||||||
{
|
{
|
||||||
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
|
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
|
||||||
|
{
|
||||||
_colors[i] = ColorTypes(NUM_COLOR_TYPES);
|
_colors[i] = ColorTypes(NUM_COLOR_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
if (3 < args.size())
|
if (3 < args.size())
|
||||||
|
{
|
||||||
InitColors(name, args[3]);
|
InitColors(name, args[3]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppenderConsole::InitColors(std::string const& name, std::string_view str)
|
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)
|
for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
|
||||||
{
|
{
|
||||||
if (Optional<uint8> color = Acore::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color))
|
if (Optional<uint8> color = Acore::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color))
|
||||||
|
{
|
||||||
_colors[i] = static_cast<ColorTypes>(*color);
|
_colors[i] = static_cast<ColorTypes>(*color);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Invalid color '%s' for log level %s on console appender %s",
|
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
|
FG_WHITE // LWHITE
|
||||||
};
|
};
|
||||||
|
|
||||||
fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
|
fprintf((stdout_stream ? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppenderConsole::ResetColor(bool stdout_stream)
|
void AppenderConsole::ResetColor(bool stdout_stream)
|
||||||
@@ -163,23 +169,23 @@ void AppenderConsole::_write(LogMessage const* message)
|
|||||||
switch (message->level)
|
switch (message->level)
|
||||||
{
|
{
|
||||||
case LOG_LEVEL_TRACE:
|
case LOG_LEVEL_TRACE:
|
||||||
index = 5;
|
index = 5;
|
||||||
break;
|
break;
|
||||||
case LOG_LEVEL_DEBUG:
|
case LOG_LEVEL_DEBUG:
|
||||||
index = 4;
|
index = 4;
|
||||||
break;
|
break;
|
||||||
case LOG_LEVEL_INFO:
|
case LOG_LEVEL_INFO:
|
||||||
index = 3;
|
index = 3;
|
||||||
break;
|
break;
|
||||||
case LOG_LEVEL_WARN:
|
case LOG_LEVEL_WARN:
|
||||||
index = 2;
|
index = 2;
|
||||||
break;
|
break;
|
||||||
case LOG_LEVEL_FATAL:
|
case LOG_LEVEL_FATAL:
|
||||||
index = 0;
|
index = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
index = 1;
|
index = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetColor(stdout_stream, _colors[index]);
|
SetColor(stdout_stream, _colors[index]);
|
||||||
@@ -187,5 +193,7 @@ void AppenderConsole::_write(LogMessage const* message)
|
|||||||
ResetColor(stdout_stream);
|
ResetColor(stdout_stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
|
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)
|
_fileSize(0)
|
||||||
{
|
{
|
||||||
if (args.size() < 4)
|
if (args.size() < 4)
|
||||||
|
{
|
||||||
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s", name.c_str()));
|
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s", name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
_fileName.assign(args[3]);
|
_fileName.assign(args[3]);
|
||||||
|
|
||||||
std::string mode = "a";
|
std::string mode = "a";
|
||||||
if (4 < args.size())
|
if (4 < args.size())
|
||||||
|
{
|
||||||
mode.assign(args[4]);
|
mode.assign(args[4]);
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
|
if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
|
||||||
{
|
{
|
||||||
size_t dot_pos = _fileName.find_last_of('.');
|
size_t dot_pos = _fileName.find_last_of('.');
|
||||||
if (dot_pos != std::string::npos)
|
if (dot_pos != std::string::npos)
|
||||||
|
{
|
||||||
_fileName.insert(dot_pos, sLog->GetLogsTimestamp());
|
_fileName.insert(dot_pos, sLog->GetLogsTimestamp());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_fileName += sLog->GetLogsTimestamp();
|
_fileName += sLog->GetLogsTimestamp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (5 < args.size())
|
if (5 < args.size())
|
||||||
{
|
{
|
||||||
if (Optional<uint32> size = Acore::StringTo<uint32>(args[5]))
|
if (Optional<uint32> size = Acore::StringTo<uint32>(args[5]))
|
||||||
|
{
|
||||||
_maxFileSize = *size;
|
_maxFileSize = *size;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
throw InvalidAppenderArgsException(Acore::StringFormat("Log::CreateAppenderFromConfig: Invalid size '%s' for appender %s", std::string(args[5]).c_str(), name.c_str()));
|
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");
|
_dynamicName = std::string::npos != _fileName.find("%s");
|
||||||
_backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
|
_backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
|
||||||
|
|
||||||
if (!_dynamicName)
|
if (!_dynamicName)
|
||||||
|
{
|
||||||
logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
|
logfile = OpenFile(_fileName, mode, (mode == "w") && _backup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppenderFile::~AppenderFile()
|
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
|
// 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);
|
FILE* file = OpenFile(namebuf, "a", _backup || exceedMaxSize);
|
||||||
if (!file)
|
if (!file)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
|
fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
|
||||||
fflush(file);
|
fflush(file);
|
||||||
@@ -77,10 +93,14 @@ void AppenderFile::_write(LogMessage const* message)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (exceedMaxSize)
|
else if (exceedMaxSize)
|
||||||
|
{
|
||||||
logfile = OpenFile(_fileName, "w", true);
|
logfile = OpenFile(_fileName, "w", true);
|
||||||
|
}
|
||||||
|
|
||||||
if (!logfile)
|
if (!logfile)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
|
fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
|
||||||
fflush(logfile);
|
fflush(logfile);
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ Appender* Log::GetAppenderByName(std::string_view name)
|
|||||||
{
|
{
|
||||||
auto it = appenders.begin();
|
auto it = appenders.begin();
|
||||||
while (it != appenders.end() && it->second && it->second->getName() != name)
|
while (it != appenders.end() && it->second && it->second->getName() != name)
|
||||||
|
{
|
||||||
++it;
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
return it == appenders.end() ? nullptr : it->second.get();
|
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)
|
void Log::CreateAppenderFromConfig(std::string const& appenderName)
|
||||||
{
|
{
|
||||||
if (appenderName.empty())
|
if (appenderName.empty())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Format = type, level, flags, optional1, optional2
|
// Format = type, level, flags, optional1, optional2
|
||||||
// if type = File. optional1 = file and option2 = mode
|
// if type = File. optional1 = file and option2 = mode
|
||||||
@@ -85,7 +89,9 @@ void Log::CreateAppenderFromConfig(std::string const& appenderName)
|
|||||||
if (size > 2)
|
if (size > 2)
|
||||||
{
|
{
|
||||||
if (Optional<uint8> flagsVal = Acore::StringTo<uint8>(tokens[2]))
|
if (Optional<uint8> flagsVal = Acore::StringTo<uint8>(tokens[2]))
|
||||||
|
{
|
||||||
flags = AppenderFlags(*flagsVal);
|
flags = AppenderFlags(*flagsVal);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown flags '%s' for appender %s\n", std::string(tokens[2]).c_str(), name.c_str());
|
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)
|
void Log::CreateLoggerFromConfig(std::string const& appenderName)
|
||||||
{
|
{
|
||||||
if (appenderName.empty())
|
if (appenderName.empty())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LogLevel level = LOG_LEVEL_DISABLED;
|
LogLevel level = LOG_LEVEL_DISABLED;
|
||||||
|
|
||||||
@@ -143,7 +151,9 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (level > highestLogLevel)
|
if (level > highestLogLevel)
|
||||||
|
{
|
||||||
highestLogLevel = level;
|
highestLogLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
logger = std::make_unique<Logger>(name, level);
|
logger = std::make_unique<Logger>(name, level);
|
||||||
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), 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());
|
//fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist\n", std::string(appenderName).c_str(), name.c_str());
|
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.");
|
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
|
||||||
for (std::string const& appenderName : keys)
|
for (std::string const& appenderName : keys)
|
||||||
|
{
|
||||||
CreateAppenderFromConfig(appenderName);
|
CreateAppenderFromConfig(appenderName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::ReadLoggersFromConfig()
|
void Log::ReadLoggersFromConfig()
|
||||||
{
|
{
|
||||||
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
|
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
|
||||||
for (std::string const& loggerName : keys)
|
for (std::string const& loggerName : keys)
|
||||||
|
{
|
||||||
CreateLoggerFromConfig(loggerName);
|
CreateLoggerFromConfig(loggerName);
|
||||||
|
}
|
||||||
|
|
||||||
// Bad config configuration, creating default config
|
// Bad config configuration, creating default config
|
||||||
if (loggers.find(LOGGER_ROOT) == loggers.end())
|
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);
|
auto it = loggers.find(type);
|
||||||
if (it != loggers.end())
|
if (it != loggers.end())
|
||||||
|
{
|
||||||
return it->second.get();
|
return it->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
if (type == LOGGER_ROOT)
|
if (type == LOGGER_ROOT)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::string parentLogger = LOGGER_ROOT;
|
std::string parentLogger = LOGGER_ROOT;
|
||||||
size_t found = type.find_last_of('.');
|
size_t found = type.find_last_of('.');
|
||||||
if (found != std::string::npos)
|
if (found != std::string::npos)
|
||||||
|
{
|
||||||
parentLogger = type.substr(0, found);
|
parentLogger = type.substr(0, found);
|
||||||
|
}
|
||||||
|
|
||||||
return GetLoggerByType(parentLogger);
|
return GetLoggerByType(parentLogger);
|
||||||
}
|
}
|
||||||
@@ -255,7 +277,9 @@ std::string Log::GetTimestampStr()
|
|||||||
bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /* = true */)
|
bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /* = true */)
|
||||||
{
|
{
|
||||||
if (newLeveli < 0)
|
if (newLeveli < 0)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LogLevel newLevel = LogLevel(newLeveli);
|
LogLevel newLevel = LogLevel(newLeveli);
|
||||||
|
|
||||||
@@ -263,21 +287,29 @@ bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /*
|
|||||||
{
|
{
|
||||||
auto it = loggers.begin();
|
auto it = loggers.begin();
|
||||||
while (it != loggers.end() && it->second->getName() != name)
|
while (it != loggers.end() && it->second->getName() != name)
|
||||||
|
{
|
||||||
++it;
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
if (it == loggers.end())
|
if (it == loggers.end())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
it->second->setLogLevel(newLevel);
|
it->second->setLogLevel(newLevel);
|
||||||
|
|
||||||
if (newLevel != LOG_LEVEL_DISABLED && newLevel > highestLogLevel)
|
if (newLevel != LOG_LEVEL_DISABLED && newLevel > highestLogLevel)
|
||||||
|
{
|
||||||
highestLogLevel = newLevel;
|
highestLogLevel = newLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Appender* appender = GetAppenderByName(name);
|
Appender* appender = GetAppenderByName(name);
|
||||||
if (!appender)
|
if (!appender)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
appender->setLogLevel(newLevel);
|
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)
|
void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const* name)
|
||||||
{
|
{
|
||||||
if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO))
|
if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
|
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)
|
void Log::SetRealmId(uint32 id)
|
||||||
{
|
{
|
||||||
for (std::pair<uint8 const, std::unique_ptr<Appender>>& appender : appenders)
|
for (std::pair<uint8 const, std::unique_ptr<Appender>>& appender : appenders)
|
||||||
|
{
|
||||||
appender.second->setRealmId(id);
|
appender.second->setRealmId(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::Close()
|
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
|
// Don't even look for a logger if the LogLevel is higher than the highest log levels across all loggers
|
||||||
if (level > highestLogLevel)
|
if (level > highestLogLevel)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Logger const* logger = GetLoggerByType(type);
|
Logger const* logger = GetLoggerByType(type);
|
||||||
if (!logger)
|
if (!logger)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LogLevel logLevel = logger->getLogLevel();
|
LogLevel logLevel = logger->getLogLevel();
|
||||||
return logLevel != LOG_LEVEL_DISABLED && logLevel >= level;
|
return logLevel != LOG_LEVEL_DISABLED && logLevel >= level;
|
||||||
@@ -354,7 +394,9 @@ void Log::LoadFromConfig()
|
|||||||
|
|
||||||
if (!m_logsDir.empty())
|
if (!m_logsDir.empty())
|
||||||
if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
|
if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
|
||||||
|
{
|
||||||
m_logsDir.push_back('/');
|
m_logsDir.push_back('/');
|
||||||
|
}
|
||||||
|
|
||||||
ReadAppendersFromConfig();
|
ReadAppendersFromConfig();
|
||||||
ReadLoggersFromConfig();
|
ReadLoggersFromConfig();
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ public:
|
|||||||
void outCommand(uint32 account, Format&& fmt, Args&&... args)
|
void outCommand(uint32 account, Format&& fmt, Args&&... args)
|
||||||
{
|
{
|
||||||
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
|
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
outCommand(Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...), std::to_string(account));
|
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)
|
void outErrorDb(Format&& fmt, Args&& ... args)
|
||||||
{
|
{
|
||||||
if (!ShouldLog("sql.sql", LOG_LEVEL_ERROR))
|
if (!ShouldLog("sql.sql", LOG_LEVEL_ERROR))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
outMessage("sql.sql", LOG_LEVEL_ERROR, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
|
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)
|
void outSQLDev(Format&& fmt, Args&& ... args)
|
||||||
{
|
{
|
||||||
if (!ShouldLog("sql.dev", LOG_LEVEL_INFO))
|
if (!ShouldLog("sql.dev", LOG_LEVEL_INFO))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
outMessage("sql.dev", LOG_LEVEL_INFO, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
|
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)
|
void outSQLDriver(Format&& fmt, Args&& ... args)
|
||||||
{
|
{
|
||||||
if (!ShouldLog("sql.driver", LOG_LEVEL_INFO))
|
if (!ShouldLog("sql.driver", LOG_LEVEL_INFO))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
outMessage("sql.driver", LOG_LEVEL_INFO, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
|
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)
|
void outDebug(DebugLogFilters filter, Format&& fmt, Args&& ... args)
|
||||||
{
|
{
|
||||||
if (!(_debugLogMask & filter))
|
if (!(_debugLogMask & filter))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ShouldLog("server", LOG_LEVEL_DEBUG))
|
if (!ShouldLog("server", LOG_LEVEL_DEBUG))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
outMessage("server", LOG_LEVEL_DEBUG, Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
|
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)
|
for (std::pair<uint8 const, Appender*> const& appender : appenders)
|
||||||
if (appender.second)
|
if (appender.second)
|
||||||
|
{
|
||||||
appender.second->write(message);
|
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 /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
|
||||||
const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
|
const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
|
||||||
{
|
{
|
||||||
float startX=pa[2], startY=pa[0], startZ=pa[1];
|
float startX = pa[2], startY = pa[0], startZ = pa[1];
|
||||||
float destX=pb[2], destY=pb[0], destZ=pb[1];
|
float destX = pb[2], destY = pb[0], destZ = pb[1];
|
||||||
float slopeAngle = getSlopeAngle(startX, startY, startZ, destX, destY, destZ);
|
float slopeAngle = getSlopeAngle(startX, startY, startZ, destX, destY, destZ);
|
||||||
float slopeAngleDegree = (slopeAngle * 180.0f / M_PI);
|
float slopeAngleDegree = (slopeAngle * 180.0f / M_PI);
|
||||||
float cost = slopeAngleDegree > 0 ? 1.0f + (1.0f * (slopeAngleDegree/100)) : 1.0f;
|
float cost = slopeAngleDegree > 0 ? 1.0f + (1.0f * (slopeAngleDegree / 100)) : 1.0f;
|
||||||
float dist = dtVdist(pa, pb);
|
float dist = dtVdist(pa, pb);
|
||||||
auto totalCost = dist * cost * getAreaCost(curPoly->getArea());
|
auto totalCost = dist * cost * getAreaCost(curPoly->getArea());
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,9 @@ bool WinServiceUninstall()
|
|||||||
if (QueryServiceStatus(service, &serviceStatus2))
|
if (QueryServiceStatus(service, &serviceStatus2))
|
||||||
{
|
{
|
||||||
if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
|
if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
|
||||||
|
{
|
||||||
DeleteService(service);
|
DeleteService(service);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CloseServiceHandle(service);
|
CloseServiceHandle(service);
|
||||||
}
|
}
|
||||||
@@ -163,10 +165,14 @@ void WINAPI ServiceControlHandler(DWORD controlCode)
|
|||||||
default:
|
default:
|
||||||
if ( controlCode >= 128 && controlCode <= 255 )
|
if ( controlCode >= 128 && controlCode <= 255 )
|
||||||
// user defined control code
|
// user defined control code
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// unrecognized control code
|
// unrecognized control code
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
SetServiceStatus(serviceStatusHandle, &serviceStatus);
|
||||||
@@ -194,7 +200,7 @@ void WINAPI ServiceMain(DWORD argc, char* argv[])
|
|||||||
|
|
||||||
for (i = 0; i < std::strlen(path); i++)
|
for (i = 0; i < std::strlen(path); i++)
|
||||||
{
|
{
|
||||||
if (path[i] == '\\') last_slash = i;
|
if (path[i] == '\\') { last_slash = i; }
|
||||||
}
|
}
|
||||||
|
|
||||||
path[last_slash] = 0;
|
path[last_slash] = 0;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
template <class T, typename StorageType = std::deque<T> >
|
template <class T, typename StorageType = std::deque<T>>
|
||||||
class LockedQueue
|
class LockedQueue
|
||||||
{
|
{
|
||||||
//! Lock access to the queue.
|
//! Lock access to the queue.
|
||||||
@@ -59,7 +59,9 @@ public:
|
|||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
|
|
||||||
if (_queue.empty())
|
if (_queue.empty())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
result = _queue.front();
|
result = _queue.front();
|
||||||
_queue.pop_front();
|
_queue.pop_front();
|
||||||
@@ -73,11 +75,15 @@ public:
|
|||||||
std::lock_guard<std::mutex> lock(_lock);
|
std::lock_guard<std::mutex> lock(_lock);
|
||||||
|
|
||||||
if (_queue.empty())
|
if (_queue.empty())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
result = _queue.front();
|
result = _queue.front();
|
||||||
if (!check.Process(result))
|
if (!check.Process(result))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_queue.pop_front();
|
_queue.pop_front();
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +97,9 @@ public:
|
|||||||
T& result = _queue.front();
|
T& result = _queue.front();
|
||||||
|
|
||||||
if (autoUnlock)
|
if (autoUnlock)
|
||||||
|
{
|
||||||
unlock();
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ public:
|
|||||||
std::lock_guard<std::mutex> lock(_queueLock);
|
std::lock_guard<std::mutex> lock(_queueLock);
|
||||||
|
|
||||||
if (_queue.empty() || _shutdown)
|
if (_queue.empty() || _shutdown)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
value = _queue.front();
|
value = _queue.front();
|
||||||
|
|
||||||
@@ -61,10 +63,14 @@ public:
|
|||||||
// we could be using .wait(lock, predicate) overload here but it is broken
|
// we could be using .wait(lock, predicate) overload here but it is broken
|
||||||
// https://connect.microsoft.com/VisualStudio/feedback/details/1098841
|
// https://connect.microsoft.com/VisualStudio/feedback/details/1098841
|
||||||
while (_queue.empty() && !_shutdown)
|
while (_queue.empty() && !_shutdown)
|
||||||
|
{
|
||||||
_condition.wait(lock);
|
_condition.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (_queue.empty() || _shutdown)
|
if (_queue.empty() || _shutdown)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
value = _queue.front();
|
value = _queue.front();
|
||||||
|
|
||||||
|
|||||||
@@ -31,20 +31,30 @@ void SetProcessPriority(std::string const& logChannel, uint32 affinity, bool hig
|
|||||||
ULONG_PTR currentAffinity = affinity & appAff;
|
ULONG_PTR currentAffinity = affinity & appAff;
|
||||||
|
|
||||||
if (!currentAffinity)
|
if (!currentAffinity)
|
||||||
|
{
|
||||||
LOG_ERROR(logChannel, "Processors marked in UseProcessors bitmask (hex) %x are not accessible. Accessible processors bitmask (hex): %x", affinity, appAff);
|
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))
|
else if (SetProcessAffinityMask(hProcess, currentAffinity))
|
||||||
|
{
|
||||||
LOG_INFO(logChannel, "Using processors (bitmask, hex): %x", currentAffinity);
|
LOG_INFO(logChannel, "Using processors (bitmask, hex): %x", currentAffinity);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG_ERROR(logChannel, "Can't set used processors (hex): %x", currentAffinity);
|
LOG_ERROR(logChannel, "Can't set used processors (hex): %x", currentAffinity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highPriority)
|
if (highPriority)
|
||||||
{
|
{
|
||||||
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
|
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
|
||||||
|
{
|
||||||
LOG_INFO(logChannel, "Process priority class set to HIGH");
|
LOG_INFO(logChannel, "Process priority class set to HIGH");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG_ERROR(logChannel, "Can't set process priority class.");
|
LOG_ERROR(logChannel, "Can't set process priority class.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__linux__) // Linux
|
#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)
|
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
|
||||||
if (affinity & (1 << i))
|
if (affinity & (1 << i))
|
||||||
|
{
|
||||||
CPU_SET(i, &mask);
|
CPU_SET(i, &mask);
|
||||||
|
}
|
||||||
|
|
||||||
if (sched_setaffinity(0, sizeof(mask), &mask))
|
if (sched_setaffinity(0, sizeof(mask), &mask))
|
||||||
|
{
|
||||||
LOG_ERROR(logChannel, "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
|
LOG_ERROR(logChannel, "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPU_ZERO(&mask);
|
CPU_ZERO(&mask);
|
||||||
@@ -71,9 +85,13 @@ void SetProcessPriority(std::string const& logChannel, uint32 affinity, bool hig
|
|||||||
if (highPriority)
|
if (highPriority)
|
||||||
{
|
{
|
||||||
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
|
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
|
||||||
|
{
|
||||||
LOG_ERROR(logChannel, "Can't set process priority class, error: %s", strerror(errno));
|
LOG_ERROR(logChannel, "Can't set process priority class, error: %s", strerror(errno));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG_INFO(logChannel, "Process priority class set to %i", getpriority(PRIO_PROCESS, 0));
|
LOG_INFO(logChannel, "Process priority class set to %i", getpriority(PRIO_PROCESS, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#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
|
// register reference to m_task to prevent it deeltion until destructor
|
||||||
if (m_task)
|
if (m_task)
|
||||||
|
{
|
||||||
m_task->incReference();
|
m_task->incReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::~Thread()
|
Thread::~Thread()
|
||||||
@@ -34,13 +36,17 @@ Thread::~Thread()
|
|||||||
|
|
||||||
// deleted runnable object (if no other references)
|
// deleted runnable object (if no other references)
|
||||||
if (m_task)
|
if (m_task)
|
||||||
|
{
|
||||||
m_task->decReference();
|
m_task->decReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::wait()
|
bool Thread::wait()
|
||||||
{
|
{
|
||||||
if (m_iThreadId == std::thread::id() || !m_task)
|
if (m_iThreadId == std::thread::id() || !m_task)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
|
||||||
@@ -61,7 +67,9 @@ bool Thread::wait()
|
|||||||
void Thread::destroy()
|
void Thread::destroy()
|
||||||
{
|
{
|
||||||
if (m_iThreadId == std::thread::id() || !m_task)
|
if (m_iThreadId == std::thread::id() || !m_task)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: We need to make sure that all threads can be trusted to
|
// FIXME: We need to make sure that all threads can be trusted to
|
||||||
// halt execution on their own as this is not an interrupt
|
// halt execution on their own as this is not an interrupt
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ namespace Acore
|
|||||||
void decReference()
|
void decReference()
|
||||||
{
|
{
|
||||||
if (!--m_refs)
|
if (!--m_refs)
|
||||||
|
{
|
||||||
delete this;
|
delete this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::atomic_long m_refs;
|
std::atomic_long m_refs;
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class CircularBuffer {
|
class CircularBuffer
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
explicit CircularBuffer(size_t size) :
|
explicit CircularBuffer(size_t size) :
|
||||||
buf_(std::unique_ptr<T[]>(new 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_
|
// 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
|
// when compared to the original implementation of this class
|
||||||
std::vector<T> content() {
|
std::vector<T> content()
|
||||||
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
return std::vector<T>(buf_.get(), buf_.get() + size());
|
return std::vector<T>(buf_.get(), buf_.get() + size());
|
||||||
}
|
}
|
||||||
|
|
||||||
T peak_back() {
|
T peak_back()
|
||||||
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
return empty() ? T() : buf_[tail_];
|
return empty() ? T() : buf_[tail_];
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ namespace Acore
|
|||||||
void check() const
|
void check() const
|
||||||
{
|
{
|
||||||
if (!(_buf < _end))
|
if (!(_buf < _end))
|
||||||
|
{
|
||||||
throw std::out_of_range("index");
|
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");
|
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)
|
if (std::size(container) <= requestedSize)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto keepIt = std::begin(container), curIt = std::begin(container);
|
auto keepIt = std::begin(container), curIt = std::begin(container);
|
||||||
uint32 elementsToKeep = requestedSize, elementsToProcess = std::size(container);
|
uint32 elementsToKeep = requestedSize, elementsToProcess = std::size(container);
|
||||||
@@ -81,7 +85,9 @@ namespace Acore::Containers
|
|||||||
if (urand(1, elementsToProcess) <= elementsToKeep)
|
if (urand(1, elementsToProcess) <= elementsToKeep)
|
||||||
{
|
{
|
||||||
if (keepIt != curIt)
|
if (keepIt != curIt)
|
||||||
|
{
|
||||||
*keepIt = std::move(*curIt);
|
*keepIt = std::move(*curIt);
|
||||||
|
}
|
||||||
|
|
||||||
++keepIt;
|
++keepIt;
|
||||||
--elementsToKeep;
|
--elementsToKeep;
|
||||||
@@ -102,7 +108,9 @@ namespace Acore::Containers
|
|||||||
std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate);
|
std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate);
|
||||||
|
|
||||||
if (requestedSize)
|
if (requestedSize)
|
||||||
|
{
|
||||||
RandomResize(containerCopy, requestedSize);
|
RandomResize(containerCopy, requestedSize);
|
||||||
|
}
|
||||||
|
|
||||||
container = std::move(containerCopy);
|
container = std::move(containerCopy);
|
||||||
}
|
}
|
||||||
@@ -160,7 +168,9 @@ namespace Acore::Containers
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (weightSum <= 0.0)
|
if (weightSum <= 0.0)
|
||||||
|
{
|
||||||
weights.assign(std::size(container), 1.0);
|
weights.assign(std::size(container), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
return SelectRandomWeightedContainerElement(container, weights);
|
return SelectRandomWeightedContainerElement(container, weights);
|
||||||
}
|
}
|
||||||
@@ -195,9 +205,13 @@ namespace Acore::Containers
|
|||||||
for (auto itr = range.first; itr != range.second;)
|
for (auto itr = range.first; itr != range.second;)
|
||||||
{
|
{
|
||||||
if (itr->second == value)
|
if (itr->second == value)
|
||||||
|
{
|
||||||
itr = multimap.erase(itr);
|
itr = multimap.erase(itr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++itr;
|
++itr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,15 @@ public:
|
|||||||
{
|
{
|
||||||
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
|
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
|
||||||
if (Container.empty())
|
if (Container.empty())
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto it = Container.find(k);
|
auto it = Container.find(k);
|
||||||
if (it != Container.end())
|
if (it != Container.end())
|
||||||
|
{
|
||||||
return dynamic_cast<T*>(it->second.get());
|
return dynamic_cast<T*>(it->second.get());
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +51,9 @@ public:
|
|||||||
{
|
{
|
||||||
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
|
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
|
||||||
if (T* v = Get<T>(k))
|
if (T* v = Get<T>(k))
|
||||||
|
{
|
||||||
return v;
|
return v;
|
||||||
|
}
|
||||||
T* v = new T();
|
T* v = new T();
|
||||||
Container.emplace(k, std::unique_ptr<T>(v));
|
Container.emplace(k, std::unique_ptr<T>(v));
|
||||||
return v;
|
return v;
|
||||||
|
|||||||
@@ -64,18 +64,22 @@ void EventProcessor::KillAllEvents(bool force)
|
|||||||
delete i_old->second;
|
delete i_old->second;
|
||||||
|
|
||||||
if (!force) // need per-element cleanup
|
if (!force) // need per-element cleanup
|
||||||
|
{
|
||||||
m_events.erase (i_old);
|
m_events.erase (i_old);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fast clear event list (in force case)
|
// fast clear event list (in force case)
|
||||||
if (force)
|
if (force)
|
||||||
|
{
|
||||||
m_events.clear();
|
m_events.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)
|
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;
|
Event->m_execTime = e_time;
|
||||||
m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event));
|
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)
|
[[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));
|
return atan(abs(destZ - startZ) / abs(floorDist));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ inline T standard_deviation(Container&& c)
|
|||||||
auto mean = sum / size;
|
auto mean = sum / size;
|
||||||
|
|
||||||
if (size == 1)
|
if (size == 1)
|
||||||
|
{
|
||||||
return (T) 0;
|
return (T) 0;
|
||||||
|
}
|
||||||
|
|
||||||
T accum = T();
|
T accum = T();
|
||||||
for (const auto d : c)
|
for (const auto d : c)
|
||||||
|
{
|
||||||
accum += (d - mean) * (d - mean);
|
accum += (d - mean) * (d - mean);
|
||||||
|
}
|
||||||
return std::sqrt(accum / (size - 1));
|
return std::sqrt(accum / (size - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +47,8 @@ inline T median(std::vector<T> a)
|
|||||||
{
|
{
|
||||||
size_t n = a.size();
|
size_t n = a.size();
|
||||||
// If size of the arr[] is even
|
// If size of the arr[] is even
|
||||||
if (n % 2 == 0) {
|
if (n % 2 == 0)
|
||||||
|
{
|
||||||
|
|
||||||
// Applying nth_element
|
// Applying nth_element
|
||||||
// on n/2th index
|
// on n/2th index
|
||||||
@@ -65,7 +70,8 @@ inline T median(std::vector<T> a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If size of the arr[] is odd
|
// If size of the arr[] is odd
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
|
|
||||||
// Applying nth_element
|
// Applying nth_element
|
||||||
// on n/2
|
// on n/2
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ static RandomEngine engine;
|
|||||||
static SFMTRand* GetRng()
|
static SFMTRand* GetRng()
|
||||||
{
|
{
|
||||||
if (!sfmtRand)
|
if (!sfmtRand)
|
||||||
|
{
|
||||||
sfmtRand = std::make_unique<SFMTRand>();
|
sfmtRand = std::make_unique<SFMTRand>();
|
||||||
|
}
|
||||||
|
|
||||||
return sfmtRand.get();
|
return sfmtRand.get();
|
||||||
}
|
}
|
||||||
@@ -51,7 +53,7 @@ Milliseconds randtime(Milliseconds min, Milliseconds max)
|
|||||||
{
|
{
|
||||||
long long diff = max.count() - min.count();
|
long long diff = max.count() - min.count();
|
||||||
ASSERT(diff >= 0);
|
ASSERT(diff >= 0);
|
||||||
ASSERT(diff <= (uint32)-1);
|
ASSERT(diff <= (uint32) - 1);
|
||||||
return min + Milliseconds(urand(0, diff));
|
return min + Milliseconds(urand(0, diff));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ namespace Acore
|
|||||||
std::lock_guard lock(_mutex);
|
std::lock_guard lock(_mutex);
|
||||||
|
|
||||||
if (_handled.find(sig) != _handled.end())
|
if (_handled.find(sig) != _handled.end())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_handled.insert(sig);
|
_handled.insert(sig);
|
||||||
signal(sig, func);
|
signal(sig, func);
|
||||||
@@ -36,7 +38,9 @@ namespace Acore
|
|||||||
~SignalHandler()
|
~SignalHandler()
|
||||||
{
|
{
|
||||||
for (auto const& sig : _handled)
|
for (auto const& sig : _handled)
|
||||||
|
{
|
||||||
signal(sig, nullptr);
|
signal(sig, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,87 +34,88 @@ namespace Acore::Impl::EnumUtilsImpl
|
|||||||
|
|
||||||
class EnumUtils
|
class EnumUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static size_t Count() { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::Count(); }
|
static size_t Count() { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::Count(); }
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static EnumText ToString(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToString(value); }
|
static EnumText ToString(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToString(value); }
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static Enum FromIndex(size_t index) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::FromIndex(index); }
|
static Enum FromIndex(size_t index) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::FromIndex(index); }
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static uint32 ToIndex(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);}
|
static uint32 ToIndex(Enum value) { return Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);}
|
||||||
|
|
||||||
template<typename Enum>
|
template<typename Enum>
|
||||||
static bool IsValid(Enum value)
|
static bool IsValid(Enum value)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);
|
||||||
{
|
return true;
|
||||||
Acore::Impl::EnumUtilsImpl::EnumUtils<Enum>::ToIndex(value);
|
|
||||||
return true;
|
|
||||||
} catch (...)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (...)
|
||||||
template<typename Enum>
|
|
||||||
static bool IsValid(std::underlying_type_t<Enum> value) { return IsValid(static_cast<Enum>(value)); }
|
|
||||||
|
|
||||||
template <typename Enum>
|
|
||||||
class Iterator
|
|
||||||
{
|
{
|
||||||
public:
|
return false;
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
}
|
||||||
using value_type = Enum;
|
}
|
||||||
using pointer = Enum*;
|
|
||||||
using reference = Enum&;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
|
|
||||||
Iterator() : _index(EnumUtils::Count<Enum>()) {}
|
template<typename Enum>
|
||||||
explicit Iterator(size_t index) : _index(index) { }
|
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; }
|
template <typename Enum>
|
||||||
bool operator!=(const Iterator& other) const { return !operator==(other); }
|
class Iterator
|
||||||
difference_type operator-(Iterator const& other) const { return _index - other._index; }
|
{
|
||||||
bool operator<(const Iterator& other) const { return _index < other._index; }
|
public:
|
||||||
bool operator<=(const Iterator& other) const { return _index <= other._index; }
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
bool operator>(const Iterator& other) const { return _index > other._index; }
|
using value_type = Enum;
|
||||||
bool operator>=(const Iterator& other) const { return _index >= other._index; }
|
using pointer = Enum*;
|
||||||
|
using reference = Enum&;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
value_type operator[](difference_type d) const { return FromIndex<Enum>(_index + d); }
|
Iterator() : _index(EnumUtils::Count<Enum>()) {}
|
||||||
value_type operator*() const { return operator[](0); }
|
explicit Iterator(size_t index) : _index(index) { }
|
||||||
|
|
||||||
Iterator& operator+=(difference_type d) { _index += d; return *this; }
|
bool operator==(const Iterator& other) const { return other._index == _index; }
|
||||||
Iterator& operator++() { return operator+=(1); }
|
bool operator!=(const Iterator& other) const { return !operator==(other); }
|
||||||
Iterator operator++(int) { Iterator i = *this; operator++(); return i; }
|
difference_type operator-(Iterator const& other) const { return _index - other._index; }
|
||||||
Iterator operator+(difference_type d) const { Iterator i = *this; i += d; return i; }
|
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; }
|
value_type operator[](difference_type d) const { return FromIndex<Enum>(_index + d); }
|
||||||
Iterator& operator--() { return operator-=(1); }
|
value_type operator*() const { return operator[](0); }
|
||||||
Iterator operator--(int) { Iterator i = *this; operator--(); return i; }
|
|
||||||
Iterator operator-(difference_type d) const { Iterator i = *this; i -= d; return i; }
|
|
||||||
|
|
||||||
private:
|
Iterator& operator+=(difference_type d) { _index += d; return *this; }
|
||||||
difference_type _index;
|
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>
|
Iterator& operator-=(difference_type d) { _index -= d; return *this; }
|
||||||
static Iterator<Enum> Begin() { return Iterator<Enum>(0); }
|
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>
|
private:
|
||||||
static Iterator<Enum> End() { return Iterator<Enum>(); }
|
difference_type _index;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static Acore::IteratorPair<Iterator<Enum>> Iterate() { return { Begin<Enum>(), End<Enum>() }; }
|
static Iterator<Enum> Begin() { return Iterator<Enum>(0); }
|
||||||
|
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static char const* ToConstant(Enum value) { return ToString(value).Constant; }
|
static Iterator<Enum> End() { return Iterator<Enum>(); }
|
||||||
|
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static char const* ToTitle(Enum value) { return ToString(value).Title; }
|
static Acore::IteratorPair<Iterator<Enum>> Iterate() { return { Begin<Enum>(), End<Enum>() }; }
|
||||||
|
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
static char const* ToDescription(Enum value) { return ToString(value).Description; }
|
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
|
#endif
|
||||||
|
|||||||
@@ -41,10 +41,14 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
str.remove_prefix(2);
|
str.remove_prefix(2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
base = 10;
|
base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* const start = str.data();
|
char const* const start = str.data();
|
||||||
@@ -53,14 +57,18 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
T val;
|
T val;
|
||||||
std::from_chars_result const res = std::from_chars(start, end, val, base);
|
std::from_chars_result const res = std::from_chars(start, end, val, base);
|
||||||
if ((res.ptr == end) && (res.ec == std::errc()))
|
if ((res.ptr == end) && (res.ec == std::errc()))
|
||||||
|
{
|
||||||
return val;
|
return val;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string ToString(T val)
|
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 start = buf.data();
|
||||||
char* const end = (start + buf.length());
|
char* const end = (start + buf.length());
|
||||||
std::to_chars_result const res = std::to_chars(start, end, val);
|
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)
|
static Optional<uint64> FromString(std::string_view str, int base = 10)
|
||||||
{
|
{
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
uint64 val = std::stoull(std::string(str), &n, base);
|
uint64 val = std::stoull(std::string(str), &n, base);
|
||||||
if (n != str.length())
|
if (n != str.length())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
catch (...) { return std::nullopt; }
|
catch (...) { return std::nullopt; }
|
||||||
@@ -107,13 +119,18 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
{
|
{
|
||||||
static Optional<int64> FromString(std::string_view str, int base = 10)
|
static Optional<int64> FromString(std::string_view str, int base = 10)
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
size_t n;
|
size_t n;
|
||||||
int64 val = std::stoll(std::string(str), &n, base);
|
int64 val = std::stoll(std::string(str), &n, base);
|
||||||
if (n != str.length())
|
if (n != str.length())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
catch (...) { return std::nullopt; }
|
catch (...) { return std::nullopt; }
|
||||||
@@ -134,17 +151,25 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
if (strict)
|
if (strict)
|
||||||
{
|
{
|
||||||
if (str == "1")
|
if (str == "1")
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (str == "0")
|
if (str == "0")
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true"))
|
if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true"))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false"))
|
if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false"))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return std::nullopt;
|
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())
|
static Optional<T> FromString(std::string_view str, std::chars_format fmt = std::chars_format())
|
||||||
{
|
{
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
if (fmt == std::chars_format())
|
if (fmt == std::chars_format())
|
||||||
{
|
{
|
||||||
@@ -172,10 +199,14 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
str.remove_prefix(2);
|
str.remove_prefix(2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
fmt = std::chars_format::general;
|
fmt = std::chars_format::general;
|
||||||
|
}
|
||||||
|
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* const start = str.data();
|
char const* const start = str.data();
|
||||||
@@ -184,20 +215,30 @@ namespace Acore::Impl::StringConvertImpl
|
|||||||
T val;
|
T val;
|
||||||
std::from_chars_result const res = std::from_chars(start, end, val, fmt);
|
std::from_chars_result const res = std::from_chars(start, end, val, fmt);
|
||||||
if ((res.ptr == end) && (res.ec == std::errc()))
|
if ((res.ptr == end) && (res.ec == std::errc()))
|
||||||
|
{
|
||||||
return val;
|
return val;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this allows generic converters for all numeric types (easier templating!)
|
// this allows generic converters for all numeric types (easier templating!)
|
||||||
static Optional<T> FromString(std::string_view str, int base)
|
static Optional<T> FromString(std::string_view str, int base)
|
||||||
{
|
{
|
||||||
if (base == 16)
|
if (base == 16)
|
||||||
|
{
|
||||||
return FromString(str, std::chars_format::hex);
|
return FromString(str, std::chars_format::hex);
|
||||||
|
}
|
||||||
else if (base == 10)
|
else if (base == 10)
|
||||||
|
{
|
||||||
return FromString(str, std::chars_format::general);
|
return FromString(str, std::chars_format::general);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return FromString(str, std::chars_format());
|
return FromString(str, std::chars_format());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string ToString(T val)
|
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)
|
static Optional<T> FromString(std::string_view str, int base = 0)
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
if ((base == 10) && StringEqualI(str.substr(0, 2), "0x"))
|
if ((base == 10) && StringEqualI(str.substr(0, 2), "0x"))
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
if (base == 16)
|
if (base == 16)
|
||||||
|
{
|
||||||
tmp.append("0x");
|
tmp.append("0x");
|
||||||
|
}
|
||||||
tmp.append(str);
|
tmp.append(str);
|
||||||
|
|
||||||
size_t n;
|
size_t n;
|
||||||
T val = static_cast<T>(std::stold(tmp, &n));
|
T val = static_cast<T>(std::stold(tmp, &n));
|
||||||
if (n != tmp.length())
|
if (n != tmp.length())
|
||||||
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
catch (...) { return std::nullopt; }
|
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();
|
typename Str::const_iterator end = s.end();
|
||||||
|
|
||||||
while (first != end && std::isspace(*first, loc))
|
while (first != end && std::isspace(*first, loc))
|
||||||
|
{
|
||||||
++first;
|
++first;
|
||||||
|
}
|
||||||
|
|
||||||
if (first == end)
|
if (first == end)
|
||||||
|
{
|
||||||
return Str();
|
return Str();
|
||||||
|
}
|
||||||
|
|
||||||
typename Str::const_iterator last = end;
|
typename Str::const_iterator last = end;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
{
|
||||||
--last;
|
--last;
|
||||||
while (std::isspace(*last, loc));
|
} while (std::isspace(*last, loc));
|
||||||
|
|
||||||
if (first != s.begin() || last + 1 != end)
|
if (first != s.begin() || last + 1 != end)
|
||||||
|
{
|
||||||
return Str(first, last + 1);
|
return Str(first, last + 1);
|
||||||
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ void TaskScheduler::Dispatch(success_t const& callback)
|
|||||||
{
|
{
|
||||||
// If the validation failed abort the dispatching here.
|
// If the validation failed abort the dispatching here.
|
||||||
if (!_predicate())
|
if (!_predicate())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Process all asyncs
|
// Process all asyncs
|
||||||
while (!_asyncHolder.empty())
|
while (!_asyncHolder.empty())
|
||||||
@@ -75,13 +77,17 @@ void TaskScheduler::Dispatch(success_t const& callback)
|
|||||||
|
|
||||||
// If the validation failed abort the dispatching here.
|
// If the validation failed abort the dispatching here.
|
||||||
if (!_predicate())
|
if (!_predicate())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!_task_holder.IsEmpty())
|
while (!_task_holder.IsEmpty())
|
||||||
{
|
{
|
||||||
if (_task_holder.First()->_end > _now)
|
if (_task_holder.First()->_end > _now)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Perfect forward the context to the handler
|
// Perfect forward the context to the handler
|
||||||
// Use weak references to catch destruction before callbacks.
|
// 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 the validation failed abort the dispatching here.
|
||||||
if (!_predicate())
|
if (!_predicate())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On finish call the final callback
|
// 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();)
|
for (auto itr = container.begin(); itr != container.end();)
|
||||||
if (filter(*itr))
|
if (filter(*itr))
|
||||||
|
{
|
||||||
itr = container.erase(itr);
|
itr = container.erase(itr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++itr;
|
++itr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
|
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);
|
itr = container.erase(itr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++itr;
|
++itr;
|
||||||
|
}
|
||||||
|
|
||||||
container.insert(cache.begin(), cache.end());
|
container.insert(cache.begin(), cache.end());
|
||||||
}
|
}
|
||||||
@@ -153,7 +167,9 @@ bool TaskScheduler::TaskQueue::IsEmpty() const
|
|||||||
TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
|
TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
|
||||||
{
|
{
|
||||||
if (auto const owner = _owner.lock())
|
if (auto const owner = _owner.lock())
|
||||||
|
{
|
||||||
apply(*owner);
|
apply(*owner);
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,7 +292,9 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -340,7 +342,9 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return *this;
|
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
|
// getMSTime() have limited data range and this is case when it overflow in this tick
|
||||||
if (oldMSTime > newMSTime)
|
if (oldMSTime > newMSTime)
|
||||||
|
{
|
||||||
return (0xFFFFFFFF - oldMSTime) + newMSTime;
|
return (0xFFFFFFFF - oldMSTime) + newMSTime;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return newMSTime - oldMSTime;
|
return newMSTime - oldMSTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 getMSTimeDiff(uint32 oldMSTime, TimePoint newTime)
|
inline uint32 getMSTimeDiff(uint32 oldMSTime, TimePoint newTime)
|
||||||
@@ -60,7 +64,9 @@ public:
|
|||||||
{
|
{
|
||||||
_current += diff;
|
_current += diff;
|
||||||
if (_current < 0)
|
if (_current < 0)
|
||||||
|
{
|
||||||
_current = 0;
|
_current = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Passed()
|
bool Passed()
|
||||||
@@ -71,7 +77,9 @@ public:
|
|||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
if (_current >= _interval)
|
if (_current >= _interval)
|
||||||
|
{
|
||||||
_current %= _interval;
|
_current %= _interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCurrent(time_t current)
|
void SetCurrent(time_t current)
|
||||||
@@ -174,7 +182,9 @@ public:
|
|||||||
bool Update(const uint32 diff)
|
bool Update(const uint32 diff)
|
||||||
{
|
{
|
||||||
if ((i_expireTime -= diff) > 0)
|
if ((i_expireTime -= diff) > 0)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
i_expireTime += i_period > int32(diff) ? i_period : diff;
|
i_expireTime += i_period > int32(diff) ? i_period : diff;
|
||||||
return true;
|
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))
|
for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start))
|
||||||
{
|
{
|
||||||
if (keepEmpty || (start < end))
|
if (keepEmpty || (start < end))
|
||||||
|
{
|
||||||
tokens.push_back(str.substr(start, end - start));
|
tokens.push_back(str.substr(start, end - start));
|
||||||
|
}
|
||||||
|
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keepEmpty || (start < str.length()))
|
if (keepEmpty || (start < str.length()))
|
||||||
|
{
|
||||||
tokens.push_back(str.substr(start));
|
tokens.push_back(str.substr(start));
|
||||||
|
}
|
||||||
|
|
||||||
return tokens;
|
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);
|
memcpy(m_str, src.c_str(), src.length() + 1);
|
||||||
|
|
||||||
if (vectorReserve)
|
if (vectorReserve)
|
||||||
|
{
|
||||||
m_storage.reserve(vectorReserve);
|
m_storage.reserve(vectorReserve);
|
||||||
|
}
|
||||||
|
|
||||||
char* posold = m_str;
|
char* posold = m_str;
|
||||||
char* posnew = 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,
|
// Hack like, but the old code accepted these kind of broken strings,
|
||||||
// so changing it would break other things
|
// so changing it would break other things
|
||||||
if (posold != posnew)
|
if (posold != posnew)
|
||||||
|
{
|
||||||
m_storage.push_back(posold);
|
m_storage.push_back(posold);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -88,7 +92,9 @@ time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime)
|
|||||||
time_t hourLocal = midnightLocal + hour * HOUR;
|
time_t hourLocal = midnightLocal + hour * HOUR;
|
||||||
|
|
||||||
if (onlyAfterTime && hourLocal <= time)
|
if (onlyAfterTime && hourLocal <= time)
|
||||||
|
{
|
||||||
hourLocal += DAY;
|
hourLocal += DAY;
|
||||||
|
}
|
||||||
|
|
||||||
return hourLocal;
|
return hourLocal;
|
||||||
}
|
}
|
||||||
@@ -113,17 +119,25 @@ void stripLineInvisibleChars(std::string& str)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (wpos != pos)
|
if (wpos != pos)
|
||||||
|
{
|
||||||
str[wpos++] = str[pos];
|
str[wpos++] = str[pos];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++wpos;
|
++wpos;
|
||||||
|
}
|
||||||
space = false;
|
space = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpos < str.size())
|
if (wpos < str.size())
|
||||||
|
{
|
||||||
str.erase(wpos, str.size());
|
str.erase(wpos, str.size());
|
||||||
|
}
|
||||||
if (str.find("|TInterface") != std::string::npos)
|
if (str.find("|TInterface") != std::string::npos)
|
||||||
|
{
|
||||||
str.clear();
|
str.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string secsToTimeString(uint64 timeInSecs, bool shortText)
|
std::string secsToTimeString(uint64 timeInSecs, bool shortText)
|
||||||
@@ -135,18 +149,28 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText)
|
|||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
if (days)
|
if (days)
|
||||||
|
{
|
||||||
ss << days << (shortText ? "d" : " day(s) ");
|
ss << days << (shortText ? "d" : " day(s) ");
|
||||||
|
}
|
||||||
if (hours)
|
if (hours)
|
||||||
|
{
|
||||||
ss << hours << (shortText ? "h" : " hour(s) ");
|
ss << hours << (shortText ? "h" : " hour(s) ");
|
||||||
|
}
|
||||||
if (minutes)
|
if (minutes)
|
||||||
|
{
|
||||||
ss << minutes << (shortText ? "m" : " minute(s) ");
|
ss << minutes << (shortText ? "m" : " minute(s) ");
|
||||||
|
}
|
||||||
if (secs || (!days && !hours && !minutes) )
|
if (secs || (!days && !hours && !minutes) )
|
||||||
|
{
|
||||||
ss << secs << (shortText ? "s" : " second(s) ");
|
ss << secs << (shortText ? "s" : " second(s) ");
|
||||||
|
}
|
||||||
|
|
||||||
std::string str = ss.str();
|
std::string str = ss.str();
|
||||||
|
|
||||||
if (!shortText && !str.empty() && str[str.size() - 1] == ' ')
|
if (!shortText && !str.empty() && str[str.size() - 1] == ' ')
|
||||||
|
{
|
||||||
str.resize(str.size() - 1);
|
str.resize(str.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -158,7 +182,9 @@ int32 MoneyStringToMoney(const std::string& moneyString)
|
|||||||
if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 ||
|
if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 ||
|
||||||
std::count(moneyString.begin(), moneyString.end(), 's') == 1 ||
|
std::count(moneyString.begin(), moneyString.end(), 's') == 1 ||
|
||||||
std::count(moneyString.begin(), moneyString.end(), 'c') == 1))
|
std::count(moneyString.begin(), moneyString.end(), 'c') == 1))
|
||||||
return 0; // Bad format
|
{
|
||||||
|
return 0; // Bad format
|
||||||
|
}
|
||||||
|
|
||||||
Tokenizer tokens(moneyString, ' ');
|
Tokenizer tokens(moneyString, ' ');
|
||||||
for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
|
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 sCount = std::count(tokenString.begin(), tokenString.end(), 's');
|
||||||
size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c');
|
size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c');
|
||||||
if (gCount + sCount + cCount != 1)
|
if (gCount + sCount + cCount != 1)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 amount = atoi(*itr);
|
uint32 amount = atoi(*itr);
|
||||||
if (gCount == 1)
|
if (gCount == 1)
|
||||||
|
{
|
||||||
money += amount * 100 * 100;
|
money += amount * 100 * 100;
|
||||||
|
}
|
||||||
else if (sCount == 1)
|
else if (sCount == 1)
|
||||||
|
{
|
||||||
money += amount * 100;
|
money += amount * 100;
|
||||||
|
}
|
||||||
else if (cCount == 1)
|
else if (cCount == 1)
|
||||||
|
{
|
||||||
money += amount;
|
money += amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return money;
|
return money;
|
||||||
@@ -257,7 +291,9 @@ std::string TimeToHumanReadable(time_t t)
|
|||||||
bool IsIPAddress(char const* ipaddress)
|
bool IsIPAddress(char const* ipaddress)
|
||||||
{
|
{
|
||||||
if (!ipaddress)
|
if (!ipaddress)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Let the big boys do it.
|
// Let the big boys do it.
|
||||||
// Drawback: all valid ip address formats are recognized e.g.: 12.23, 121234, 0xABCD)
|
// 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();
|
uint32 mask = subnetMask.get_ip_address();
|
||||||
if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
|
if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +322,9 @@ uint32 CreatePIDFile(std::string const& filename)
|
|||||||
{
|
{
|
||||||
FILE* pid_file = fopen(filename.c_str(), "w");
|
FILE* pid_file = fopen(filename.c_str(), "w");
|
||||||
if (pid_file == nullptr)
|
if (pid_file == nullptr)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 pid = GetPID();
|
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());
|
size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
|
||||||
if (wlen <= len)
|
if (wlen <= len)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring wstr;
|
std::wstring wstr;
|
||||||
wstr.resize(wlen);
|
wstr.resize(wlen);
|
||||||
@@ -365,7 +407,9 @@ bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
|
|||||||
wsize = 0;
|
wsize = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
wsize = 0;
|
wsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -451,7 +495,9 @@ std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension)
|
|||||||
{
|
{
|
||||||
// supported only Cyrillic cases
|
// supported only Cyrillic cases
|
||||||
if (wname.empty() || !isCyrillicCharacter(wname[0]) || declension > 5)
|
if (wname.empty() || !isCyrillicCharacter(wname[0]) || declension > 5)
|
||||||
|
{
|
||||||
return wname;
|
return wname;
|
||||||
|
}
|
||||||
|
|
||||||
// Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
|
// 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) };
|
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::wstring const& ending = **itr;
|
||||||
std::size_t const endLen = ending.length();
|
std::size_t const endLen = ending.length();
|
||||||
if (!(endLen <= thisLen))
|
if (!(endLen <= thisLen))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (wname.substr(thisLen - endLen, thisLen) == ending)
|
if (wname.substr(thisLen - endLen, thisLen) == ending)
|
||||||
|
{
|
||||||
return wname.substr(0, thisLen - endLen);
|
return wname.substr(0, thisLen - endLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return wname;
|
return wname;
|
||||||
@@ -502,7 +552,9 @@ bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
|
|||||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||||
std::wstring wstr;
|
std::wstring wstr;
|
||||||
if (!Utf8toWStr(utf8str, wstr))
|
if (!Utf8toWStr(utf8str, wstr))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
conStr.resize(wstr.size());
|
conStr.resize(wstr.size());
|
||||||
CharToOemBuffW(&wstr[0], &conStr[0], 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;
|
std::wstring temp;
|
||||||
|
|
||||||
if (!Utf8toWStr(str, temp))
|
if (!Utf8toWStr(str, temp))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// converting to lower case
|
// converting to lower case
|
||||||
wstrToLower(temp);
|
wstrToLower(temp);
|
||||||
|
|
||||||
if (temp.find(search) == std::wstring::npos)
|
if (temp.find(search) == std::wstring::npos)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap);
|
||||||
//vsnprintf returns -1 if the buffer is too small
|
//vsnprintf returns -1 if the buffer is too small
|
||||||
if (temp_len == size_t(-1))
|
if (temp_len == size_t(-1))
|
||||||
|
{
|
||||||
temp_len = 32 * 1024 - 1;
|
temp_len = 32 * 1024 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t wtemp_len = 32 * 1024 - 1;
|
size_t wtemp_len = 32 * 1024 - 1;
|
||||||
Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
|
Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
|
||||||
@@ -578,7 +636,9 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String)
|
|||||||
{
|
{
|
||||||
std::wstring wstr;
|
std::wstring wstr;
|
||||||
if (!Utf8toWStr(utf8String, wstr))
|
if (!Utf8toWStr(utf8String, wstr))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin);
|
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)
|
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
|
||||||
{
|
{
|
||||||
if (val == -100.0f) // prevent set var to zero
|
if (val == -100.0f) // prevent set var to zero
|
||||||
|
{
|
||||||
val = -99.99f;
|
val = -99.99f;
|
||||||
|
}
|
||||||
var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
|
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)
|
inline bool isBasicLatinCharacter(wchar_t wchar)
|
||||||
{
|
{
|
||||||
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
|
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
|
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isExtendedLatinCharacter(wchar_t wchar)
|
inline bool isExtendedLatinCharacter(wchar_t wchar)
|
||||||
{
|
{
|
||||||
if (isBasicLatinCharacter(wchar))
|
if (isBasicLatinCharacter(wchar))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
|
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
|
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
|
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
|
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
|
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
|
if (wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
|
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isCyrillicCharacter(wchar_t wchar)
|
inline bool isCyrillicCharacter(wchar_t wchar)
|
||||||
{
|
{
|
||||||
if (wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
|
if (wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
|
if (wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isEastAsianCharacter(wchar_t wchar)
|
inline bool isEastAsianCharacter(wchar_t wchar)
|
||||||
{
|
{
|
||||||
if (wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo
|
if (wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana
|
if (wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo
|
if (wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext.
|
if (wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext.
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A
|
if (wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs
|
if (wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables
|
if (wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
if (wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms
|
if (wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +238,9 @@ inline bool isNumeric(char const* str)
|
|||||||
{
|
{
|
||||||
for (char const* c = str; *c; ++c)
|
for (char const* c = str; *c; ++c)
|
||||||
if (!isNumeric(*c))
|
if (!isNumeric(*c))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -210,7 +254,9 @@ inline bool isBasicLatinString(const std::wstring& wstr, bool numericOrSpace)
|
|||||||
{
|
{
|
||||||
for (wchar_t i : wstr)
|
for (wchar_t i : wstr)
|
||||||
if (!isBasicLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
if (!isBasicLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +264,9 @@ inline bool isExtendedLatinString(const std::wstring& wstr, bool numericOrSpace)
|
|||||||
{
|
{
|
||||||
for (wchar_t i : wstr)
|
for (wchar_t i : wstr)
|
||||||
if (!isExtendedLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
if (!isExtendedLatinCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +274,9 @@ inline bool isCyrillicString(const std::wstring& wstr, bool numericOrSpace)
|
|||||||
{
|
{
|
||||||
for (wchar_t i : wstr)
|
for (wchar_t i : wstr)
|
||||||
if (!isCyrillicCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
if (!isCyrillicCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,29 +284,45 @@ inline bool isEastAsianString(const std::wstring& wstr, bool numericOrSpace)
|
|||||||
{
|
{
|
||||||
for (wchar_t i : wstr)
|
for (wchar_t i : wstr)
|
||||||
if (!isEastAsianCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
if (!isEastAsianCharacter(i) && (!numericOrSpace || !isNumericOrSpace(i)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline wchar_t wcharToUpper(wchar_t wchar)
|
inline wchar_t wcharToUpper(wchar_t wchar)
|
||||||
{
|
{
|
||||||
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
|
if (wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) - 0x0020);
|
return wchar_t(uint16(wchar) - 0x0020);
|
||||||
|
}
|
||||||
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
|
if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
|
||||||
|
{
|
||||||
return wchar_t(0x1E9E);
|
return wchar_t(0x1E9E);
|
||||||
|
}
|
||||||
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
|
if (wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) - 0x0020);
|
return wchar_t(uint16(wchar) - 0x0020);
|
||||||
|
}
|
||||||
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
|
if (wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) - 0x0020);
|
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 >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
|
||||||
{
|
{
|
||||||
if (wchar % 2 == 1)
|
if (wchar % 2 == 1)
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) - 0x0001);
|
return wchar_t(uint16(wchar) - 0x0001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
|
if (wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) - 0x0020);
|
return wchar_t(uint16(wchar) - 0x0020);
|
||||||
|
}
|
||||||
if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
|
if (wchar == 0x0451) // CYRILLIC SMALL LETTER IO
|
||||||
|
{
|
||||||
return wchar_t(0x0401);
|
return wchar_t(0x0401);
|
||||||
|
}
|
||||||
|
|
||||||
return wchar;
|
return wchar;
|
||||||
}
|
}
|
||||||
@@ -269,22 +335,36 @@ inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
|
|||||||
inline wchar_t wcharToLower(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
|
if (wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) + 0x0020);
|
return wchar_t(uint16(wchar) + 0x0020);
|
||||||
|
}
|
||||||
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
|
if (wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) + 0x0020);
|
return wchar_t(uint16(wchar) + 0x0020);
|
||||||
|
}
|
||||||
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
|
if (wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) + 0x0020);
|
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 >= 0x0100 && wchar <= 0x012E) // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0)
|
||||||
{
|
{
|
||||||
if (wchar % 2 == 0)
|
if (wchar % 2 == 0)
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) + 0x0001);
|
return wchar_t(uint16(wchar) + 0x0001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
|
if (wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S
|
||||||
|
{
|
||||||
return wchar_t(0x00DF);
|
return wchar_t(0x00DF);
|
||||||
|
}
|
||||||
if (wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO
|
if (wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO
|
||||||
|
{
|
||||||
return wchar_t(0x0451);
|
return wchar_t(0x0451);
|
||||||
|
}
|
||||||
if (wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
|
if (wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
|
||||||
|
{
|
||||||
return wchar_t(uint16(wchar) + 0x0020);
|
return wchar_t(uint16(wchar) + 0x0020);
|
||||||
|
}
|
||||||
|
|
||||||
return wchar;
|
return wchar;
|
||||||
}
|
}
|
||||||
@@ -418,9 +498,13 @@ public:
|
|||||||
for (uint8 i = 3; i > 0; --i)
|
for (uint8 i = 3; i > 0; --i)
|
||||||
{
|
{
|
||||||
if (part[i - 1] < right.part[i - 1])
|
if (part[i - 1] < right.part[i - 1])
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
else if (part[i - 1] > right.part[i - 1])
|
else if (part[i - 1] > right.part[i - 1])
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user