368 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * vim: set ts=4 :
 | |
|  * =============================================================================
 | |
|  * Entity Lump Manager
 | |
|  * Copyright (C) 2021-2022 AlliedModders LLC.  All rights reserved.
 | |
|  * =============================================================================
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it under
 | |
|  * the terms of the GNU General Public License, version 3.0, as published by the
 | |
|  * Free Software Foundation.
 | |
|  * 
 | |
|  * This program is distributed in the hope that it will be useful, but WITHOUT
 | |
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | |
|  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | |
|  * details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License along with
 | |
|  * this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * As a special exception, AlliedModders LLC gives you permission to link the
 | |
|  * code of this program (as well as its derivative works) to "Half-Life 2," the
 | |
|  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
 | |
|  * by the Valve Corporation.  You must obey the GNU General Public License in
 | |
|  * all respects for all other code used.  Additionally, AlliedModders LLC grants
 | |
|  * this exception to all derivative works.  AlliedModders LLC defines further
 | |
|  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
 | |
|  * or <http://www.sourcemod.net/license.php>.
 | |
|  *
 | |
|  * Version: $Id$
 | |
|  */
 | |
| 
 | |
| #include "HandleSys.h"
 | |
| #include "common_logic.h"
 | |
| 
 | |
| #include "LumpManager.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| HandleType_t g_EntityLumpEntryType;
 | |
| 
 | |
| std::string g_strMapEntities;
 | |
| bool g_bLumpAvailableForWriting = false;
 | |
| 
 | |
| static EntityLumpManager s_LumpManager;
 | |
| EntityLumpManager *lumpmanager = &s_LumpManager;
 | |
| 
 | |
| class LumpManagerNatives :
 | |
| 	public IHandleTypeDispatch,
 | |
| 	public SMGlobalClass
 | |
| {
 | |
| public: //SMGlobalClass
 | |
| 	void OnSourceModAllInitialized()
 | |
| 	{
 | |
| 		g_EntityLumpEntryType = handlesys->CreateType("EntityLumpEntry", this, 0, NULL, NULL, g_pCoreIdent, NULL);
 | |
| 	}
 | |
| 	void OnSourceModShutdown()
 | |
| 	{
 | |
| 		handlesys->RemoveType(g_EntityLumpEntryType, g_pCoreIdent);
 | |
| 	}
 | |
| public: //IHandleTypeDispatch
 | |
| 	void OnHandleDestroy(HandleType_t type, void* object)
 | |
| 	{
 | |
| 		if (type == g_EntityLumpEntryType)
 | |
| 		{
 | |
| 			delete reinterpret_cast<std::weak_ptr<EntityLumpEntry>*>(object);
 | |
| 		}
 | |
| 	}
 | |
| };
 | |
| 
 | |
| static LumpManagerNatives s_LumpManagerNatives;
 | |
| 
 | |
