summaryrefslogtreecommitdiff
path: root/hammer/shell.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/shell.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/shell.cpp')
-rw-r--r--hammer/shell.cpp547
1 files changed, 547 insertions, 0 deletions
diff --git a/hammer/shell.cpp b/hammer/shell.cpp
new file mode 100644
index 0000000..239efe5
--- /dev/null
+++ b/hammer/shell.cpp
@@ -0,0 +1,547 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Handles parsing and routing of shell commands to their handlers.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "stdafx.h"
+#include "MainFrm.h"
+#include "MapDoc.h"
+#include "MapEntity.h"
+#include "Shell.h"
+#include "hammer.h"
+#include "filesystem_helpers.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Shell command handler function pointer.
+//-----------------------------------------------------------------------------
+typedef bool (CShell::*ShellHandlerFunc_t)(const char *pszCommand, const char *pszArguments);
+
+
+//-----------------------------------------------------------------------------
+// Dispatch table entry.
+//-----------------------------------------------------------------------------
+struct ShellDispatchTable_t
+{
+ const char *pszCommand; // Name of command associated with this entry.
+ ShellHandlerFunc_t pfnHandler; // Function handler for the command.
+};
+
+
+//-----------------------------------------------------------------------------
+// Dispatch table for shell commands.
+//-----------------------------------------------------------------------------
+ShellDispatchTable_t CShell::m_DispatchTable[] =
+{
+ { "session_begin", &CShell::BeginSession },
+ { "session_end", &CShell::EndSession },
+ { "entity_create", &CShell::EntityCreate },
+ { "entity_delete", &CShell::EntityDelete },
+ { "entity_set_keyvalue", &CShell::EntitySetKeyValue },
+ { "entity_rotate_incremental", &CShell::EntityRotateIncremental },
+
+ { "map_check_version", &CShell::CheckMapVersion },
+ { "node_create", &CShell::NodeCreate },
+ { "node_delete", &CShell::NodeDelete },
+ { "nodelink_create", &CShell::NodeLinkCreate },
+ { "nodelink_delete", &CShell::NodeLinkDelete },
+ { "release_video_memory", &CShell::ReleaseVideoMemory },
+ { "grab_video_memory", &CShell::GrabVideoMemory },
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+CShell::CShell(void)
+{
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor.
+//-----------------------------------------------------------------------------
+CShell::~CShell(void)
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initiates a shell editing session.
+// Input : pszCommand - Should be "session_begin".
+// pszArguments - Filename and file version in the engine.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::BeginSession(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && !m_pDoc->IsShellSessionActive())
+ {
+ if (DoVersionCheck(pszArguments))
+ {
+ m_pDoc->BeginShellSession();
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Verifies that the map begine edited in the engine is the same name
+// and version as the active document. This prevents problems with
+// editing out of sync versions of the map via the engine.
+// Input : pszCommand - Should be "map_check_version".
+// pszArguments - Filename and file version in the engine.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::CheckMapVersion(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ return(DoVersionCheck(pszArguments));
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Verifies that the map being edited in the engine is the same name
+// and version as the active document. This prevents problems with
+// editing out of sync versions of the map via the engine.
+// Input : pszCommand -
+// pszArguments -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::DoVersionCheck(const char *pszArguments)
+{
+ if (m_pDoc != NULL)
+ {
+ char szEngineMapPath[MAX_PATH];
+ int nEngineMapVersion;
+
+ if (sscanf(pszArguments, "%s %d", szEngineMapPath, &nEngineMapVersion) == 2)
+ {
+ char szEngineMapName[MAX_PATH];
+ _splitpath(szEngineMapPath, NULL, NULL, szEngineMapName, NULL);
+
+ char szDocName[MAX_PATH];
+ _splitpath(m_pDoc->GetPathName(), NULL, NULL, szDocName, NULL);
+
+ int nDocVersion = m_pDoc->GetDocVersion();
+
+ if (!stricmp(szDocName, szEngineMapName) && (nDocVersion == nEngineMapVersion))
+ {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Verifies that the map begine edited in the engine is the same name
+// and version as the active document. This prevents problems with
+// editing out of sync versions of the map via the engine.
+// Input : pszCommand - Should be "session_end".
+// pszArguments - Filename and file version in the engine.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::EndSession(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ m_pDoc->EndShellSession();
+ return(true);
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates an entity of a given class at a specified location.
+// Input : pszCommand - Should be "entity_create".
+// pszArguments - Class name of entity and x, y, z coordinate at which
+// to create it.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::EntityCreate(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ float x;
+ float y;
+ float z;
+ char szClassName[MAX_PATH];
+
+ if (sscanf(pszArguments, "%s %f %f %f", szClassName, &x, &y, &z) == 4)
+ {
+ bool bCreated = (m_pDoc->CreateEntity(szClassName, x, y, z) != NULL);
+ return(bCreated);
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes an entity by class name and origin.
+// Input : pszCommand - Should be "entity_delete".
+// pszArguments - Class name of entity and x, y, z coordinates.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::EntityDelete(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ float x;
+ float y;
+ float z;
+ char szClassName[MAX_PATH];
+
+ if (sscanf(pszArguments, "%s %f %f %f", szClassName, &x, &y, &z) == 4)
+ {
+ bool bDeleted = m_pDoc->DeleteEntity(szClassName, x, y, z);
+ return(bDeleted);
+ }
+ }
+
+ return(false);
+}
+
+static void RotateMapEntity( CMapEntity *pEntity, const QAngle &rotation )
+{
+ Vector origin;
+ pEntity->GetOrigin( origin );
+ QAngle hammerRotate;
+ hammerRotate.Init( rotation.z, -rotation.x, rotation.y );
+ pEntity->TransRotate( origin, hammerRotate );
+}
+
+bool CShell::EntityRotateIncremental(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ const int NUM_ROTATE_INCREMENTAL_ARGS = 7;
+ float x;
+ float y;
+ float z;
+ QAngle rotation;
+ char szArgs[NUM_ROTATE_INCREMENTAL_ARGS][512]; // classname, x, y, z, ax, ay, az
+ char token[1024];
+ const char *pBuffer = pszArguments;
+
+ int arg = 0;
+ while ( pBuffer && arg < NUM_ROTATE_INCREMENTAL_ARGS )
+ {
+ pBuffer = ParseFile( pBuffer, token, NULL );
+ if ( pBuffer )
+ {
+ Q_strncpy( szArgs[arg], token, ARRAYSIZE(szArgs[arg]) );
+ arg++;
+ }
+ }
+ if ( arg == NUM_ROTATE_INCREMENTAL_ARGS )
+ {
+ x = atof(szArgs[1]);
+ y = atof(szArgs[2]);
+ z = atof(szArgs[3]);
+ CMapEntity *pEntity = m_pDoc->FindEntity(szArgs[0], x, y, z);
+ if (pEntity != NULL)
+ {
+ rotation.x = atof(szArgs[4]);
+ rotation.y = atof(szArgs[5]);
+ rotation.z = atof(szArgs[6]);
+ RotateMapEntity( pEntity, rotation );
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a keyvalue on an entity, searching by classname & origin
+// Input : pszCommand - Should be "entity_delete".
+// pszArguments - Class name of entity and x, y, z coordinates.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::EntitySetKeyValue(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ const int NUM_KEY_VALUE_ARGS = 6;
+ float x;
+ float y;
+ float z;
+ char szArgs[NUM_KEY_VALUE_ARGS][512]; // classname, x, y, z, key, value
+ char token[1024];
+ const char *pBuffer = pszArguments;
+
+ int arg = 0;
+ while ( pBuffer && arg < NUM_KEY_VALUE_ARGS )
+ {
+ pBuffer = ParseFile( pBuffer, token, NULL );
+ if ( pBuffer )
+ {
+ Q_strncpy( szArgs[arg], token, ARRAYSIZE(szArgs[arg]) );
+ arg++;
+ }
+ }
+ if ( arg == NUM_KEY_VALUE_ARGS )
+ {
+ x = atof(szArgs[1]);
+ y = atof(szArgs[2]);
+ z = atof(szArgs[3]);
+ CMapEntity *pEntity = m_pDoc->FindEntity(szArgs[0], x, y, z);
+ if (pEntity != NULL)
+ {
+ if ( !Q_stricmp( szArgs[4], "origin" ) )
+ {
+ Vector origin;
+ sscanf(szArgs[5], "%f %f %f", &origin[0], &origin[1], &origin[2]);
+ Vector oldOrigin;
+ pEntity->GetOrigin( oldOrigin );
+ pEntity->TransMove(origin - oldOrigin);
+ }
+ else if ( pEntity->IsSolidClass() && !Q_stricmp( szArgs[4], "angles" ) )
+ {
+ QAngle angles;
+ sscanf(szArgs[5], "%f %f %f", &angles[0], &angles[1], &angles[2]);
+
+ // build a relative transform from the previous state to the current state
+ // NOTE: This only works once since solid classes destructively modify transform info (GetAngles always returns identity)
+ // NOTE: Use rotateIncremental instead!
+ QAngle oldAngles;
+ pEntity->GetAngles( oldAngles );
+ if ( oldAngles != angles )
+ {
+ QAngle xformAngles;
+ RotationDelta( oldAngles, angles, &xformAngles );
+ RotateMapEntity( pEntity, xformAngles );
+ }
+ }
+ else
+ {
+ pEntity->SetKeyValue( szArgs[4], szArgs[5] );
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a navigation node of a given class at a specified location.
+// Input : pszCommand - Should be "node_create".
+// pszArguments - Class name of node to create, ID to assign it, and
+// x, y, z coordinate at which to create the node.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::NodeCreate(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ float x;
+ float y;
+ float z;
+ int nID;
+ char szClassName[MAX_PATH];
+
+ if (sscanf(pszArguments, "%s %d %f %f %f", szClassName, &nID, &x, &y, &z) == 5)
+ {
+ m_pDoc->SetNextNodeID(nID);
+ m_pDoc->CreateEntity(szClassName, x, y, z);
+
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes a navigation node by ID.
+// Input : pszCommand - Should be "node_delete".
+// pszArguments - Unique node ID of node to delete.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::NodeDelete(const char *pszCommand, const char *pszArguments)
+{
+ bool bFound = false;
+
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ char szID[80];
+ if (sscanf(pszArguments, "%s", szID) == 1)
+ {
+ CMapEntityList Found;
+ if (m_pDoc->FindEntitiesByKeyValue(Found, "nodeid", szID, false))
+ {
+ FOR_EACH_OBJ( Found, pos )
+ {
+ CMapEntity *pEntity = Found.Element(pos);
+ m_pDoc->DeleteObject(pEntity);
+ bFound = true;
+ }
+ }
+ }
+ }
+
+ return(bFound);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a navigation node of a given class at a specified location.
+// Input : pszCommand - Should be "nodelink_create".
+// pszArguments - Node ids of start and end nodes, space delimited.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::NodeLinkCreate(const char *pszCommand, const char *pszArguments)
+{
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ char szIDStart[80];
+ char szIDEnd[80];
+
+ if (sscanf(pszArguments, "%s %s", szIDStart, szIDEnd) == 2)
+ {
+ //
+ // It doesn't matter where we place it because it will move to the midpoint of the
+ // start and end entities.
+ //
+ CMapEntity *pEntity = m_pDoc->CreateEntity("info_node_link", 0, 0, 0);
+ if (pEntity != NULL)
+ {
+ pEntity->SetKeyValue("startnode", szIDStart);
+ pEntity->SetKeyValue("endnode", szIDEnd);
+
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes a navigation node by class name and ID.
+// Input : pszCommand - Should be "node_delete".
+// pszArguments - Class name of node and unique node ID.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::NodeLinkDelete(const char *pszCommand, const char *pszArguments)
+{
+ bool bFound = false;
+
+ if ((m_pDoc != NULL) && m_pDoc->IsShellSessionActive())
+ {
+ char szIDStart[80];
+ char szIDEnd[80];
+
+ if (sscanf(pszArguments, "%s %s", szIDStart, szIDEnd) == 2)
+ {
+ //
+ // Look for info_node_link entities with the appropriate start/end keys.
+ //
+ CMapEntityList Found;
+ if (m_pDoc->FindEntitiesByClassName(Found, "info_node_link", false))
+ {
+ FOR_EACH_OBJ( Found, pos )
+ {
+ CMapEntity *pEntity = Found.Element(pos);
+
+ const char *pszNode1 = pEntity->GetKeyValue("startnode");
+ const char *pszNode2 = pEntity->GetKeyValue("endnode");
+ if ((pszNode1 != NULL) && (pszNode2 != NULL))
+ {
+ if (((!stricmp(pszNode1, szIDStart)) && (!stricmp(pszNode2, szIDEnd))) ||
+ ((!stricmp(pszNode1, szIDEnd)) && (!stricmp(pszNode2, szIDStart))))
+ {
+ m_pDoc->DeleteObject(pEntity);
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return(bFound);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Releases all video memory
+// Input : pszCommand - Should be "release_video_memory".
+// pszArguments - None.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::ReleaseVideoMemory(const char *pszCommand, const char *pszArguments)
+{
+ APP()->ReleaseVideoMemory();
+ APP()->SuppressVideoAllocation(true);
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Indicates it's safe to grab video memory
+// Input : pszCommand - Should be "grab_video_memory".
+// pszArguments - None.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::GrabVideoMemory(const char *pszCommand, const char *pszArguments)
+{
+ APP()->SuppressVideoAllocation(false);
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Attempts to fund a command in the dispatch table, then routes the
+// command and its arguments to the handler, if found.
+// Input : pszCommand - Command and arguments.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CShell::RunCommand(const char *pszCommand)
+{
+ for (int nCommand = 0; nCommand < sizeof(m_DispatchTable) / sizeof(m_DispatchTable[0]); nCommand++)
+ {
+ int nCommandLen = strlen(m_DispatchTable[nCommand].pszCommand);
+
+ if (!_strnicmp(pszCommand, m_DispatchTable[nCommand].pszCommand, nCommandLen))
+ {
+ return((this->*m_DispatchTable[nCommand].pfnHandler)(m_DispatchTable[nCommand].pszCommand, &pszCommand[nCommandLen]));
+ }
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the map document that this shell should operate on.
+// Input : pDoc - Pointer to document.
+//-----------------------------------------------------------------------------
+void CShell::SetDocument(CMapDoc *pDoc)
+{
+ m_pDoc = pDoc;
+}
+