core/AdminCache.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jan 25 22:36:38 2007 +0000 (2007-01-25)
changeset 370 d3a484f98f6d
parent 345 df0b05b4f50d
child 404 673ccd0935ba
permissions -rw-r--r--
added license headers
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     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
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <string.h>
    15 #include <assert.h>
    16 #include "AdminCache.h"
    17 #include "ShareSys.h"
    18 #include "ForwardSys.h"
    19 
    20 AdminCache g_Admins;
    21 
    22 AdminCache::AdminCache()
    23 {
    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();
    30 	m_pCacheFwd = NULL;
    31 }
    32 
    33 AdminCache::~AdminCache()
    34 {
    35 	if (m_pCmdGrpOverrides)
    36 	{
    37 		sm_trie_destroy(m_pCmdGrpOverrides);
    38 	}
    39 
    40 	if (m_pCmdOverrides)
    41 	{
    42 		sm_trie_destroy(m_pCmdOverrides);
    43 	}
    44 
    45 	InvalidateGroupCache();
    46 
    47 	if (m_pGroups)
    48 	{
    49 		sm_trie_destroy(m_pGroups);
    50 	}
    51 
    52 	delete m_pStrings;
    53 }
    54 
    55 void AdminCache::OnSourceModAllInitialized()
    56 {
    57 	m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
    58 	g_ShareSys.AddInterface(NULL, this);
    59 }
    60 
    61 void AdminCache::OnSourceModShutdown()
    62 {
    63 	g_Forwards.ReleaseForward(m_pCacheFwd);
    64 	m_pCacheFwd = NULL;
    65 }
    66 
    67 void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag)
    68 {
    69 	if (type == Override_Command)
    70 	{
    71 		_AddCommandOverride(cmd, flag);
    72 	} else if (type == Override_CommandGroup) {
    73 		_AddCommandGroupOverride(cmd, flag);
    74 	}
    75 }
    76 
    77 bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag)
    78 {
    79 	if (type == Override_Command)
    80 	{
    81 		return _GetCommandOverride(cmd, pFlag);
    82 	} else if (type == Override_CommandGroup) {
    83 		return _GetCommandGroupOverride(cmd, pFlag);
    84 	}
    85 
    86 	return false;
    87 }
    88 
    89 void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
    90 {
    91 	if (type == Override_Command)
    92 	{
    93 		return _UnsetCommandOverride(cmd);
    94 	} else if (type == Override_CommandGroup) {
    95 		return _UnsetCommandGroupOverride(cmd);
    96 	}
    97 }
    98 
    99 void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag)
   100 {
   101 	if (!m_pCmdGrpOverrides)
   102 	{
   103 		m_pCmdGrpOverrides = sm_trie_create();
   104 	}
   105 
   106 	/* :TODO: Notify command system */
   107 
   108 	sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag);
   109 }
   110 
   111 void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag)
   112 {
   113 	if (!m_pCmdOverrides)
   114 	{
   115 		m_pCmdOverrides = sm_trie_create();
   116 	}
   117 
   118 	/* :TODO: Notify command system */
   119 
   120 	sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag);
   121 }
   122 
   123 bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag)
   124 {
   125 	if (!m_pCmdGrpOverrides)
   126 	{
   127 		return false;
   128 	}
   129 
   130 	if (!pFlag)
   131 	{
   132 		return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL);
   133 	} else {
   134 		void *object;
   135 		bool ret;
   136 		if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object))
   137 		{
   138 			*pFlag = (AdminFlag)(int)object;
   139 		}
   140 		return ret;
   141 	}
   142 }
   143 
   144 bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag)
   145 {
   146 	if (!m_pCmdOverrides)
   147 	{
   148 		return false;
   149 	}
   150 
   151 	if (!pFlag)
   152 	{
   153 		return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL);
   154 	} else {
   155 		void *object;
   156 		bool ret;
   157 		if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object))
   158 		{
   159 			*pFlag = (AdminFlag)(int)object;
   160 		}
   161 		return ret;
   162 	}
   163 }
   164 
   165 void AdminCache::_UnsetCommandGroupOverride(const char *group)
   166 {
   167 	if (!m_pCmdGrpOverrides)
   168 	{
   169 		return;
   170 	}
   171 
   172 	/* :TODO: Notify command system */
   173 
   174 	sm_trie_delete(m_pCmdGrpOverrides, group);
   175 }
   176 
   177 void AdminCache::_UnsetCommandOverride(const char *cmd)
   178 {
   179 	if (!m_pCmdOverrides)
   180 	{
   181 		return;
   182 	}
   183 
   184 	/* :TODO: Notify command system */
   185 
   186 	sm_trie_delete(m_pCmdOverrides, cmd);
   187 }
   188 
   189 void AdminCache::DumpCommandOverrideCache(OverrideType type)
   190 {
   191 	if (type == Override_Command && m_pCmdOverrides)
   192 	{
   193 		sm_trie_clear(m_pCmdOverrides);
   194 	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
   195 		sm_trie_clear(m_pCmdGrpOverrides);
   196 	}
   197 }
   198 
   199 GroupId AdminCache::AddGroup(const char *group_name)
   200 {
   201 	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
   202 	{
   203 		return INVALID_GROUP_ID;
   204 	}
   205 
   206 	GroupId id;
   207 	AdminGroup *pGroup;
   208 	if (m_FreeGroupList != INVALID_GROUP_ID)
   209 	{
   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;
   214 	} else {
   215 		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
   216 	}
   217 
   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);
   227 
   228 	if (m_FirstGroup == INVALID_GROUP_ID)
   229 	{
   230 		m_FirstGroup = id;
   231 		m_LastGroup = id;
   232 		pGroup->prev_grp = INVALID_GROUP_ID;
   233 	} else {
   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;
   238 		m_LastGroup = id;
   239 	}
   240 
   241 	sm_trie_insert(m_pGroups, group_name, (void *)id);
   242 
   243 	return id;
   244 }
   245 
   246 GroupId AdminCache::FindGroupByName(const char *group_name)
   247 {
   248 	void *object;
   249 
   250 	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
   251 	{
   252 		return INVALID_GROUP_ID;
   253 	}
   254 
   255 	GroupId id = (GroupId)object;
   256 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   257 
   258 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   259 	{
   260 		return INVALID_GROUP_ID;
   261 	}
   262 
   263 	return id;
   264 }
   265 
   266 void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
   267 {
   268 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   269 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   270 	{
   271 		return;
   272 	}
   273 
   274 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   275 	{
   276 		return;
   277 	}
   278 
   279 	pGroup->addflags[flag] = enabled;
   280 }
   281 
   282 bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
   283 {
   284 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   285 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   286 	{
   287 		return false;
   288 	}
   289 
   290 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   291 	{
   292 		return false;
   293 	}
   294 
   295 	return pGroup->addflags[flag];
   296 }
   297 
   298 unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total)
   299 {
   300 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   301 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   302 	{
   303 		return 0;
   304 	}
   305 
   306 	unsigned int i;
   307 
   308 	for (i = Admin_None;
   309 		 i < AdminFlags_TOTAL && i < total;
   310 		 i++)
   311 	{
   312 		flags[i] = pGroup->addflags[i];
   313 	}
   314 
   315 	return i;
   316 }
   317 
   318 void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
   319 {
   320 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   321 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   322 	{
   323 		return;
   324 	}
   325 
   326 	if (type == Immunity_Default)
   327 	{
   328 		pGroup->immune_default = enabled;
   329 	} else if (type == Immunity_Global) {
   330 		pGroup->immune_global = enabled;
   331 	} 
   332 }
   333 
   334 bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
   335 {
   336 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   337 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   338 	{
   339 		return false;
   340 	}
   341 
   342 	if (type == Immunity_Default)
   343 	{
   344 		return pGroup->immune_default;
   345 	} else if (type == Immunity_Global) {
   346 		return pGroup->immune_global;
   347 	}
   348 
   349 	return false;
   350 }
   351 
   352 void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
   353 {
   354 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   355 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   356 	{
   357 		return;
   358 	}
   359 
   360 	AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
   361 	if (!pOther || pOther->magic != GRP_MAGIC_SET)
   362 	{
   363 		return;
   364 	}
   365 
   366 	/* We always need to resize the immunity table */
   367 	int *table, tblidx;
   368 	if (pOther->immune_table == -1)
   369 	{
   370 		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
   371 		table[0] = 0;
   372 	} else {
   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++)
   379 		{
   380 			table[i] = old_table[i];
   381 		}
   382 	}
   383 
   384 	/* Assign */
   385 	pOther->immune_table = tblidx;
   386 
   387 	/* Add to the array */
   388 	table[0]++;
   389 	table[table[0]] = other_id;
   390 }
   391 
   392 unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
   393 {
   394 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   395 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   396 	{
   397 		return 0;
   398 	}
   399 
   400 	if (pGroup->immune_table == -1)
   401 	{
   402 		return 0;
   403 	}
   404 
   405 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   406 
   407 	return table[0];
   408 }
   409 
   410 GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
   411 {
   412 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   413 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   414 	{
   415 		return INVALID_GROUP_ID;
   416 	}
   417 
   418 	if (pGroup->immune_table == -1)
   419 	{
   420 		return INVALID_GROUP_ID;
   421 	}
   422 
   423 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   424 	if (number >= (unsigned int)table[0])
   425 	{
   426 		return INVALID_GROUP_ID;
   427 	}
   428 
   429 	return table[1 + number];
   430 }
   431 
   432 void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
   433 {
   434 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   435 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   436 	{
   437 		return;
   438 	}
   439 
   440 	Trie *pTrie = NULL;
   441 	if (type == Override_Command)
   442 	{
   443 		if (pGroup->pCmdTable == NULL)
   444 		{
   445 			pGroup->pCmdTable = sm_trie_create();
   446 		}
   447 		pTrie = pGroup->pCmdTable;
   448 	} else if (type == Override_CommandGroup) {
   449 		if (pGroup->pCmdGrpTable == NULL)
   450 		{
   451 			pGroup->pCmdGrpTable = sm_trie_create();
   452 		}
   453 		pTrie = pGroup->pCmdGrpTable;
   454 	} else {
   455 		return;
   456 	}
   457 
   458 	sm_trie_insert(pTrie, name, (void *)(int)rule);
   459 }
   460 
   461 bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
   462 {
   463 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   464 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   465 	{
   466 		return false;
   467 	}
   468 
   469 	Trie *pTrie = NULL;
   470 	if (type == Override_Command)
   471 	{
   472 		if (pGroup->pCmdTable == NULL)
   473 		{
   474 			return false;
   475 		}
   476 		pTrie = pGroup->pCmdTable;
   477 	} else if (type == Override_CommandGroup) {
   478 		if (pGroup->pCmdGrpTable == NULL)
   479 		{
   480 			return false;
   481 		}
   482 		pTrie = pGroup->pCmdGrpTable;
   483 	} else {
   484 		return false;
   485 	}
   486 
   487 	void *object;
   488 	if (!sm_trie_retrieve(pTrie, name, &object))
   489 	{
   490 		return false;
   491 	}
   492 
   493 	if (pRule)
   494 	{
   495 		*pRule = (OverrideRule)(int)object;
   496 	}
   497 	
   498 	return true;
   499 }
   500 
   501 void AdminCache::InvalidateGroup(GroupId id)
   502 {
   503 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   504 	AdminGroup *pOther;
   505 
   506 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   507 	{
   508 		return;
   509 	}
   510 
   511 	const char *str = m_pStrings->GetString(pGroup->nameidx);
   512 	sm_trie_delete(m_pGroups, str);
   513 
   514 	/* Unlink from the live dbllink list */
   515 	if (id == m_FirstGroup && id == m_LastGroup)
   516 	{
   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;
   527 	} else {
   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;
   532 	}
   533 
   534 	/* Free any used memory to be safe */
   535 	if (pGroup->pCmdGrpTable)
   536 	{
   537 		sm_trie_destroy(pGroup->pCmdGrpTable);
   538 		pGroup->pCmdGrpTable = NULL;
   539 	}
   540 	if (pGroup->pCmdTable)
   541 	{
   542 		sm_trie_destroy(pGroup->pCmdTable);
   543 		pGroup->pCmdTable = NULL;
   544 	}
   545 
   546 	/* Link into the free list */
   547 	pGroup->magic = GRP_MAGIC_UNSET;
   548 	pGroup->next_grp = m_FreeGroupList;
   549 	m_FreeGroupList = id;
   550 
   551 	/* :TODO: remove this group from any users */
   552 }
   553 
   554 void AdminCache::InvalidateGroupCache()
   555 {
   556 	/* Nuke the free list */
   557 	m_FreeGroupList = -1;
   558 
   559 	/* Nuke reverse lookups */
   560 	sm_trie_clear(m_pGroups);
   561 
   562 	/* Free memory on groups */
   563 	GroupId cur = m_FirstGroup;
   564 	AdminGroup *pGroup;
   565 	while (cur != INVALID_GROUP_ID)
   566 	{
   567 		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
   568 		assert(pGroup->magic == GRP_MAGIC_SET);
   569 		if (pGroup->pCmdGrpTable)
   570 		{
   571 			sm_trie_destroy(pGroup->pCmdGrpTable);
   572 		}
   573 		if (pGroup->pCmdTable)
   574 		{
   575 			sm_trie_destroy(pGroup->pCmdTable);
   576 		}
   577 		cur = pGroup->next_grp;
   578 	}
   579 
   580 	m_FirstGroup = INVALID_GROUP_ID;
   581 	m_LastGroup = INVALID_GROUP_ID;
   582 
   583 	/* :TODO: dump the admin cache */
   584 
   585 	/* Reset the memory table */
   586 	m_pMemory->Reset();
   587 }
   588 
   589 void AdminCache::AddAdminListener(IAdminListener *pListener)
   590 {
   591 	m_hooks.push_back(pListener);
   592 }
   593 
   594 void AdminCache::RemoveAdminListener(IAdminListener *pListener)
   595 {
   596 	m_hooks.remove(pListener);
   597 }
   598 
   599 void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
   600 {
   601 	if (cache_flags & ADMIN_CACHE_OVERRIDES)
   602 	{
   603 		DumpCommandOverrideCache(Override_Command);
   604 		DumpCommandOverrideCache(Override_CommandGroup);
   605 	}
   606 
   607 	if ((cache_flags & ADMIN_CACHE_ADMINS) ||
   608 		(cache_flags & ADMIN_CACHE_GROUPS))
   609 	{
   610 		/* Make sure the flag is set */
   611 		cache_flags |= ADMIN_CACHE_ADMINS;
   612 		/* :TODO: Dump admin cache */
   613 	}
   614 
   615 	if (cache_flags & ADMIN_CACHE_GROUPS)
   616 	{
   617 		InvalidateGroupCache();
   618 	}
   619 
   620 	if (rebuild)
   621 	{
   622 		List<IAdminListener *>::iterator iter;
   623 		IAdminListener *pListener;
   624 		cell_t result;
   625 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   626 		{
   627 			pListener = (*iter);
   628 			pListener->OnRebuildAdminCache(cache_flags);
   629 		}
   630 		m_pCacheFwd->PushCell(cache_flags);
   631 		m_pCacheFwd->Execute(&result);
   632 	}
   633 }