diff --git a/as.predefined b/as.predefined index 583c379..60ef940 100644 --- a/as.predefined +++ b/as.predefined @@ -1678,6 +1678,21 @@ class StorageScope{ void SetVector(const string&in key, const Vector&in value); void SetString(const string&in key, const string&in value); } +class EHandle{ + ~EHandle(); + EHandle(int&in); + EHandle(int&in, const T@ entity); + void opAssign(const EHandle&in other); + void opHndlAssign(const EHandle&in other); + void opHndlAssign(const T@ entity); + void Set(const T@ entity); + T@ Get() const; + T@ opImplCast() const; + bool opEquals(const EHandle&in other) const; + bool opEquals(const T@ entity) const; + bool ChangedFrom(const T@ entity) const; + bool IsValid() const; +} class trace_t{ ~trace_t(); trace_t(); @@ -1873,6 +1888,10 @@ class CBaseEntity{ string GetDebugName(); int GetEntityIndex() const; bool GetKeyValue(const string&in key, string&out value) const; + bool KeyValue(const string&in key, const string&in value); + bool KeyValue(const string&in key, float value); + bool KeyValue(const string&in key, int value); + bool KeyValue(const string&in key, const Vector&in value); string GetModelName() const; float GetElasticity() const; void SetElasticity(float elasticity); @@ -1895,6 +1914,14 @@ class CBaseEntity{ bool TestCollision(const Ray_t&in ray, uint mask, trace_t&out trace); bool TestHitboxes(const Ray_t&in ray, uint mask, trace_t&out trace); void ComputeWorldSpaceSurroundingBox(Vector&out mins, Vector&out maxs); + int GetSpawnFlags() const; + void AddSpawnFlags(int flags); + void RemoveSpawnFlags(int flags); + void ClearSpawnFlags(); + bool HasSpawnFlags(int flags) const; + bool IsTrigger() const; + bool IsPlayer() const; + bool IsBaseCombatWeapon() const; } class InputData{ ~InputData(); @@ -1911,35 +1938,53 @@ class CBaseEntityOutput{ class COutputVariant : CBaseEntityOutput{ COutputVariant(); void Fire(const Variant&in value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(const Variant&in value); + Variant Get() const; } class COutputInt : CBaseEntityOutput{ COutputInt(); void Fire(int value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(int value); + int Get() const; } class COutputFloat : CBaseEntityOutput{ COutputFloat(); void Fire(float value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(float value); + float Get() const; } class COutputString : CBaseEntityOutput{ COutputString(); void Fire(const string&in value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(const string&in value); + string Get() const; } class COutputEntity : CBaseEntityOutput{ COutputEntity(); void Fire(CBaseEntity@ value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(CBaseEntity@ value); + CBaseEntity@ Get() const; } class COutputVector : CBaseEntityOutput{ COutputVector(); void Fire(const Vector&in value, CBaseEntity@ activator, CBaseEntity@ caller); void Fire(const QAngle&in value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(const QAngle&in value); + void Init(const Vector&in value); + void Get(QAngle&out value) const; + void Get(Vector&out value) const; } class COutputPosVector : CBaseEntityOutput{ COutputPosVector(); void Fire(const Vector&in value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(const Vector&in value); + void Get(Vector&out value) const; } class COutputColor : CBaseEntityOutput{ COutputColor(); void Fire(Color value, CBaseEntity@ activator, CBaseEntity@ caller); + void Init(Color value); + Color Get() const; } class COutputEvent : CBaseEntityOutput{ COutputEvent(); @@ -2405,6 +2450,8 @@ void VectorAngles(const Vector&in forward, QAngle&out angles); void VectorAngles(const Vector&in forward, const Vector&in pseudoup, QAngle&out angles); void VectorMatrix(const Vector&in forward, matrix3x4_t&out mat); void VectorVectors(const Vector&in forward, Vector&out right, Vector&out up); +void AngleVectors(const QAngle&in angle, Vector&out forward, Vector&out right, Vector&out up); +void AngleVectors(const QAngle&in angle, Vector&out forward); void SetIdentityMatrix(matrix3x4_t&out mat); void SetScaleMatrix(float x, float y, float z, matrix3x4_t&out dst); void MatrixBuildRotationAboutAxis(const Vector&in vAxisOfRot, float angleDegrees, matrix3x4_t&out dst); diff --git a/entities/entityarray.as b/entities/entityarray.as new file mode 100644 index 0000000..8b1de62 --- /dev/null +++ b/entities/entityarray.as @@ -0,0 +1,557 @@ +/** +* @brief EntityList is custom array type that stores specifically added sets of Entities and information about them. +* @details +* @authors Orsell +* +* @license Distributed under the MIT license - Copyright (c) 2026 Project Collapse Studios +*/ + +#include "../misc/logger.as" + +Logger entArrayLog("EntityArray", 2); + +// Tags that can be appended to various EntityInfo's in the EntityArray to find certain specific entities in the array. +//? Maybe we could have a way to implement custom tags that can be made and applied in special cases at runtime? +// TODO: Currently these were just examples of tags we could have, these can be changed out or changed with whatever. +enum EntityTag +{ + NONE = 0, // Entity has no tags. + LOGIC = 1 << 0, // Ex. logic_relay + MODEL = 1 << 1, // Ex. prop_dynamic + PUZZLE_ELEMENT = 1 << 2, // Ex. prop_weighted_cube + NPC = 1 << 3, // Ex. npc_barney + FRIENDLY = 1 << 4, // Ex. Rebels + ENEMY = 1 << 5, // Ex. Combine + CUSTOM = 1 << 6, // A custom AngelScript entity. + + LAST_TAG = 1 << 7 // To indicate how many tags exist. +} +typedef uint16 EntityTags; // Max allowed amount of tags currently is 1 << 15, this can easily be changed later. + +// "Struct" to contain the information about an entity in the EntityArray. +final class EntityInfo +{ + CBaseEntity@ entHandle; // Handle for the entity. + EntityTags entInfoTags; // unint16 number that holds bits. + + /** + * @brief Default constructor. + */ + EntityInfo() + { + @entHandle = null; + entInfoTags = EntityTag::NONE; + } + + /** + * @brief Constructor with arguments. + * @param newEntHandle A CBaseEntity handle to pass to the EntityInfo to store. + * @param tags What tags should be associated with the entity. + */ + EntityInfo( CBaseEntity@ newEntHandle, const EntityTags tags = EntityTag::NONE ) + { + @entHandle = @newEntHandle; + entInfoTags = tags; + } + + /** + * @brief Assign the contents of one EntityInfo's to another. + * @param rhs EntityInfo on the right hand side. + */ + EntityInfo& opAssign( const EntityInfo&in rhs ) + { + if (this == rhs) + return this; + + @this.entHandle = @rhs.entHandle; + this.entInfoTags = rhs.entInfoTags; + + return this; + } + + /** + * @brief Check if two EntityInfo's are equal. + * @param rhs EntityInfo on the right hand side. + */ + bool opEquals( const EntityInfo&in rhs ) const + { + if ((@this.entHandle != @rhs.entHandle) || (this.entInfoTags != rhs.entInfoTags)) + return false; + + return true; + } + + void Print() + { + Msg("Entity Name: " + this.entHandle.GetEntityName() + " | "); + Msg("Entity Index: " + this.entHandle.GetEntityIndex() + " | "); + Msg("Tags: " + this.entInfoTags + "\n"); + } +} + +// Custom array type that stores specifically added sets of Entities and information about them. +class EntityArray +{ + // ---------------- CLASS MEMBERS VARIABLES ---------------- \\ + + // The underlying array that holds all the EntityInfo "structs". + private array entArr; + + + // ---------------- CLASS CTORs/DTORs ---------------- \\ + + /** + * @brief Default constructor for the EntityArray. + */ + EntityArray() + { + entArr.resize(0); + } + + /** + * @brief Copy constructor for the EntityArray. + */ + EntityArray( const EntityArray&inout rhs ) + { + this.entArr = rhs.entArr; + } + + + // ---------------- ARRAY FUNCTIONS ---------------- \\ + + /** + * @brief Assign the contents of one EntityArray array to another EntityArray. + * @param rhs EntityArray on the right hand side. + */ + EntityArray& opAssign( const EntityArray&inout rhs ) + { + if (this == rhs) + return this; + + this.entArr = rhs.entArr; + + return this; + } + + /** + * @brief Check if two EntityArray's are equal. + * @param rhs EntityArray on the right hand side. + * @note Order of EntityInfo's in the array matters, and for each index the inside items match. + */ + bool opEquals( const EntityArray&in rhs ) const + { + // Checking if the length is different. + if (this.entArr.length() != rhs.entArr.length()) + return false; + + // Checking individual items of the array. + for (uint i = 0; i < this.entArr.length(); i++) + { + if (this.entArr[i] != rhs.entArr[i]) + return false; + } + + return true; + } + + /** + * @brief Access a EntityInfo by index from the array. + */ + EntityInfo& opIndex( uint index ) { return entArr[index]; } + const EntityInfo& opIndex( uint index ) const { return entArr[index]; } + + /** + * @brief For statement operator overloads for usage with foreach as indexes. + */ + uint opForBegin() const { return 0; } + bool opForEnd( uint index ) const { return index >= entArr.length(); } + uint opForNext( uint index ) const { return index + 1; } + + /** + * @brief Add assignment operator overload for adding and setting a array. + */ + EntityArray& opAddAssign( const EntityArray&in rhs ) + { + for (uint i = 0; i < entArr.length(); i++) + { + AddByInfo(rhs[i]); + } + + return this; + } + + /** + * @brief Add operator overload for adding arrays together. + */ + EntityArray opAdd( const EntityArray&in rhs ) const + { + EntityArray result(this); + return (result += rhs); + } + + + // ---------------- ARRAY FUNCTIONS ---------------- \\ + + /** + * @brief Clear all the entities from the EntityArray. + */ + void Clear() { entArr.removeRange(0, entArr.length()); } + + /** + * @brief Get length of the EntityArray. + */ + int Length() { return entArr.length(); } + + /** + * @brief Print all the contents of the array. + */ + void PrintArray() + { + for (uint i = 0; i < entArr.length(); i++) + { + Msg("Array Position: " + i + " | "); + entArr[i].Print(); + } + } + + + // ---------------- ADDING FUNCTIONS ---------------- \\ + + + /** + * @brief Add a entity to the EntityArray by its entity name. + * @param entName Entity name of the entity to add. + * @param tags (optional) What tags should be added with the entity. + * @param addAmt (optional) How many of the entities by entity name should be added. + */ + void AddByEntityName( const string&in entName, const EntityTags tags = EntityTag::NONE, uint addAmt = 1 ) + { + for (CBaseEntity@ ent = null; (@ent = EntityList().FindByName(ent, entName)) != null;) + { + if (@ent == null) + continue; + + if (ent.GetEntityName() != entName) + continue; + + entArr.insertLast(EntityInfo(ent, tags)); + entArrayLog.Info("Added entity \"" + ent.GetEntityName() + "\" with entindex \"" + ent.GetEntityIndex() + "\"."); + if (tags > 0) + entArrayLog.Info("Entity tag value is: \"" + tags + "\""); + + if (--addAmt <= 0) + return; + } + } + + /** + * @brief Add a entity to the EntityArray by its class name. + * @param className Class name of the entity to add. + * @param tags (optional) What tags should be added with the entity. + * @param addAmt (optional) How many of the entities by class name should be added. + */ + void AddByClassname( const string&in className, const EntityTags tags = EntityTag::NONE, uint addAmt = 1 ) + { + for (CBaseEntity@ ent = null; (@ent = EntityList().FindByClassname(ent, className)) != null;) + { + if (@ent == null) + continue; + + if (ent.GetClassname() != className) + continue; + + entArr.insertLast(EntityInfo(ent, tags)); + entArrayLog.Info("Added entity \"" + ent.GetEntityName() + "\" with entindex \"" + ent.GetEntityIndex() + "\"."); + + if (tags > 0) + entArrayLog.Info("Entity tag value is: \"" + tags + "\""); + + if (--addAmt <= 0) + return; + } + } + + /** + * @brief Add a entity to the EntityArray by its handle. + * @param entHandle Handle of the entity to add. + * @param tags (optional) What tags should be added with the entity. + */ + void AddByHandle( CBaseEntity@ entHandle, const EntityTags tags = EntityTag::NONE ) + { + if (@entHandle == null) + { + entArrayLog.Warn("Invalid handle passed to AddByHandle!"); + return; + } + + entArr.insertLast(EntityInfo(entHandle, tags)); + entArrayLog.Info("Added entity \"" + entHandle.GetEntityName() + "\" with entindex \"" + entHandle.GetEntityIndex() + "\"."); + + if (tags > 0) + entArrayLog.Info("Entity tag value is: \"" + tags + "\""); + } + + /** + * @brief Add a EntityInfo to the EntityArray + * @param entInfo EntityInfo to add. + */ + void AddByInfo( const EntityInfo&in entInfo ) + { + entArr.insertLast(entInfo); + if (@entInfo.entHandle != null) + entArrayLog.Info("Added entity \"" + entInfo.entHandle.GetEntityName() + "\" with entindex \"" + entInfo.entHandle.GetEntityIndex() + "\"."); + else + entArrayLog.Warn("EntityInfo with a null entity handle has been added!"); + + if (entInfo.entInfoTags > 0) + entArrayLog.Info("Entity tag value is: \"" + entInfo.entInfoTags + "\""); + } + + + // ---------------- REMOVING FUNCTIONS ---------------- \\ + + /** + * @brief Remove entities from the EntityArray by a entity's name. + * @param entName Name of entity to remove from the array. + * @param rmAmt (optional) How many of the entity by it's name should be removed. + */ + void RemoveByEntityName( const string&in entName, uint rmAmt = 1 ) + { + for (uint i = 0; i < entArr.length(); i++) + { + EntityInfo entInfo = entArr[i]; + if ((@entInfo.entHandle != null) && (entInfo.entHandle.GetEntityName() == entName)) + { + entArrayLog.Info("Removed entity \"" + entInfo.entHandle.GetEntityName() + "\" with entindex \"" + entInfo.entHandle.GetEntityIndex() + "\"."); + entArr.removeAt(i); + + if (--rmAmt <= 0) + return; + } + } + } + + /** + * @brief Remove entities from the EntityArray by a entity's class name. + * @param className Class name of entity to remove from the array. + * @param rmAmt (optional) How many of the entity by it's class name should be removed. + */ + void RemoveByClassname( const string&in className, uint rmAmt = 1 ) + { + for (uint i = 0; i < entArr.length(); i++) + { + EntityInfo entInfo = entArr[i]; + if ((@entInfo.entHandle != null) && (entInfo.entHandle.GetClassname() == className)) + { + entArrayLog.Info("Removed entity \"" + entInfo.entHandle.GetEntityName() + "\" with entindex \"" + entInfo.entHandle.GetEntityIndex() + "\"."); + entArr.removeAt(i); + + if (--rmAmt <= 0) + return; + } + } + } + + /** + * @brief Remove entity from the EntityArray by a CBaseEntity handle. + * @param entHandle Handle of the entity to remove from the array. + */ + void RemoveByHandle( const CBaseEntity@ entHandle ) + { + for (uint i = 0; i < entArr.length(); i++) + { + EntityInfo entInfo = entArr[i]; + if ((@entInfo.entHandle != null) && (entInfo.entHandle is entHandle)) + { + entArrayLog.Info("Removed entity \"" + entInfo.entHandle.GetEntityName() + "\" with entindex \"" + entInfo.entHandle.GetEntityIndex() + "\"."); + entArr.removeAt(i); + return; + } + } + } + + + // ---------------- SORTING FUNCTIONS ---------------- \\ + // TODO: Repetitive code, should be consolidated and optimized a bit. + + /** + * @brief Sort entities in the EntityArray by their tag value. + * @param ascending Whether to sort ascending or descending. + */ + void SortEntitiesByTags( bool ascending = true ) + { + if (ascending) + { + entArr.sort( + function(const EntityInfo&in A, const EntityInfo&in B) + { + return A.entInfoTags < B.entInfoTags; + } + ); + } + else + { + entArr.sort( + function(const EntityInfo&in A, const EntityInfo&in B) + { + return A.entInfoTags > B.entInfoTags; + } + ); + } + } + + /** + * @brief Sort entities in the EntityArray by their entity name. + * @param ascending Whether to sort ascending or descending. + */ + // TODO: Figure out string comparison + // void SortEntitiesByName( bool ascending = true ) + // { + // if (ascending) + // { + // entArr.sort( + // function(const EntityInfo&in A, const EntityInfo&in B) + // { + // return A.entHandle.GetEntityName() < B.entHandle.GetEntityName(); + // } + // ); + // } + // else + // { + // entArr.sort( + // function(const EntityInfo&in A, const EntityInfo&in B) + // { + // return A.entHandle.GetEntityName() > B.entHandle.GetEntityName(); + // } + // ); + // } + // } + + /** + * @brief Sort entities in the EntityArray by their entity classname. + * @param ascending Whether to sort ascending or descending. + */ + // TODO: Figure out string comparison + // void SortEntitiesByClassname( bool ascending = true ) + // { + // if (ascending) + // { + // entArr.sort( + // function(const EntityInfo&in A, const EntityInfo&in B) + // { + // return A.entHandle.GetClassname() < B.entHandle.GetClassname(); + // } + // ); + // } + // else + // { + // entArr.sort( + // function(const EntityInfo&in A, const EntityInfo&in B) + // { + // return A.entHandle.GetClassname() > B.entHandle.GetClassname(); + // } + // ); + // } + // } + + /** + * @brief Sort entities in the EntityArray by their entity entity index. + * @param ascending Whether to sort ascending or descending. + */ + void SortEntitiesByIndex( bool ascending = true ) + { + if (ascending) + { + entArr.sort( + function(const EntityInfo&in A, const EntityInfo&in B) + { + return A.entHandle.GetEntityIndex() < B.entHandle.GetEntityIndex(); + } + ); + } + else + { + entArr.sort( + function(const EntityInfo&in A, const EntityInfo&in B) + { + return A.entHandle.GetEntityIndex() > B.entHandle.GetEntityIndex(); + } + ); + } + } + + // ---------------- FIND FUNCTIONS ---------------- \\ + + /** + * @brief Find entities in the EntityArray by a CBaseEntity handle. + * @param handle Handle to search for in the array. + * @return Simple array of EntityInfo with the given handle. + */ + array@ FindByHandle( const CBaseEntity@ handle ) + { + array results; + + for (uint i = 0; i < entArr.length(); i++) + { + if (@entArr[i].entHandle == @handle) + results.insertLast(entArr[i]); + } + + return results; + } + + /** + * @brief Find entities in the EntityArray by an entity name. + * @param entName Name of entity to search for in the array. + * @return Simple array of EntityInfo with the given name. + */ + array@ FindByEntityName( const string&in entName ) + { + array results; + for (uint i = 0; i < entArr.length(); i++) + { + if (entArr[i].entHandle.GetEntityName() == entName) + results.insertLast(entArr[i]); + } + + return results; + } + + /** + * @brief Find entities in the EntityArray by a class name. + * @param className Class name of entity to search for in the array. + * @return Simple array of EntityInfo with the given class name. + */ + array@ FindByClassname( const string&in className ) + { + array results; + for (uint i = 0; i < entArr.length(); i++) + { + if (entArr[i].entHandle.GetClassname() == className) + results.insertLast(entArr[i]); + } + + return results; + } + + /** + * @brief Find entities in the EntityArray by EntityTags. + * @param tag Tags to search for in the array. + * @return Array of entities with the given tags. + */ + array@ FindByTag( const EntityTags tag ) + { + array results; + for (uint i = 0; i < entArr.length(); i++) + { + //! The LSP will say this is invalid when actually it is valid, + //! there is no need for a defined operator overload for the bitwise AND. + if ((entArr[i].entInfoTags & tag) != 0) + { + results.insertLast(entArr[i]); + } + } + + return results; + } +} diff --git a/misc/assert.as b/misc/assert.as index 7f7abb1..581fa7f 100644 --- a/misc/assert.as +++ b/misc/assert.as @@ -16,7 +16,6 @@ void assert( const bool testStatement, const string&in errMsg = "Passed statemen { if (!testStatement) { - debugbreak(); throw("Assertion hit! Error: " + errMsg); } } diff --git a/misc/logger.as b/misc/logger.as index 77cfb44..a48437a 100644 --- a/misc/logger.as +++ b/misc/logger.as @@ -10,7 +10,7 @@ class Logger { private ConVar developerCV; // Create a logger with a given name, will print out messages as [scriptsys][name]: Message - // required_developer_level = 0, Message will only print out when the developer convar is greator or equal to this value. + // required_developer_level = 0, Message will only print out when the developer ConVar is greater or equal to this value. Logger(string name, int required_developer_level = 0) { this.name = name; this.required_developer_level = required_developer_level; @@ -25,14 +25,14 @@ class Logger { // Print an info message to the console // string message - the message to print // string end - string that gets appended to the end of the message - // int required_developer_level (optional) - This message will only print out when the developer convar is greator or equal to this value. Additionally, any negative value will make it use the global required level passed in the constructor. + // int required_developer_level (optional) - This message will only print out when the developer ConVar is greater or equal to this value. Additionally, any negative value will make it use the global required level passed in the constructor. void Info(string message, string end, int required_developer_level = -1) { this.__info(message, end, required_developer_level); } // Print an info message to the console // string message - the message to print - // int required_developer_level - This message will only print out when the developer convar is greator or equal to this value. Additionally, any negative value will make it use the global required level passed in the constructor. + // int required_developer_level - This message will only print out when the developer ConVar is greater or equal to this value. Additionally, any negative value will make it use the global required level passed in the constructor. void Info(string message, int required_developer_level) { this.__info(message, "\n", required_developer_level); } @@ -41,8 +41,8 @@ class Logger { void Info(string message) { this.__info(message, "\n", -1); } - - + + private void __info(string message, string end, int required_developer_level) { int dv_lvl = this.GetDeveloperLevel(); if ( @@ -57,14 +57,14 @@ class Logger { // Print an warning message to the console // string message - the message to print // string end - string that gets appended to the end of the message - // int required_developer_level (optional) - This message will only print out when the developer convar is set to this value. Additionally, any negative value will make it use the global required level passed in the constructor. + // int required_developer_level (optional) - This message will only print out when the developer ConVar is set to this value. Additionally, any negative value will make it use the global required level passed in the constructor. void Warn(string message, string end, int required_developer_level = -1) { this.__warn(message, end, required_developer_level); } // Print an warning message to the console // string message - the message to print - // int required_developer_level - This message will only print out when the developer convar is set to this value. Additionally, any negative value will make it use the global required level passed in the constructor. + // int required_developer_level - This message will only print out when the developer ConVar is set to this value. Additionally, any negative value will make it use the global required level passed in the constructor. void Warn(string message, int required_developer_level) { this.__warn(message, "\n", required_developer_level); } @@ -73,8 +73,8 @@ class Logger { void Warn(string message) { this.__warn(message, "\n", -1); } - - + + private void __warn(string message, string end = "\n", int required_developer_level = -1) { int dv_lvl = this.GetDeveloperLevel(); if ( diff --git a/tests/load_all.as b/tests/load_all.as index d97e77c..bf5f0ee 100644 --- a/tests/load_all.as +++ b/tests/load_all.as @@ -4,4 +4,5 @@ #include "test_assert.as" #include "test_CuboidVolumeSimple.as" +#include "test_EntityArray.as" #include "test_logger.as" diff --git a/tests/test_EntityArray.as b/tests/test_EntityArray.as new file mode 100644 index 0000000..5003c1c --- /dev/null +++ b/tests/test_EntityArray.as @@ -0,0 +1,124 @@ +/** +* @brief Test the EntityArray special array type. +* @details +* @authors Orsell +* +* @license Distributed under the MIT license - Copyright (c) 2026 Project Collapse Studios +*/ + +#include "../misc/logger.as" +#include "../misc/assert.as" + +#include "../entities/entityarray.as" + +[ServerCommand("as_test_entarray", "Testing EntityArray functionality.")] +void TestEntityArray(const CommandArgs@ args) +{ + Logger log("EntityArrayTest_Logger"); + + log.Info("Testing EntityArray functionality!"); + + log.Info("// ---------- TEST 1: Testing Ideal Functionality"); + log.Info("// ---------- TEST 1-1: Adding entities to an EntityArray by entity name and with a tag."); + + EntityArray entArray; + + // Test adding entities by name with tags + entArray.AddByEntityName("barney1", EntityTag::NPC, 1); + entArray.AddByClassname("player", EntityTag::FRIENDLY, 1); + entArray.AddByClassname("weapon_pistol", EntityTag::CUSTOM, 1); + entArray.AddByClassname("prop_dynamic", EntityTag::MODEL, 10); + entArray.PrintArray(); + + // Test if entities are correctly added + //assert(entArray.Length() == 12, "TEST 1-1: Check 1 failed!"); + //assert(entArray.FindByEntityName("relay1").length() == 1, "TEST 1-1: Check 2 failed!"); + //assert(entArray.FindByClassname("npc_barney").length() == 1, "TEST 1-1: Check 3 failed!"); + //assert(entArray.FindByClassname("prop_dynamic").length() == 10, "TEST 1-1: Check 4 failed!"); + //assert(entArray.FindByTag(EntityTag::LOGIC).length() == 1, "TEST 1-1: Check 5 failed!"); + + return; + + log.Info("\n"); + log.Info("// ---------- TEST 1-2: Testing equality with another EntityArray."); + // // Test equality operator + EntityArray anotherArray; + anotherArray.AddByEntityName("barney1", EntityTag::NPC, 1); + anotherArray.AddByClassname("logic_relay", EntityTag::LOGIC, 1); + anotherArray.AddByClassname("prop_dynamic", EntityTag::MODEL, 10); + // assert(entArray == anotherArray, "TEST 1-2: Check failed!"); + + log.Info("\n"); + log.Info("// ---------- TEST 1-3: Testing removing entities by name."); + // Test removing entities by name + entArray.RemoveByEntityName("npc_barney", 1); + //assert(entArray.Length() == 11, "TEST 1-3: Check 1 failed!"); + //assert(entArray.FindByEntityName("npc_barney").length() == 0, "TEST 1-3: Check 2 failed!"); + + // log.Info("\n"); + // log.Info("// ---------- TEST 1-4: Testing sorting entities by tags."); + // // Test sorting entities by tags + // entArray.SortEntitiesByTags(true); // Ascending order by tags + // assert(entArray[0].tags == EntityTag::LOGIC, "TEST 1-4: Check 1 failed!"); + // assert(entArray[1].tags == EntityTag::MODEL, "TEST 1-4: Check 2 failed!"); + + // Stress Test + + //log.Info("// ---------- TEST 2-1: Testing stress test scenario adding 1000 entities with random tags."); + // Add 1000 entities with random tags + // for (int i = 0; i < 1000; i++) + // { + // EntityTags randomTag = (EntityTags)(1 << (i % 7)); // Cycle through some tags + // entArray.AddByEntityName("entity_" + i, randomTag); + // } + // assert(entArray.Length() == 1002); // Original 2 entities + 1000 added + // assert(entArray.FindByTag(EntityTag::LOGIC).length() == 1); // LOGIC should still be there + // assert(entArray.FindByTag(EntityTag::NONE).length() == 1000); // None should have many added entities + + // // Test removal of entities by class name + // entArray.RemoveByClassname("prop_dynamic", 1); + // assert(entArray.FindByClassname("prop_dynamic").length() == 0); + + // // Stress Test - Remove entities and ensure correct removal + // entArray.RemoveByEntityName("entity_0", 1); + // assert(entArray.Length() == 1001); // One entity removed + // assert(entArray.FindByEntityName("entity_0").length() == 0); + + // Error Cases + // log.Info("\n"); + // log.Info("// ---------- TEST 3: Testing Error Cases"); + // log.Info("// ---------- TEST 3-1: Testing adding an invalid entity handle."); + + // // Test adding an invalid entity handle + // entArray.AddByHandle(null, EntityTag::NONE); // Should not crash, should be ignored + + // log.Info("\n"); + // log.Info("// ---------- TEST 3-2: Testing removing a non-existing entity."); + // // Test removing a non-existing entity + // entArray.RemoveByEntityName("non_existing_entity"); + // assert(entArray.Length() == 1001, "TEST 3-2: Check failed!"); // Should not have changed length + + // log.Info("\n"); + // log.Info("// ---------- TEST 3-3: Testing find a non-existing entity."); + // // Test finding a non-existing entity + // array nonExistent = entArray.FindByEntityName("non_existing_entity"); + // assert(nonExistent.length() == 0, "TEST 3-3: Check failed!"); // Should return an empty array + + // log.Info("\n"); + // log.Info("// ---------- TEST 3-4: Testing adding entities with conflicting tags."); + // // Test adding entities with conflicting tags + // entArray.AddByEntityName("entity_conflict", EntityTag::ENEMY | EntityTag::FRIENDLY); + // assert(entArray.FindByTag(EntityTag::ENEMY).length() == 1, "TEST 3-4: Check 1 failed!"); + // assert(entArray.FindByTag(EntityTag::FRIENDLY).length() == 1, "TEST 3-4: Check 2 failed!"); + // assert(entArray.FindByTag(EntityTag::ENEMY | EntityTag::FRIENDLY).length() == 1, "TEST 3-4: Check 3 failed!"); + + // log.Info("\n"); + // log.Info("// ---------- TEST 4: Testing removing a non-existing entity."); + // // Remove all entities + // entArray.Clear(); + // assert(entArray.Length() == 0, "TEST 4: Check failed!"); // After clearing, array should be empty + + log.Info("\n"); + log.Info("EntityArray functionality testing completed!"); + log.Info("----------------------------------------\n"); +}