| cell_t sm_LumpManagerGet(IPluginContext *pContext, const cell_t *params) {
 | |
| 	int index = params[1];
 | |
| 	if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* pReference = new std::weak_ptr<EntityLumpEntry>;
 | |
| 	*pReference = lumpmanager->Get(index);
 | |
| 	
 | |
| 	return handlesys->CreateHandle(g_EntityLumpEntryType, pReference,
 | |
| 			pContext->GetIdentity(), g_pCoreIdent, NULL);
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpManagerErase(IPluginContext *pContext, const cell_t *params) {
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Erase() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	int index = params[1];
 | |
| 	if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	lumpmanager->Erase(index);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpManagerInsert(IPluginContext *pContext, const cell_t *params) {
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Insert() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	int index = params[1];
 | |
| 	if (index < 0 || index > static_cast<int>(lumpmanager->Length())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	lumpmanager->Insert(index);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpManagerAppend(IPluginContext *pContext, const cell_t *params) {
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLump.Append() outside of OnMapInit");
 | |
| 	}
 | |
| 	return lumpmanager->Append();
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpManagerLength(IPluginContext *pContext, const cell_t *params) {
 | |
| 	return lumpmanager->Length();
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryGet(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	int index = params[2];
 | |
| 	if (index < 0 || index >= static_cast<int>(entry->size())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	const auto& pair = (*entry)[index];
 | |
| 	
 | |
| 	size_t nBytes;
 | |
| 	pContext->StringToLocalUTF8(params[3], params[4], pair.first.c_str(), &nBytes);
 | |
| 	pContext->StringToLocalUTF8(params[5], params[6], pair.second.c_str(), &nBytes);
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryUpdate(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Update() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	int index = params[2];
 | |
| 	if (index < 0 || index >= static_cast<int>(entry->size())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	char *key, *value;
 | |
| 	pContext->LocalToStringNULL(params[3], &key);
 | |
| 	pContext->LocalToStringNULL(params[4], &value);
 | |
| 	
 | |
| 	auto& pair = (*entry)[index];
 | |
| 	if (key != nullptr) {
 | |
| 		pair.first = key;
 | |
| 	}
 | |
| 	if (value != nullptr) {
 | |
| 		pair.second = value;
 | |
| 	}
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryInsert(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Insert() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	int index = params[2];
 | |
| 	if (index < 0 || index > static_cast<int>(entry->size())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	char *key, *value;
 | |
| 	pContext->LocalToString(params[3], &key);
 | |
| 	pContext->LocalToString(params[4], &value);
 | |
| 	
 | |
| 	entry->emplace(entry->begin() + index, key, value);
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryErase(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Erase() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	int index = params[2];
 | |
| 	if (index < 0 || index >= static_cast<int>(entry->size())) {
 | |
| 		return pContext->ThrowNativeError("Invalid index %d", index);
 | |
| 	}
 | |
| 	
 | |
| 	entry->erase(entry->begin() + index);
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryAppend(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	if (!g_bLumpAvailableForWriting) {
 | |
| 		return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Append() outside of OnMapInit");
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	char *key, *value;
 | |
| 	pContext->LocalToString(params[2], &key);
 | |
| 	pContext->LocalToString(params[3], &value);
 | |
| 	
 | |
| 	entry->emplace_back(key, value);
 | |
| 	
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryFindKey(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	// start from the index after the current one
 | |
| 	int start = params[3] + 1;
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	
 | |
| 	if (start < 0 || start >= static_cast<int>(entry->size())) {
 | |
| 		return -1;
 | |
| 	}
 | |
| 	
 | |
| 	char *key;
 | |
| 	pContext->LocalToString(params[2], &key);
 | |
| 	
 | |
| 	auto matches_key = [&key](std::pair<std::string,std::string> pair) {
 | |
| 		return pair.first == key;
 | |
| 	};
 | |
| 	
 | |
| 	auto result = std::find_if(entry->begin() + start, entry->end(), matches_key);
 | |
| 	
 | |
| 	if (result == entry->end()) {
 | |
| 		return -1;
 | |
| 	}
 | |
| 	return std::distance(entry->begin(), result);
 | |
| }
 | |
| 
 | |
| cell_t sm_LumpEntryLength(IPluginContext *pContext, const cell_t *params) {
 | |
| 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
 | |
| 	HandleError err;
 | |
| 	
 | |
| 	Handle_t hndl = static_cast<Handle_t>(params[1]);
 | |
| 	
 | |
| 	std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
 | |
| 	if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
 | |
| 	}
 | |
| 	
 | |
| 	if (entryref->expired()) {
 | |
| 		return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
 | |
| 	}
 | |
| 	
 | |
| 	auto entry = entryref->lock();
 | |
| 	return entry->size();
 | |
| }
 | |
| 
 | |
| REGISTER_NATIVES(entityLumpNatives)
 | |
| {
 | |
| 	{ "EntityLump.Get", sm_LumpManagerGet },
 | |
| 	{ "EntityLump.Erase", sm_LumpManagerErase },
 | |
| 	{ "EntityLump.Insert", sm_LumpManagerInsert },
 | |
| 	{ "EntityLump.Append", sm_LumpManagerAppend },
 | |
| 	{ "EntityLump.Length", sm_LumpManagerLength },
 | |
| 	
 | |
| 	{ "EntityLumpEntry.Get", sm_LumpEntryGet },
 | |
| 	{ "EntityLumpEntry.Update", sm_LumpEntryUpdate },
 | |
| 	{ "EntityLumpEntry.Insert", sm_LumpEntryInsert },
 | |
| 	{ "EntityLumpEntry.Erase", sm_LumpEntryErase },
 | |
| 	{ "EntityLumpEntry.Append", sm_LumpEntryAppend },
 | |
| 	{ "EntityLumpEntry.FindKey", sm_LumpEntryFindKey },
 | |
| 	{ "EntityLumpEntry.Length.get", sm_LumpEntryLength },
 | |
| 	
 | |
| 	{NULL, NULL}
 | |
| };
 |