Raised This Month: $51 Target: $400
 12% 

View Poll Results: Which method is the best?
Use a static array. 4 80.00%
Use a global dynamic array. 2 40.00%
Modify the ent prop data. 0 0%
Best solution not listed here (please post your solution). 0 0%
Multiple Choice Poll. Voters: 5. You may not vote on this poll

[POLL] What is the best way to store entity indicies for fast retrieval?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Bugzy
Junior Member
Join Date: Nov 2013
Location: Perth, Australia
Old 08-05-2014 , 10:53   [POLL] What is the best way to store entity indicies for fast retrieval?
Reply With Quote #1

In my plugin, I need to detect when a player touches a trigger_multiple and then uniquely identify the entity touched using a mapping that looks like:

entity_index -> ID

Where the ID is simply an unsigned integer.

Assume, that all data structures are built once and only once, never to be have entries inserted/deleted post-initialization. In your opinion, which of the following ways is the best for data retrieval?

Edit: Assume further that the data retrieval happens the instant OnTouch event fires, and that a client can touch multiple trigger_multiple entities at a time.

1. Use a hard-coded constant and large global static array
Code:
#define MAXENTITIES 2048 
new g_iMyIDs[MAXENTITIES];

public OnTouch(const String:output[], caller, activator, Float:delay)
{
    if (caller < MAXENTITIES)
        PrintToChatAll("Entity id is %d", g_iMyIDs[caller]);
}
Advantages:
  • Super-quick, constant-time retrieval.
Disadvantages:
  • Wastes a small amount of memory. Array will be sparse.
  • You can't, on initialization, store more entities than the MAXENTITIES constant allows. The program must be recompiled with a new larger constant.
2. Use a global dynamic array

Code:
new Handle:g_hMyIDs = CreateArray(2);

public OnTouch(const String:output[], caller, activator, Float:delay)
{
    new ref = EntIndexToEntRef(caller);
    for (new i = 0; i < GetArraySize(g_hMyIDs); i++)
    {
        if (GetArrayCell(g_hMyIDs, i, 0) == ref)
        {
            PrintToChatAll("Entity id is %d", GetArrayCell(g_hMyIDs, i, 1));
            break;
        }
    }
}
Advantages:
  • No memory is wasted.
  • No need to set arbitrary constants pre-compilation, the array will automatically grow larger to accomodate the entities.
Disadvantages:
  • Dynamic arrays are slower than static arrays. It takes linear time to find the entity, and assuming GetArrayCell() also takes linear(?) time, it would, at worst, take exponential time.
3. Modify the m_iName ent prop data at initialization to include the ID

