diff --git a/Source/Game/Collision/BoundingIntervalHierarchy.cs b/Source/Game/Collision/BoundingIntervalHierarchy.cs index ff39e95ac..6ef53f1ee 100644 --- a/Source/Game/Collision/BoundingIntervalHierarchy.cs +++ b/Source/Game/Collision/BoundingIntervalHierarchy.cs @@ -41,281 +41,6 @@ namespace Game.Collision tree.Add(0); } - public void build(List primitives, uint leafSize = 3, bool printStats = false) where T : IModel - { - if (primitives.Count == 0) - { - init_empty(); - return; - } - - buildData dat; - dat.maxPrims = (int)leafSize; - dat.numPrims = (uint)primitives.Count; - dat.indices = new uint[dat.numPrims]; - dat.primBound = new AxisAlignedBox[dat.numPrims]; - bounds = primitives[0].getBounds(); - for (int i = 0; i < dat.numPrims; ++i) - { - dat.indices[i] = (uint)i; - dat.primBound[i] = primitives[i].getBounds(); - bounds.merge(dat.primBound[i]); - } - List tempTree = new List(); - BuildStats stats = new BuildStats(); - buildHierarchy(tempTree, dat, stats); - if (printStats) - stats.printStats(); - - for (int i = 0; i < dat.numPrims; ++i) - objects.Add(dat.indices[i]); - tree = tempTree; - } - public uint primCount() { return (uint)objects.Count; } - - public bool readFromFile(BinaryReader reader) - { - var lo = reader.ReadStruct(); - var hi = reader.ReadStruct(); - bounds = new AxisAlignedBox(lo, hi); - - uint treeSize = reader.ReadUInt32(); - tree.Clear(); - for (var i = 0; i < treeSize; i++) - tree.Add(reader.ReadUInt32()); - - var count = reader.ReadUInt32(); - objects.Clear(); - for (var i = 0; i < count; i++) - objects.Add(reader.ReadUInt32()); - - return true; - } - - public void intersectRay(Ray r, WorkerCallback intersectCallback, ref float maxDist, bool stopAtFirst = false) - { - float intervalMin = -1.0f; - float intervalMax = -1.0f; - Vector3 org = r.Origin; - Vector3 dir = r.Direction; - Vector3 invDir = new Vector3(); - for (int i = 0; i < 3; ++i) - { - invDir[i] = 1.0f / dir[i]; - if (MathFunctions.fuzzyNe(dir[i], 0.0f)) - { - float t1 = (bounds.Lo[i] - org[i]) * invDir[i]; - float t2 = (bounds.Hi[i] - org[i]) * invDir[i]; - if (t1 > t2) - MathFunctions.Swap(ref t1, ref t2); - if (t1 > intervalMin) - intervalMin = t1; - if (t2 < intervalMax || intervalMax < 0.0f) - intervalMax = t2; - // intervalMax can only become smaller for other axis, - // and intervalMin only larger respectively, so stop early - if (intervalMax <= 0 || intervalMin >= maxDist) - return; - } - } - - if (intervalMin > intervalMax) - return; - intervalMin = Math.Max(intervalMin, 0.0f); - intervalMax = Math.Min(intervalMax, maxDist); - - uint[] offsetFront = new uint[3]; - uint[] offsetBack = new uint[3]; - uint[] offsetFront3 = new uint[3]; - uint[] offsetBack3 = new uint[3]; - // compute custom offsets from direction sign bit - - for (int i = 0; i < 3; ++i) - { - offsetFront[i] = floatToRawIntBits(dir[i]) >> 31; - offsetBack[i] = offsetFront[i] ^ 1; - offsetFront3[i] = offsetFront[i] * 3; - offsetBack3[i] = offsetBack[i] * 3; - - // avoid always adding 1 during the inner loop - ++offsetFront[i]; - ++offsetBack[i]; - } - - StackNode[] stack = new StackNode[64]; - int stackPos = 0; - int node = 0; - - while (true) - { - while (true) - { - uint tn = tree[node]; - uint axis = (uint)(tn & (3 << 30)) >> 30; - bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); - int offset = (int)(tn & ~(7 << 29)); - if (!BVH2) - { - if (axis < 3) - { - // "normal" interior node - float tf = (intBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; - float tb = (intBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; - // ray passes between clip zones - if (tf < intervalMin && tb > intervalMax) - break; - int back = (int)(offset + offsetBack3[axis]); - node = back; - // ray passes through far node only - if (tf < intervalMin) - { - intervalMin = (tb >= intervalMin) ? tb : intervalMin; - continue; - } - node = offset + (int)offsetFront3[axis]; // front - // ray passes through near node only - if (tb > intervalMax) - { - intervalMax = (tf <= intervalMax) ? tf : intervalMax; - continue; - } - // ray passes through both nodes - // push back node - stack[stackPos].node = (uint)back; - stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin; - stack[stackPos].tfar = intervalMax; - stackPos++; - // update ray interval for front node - intervalMax = (tf <= intervalMax) ? tf : intervalMax; - continue; - } - else - { - // leaf - test some objects - int n = (int)tree[node + 1]; - while (n > 0) - { - bool hit = intersectCallback.Invoke(r, objects[offset], ref maxDist, stopAtFirst); - if (stopAtFirst && hit) - return; - --n; - ++offset; - } - break; - } - } - else - { - if (axis > 2) - return; // should not happen - float tf = (intBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; - float tb = (intBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; - node = offset; - intervalMin = (tf >= intervalMin) ? tf : intervalMin; - intervalMax = (tb <= intervalMax) ? tb : intervalMax; - if (intervalMin > intervalMax) - break; - continue; - } - } // traversal loop - do - { - // stack is empty? - if (stackPos == 0) - return; - // move back up the stack - stackPos--; - intervalMin = stack[stackPos].tnear; - if (maxDist < intervalMin) - continue; - node = (int)stack[stackPos].node; - intervalMax = stack[stackPos].tfar; - break; - } while (true); - } - } - - public void intersectPoint(Vector3 p, WorkerCallback intersectCallback) - { - if (!bounds.contains(p)) - return; - - StackNode[] stack = new StackNode[64]; - int stackPos = 0; - int node = 0; - - while (true) - { - while (true) - { - uint tn = tree[node]; - uint axis = (uint)(tn & (3 << 30)) >> 30; - bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); - int offset = (int)(tn & ~(7 << 29)); - if (!BVH2) - { - if (axis < 3) - { - // "normal" interior node - float tl = intBitsToFloat(tree[node + 1]); - float tr = intBitsToFloat(tree[node + 2]); - // point is between clip zones - if (tl < p[(int)axis] && tr > p[axis]) - break; - int right = offset + 3; - node = right; - // point is in right node only - if (tl < p[(int)axis]) - { - continue; - } - node = offset; // left - // point is in left node only - if (tr > p[axis]) - { - continue; - } - // point is in both nodes - // push back right node - stack[stackPos].node = (uint)right; - stackPos++; - continue; - } - else - { - // leaf - test some objects - uint n = tree[node + 1]; - while (n > 0) - { - intersectCallback.Invoke(p, objects[offset]); // !!! - --n; - ++offset; - } - break; - } - } - else // BVH2 node (empty space cut off left and right) - { - if (axis > 2) - return; // should not happen - float tl = intBitsToFloat(tree[node + 1]); - float tr = intBitsToFloat(tree[node + 2]); - node = offset; - if (tl > p[axis] || tr < p[axis]) - break; - continue; - } - } // traversal loop - - // stack is empty? - if (stackPos == 0) - return; - // move back up the stack - stackPos--; - node = (int)stack[stackPos].node; - } - } - void buildHierarchy(List tempTree, buildData dat, BuildStats stats) { // create space for the first node @@ -546,6 +271,280 @@ namespace Game.Collision stats.updateLeaf(depth + 1, 0); } + public bool readFromFile(BinaryReader reader) + { + var lo = reader.ReadStruct(); + var hi = reader.ReadStruct(); + bounds = new AxisAlignedBox(lo, hi); + + uint treeSize = reader.ReadUInt32(); + tree.Clear(); + for (var i = 0; i < treeSize; i++) + tree.Add(reader.ReadUInt32()); + + var count = reader.ReadUInt32(); + objects.Clear(); + for (var i = 0; i < count; i++) + objects.Add(reader.ReadUInt32()); + + return true; + } + + public void build(List primitives, uint leafSize = 3, bool printStats = false) where T : IModel + { + if (primitives.Count == 0) + { + init_empty(); + return; + } + + buildData dat; + dat.maxPrims = (int)leafSize; + dat.numPrims = (uint)primitives.Count; + dat.indices = new uint[dat.numPrims]; + dat.primBound = new AxisAlignedBox[dat.numPrims]; + bounds = primitives[0].getBounds(); + for (int i = 0; i < dat.numPrims; ++i) + { + dat.indices[i] = (uint)i; + dat.primBound[i] = primitives[i].getBounds(); + bounds.merge(dat.primBound[i]); + } + List tempTree = new List(); + BuildStats stats = new BuildStats(); + buildHierarchy(tempTree, dat, stats); + + for (int i = 0; i < dat.numPrims; ++i) + objects.Add(dat.indices[i]); + tree = tempTree; + } + + public uint primCount() { return (uint)objects.Count; } + + public void intersectRay(Ray r, WorkerCallback intersectCallback, ref float maxDist, bool stopAtFirst = false) + { + float intervalMin = -1.0f; + float intervalMax = -1.0f; + Vector3 org = r.Origin; + Vector3 dir = r.Direction; + Vector3 invDir = new Vector3(); + for (int i = 0; i < 3; ++i) + { + invDir[i] = 1.0f / dir[i]; + if (MathFunctions.fuzzyNe(dir[i], 0.0f)) + { + float t1 = (bounds.Lo[i] - org[i]) * invDir[i]; + float t2 = (bounds.Hi[i] - org[i]) * invDir[i]; + if (t1 > t2) + MathFunctions.Swap(ref t1, ref t2); + if (t1 > intervalMin) + intervalMin = t1; + if (t2 < intervalMax || intervalMax < 0.0f) + intervalMax = t2; + // intervalMax can only become smaller for other axis, + // and intervalMin only larger respectively, so stop early + if (intervalMax <= 0 || intervalMin >= maxDist) + return; + } + } + + if (intervalMin > intervalMax) + return; + intervalMin = Math.Max(intervalMin, 0.0f); + intervalMax = Math.Min(intervalMax, maxDist); + + uint[] offsetFront = new uint[3]; + uint[] offsetBack = new uint[3]; + uint[] offsetFront3 = new uint[3]; + uint[] offsetBack3 = new uint[3]; + // compute custom offsets from direction sign bit + + for (int i = 0; i < 3; ++i) + { + offsetFront[i] = floatToRawIntBits(dir[i]) >> 31; + offsetBack[i] = offsetFront[i] ^ 1; + offsetFront3[i] = offsetFront[i] * 3; + offsetBack3[i] = offsetBack[i] * 3; + + // avoid always adding 1 during the inner loop + ++offsetFront[i]; + ++offsetBack[i]; + } + + StackNode[] stack = new StackNode[64]; + int stackPos = 0; + int node = 0; + + while (true) + { + while (true) + { + uint tn = tree[node]; + uint axis = (uint)(tn & (3 << 30)) >> 30; + bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); + int offset = (int)(tn & ~(7 << 29)); + if (!BVH2) + { + if (axis < 3) + { + // "normal" interior node + float tf = (intBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; + float tb = (intBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; + // ray passes between clip zones + if (tf < intervalMin && tb > intervalMax) + break; + int back = (int)(offset + offsetBack3[axis]); + node = back; + // ray passes through far node only + if (tf < intervalMin) + { + intervalMin = (tb >= intervalMin) ? tb : intervalMin; + continue; + } + node = offset + (int)offsetFront3[axis]; // front + // ray passes through near node only + if (tb > intervalMax) + { + intervalMax = (tf <= intervalMax) ? tf : intervalMax; + continue; + } + // ray passes through both nodes + // push back node + stack[stackPos].node = (uint)back; + stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin; + stack[stackPos].tfar = intervalMax; + stackPos++; + // update ray interval for front node + intervalMax = (tf <= intervalMax) ? tf : intervalMax; + continue; + } + else + { + // leaf - test some objects + int n = (int)tree[node + 1]; + while (n > 0) + { + bool hit = intersectCallback.Invoke(r, objects[offset], ref maxDist, stopAtFirst); + if (stopAtFirst && hit) + return; + --n; + ++offset; + } + break; + } + } + else + { + if (axis > 2) + return; // should not happen + float tf = (intBitsToFloat(tree[(int)(node + offsetFront[axis])]) - org[axis]) * invDir[axis]; + float tb = (intBitsToFloat(tree[(int)(node + offsetBack[axis])]) - org[axis]) * invDir[axis]; + node = offset; + intervalMin = (tf >= intervalMin) ? tf : intervalMin; + intervalMax = (tb <= intervalMax) ? tb : intervalMax; + if (intervalMin > intervalMax) + break; + continue; + } + } // traversal loop + do + { + // stack is empty? + if (stackPos == 0) + return; + // move back up the stack + stackPos--; + intervalMin = stack[stackPos].tnear; + if (maxDist < intervalMin) + continue; + node = (int)stack[stackPos].node; + intervalMax = stack[stackPos].tfar; + break; + } while (true); + } + } + + public void intersectPoint(Vector3 p, WorkerCallback intersectCallback) + { + if (!bounds.contains(p)) + return; + + StackNode[] stack = new StackNode[64]; + int stackPos = 0; + int node = 0; + + while (true) + { + while (true) + { + uint tn = tree[node]; + uint axis = (uint)(tn & (3 << 30)) >> 30; + bool BVH2 = Convert.ToBoolean(tn & (1 << 29)); + int offset = (int)(tn & ~(7 << 29)); + if (!BVH2) + { + if (axis < 3) + { + // "normal" interior node + float tl = intBitsToFloat(tree[node + 1]); + float tr = intBitsToFloat(tree[node + 2]); + // point is between clip zones + if (tl < p[(int)axis] && tr > p[axis]) + break; + int right = offset + 3; + node = right; + // point is in right node only + if (tl < p[(int)axis]) + { + continue; + } + node = offset; // left + // point is in left node only + if (tr > p[axis]) + { + continue; + } + // point is in both nodes + // push back right node + stack[stackPos].node = (uint)right; + stackPos++; + continue; + } + else + { + // leaf - test some objects + uint n = tree[node + 1]; + while (n > 0) + { + intersectCallback.Invoke(p, objects[offset]); // !!! + --n; + ++offset; + } + break; + } + } + else // BVH2 node (empty space cut off left and right) + { + if (axis > 2) + return; // should not happen + float tl = intBitsToFloat(tree[node + 1]); + float tr = intBitsToFloat(tree[node + 2]); + node = offset; + if (tl > p[axis] || tr < p[axis]) + break; + continue; + } + } // traversal loop + + // stack is empty? + if (stackPos == 0) + return; + // move back up the stack + stackPos--; + node = (int)stack[stackPos].node; + } + } + void createNode(List tempTree, int nodeIndex, int left, int right) { // write leaf node @@ -597,8 +596,18 @@ namespace Game.Collision public void updateInner() { numNodes++; } public void updateBVH2() { numBVH2++; } - public void updateLeaf(int depth, int n) { } - public void printStats() { } + public void updateLeaf(int depth, int n) + { + numLeaves++; + minDepth = Math.Min(depth, minDepth); + maxDepth = Math.Max(depth, maxDepth); + sumDepth += depth; + minObjects = Math.Min(n, minObjects); + maxObjects = Math.Max(n, maxObjects); + sumObjects += n; + int nl = Math.Min(n, 5); + ++numLeavesN[nl]; + } } diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index cae30621c..96f9a5955 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -22,6 +22,7 @@ using Game.Network.Packets; using Game.Spells; using System; using System.Collections.Generic; +using Game.BattlePets; namespace Game.Entities { @@ -2520,6 +2521,17 @@ namespace Game.Entities if (Global.DB2Mgr.GetMount(spellId) != null) GetSession().GetCollectionMgr().AddMount(spellId, MountStatusFlags.None, false, IsInWorld ? false : true); + // need to add Battle pets automatically into pet journal + foreach (BattlePetSpeciesRecord entry in CliDB.BattlePetSpeciesStorage.Values) + { + if (entry.SummonSpellID == spellId && GetSession().GetBattlePetMgr().GetPetCount(entry.Id) == 0) + { + GetSession().GetBattlePetMgr().AddPet(entry.Id, entry.CreatureID, BattlePetMgr.RollPetBreed(entry.Id), BattlePetMgr.GetDefaultPetQuality(entry.Id)); + UpdateCriteria(CriteriaTypes.OwnBattlePetCount); + break; + } + } + // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell return active && !disabled && !superceded_old; }