2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
16 #include "AdminCache.h"
18 #include "ForwardSys.h"
22 AdminCache::AdminCache()
24 m_pCmdOverrides = NULL;
25 m_pCmdGrpOverrides = NULL;
26 m_pStrings = new BaseStringTable(1024);
27 m_pMemory = m_pStrings->GetMemTable();
28 m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
29 m_pGroups = sm_trie_create();
33 AdminCache::~AdminCache()
35 if (m_pCmdGrpOverrides)
37 sm_trie_destroy(m_pCmdGrpOverrides);
42 sm_trie_destroy(m_pCmdOverrides);
45 InvalidateGroupCache();
49 sm_trie_destroy(m_pGroups);
55 void AdminCache::OnSourceModAllInitialized()
57 m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
58 g_ShareSys.AddInterface(NULL, this);
61 void AdminCache::OnSourceModShutdown()
63 g_Forwards.ReleaseForward(m_pCacheFwd);
67 void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag)
69 if (type == Override_Command)
71 _AddCommandOverride(cmd, flag);
72 } else if (type == Override_CommandGroup) {
73 _AddCommandGroupOverride(cmd, flag);
77 bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag)
79 if (type == Override_Command)
81 return _GetCommandOverride(cmd, pFlag);
82 } else if (type == Override_CommandGroup) {
83 return _GetCommandGroupOverride(cmd, pFlag);
89 void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
91 if (type == Override_Command)
93 return _UnsetCommandOverride(cmd);
94 } else if (type == Override_CommandGroup) {
95 return _UnsetCommandGroupOverride(cmd);
99 void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag)
101 if (!m_pCmdGrpOverrides)
103 m_pCmdGrpOverrides = sm_trie_create();
106 /* :TODO: Notify command system */
108 sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag);
111 void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag)
113 if (!m_pCmdOverrides)
115 m_pCmdOverrides = sm_trie_create();
118 /* :TODO: Notify command system */
120 sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag);
123 bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag)
125 if (!m_pCmdGrpOverrides)
132 return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL);
136 if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object))
138 *pFlag = (AdminFlag)(int)object;
144 bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag)
146 if (!m_pCmdOverrides)
153 return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL);
157 if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object))
159 *pFlag = (AdminFlag)(int)object;
165 void AdminCache::_UnsetCommandGroupOverride(const char *group)
167 if (!m_pCmdGrpOverrides)
172 /* :TODO: Notify command system */
174 sm_trie_delete(m_pCmdGrpOverrides, group);
177 void AdminCache::_UnsetCommandOverride(const char *cmd)
179 if (!m_pCmdOverrides)
184 /* :TODO: Notify command system */
186 sm_trie_delete(m_pCmdOverrides, cmd);
189 void AdminCache::DumpCommandOverrideCache(OverrideType type)
191 if (type == Override_Command && m_pCmdOverrides)
193 sm_trie_clear(m_pCmdOverrides);
194 } else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
195 sm_trie_clear(m_pCmdGrpOverrides);
199 GroupId AdminCache::AddGroup(const char *group_name)
201 if (sm_trie_retrieve(m_pGroups, group_name, NULL))
203 return INVALID_GROUP_ID;
208 if (m_FreeGroupList != INVALID_GROUP_ID)
210 pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
211 assert(pGroup->magic == GRP_MAGIC_UNSET);
212 id = m_FreeGroupList;
213 m_FreeGroupList = pGroup->next_grp;
215 id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
218 pGroup->immune_default = false;
219 pGroup->immune_global = false;
220 pGroup->immune_table = -1;
221 pGroup->magic = GRP_MAGIC_SET;
222 pGroup->next_grp = INVALID_GROUP_ID;
223 pGroup->pCmdGrpTable = NULL;
224 pGroup->pCmdTable = NULL;
225 pGroup->nameidx = m_pStrings->AddString(group_name);
226 memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL);
228 if (m_FirstGroup == INVALID_GROUP_ID)
232 pGroup->prev_grp = INVALID_GROUP_ID;
234 AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
235 assert(pPrev->magic == GRP_MAGIC_SET);
236 pPrev->next_grp = id;
237 pGroup->prev_grp = m_LastGroup;
241 sm_trie_insert(m_pGroups, group_name, (void *)id);
246 GroupId AdminCache::FindGroupByName(const char *group_name)
250 if (!sm_trie_retrieve(m_pGroups, group_name, &object))
252 return INVALID_GROUP_ID;
255 GroupId id = (GroupId)object;
256 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
258 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
260 return INVALID_GROUP_ID;
266 void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
268 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
269 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
274 if (flag < Admin_None || flag >= AdminFlags_TOTAL)
279 pGroup->addflags[flag] = enabled;
282 bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
284 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
285 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
290 if (flag < Admin_None || flag >= AdminFlags_TOTAL)
295 return pGroup->addflags[flag];
298 unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total)
300 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
301 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
309 i < AdminFlags_TOTAL && i < total;
312 flags[i] = pGroup->addflags[i];
318 void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
320 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
321 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
326 if (type == Immunity_Default)
328 pGroup->immune_default = enabled;
329 } else if (type == Immunity_Global) {
330 pGroup->immune_global = enabled;
334 bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
336 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
337 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
342 if (type == Immunity_Default)
344 return pGroup->immune_default;
345 } else if (type == Immunity_Global) {
346 return pGroup->immune_global;
352 void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
354 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
355 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
360 AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
361 if (!pOther || pOther->magic != GRP_MAGIC_SET)
366 /* We always need to resize the immunity table */
368 if (pOther->immune_table == -1)
370 tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
373 int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
374 tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
375 /* Get the old address again in caes of resize */
376 old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
377 table[0] = old_table[0];
378 for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
380 table[i] = old_table[i];
385 pOther->immune_table = tblidx;
387 /* Add to the array */
389 table[table[0]] = other_id;
392 unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
394 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
395 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
400 if (pGroup->immune_table == -1)
405 int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
410 GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
412 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
413 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
415 return INVALID_GROUP_ID;
418 if (pGroup->immune_table == -1)
420 return INVALID_GROUP_ID;
423 int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
424 if (number >= (unsigned int)table[0])
426 return INVALID_GROUP_ID;
429 return table[1 + number];
432 void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
434 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
435 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
441 if (type == Override_Command)
443 if (pGroup->pCmdTable == NULL)
445 pGroup->pCmdTable = sm_trie_create();
447 pTrie = pGroup->pCmdTable;
448 } else if (type == Override_CommandGroup) {
449 if (pGroup->pCmdGrpTable == NULL)
451 pGroup->pCmdGrpTable = sm_trie_create();
453 pTrie = pGroup->pCmdGrpTable;
458 sm_trie_insert(pTrie, name, (void *)(int)rule);
461 bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
463 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
464 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
470 if (type == Override_Command)
472 if (pGroup->pCmdTable == NULL)
476 pTrie = pGroup->pCmdTable;
477 } else if (type == Override_CommandGroup) {
478 if (pGroup->pCmdGrpTable == NULL)
482 pTrie = pGroup->pCmdGrpTable;
488 if (!sm_trie_retrieve(pTrie, name, &object))
495 *pRule = (OverrideRule)(int)object;
501 void AdminCache::InvalidateGroup(GroupId id)
503 AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
506 if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
511 const char *str = m_pStrings->GetString(pGroup->nameidx);
512 sm_trie_delete(m_pGroups, str);
514 /* Unlink from the live dbllink list */
515 if (id == m_FirstGroup && id == m_LastGroup)
517 m_LastGroup = INVALID_GROUP_ID;
518 m_FirstGroup = INVALID_GROUP_ID;
519 } else if (id == m_FirstGroup) {
520 m_FirstGroup = pGroup->next_grp;
521 pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
522 pOther->prev_grp = INVALID_GROUP_ID;
523 } else if (id == m_LastGroup) {
524 m_LastGroup = pGroup->prev_grp;
525 pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
526 pOther->next_grp = INVALID_GROUP_ID;
528 pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
529 pOther->next_grp = pGroup->next_grp;
530 pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
531 pOther->prev_grp = pGroup->prev_grp;
534 /* Free any used memory to be safe */
535 if (pGroup->pCmdGrpTable)
537 sm_trie_destroy(pGroup->pCmdGrpTable);
538 pGroup->pCmdGrpTable = NULL;
540 if (pGroup->pCmdTable)
542 sm_trie_destroy(pGroup->pCmdTable);
543 pGroup->pCmdTable = NULL;
546 /* Link into the free list */
547 pGroup->magic = GRP_MAGIC_UNSET;
548 pGroup->next_grp = m_FreeGroupList;
549 m_FreeGroupList = id;
551 /* :TODO: remove this group from any users */
554 void AdminCache::InvalidateGroupCache()
556 /* Nuke the free list */
557 m_FreeGroupList = -1;
559 /* Nuke reverse lookups */
560 sm_trie_clear(m_pGroups);
562 /* Free memory on groups */
563 GroupId cur = m_FirstGroup;
565 while (cur != INVALID_GROUP_ID)
567 pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
568 assert(pGroup->magic == GRP_MAGIC_SET);
569 if (pGroup->pCmdGrpTable)
571 sm_trie_destroy(pGroup->pCmdGrpTable);
573 if (pGroup->pCmdTable)
575 sm_trie_destroy(pGroup->pCmdTable);
577 cur = pGroup->next_grp;
580 m_FirstGroup = INVALID_GROUP_ID;
581 m_LastGroup = INVALID_GROUP_ID;
583 /* :TODO: dump the admin cache */
585 /* Reset the memory table */
589 void AdminCache::AddAdminListener(IAdminListener *pListener)
591 m_hooks.push_back(pListener);
594 void AdminCache::RemoveAdminListener(IAdminListener *pListener)
596 m_hooks.remove(pListener);
599 void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
601 if (cache_flags & ADMIN_CACHE_OVERRIDES)
603 DumpCommandOverrideCache(Override_Command);
604 DumpCommandOverrideCache(Override_CommandGroup);
607 if ((cache_flags & ADMIN_CACHE_ADMINS) ||
608 (cache_flags & ADMIN_CACHE_GROUPS))
610 /* Make sure the flag is set */
611 cache_flags |= ADMIN_CACHE_ADMINS;
612 /* :TODO: Dump admin cache */
615 if (cache_flags & ADMIN_CACHE_GROUPS)
617 InvalidateGroupCache();
622 List<IAdminListener *>::iterator iter;
623 IAdminListener *pListener;
625 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
628 pListener->OnRebuildAdminCache(cache_flags);
630 m_pCacheFwd->PushCell(cache_flags);
631 m_pCacheFwd->Execute(&result);