Code:
public OnTouch(const String:output[], caller, activator, Float:delay)
{
    decl String:sTargetName[256];
    GetEntPropString(caller, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
    PrintToChatAll("Entity id is %d", StringToInt(sTargetName));
}
Advantages:
  • No space is wasted.
  • Constant-time retrieval.
Disadvantages:
  • This will break communication if one entity hooked receives output from another entity.

Last edited by Bugzy; 08-05-2014 at 16:13. Reason: Clarifications
Bugzy is offline
Powerlord
AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
Old 08-05-2014 , 11:19   Re: [POLL] What is the best way to store entity indicies for fast retrieval?
Reply With Quote #2

Can a player ever be touching more than on trigger_multiple at a time?

If not, you could do something like this...

Code:
new giMyPlayersTouch[MAXPLAYERS+1];

// in code somewhere
    for (new i = 1; i <= MaxClients; i++)
    {
        if (IsClientInGame(i) && giMyPlayersTouch[i] == myId)
        {
            // Do something because they're touching the ID thing
        }
    }
That is assuming you're hooking OnStartTouch, OnEndTouch, and using ClientDisconnect to keep track of the ID the client is touching (keeping in mind that ClientDisconnect also fires for each client on map change).
__________________
Not currently working on SourceMod plugin development.

Last edited by Powerlord; 08-05-2014 at 11:21.
Powerlord is offline
Bugzy
Junior Member
Join Date: Nov 2013
Location: Perth, Australia
Old 08-05-2014 , 16:09   Re: [POLL] What is the best way to store entity indicies for fast retrieval?
Reply With Quote #3

Quote:
Originally Posted by Powerlord View Post
Can a player ever be touching more than on trigger_multiple at a time?

If not, you could do something like this...

Code:
new giMyPlayersTouch[MAXPLAYERS+1];

// in code somewhere
    for (new i = 1; i <= MaxClients; i++)
    {
        if (IsClientInGame(i) && giMyPlayersTouch[i] == myId)
        {
            // Do something because they're touching the ID thing
        }
    }
That is assuming you're hooking OnStartTouch, OnEndTouch, and using ClientDisconnect to keep track of the ID the client is touching (keeping in mind that ClientDisconnect also fires for each client on map change).
Thanks for your feedback and I appreciate your lateral thinking. Sorry for not being more clear but yes, it's allowed for a client to touch multiple triggers at the same time. Not only this, but it's also important that the plugin detects what trigger was touched the instant it occurred (as oppose to retroactively detecting it at some later event). This is because I'm developing a special timer plugin unlike the ones that exist so far.

Last edited by Bugzy; 08-05-2014 at 16:24. Reason: Grammar
Bugzy is offline
friagram
Veteran Member
Join Date: Sep 2012
Location: Silicon Valley
Old 08-05-2014 , 16:39   Re: [POLL] What is the best way to store entity indicies for fast retrieval?
Reply With Quote #4

I have a mod that uses zones.

I store the zones in a dynamic array, but most overhead occurs only in external native calls (infrequently).
Since on/off touch fires very infrequently, its fine to use dynamic arrays.
Almost everything can be done by getting one cell from a dynamic array on/off touch, I just use an integer to store flags. You could store this informstion in a netprop also, (like m_inname or possibly some unused int) but this would have overhead also. Again, you can store the flags count for each client, so you know how many zones of that type they are in, and overlaps are accounted for.

The dynamic arrays are not *that* slow. And unless you are doing several thousands of operations a second, you're not going to notice anything. I assume the problem with the dynamic arrays is that it is not contiguous, so it takes longer to calculate the memory location... The more fragmented, the slower, as it had to iterate over an index of memory ranges to find where the data is. I really have no idea. I don't think you can multiply indexes in arrays to calculate multidimensional cells like you can in c. Either that, or it is contiguously allocating the arrays like malloc/calloc, but then using realloc each time the array is resized. If this is the case, there is even less overhead overall (as add/remove is done less frequently than simple retrieval). This would probably be the better solution, but again I don't know and am a shit c programmer.

When you allocate something contiguously, you can find it simply by multiplying the start address by the size of each cell.
__________________
Profile - Plugins
Add me on steam if you are seeking sp/map/model commissions.
friagram is offline
Bugzy
Junior Member
Join Date: Nov 2013
Location: Perth, Australia
Old 08-06-2014 , 14:38   Re: [POLL] What is the best way to store entity indicies for fast retrieval?
Reply With Quote #5

Quote:
Originally Posted by friagram View Post
I have a mod that uses zones.

I store the zones in a dynamic array, but most overhead occurs only in external native calls (infrequently).
Since on/off touch fires very infrequently, its fine to use dynamic arrays.
Almost everything can be done by getting one cell from a dynamic array on/off touch, I just use an integer to store flags. You could store this informstion in a netprop also, (like m_inname or possibly some unused int) but this would have overhead also. Again, you can store the flags count for each client, so you know how many zones of that type they are in, and overlaps are accounted for.

The dynamic arrays are not *that* slow. And unless you are doing several thousands of operations a second, you're not going to notice anything. I assume the problem with the dynamic arrays is that it is not contiguous, so it takes longer to calculate the memory location... The more fragmented, the slower, as it had to iterate over an index of memory ranges to find where the data is. I really have no idea. I don't think you can multiply indexes in arrays to calculate multidimensional cells like you can in c. Either that, or it is contiguously allocating the arrays like malloc/calloc, but then using realloc each time the array is resized. If this is the case, there is even less overhead overall (as add/remove is done less frequently than simple retrieval). This would probably be the better solution, but again I don't know and am a shit c programmer.

When you allocate something contiguously, you can find it simply by multiplying the start address by the size of each cell.
Thanks so much for helping out again! I admit linear time for indexing a dynamic array was a gross estimation but I couldn't find info on how it's implemented, so I began to worry that maybe a linked list was used. Your explanation of why dynamic arrays are considered slow is because they probably use realloc in the background does make sense. Hence, from a more optimistic standpoint, I think it would be worthwhile, post-initialization to use SortADTArrayCustom and thereafter use binary search to index the array. This will whittle indexing time right down to O(2 * log_2(n - 1)). With respect to the fact that the game engine can only store a maximum of 2048 edicts, the maximum number of comparison will be 22, which might as well be constant time.

Last edited by Bugzy; 08-06-2014 at 14:54. Reason: Math mistake
Bugzy is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 05:14.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode