|
Veteran Member
|

05-21-2011
, 20:03
Getting the entity list directly from any BSP file
|
#1
|
I've needed a way to get the entity list straight from a bsp file at runtime.
This is not beautified or anything, but what i've came up with in a hurry:
PHP Code:
#define READSIZE 4096
#define GET_LITTLE_ENDIAN_INT(%1,%2,%3)\ %2 |= %3[%1+3] & 0xFF;\ %2 <<= 8;\ %2 |= %3[%1+2] & 0xFF;\ %2 <<= 8;\ %2 |= %3[%1+1] & 0xFF;\ %2 <<= 8;\ %2 |= %3[%1] & 0xFF;
stock bool:JumpToEntityByClassname(Handle:hKV, const String:sClassName[]) { while (KvGotoNextKey(hKV, true)) { new String:sValue[255]; KvGetString(hKV, "classname", sValue, sizeof(sValue), "");
if(StrEqual(sValue, sClassName)) { return true; } }
return false; }
stock Handle:ExtractEntities(const String:sIn[]) { new String:sMap[PLATFORM_MAX_PATH]; Format(sMap, sizeof(sMap), "%s%s", sIn, StrContains(sMap, ".bsp", false) == -1 ? ".bsp" : "");
new String:sPath[PLATFORM_MAX_PATH]; Format(sPath, sizeof(sPath), "maps/%s", sMap);
if(!FileExists(sPath)) { LogError("Map \"%s\" does not exists", sMap); return INVALID_HANDLE; }
new String:sOutput[PLATFORM_MAX_PATH]; Format(sOutput, sizeof(sOutput), "%s.entities.txt", sPath);
if(!FileExists(sOutput)) { LogMessage("Grabbing entity list from %s", sMap); new Handle:hFile = OpenFile(sPath, "rb");
new String:sFormat[5]; ReadFileString(hFile, sFormat, sizeof(sFormat), 4);
new String:sVersion[5]; ReadFileString(hFile, sVersion, sizeof(sVersion), 4); new iVersion = 0; GET_LITTLE_ENDIAN_INT(0,iVersion,sVersion)
LogMessage("BSP-Format: %s", sFormat); if(!StrEqual(sFormat, "VBSP")) { LogError("Map %s is no Valve BSP File.", sMap); CloseHandle(hFile); return INVALID_HANDLE; } LogMessage("Version: %i", iVersion);
new iOffset, iLength, iVersionLump, iFourCC;
new String:sLump[17]; ReadFileString(hFile, sLump, sizeof(sLump), 16); ReadLump(sLump, iOffset, iLength, iVersionLump, iFourCC);
LogMessage("Found Entity Lump: offset %i, length %i", iOffset, iLength);
new Handle:hWFile = OpenFile(sOutput, "w");
new iNum = 0; for(new iPos = 0; iPos < iLength; iPos += READSIZE) { FileSeek(hFile, iOffset + iPos, SEEK_SET);
new String:sEntities[READSIZE+1 +READSIZE]; ReadFileString(hFile, sEntities, sizeof(sEntities), READSIZE);
new iProcessed = 0; new String:sReplacement[16];
new iResult = 0; while(iResult != -1) { Format(sReplacement, sizeof(sReplacement), "\"%i\"\n{", iNum);
iResult = ReplaceStringEx(sEntities[iProcessed], sizeof(sEntities), "{", sReplacement); iProcessed += iResult; if(iResult != -1)iNum++; }
WriteFileString(hWFile, sEntities, false); }
CloseHandle(hWFile); CloseHandle(hFile); }
new Handle:hKV = CreateKeyValues(""); FileToKeyValues(hKV, sOutput);
return hKV; }
stock ReadLump(const String:sLump[17], &iOffset, &iLength, &iVersion, &iFourCC) { GET_LITTLE_ENDIAN_INT(0,iOffset,sLump) GET_LITTLE_ENDIAN_INT(4,iLength,sLump) GET_LITTLE_ENDIAN_INT(8,iVersion,sLump) GET_LITTLE_ENDIAN_INT(12,iFourCC,sLump) }
This allows you to do something like this (as an example):
PHP Code:
#pragma semicolon 1 #include <sourcemod>
public OnPluginStart() { RegConsoleCmd("sm_getmapmode", Command_GetMapMode); }
public Action:Command_GetMapMode(client,args) { if(args != 1) { ReplyToCommand(client, "[Usage] sm_getmapmode <mapname>[.bsp]"); return Plugin_Handled; } else { new String:sBuffer[255]; GetCmdArg(1, sBuffer, sizeof(sBuffer));
new Handle:hKVEntities = ExtractEntities(sBuffer); if(hKVEntities == INVALID_HANDLE) { ReplyToCommand(client, "Map not found or wrong format"); return Plugin_Handled; }
new bool:bHasRedCapturePoints = false; while(JumpToEntityByClassname(hKVEntities, "team_control_point")) { new iTeam = KvGetNum(hKVEntities, "point_default_owner", 0); if(iTeam == 3)bHasRedCapturePoints = true; }
CloseHandle(hKVEntities);
ReplyToCommand(client, "%s is a %s mode map", sBuffer, bHasRedCapturePoints ? "Push" : "Attack/Defense"); }
return Plugin_Handled; }
resulting in:
PHP Code:
[SM] Plugin tExtractEntitiesFromBSP reloaded successfully. sm_textract cp_dustbowl cp_dustbowl is a Attack/Defense mode map sm_textract cp_badlands cp_badlands is a Push mode map sm_textract qwerty L 05/22/2011 - 01:45:07: [tExtractEntitiesFromBSP.smx] Map "qwerty.bsp" does not exists Map not found or wrong format sm_textract cp_granary L 05/22/2011 - 01:45:20: [tExtractEntitiesFromBSP.smx] Grabbing entity list from cp_granary.bsp L 05/22/2011 - 01:45:20: [tExtractEntitiesFromBSP.smx] BSP-Format: VBSP L 05/22/2011 - 01:45:20: [tExtractEntitiesFromBSP.smx] Version: 20 L 05/22/2011 - 01:45:20: [tExtractEntitiesFromBSP.smx] Found Entity Lump: offset 31278296, length 225412 cp_granary is a Push mode map
btw, the entity list will only be grabbed if it has not been already. The ExtractEntities stock will create a <mapname>.bsp.entities.txt in your maps folder. This should be changed to a different and dedicated folder or sth.
more information about the bsp structure can be found here.
__________________
einmal mit profis arbeiten. einmal.
Last edited by Thrawn2; 05-21-2011 at 20:08.
|
|