diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vmf_tweak | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/vmf_tweak')
| -rw-r--r-- | utils/vmf_tweak/stdafx.cpp | 15 | ||||
| -rw-r--r-- | utils/vmf_tweak/stdafx.h | 29 | ||||
| -rw-r--r-- | utils/vmf_tweak/vmf_tweak.cpp | 540 | ||||
| -rw-r--r-- | utils/vmf_tweak/vmf_tweak.vpc | 47 |
4 files changed, 631 insertions, 0 deletions
diff --git a/utils/vmf_tweak/stdafx.cpp b/utils/vmf_tweak/stdafx.cpp new file mode 100644 index 0000000..d9aff89 --- /dev/null +++ b/utils/vmf_tweak/stdafx.cpp @@ -0,0 +1,15 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// stdafx.cpp : source file that includes just the standard includes +// vmf_tweak.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/utils/vmf_tweak/stdafx.h b/utils/vmf_tweak/stdafx.h new file mode 100644 index 0000000..16ffef2 --- /dev/null +++ b/utils/vmf_tweak/stdafx.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__9C5E2B7D_643D_4915_9379_C2FE14AF0A52__INCLUDED_) +#define AFX_STDAFX_H__9C5E2B7D_643D_4915_9379_C2FE14AF0A52__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include <stdio.h> + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__9C5E2B7D_643D_4915_9379_C2FE14AF0A52__INCLUDED_) diff --git a/utils/vmf_tweak/vmf_tweak.cpp b/utils/vmf_tweak/vmf_tweak.cpp new file mode 100644 index 0000000..d133d9e --- /dev/null +++ b/utils/vmf_tweak/vmf_tweak.cpp @@ -0,0 +1,540 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// vmf_tweak.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "chunkfile.h" +#include "utllinkedlist.h" +#include <stdlib.h> +#include "tier1/strtools.h" +#include "tier0/icommandline.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlbuffer.h" +#include "tier1/KeyValues.h" +#include "filesystem.h" +#include "FileSystem_Tools.h" +#include "cmdlib.h" + +#include <windows.h> + +char const *g_pInFilename = NULL; + +char *CopyString( char const *pStr ); + +unsigned long g_CurLoadOrder = 0; + + +//----------------------------------------------------------------------------- +// default spec function +//----------------------------------------------------------------------------- +SpewRetval_t VMFTweakSpewFunc( SpewType_t spewType, char const *pMsg ) +{ + OutputDebugString( pMsg ); + printf( pMsg ); + switch( spewType ) + { + case SPEW_MESSAGE: + case SPEW_WARNING: + case SPEW_LOG: + return SPEW_CONTINUE; + + case SPEW_ASSERT: + case SPEW_ERROR: + default: + return SPEW_DEBUGGER; + } +} + +void logprint( char const *logfile, const char *fmt, ... ) +{ + char string[ 8192 ]; + va_list va; + va_start( va, fmt ); + vsprintf( string, fmt, va ); + va_end( va ); + + FILE *fp = NULL; + static bool first = false; + if ( first ) + { + first = false; + fp = fopen( logfile, "wb" ); + } + else + { + fp = fopen( logfile, "ab" ); + } + if ( fp ) + { + char *p = string; + while ( *p ) + { + if ( *p == '\n' ) + { + fputc( '\r', fp ); + } + fputc( *p, fp ); + p++; + } + fclose( fp ); + } +} + + +class CChunkKeyBase +{ +public: + unsigned long m_LoadOrder; // Which order it appeared in the file. +}; + + +class CKeyValue : public CChunkKeyBase +{ +public: + void SetKey( const char *pStr ) + { + delete [] m_pKey; + m_pKey = CopyString( pStr ); + } + + void SetValue( const char *pStr ) + { + delete [] m_pValue; + m_pValue = CopyString( pStr ); + } + + +public: + char *m_pKey; + char *m_pValue; +}; + + +class CChunk : public CChunkKeyBase +{ +public: + // Returns true if the chunk has the specified key and if its value + // is equal to pValueStr (case-insensitive). + bool CompareKey( char const *pKeyName, char const *pValueStr ); + + // Look for a key by name. + CKeyValue* FindKey( char const *pKeyName ); + CKeyValue* FindKey( char const *pKeyName, const char *pValue ); + + CChunk* FindChunk( char const *pKeyName ); + + // Find a key by name, and replace any occurences with the new name. + void RenameKey( const char *szOldName, const char *szNewName ); + +public: + + char *m_pChunkName; + CUtlLinkedList<CKeyValue*, unsigned short> m_Keys; + CUtlLinkedList<CChunk*, unsigned short> m_Chunks; +}; + + +CChunk* ParseChunk( char const *pChunkName, bool bOnlyOne ); + + +CChunk *g_pCurChunk = 0; +CChunkFile *g_pChunkFile = 0; +int g_DotCounter = 0; + + + +// --------------------------------------------------------------------------------- // +// CChunk implementation. +// --------------------------------------------------------------------------------- // + +bool CChunk::CompareKey( char const *pKeyName, char const *pValueStr ) +{ + CKeyValue *pKey = FindKey( pKeyName ); + + if( pKey && stricmp( pKey->m_pValue, pValueStr ) == 0 ) + return true; + else + return false; +} + + +CKeyValue* CChunk::FindKey( char const *pKeyName ) +{ + for( unsigned short i=m_Keys.Head(); i != m_Keys.InvalidIndex(); i=m_Keys.Next(i) ) + { + CKeyValue *pKey = m_Keys[i]; + + if( stricmp( pKey->m_pKey, pKeyName ) == 0 ) + return pKey; + } + + return NULL; +} + + +CChunk* CChunk::FindChunk( char const *pChunkName ) +{ + for( unsigned short i=m_Chunks.Head(); i != m_Chunks.InvalidIndex(); i=m_Chunks.Next(i) ) + { + CChunk *pChunk = m_Chunks[i]; + + if( stricmp( pChunk->m_pChunkName, pChunkName ) == 0 ) + return pChunk; + } + + return NULL; +} + +CKeyValue* CChunk::FindKey( char const *pKeyName, const char *pValue ) +{ + for( unsigned short i=m_Keys.Head(); i != m_Keys.InvalidIndex(); i=m_Keys.Next(i) ) + { + CKeyValue *pKey = m_Keys[i]; + + if( stricmp( pKey->m_pKey, pKeyName ) == 0 && stricmp( pKey->m_pValue, pValue ) == 0 ) + return pKey; + } + + return NULL; +} + + +void CChunk::RenameKey( const char *szOldName, const char *szNewName ) +{ + if ((!szOldName) || (!szNewName)) + return; + + CKeyValue *pKey = FindKey( szOldName ); + if ( pKey ) + { + delete pKey->m_pKey; + pKey->m_pKey = CopyString( szNewName ); + } +} + + +// --------------------------------------------------------------------------------- // +// Util functions. +// --------------------------------------------------------------------------------- // +char *CopyString( char const *pStr ) +{ + char *pRet = new char[ strlen(pStr) + 1 ]; + strcpy( pRet, pStr ); + return pRet; +} + +ChunkFileResult_t MyDefaultHandler( CChunkFile *pFile, void *pData, char const *pChunkName ) +{ + CChunk *pChunk = ParseChunk( pChunkName, true ); + g_pCurChunk->m_Chunks.AddToTail( pChunk ); + return ChunkFile_Ok; +} + + +ChunkFileResult_t MyKeyHandler( const char *szKey, const char *szValue, void *pData ) +{ + // Add the key to the current chunk. + CKeyValue *pKey = new CKeyValue; + pKey->m_LoadOrder = g_CurLoadOrder++; + + pKey->m_pKey = CopyString( szKey ); + pKey->m_pValue = CopyString( szValue ); + + g_pCurChunk->m_Keys.AddToTail( pKey ); + return ChunkFile_Ok; +} + + +CChunk* ParseChunk( char const *pChunkName, bool bOnlyOne ) +{ + // Add the new chunk. + CChunk *pChunk = new CChunk; + pChunk->m_pChunkName = CopyString( pChunkName ); + pChunk->m_LoadOrder = g_CurLoadOrder++; + + // Parse it out.. + CChunk *pOldChunk = g_pCurChunk; + g_pCurChunk = pChunk; + + //if( ++g_DotCounter % 16 == 0 ) + // printf( "." ); + + while( 1 ) + { + if( g_pChunkFile->ReadChunk( MyKeyHandler ) != ChunkFile_Ok ) + break; + + if( bOnlyOne ) + break; + } + + g_pCurChunk = pOldChunk; + return pChunk; +} + + +CChunk* ReadChunkFile( char const *pInFilename ) +{ + CChunkFile chunkFile; + + if( chunkFile.Open( pInFilename, ChunkFile_Read ) != ChunkFile_Ok ) + { + printf( "Error opening chunk file %s for reading.\n", pInFilename ); + return NULL; + } + + printf( "Reading.." ); + chunkFile.SetDefaultChunkHandler( MyDefaultHandler, 0 ); + g_pChunkFile = &chunkFile; + + CChunk *pRet = ParseChunk( "***ROOT***", false ); + printf( "\n\n" ); + + return pRet; +} + +class CChunkHolder +{ +public: + static bool SortChunkFn( const CChunkHolder &a, const CChunkHolder &b ) + { + return a.m_LoadOrder < b.m_LoadOrder; + } + + unsigned long m_LoadOrder; + CKeyValue *m_pKey; + CChunk *m_pChunk; +}; + + +void WriteChunks_R( CChunkFile *pFile, CChunk *pChunk, bool bRoot ) +{ + if( !bRoot ) + { + pFile->BeginChunk( pChunk->m_pChunkName ); + } + + // Sort them.. + CUtlRBTree<CChunkHolder,int> sortedStuff( 0, 0, &CChunkHolder::SortChunkFn ); + + // Write keys. + for( unsigned short i=pChunk->m_Keys.Head(); i != pChunk->m_Keys.InvalidIndex(); i = pChunk->m_Keys.Next( i ) ) + { + CChunkHolder holder; + holder.m_pKey = pChunk->m_Keys[i]; + holder.m_LoadOrder = holder.m_pKey->m_LoadOrder; + holder.m_pChunk = NULL; + sortedStuff.Insert( holder ); + } + + // Write subchunks. + for( int i=pChunk->m_Chunks.Head(); i != pChunk->m_Chunks.InvalidIndex(); i = pChunk->m_Chunks.Next( i ) ) + { + CChunkHolder holder; + holder.m_pChunk = pChunk->m_Chunks[i]; + holder.m_LoadOrder = holder.m_pChunk->m_LoadOrder; + holder.m_pKey = NULL; + sortedStuff.Insert( holder ); + } + + // Write stuff in sorted order. + int i = sortedStuff.FirstInorder(); + if ( i != sortedStuff.InvalidIndex() ) + { + while ( 1 ) + { + CChunkHolder &h = sortedStuff[i]; + if ( h.m_pKey ) + { + pFile->WriteKeyValue( h.m_pKey->m_pKey, h.m_pKey->m_pValue ); + } + else + { + WriteChunks_R( pFile, h.m_pChunk, false ); + } + if ( i == sortedStuff.LastInorder() ) + break; + i = sortedStuff.NextInorder( i ); + } + } + + if( !bRoot ) + { + pFile->EndChunk(); + } +} + + +bool WriteChunkFile( char const *pOutFilename, CChunk *pRoot ) +{ + CChunkFile chunkFile; + + if( chunkFile.Open( pOutFilename, ChunkFile_Write ) != ChunkFile_Ok ) + { + printf( "Error opening chunk file %s for writing.\n", pOutFilename ); + return false; + } + + printf( "Writing.." ); + WriteChunks_R( &chunkFile, pRoot, true ); + printf( "\n\n" ); + + return true; +} + + +// +// +// EXAMPLE +// +// +void ScanRopeSlack( CChunk *pChunk ) +{ + if( stricmp( pChunk->m_pChunkName, "entity" ) == 0 ) + { + if( pChunk->CompareKey( "classname", "keyframe_rope" ) || + pChunk->CompareKey( "classname", "move_rope" ) ) + { + CKeyValue *pKey = pChunk->FindKey( "slack" ); + if( pKey ) + { + // Subtract 100 from all the Slack properties. + float flCur = (float)atof( pKey->m_pValue ); + char str[256]; + sprintf( str, "%f", flCur + 100 ); + pKey->m_pValue = CopyString( str ); + } + } + } +} + +int g_nLogicAutoReplacementsMade = 0; +void LogicAuto( CChunk *pChunk ) +{ + if ( pChunk->CompareKey( "classname", "logic_auto" ) ) + { + CChunk *pConnections = pChunk->FindChunk( "connections" ); + if ( !pConnections ) + return; + + bool bFound = false; + for ( int i=0; i < pConnections->m_Keys.Count(); i++ ) + { + CKeyValue *pTestKV = pConnections->m_Keys[i]; + if ( V_stristr( pTestKV->m_pValue, "tonemap" ) == pTestKV->m_pValue ) + { + bFound = true; + break; + } + } + + if ( !bFound ) + return; + + ++g_nLogicAutoReplacementsMade; + + // Ok, this is a logic_auto with OnMapSpawn outputs in its connections. + CUtlLinkedList<CKeyValue*,int> newKeys; + FOR_EACH_LL( pConnections->m_Keys, i ) + { + CKeyValue *pTestKV = pConnections->m_Keys[i]; + if ( V_stricmp( pTestKV->m_pKey, "OnMapSpawn" ) == 0 ) + { + if ( V_stristr( pTestKV->m_pValue, "tonemap" ) == pTestKV->m_pValue ) + { + CKeyValue *pNewKV = new CKeyValue; + pNewKV->SetKey( "OnMapTransition" ); + pNewKV->SetValue( pTestKV->m_pValue ); + newKeys.AddToTail( pNewKV ); + } + } + } + + FOR_EACH_LL( newKeys, i ) + { + if ( !pConnections->FindKey( "OnMapTransition", newKeys[i]->m_pValue ) ) + { + pConnections->m_Keys.AddToTail( newKeys[i] ); + } + } + + // Fix spawnflags. + CKeyValue *pFlags = pChunk->FindKey("spawnflags"); + if ( pFlags ) + { + unsigned long curVal; + sscanf( pFlags->m_pValue, "%lu", &curVal ); + if ( curVal & 1 ) + { + --curVal; + char str[512]; + sprintf( str, "%lu", curVal ); + pFlags->SetValue( str ); + } + } + } +} + + +void ScanChunks( CChunk *pChunk, void (*fn)(CChunk *) ) +{ + fn( pChunk ); + + // Recurse into the children. + for( unsigned short i=pChunk->m_Chunks.Head(); i != pChunk->m_Chunks.InvalidIndex(); i = pChunk->m_Chunks.Next( i ) ) + { + ScanChunks( pChunk->m_Chunks[i], fn ); + } +} + +int main(int argc, char* argv[]) +{ + CommandLine()->CreateCmdLine( argc, argv ); + SpewOutputFunc( VMFTweakSpewFunc ); + + if( argc < 2 ) + { + printf( "vmf_tweak <input file> [output file]\n" ); + return 1; + } + + g_pInFilename = argv[1]; + char const *pOutFilename = argc >= 3 ? argv[2] : ""; + + CChunk *pRoot = ReadChunkFile( g_pInFilename ); + if( !pRoot ) + return 2; + + // + // + // + // This is where you can put code to modify the VMF. + // + // + // + + // If they didn't specify -game on the command line, use VPROJECT. + char workingdir[ 256 ]; + workingdir[0] = 0; + Q_getwd( workingdir, sizeof(workingdir) ); + CmdLib_InitFileSystem( workingdir ); + ScanChunks( pRoot, LogicAuto ); + FileSystem_Term(); + + Msg( "%s: %d logic_auto replacements made.\n", g_pInFilename, g_nLogicAutoReplacementsMade ); + + if ( argc >= 3 ) + { + if( !WriteChunkFile( pOutFilename, pRoot ) ) + return 3; + } + + return 0; +} + diff --git a/utils/vmf_tweak/vmf_tweak.vpc b/utils/vmf_tweak/vmf_tweak.vpc new file mode 100644 index 0000000..8fc3f7e --- /dev/null +++ b/utils/vmf_tweak/vmf_tweak.vpc @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// VMF_TWEAK.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE,$SRCDIR\game\shared,..\common" + } +} + +$Project "Vmf_tweak" +{ + $Folder "Source Files" + { + $File "$SRCDIR\public\ChunkFile.cpp" + $File "..\common\cmdlib.cpp" + $File "..\common\cmdlib.h" + $File "$SRCDIR\public\filesystem_helpers.cpp" + $File "$SRCDIR\public\filesystem_helpers.h" + $File "$SRCDIR\public\filesystem_init.cpp" + $File "..\common\filesystem_tools.cpp" + $File "..\common\filesystem_tools.h" + $File "StdAfx.cpp" + $File "vmf_tweak.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\public\ChunkFile.h" + $File "StdAfx.h" + $File "$SRCDIR\public\tier1\tokenreader.h" + } + + $Folder "Link Libraries" + { + $Lib tier2 + } +} |