//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //============================================================================= // // TODO: // * Bring in Jeff Hameluck's translucency support: // QC with any $translucent 1 VMT should have $mostlyopaque // * Add help icons with tooltips on valid asset constraints // // Maybe TODO: // * Add wireframe view to preview // * Fix issues with gesture support (no animation blending/easing, no weapon state logic) // //============================================================================= #include "cbase.h" #include "tier2/tier2.h" #include "tier2/p4helpers.h" #include "tier2/fileutils.h" #include "ienginevgui.h" #include "imageutils.h" #include "filesystem.h" #include "vgui_controls/FileOpenDialog.h" #include "vgui_controls/ImagePanel.h" #include "vgui_controls/Label.h" #include "vgui_bitmapimage.h" #include "bitmap/bitmap.h" #include "itemtest/itemtest.h" #include "econ_controls.h" #include "econ_item_system.h" #include "tf_item_inventory.h" #include "c_tf_player.h" #include "confirm_dialog.h" #include "steampublishedfiles/publish_file_dialog.h" #include "vgui/store/v2/tf_store_preview_item2.h" #include "vgui/tf_playermodelpanel.h" #include "bone_setup.h" #include "scenefilecache/ISceneFileCache.h" #include "workshop/item_import.h" #include "choreoscene.h" #include "choreoactor.h" #include "choreochannel.h" #include "../public/zip_utils.h" // memdbgon must be the last include file in a .cpp file!!! #include static const char *kClassFolders[TF_LAST_NORMAL_CLASS] = { "", // TF_CLASS_UNDEFINED "scout", // TF_CLASS_SCOUT "sniper", // TF_CLASS_SNIPER, "soldier", // TF_CLASS_SOLDIER, "demo", // TF_CLASS_DEMOMAN, "medic", // TF_CLASS_MEDIC, "heavy", //TF_CLASS_HEAVYWEAPONS, "pyro", // TF_CLASS_PYRO, "spy", // TF_CLASS_SPY, "engineer", // TF_CLASS_ENGINEER, }; static const char *kClassFolderMulticlass = "all_class"; static const int NUM_IMPORT_LODS = 3; static const int NUM_IMPORT_MATERIALS_PER_TEAM = 2; static const int MAX_MATERIAL_COUNT = NUM_IMPORT_MATERIALS_PER_TEAM * 2; static const int MAX_TEXT_EDIT_SIZE = 8192; static const int MAX_TAUNT_DURATION = 30.f; static const int kStartWorkshopItemIndex = 30000; static const char *kBodygroupArray[] = { "backpack", "dogtags", "grenades", "hands", "hat", "head", "headphones", "shoes", "shoes_socks", }; extern IFileSystem *g_pFullFileSystem; // This should be a constant since it's in the game directory hierarchy now //static ConVar tf_steam_workshop_dir( "tf_steam_workshop_dir", "workshop", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Directory used to hold import sessions for the Steam Workshop." ); static const char *kSteamWorkshopDir = "%s/import_source"; static const char *kWorkshopSchemaFile = "scripts/items/unencrypted/_items_workshop.txt"; static const char *kWorkshopSoundScriptFile = "scripts/game_sounds_taunt_workshop.txt"; static ConVar tf_steam_workshop_import_icon_path( "tf_steam_workshop_import_icon_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load backpack icons from" ); static ConVar tf_steam_workshop_import_model_path( "tf_steam_workshop_import_model_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load models from" ); static ConVar tf_steam_workshop_import_material_path( "tf_steam_workshop_import_material_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load materials from" ); #ifdef STAGING_ONLY static ConVar tf_steam_workshop_max_taunt_duration( "tf_steam_workshop_max_taunt_duration", "-1" ); #endif // STAGING_ONLY // Item data tokens static const char *kItemName = "name"; static const char *kWorkshopName = "import_name"; static const char *kTFEnglishName = "tf_english_name"; static const char *kItemPrefab = "prefab"; static const char *kItemIcon = "icon"; static const char *kItemPaintable = "paintable%d"; static const char *kAnimationLoopable = "loopable"; static const char *kClassQC = "Classes/%s/QC"; static const char *kClassQCI = "Classes/%s/QCI"; static const char *kClassLODN = "Classes/%s/LOD%d"; static const char *kClassLODNFile = "Classes/%s/LOD%d/file"; static const char *kClassAnimation = "Classes/%s/Animation"; static const char *kClassAnimationSourceFile = "Classes/%s/Animation/source_file"; static const char *kClassAnimationVCDFile = "Classes/%s/Animation/vcd_file"; static const char *kClassAnimationDuration = "Classes/%s/Animation/taunt_duration"; static const char *kMaterialN = "Materials/Material%d"; static const char *kMaterialSkinN = "Materials/Skins/%s/Material%d"; static const char *kMaterialSkinNFile = "Materials/Skins/%s/Material%d/%s_texture_file"; static const char *kMaterialSkinNVMT = "Materials/Skins/%s/Material%d/vmt"; static const char *kItemSchema = "ItemSchema"; static const char *kBuildOutput = "output"; static const char *kSkinType = "skin_type"; static const char *kEquipRegion = "equip_region"; static const char *kBodygroup = "bodygroup"; static const char *kPaintDefIndex = "paint_def_index"; static const char *kWorkshopID = "workshop_id"; // The default triangle budget for items static const int kDefaultTriangleBudget[] = { 1400, 1000, 700 }; COMPILE_TIME_ASSERT( ARRAYSIZE( kDefaultTriangleBudget ) == NUM_IMPORT_LODS ); static const int kDefaultBoneBudget = 5; static const char *kBuildResultMessages[] = { "", "#TF_ImportFile_BuildFailedNoSDK", "#TF_ImportFile_BuildFailedNoName", "#TF_ImportFile_BuildFailedNoType", "#TF_ImportFile_BuildFailedNoModels", "#TF_ImportFile_BuildFailedNumLODMismatch", "#TF_ImportFile_BuildFailedNoMaterials", "#TF_ImportFile_BuildFailedNumMaterialMismatch", "#TF_ImportFile_BuildFailedNoBackpackIcon", "#TF_ImportFile_BuildFailedBadName", "TF English Name already exists in item schema.", "#TF_ImportFile_BuildFailedBadType", "#TF_ImportFile_BuildFailedBadModel", "#TF_ImportFile_BuildFailedBadMaterialType", "#TF_ImportFile_BuildFailedBadMaterial", "#TF_ImportFile_BuildFailedMaterialMissingShader", "#TF_ImportFile_BuildFailedMaterialMissingCloak", "#TF_ImportFile_BuildFailedMaterialMissingBurning", "#TF_ImportFile_BuildFailedMaterialMissingJarate", "#TF_ImportFile_BuildFailedMaterialMissingPaintable", "#TF_ImportFile_BuildFailedMissingModel", "#TF_ImportFile_BuildFailedNeedMoreLOD", "#TF_ImportFile_BuildFailedComplexModel", "#TF_ImportFile_BuildFailedBadImage", "#TF_ImportFile_BuildFailedCompile", "#TF_ImportFile_BuildFailedNoWorkshopID", "#TF_ImportFile_ImageUnsupportedFileType", "#TF_ImportFile_ImageResolutionNotPowerOf2", "#TF_ImportFile_ImageResolutionOverLimit", "#TF_ImportFile_BuildFailedNoTaunts", "#TF_ImportFile_BuildFailedBadVCD", "#TF_ImportFile_BuildFailedVCDMissingEventSequence", "#TF_ImportFile_BuildFailedVCDEventSequenceTooLong", }; COMPILE_TIME_ASSERT( ARRAYSIZE( kBuildResultMessages ) == CTFFileImportDialog::NUM_BUILD_RESULTS ); static const char *kLoadResultMessages[ CTFFileImportDialog::NUM_LOAD_RESULTS ] = { "", "#TF_ImportFile_LoadFailedBadFile", "#TF_ImportFile_LoadFailedBadFile", "#TF_ImportFile_BuildFailedComplexModel", "#TF_ImportFile_LoadFailedTooManyBones", "#TF_ImportFile_LoadFailedBadFile", "#TF_ImportFile_LoadFailedTooManyMaterials", "#TF_ImportFile_LoadFailedMaterialCountMismatch", "#TF_ImportFile_LoadFailedAnimationTooLong", }; COMPILE_TIME_ASSERT( ARRAYSIZE( kLoadResultMessages ) == CTFFileImportDialog::NUM_LOAD_RESULTS ); static const char *kSaveResultMessages[ CTFFileImportDialog::NUM_SAVE_RESULTS ] = { "", "#TF_ImportFile_SaveFailedBadFile", }; COMPILE_TIME_ASSERT( ARRAYSIZE( kSaveResultMessages ) == CTFFileImportDialog::NUM_SAVE_RESULTS ); static const char *kWarningMessages[ CTFFileImportDialog::NUM_WARNINGS ] = { "TF_ImportFile_Warning_BaseAlphaMask", }; COMPILE_TIME_ASSERT( ARRAYSIZE( kWarningMessages ) == CTFFileImportDialog::NUM_WARNINGS ); static const char *kLODLevels[] = { "HIGH LOD", "MEDIUM LOD", "LOW LOD" }; COMPILE_TIME_ASSERT( ARRAYSIZE( kLODLevels ) == NUM_IMPORT_LODS ); static const char *kPrefabs[] = { "hat", "misc", "taunt" }; COMPILE_TIME_ASSERT( ARRAYSIZE( kPrefabs ) == CTFFileImportDialog::PREFAB_COUNT ); static const char* kDefaultPrefab = "hat"; static const char* kDefaultEquipRegion = "hat"; // Poses that your character can do in the item preview static const char *kModelPoses[] = { "REF", "STAND", "CROUCH", "RUN", }; static const int kDefaultModelPoseIndex = 1; static const char *kModelActions[] = { "taunt_laugh.vcd", // The attack and reload animations don't work properly with the Heavy and Pyro //"gesture_attack", //"gesture_reload", }; static const int kDefaultModelActionIndex = 0; static const char* s_pszMaterialFilePrefixes[] = { "base", "normal", "phongexponent", "selfillum" }; COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszMaterialFilePrefixes ) == NUM_MATERIAL_TEXTURE_FILE_TYPE ); // Each preview needs a unique model name so it actually gets reloaded if it changes static int s_nLastPreviewModel; static const char* kDefaultBumpmap = "models/player/shared/shared_normal"; struct LightwarpInfo_t { const char *pszName; const char *pszPath; }; static LightwarpInfo_t kLightwarps[] = { { "pyro", "models/player/pyro/pyro_lightwarp" }, { "weapon", "models/lightwarps/weapon_lightwarp" }, { "robot", "models/lightwarps/robot_lightwarp" }, { "sentry1", "models/buildables/sentry1/sentry1_lightwarp" }, { "sentry2", "models/buildables/sentry2/sentry2_lightwarp" }, { "sentry3", "models/buildables/sentry3/sentry3_lightwarp" }, { "ambassador", "models/weapons/c_items/c_ambassador_lightwarp" }, { "jarate", "models/lightwarps/jarate_lightwarp" }, }; static const char *kLightwarpPath = "lightwarp_path"; struct EnvmapInfo_t { const char *pszName; const char *pszPath; }; static EnvmapInfo_t kEnvmaps[] = { { "none", "" }, { "world cube map", "env_cubemap" }, { "saxxy gold", "effects/saxxy/saxxy_gold" }, { "pyro land goggles", "effects/pyrocube" } }; static const char *kEnvmapPath = "envmap_path"; struct EnvmapMaskInfo_t { const char *pszDisplayName; const char *pszVarName; }; static EnvmapMaskInfo_t kEnvmapMasks[] = { { "none", "" }, { "base alpha", "$basealphaenvmapmask" }, { "normal map alpha", "$normalmapalphaenvmapmask" } }; static const char *kEnvmapMaskVarName = "envmapmask_varname"; static float GetMaxTauntDuration() { #ifdef STAGING_ONLY if ( tf_steam_workshop_max_taunt_duration.GetFloat() > 0 ) { return tf_steam_workshop_max_taunt_duration.GetFloat(); } #endif // STAGING_ONLY return MAX_TAUNT_DURATION; } static const char *GetWorkshopSoundScriptFile() { static char szCorrectCaseFilePath[MAX_PATH]; char szItemWorkshopSoundScriptAbsPath[MAX_PATH]; if ( GenerateFullPath( kWorkshopSoundScriptFile, "MOD", szItemWorkshopSoundScriptAbsPath, ARRAYSIZE( szItemWorkshopSoundScriptAbsPath ) ) ) { g_pFullFileSystem->GetCaseCorrectFullPath( szItemWorkshopSoundScriptAbsPath, szCorrectCaseFilePath ); } else { Warning( "Failed to GenerateFullPath %s\n", kWorkshopSoundScriptFile ); return NULL; } return szCorrectCaseFilePath; } //----------------------------------------------------------------------------- static void SetMessageFileVariable( KeyValues *pData, const char *pszFilePath ) { if ( !pData ) return; wchar_t unicodeFile[MAX_PATH]; g_pVGuiLocalize->ConvertANSIToUnicode( pszFilePath, unicodeFile, sizeof(unicodeFile) ); pData->SetWString( "file", unicodeFile ); } //----------------------------------------------------------------------------- static void ShowMessageBoxWithFile( const char *pTitle, const char *pText, const char *pszFilePath) { KeyValuesAD pData( "data" ); SetMessageFileVariable( pData, pszFilePath ); ShowMessageBox( pTitle, pText, pData ); } static void SaveBrowsePath( ConVar &conVar, const char *pszFilePath ) { char pszDirPath[MAX_PATH]; V_ExtractFilePath( pszFilePath, pszDirPath, sizeof(pszDirPath) ); conVar.SetValue( pszDirPath ); } //----------------------------------------------------------------------------- // Purpose: Save build output for presenting to the user //----------------------------------------------------------------------------- class CBuildLog : public CItemLog { public: CBuildLog() : CItemLog(), m_log( 0, 0, CUtlBuffer::TEXT_BUFFER ) { } virtual void Log( ItemtestLogLevel_t nLogLevel, const char *pszMessage ) const { static const char *pszIgnoredMessages[] = { "CDynamicFunction: " }; // See if this is a message we want to ignore in user output for ( int i = 0; i < ARRAYSIZE(pszIgnoredMessages); ++i ) { if ( V_strncmp( pszMessage, pszIgnoredMessages[ i ], V_strlen( pszIgnoredMessages[ i ] ) ) == 0 ) return; } switch ( nLogLevel ) { case kItemtest_Log_Info: ::Msg( "%s", pszMessage ); break; case kItemtest_Log_Warning: ::Warning( "%s", pszMessage ); break; case kItemtest_Log_Error: ::Error( "%s", pszMessage ); break; } m_log.PutString( pszMessage ); } const char *Get() { return (char*)m_log.Base(); } protected: mutable CUtlBuffer m_log; }; //----------------------------------------------------------------------------- // Purpose: Import text edit dialog //----------------------------------------------------------------------------- class CTFFileImportTextEditDialog : public vgui::Frame { DECLARE_CLASS_SIMPLE( CTFFileImportTextEditDialog, Frame ); public: CTFFileImportTextEditDialog( vgui::Panel *parent, const char *pszTitle, const char *pszCommand = NULL ); virtual ~CTFFileImportTextEditDialog() { } virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); virtual void OnCommand( const char *command ); void HideCancelButton() { m_bShowCancelButton = false; } void SetText( const char *pszText ); bool GetText( char *pszText, int nMaxSize ); protected: bool m_bShowCancelButton; CUtlString m_sTitle; CUtlString m_sText; CUtlString m_sCommand; vgui::TextEntry *m_pTextEntry; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportTextEditDialog::CTFFileImportTextEditDialog( vgui::Panel *parent, const char *pszTitle, const char *pszCommand ) : Frame( parent, "ImportFileTextEditDialog" ) , m_bShowCancelButton( true ) , m_sTitle( pszTitle ) , m_sText() , m_sCommand( pszCommand ) , m_pTextEntry( NULL ) { vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); SetScheme(scheme); SetProportional( true ); SetDeleteSelfOnClose( true ); SetTitle( "", false ); SetSizeable( false ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportTextEditDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "Resource/UI/ImportFileTextEditDialog.res" ); vgui::Label *pLabel = FindControl( "TitleLabel" ); if ( pLabel ) { pLabel->SetText( m_sTitle ); } m_pTextEntry = FindControl( "TextEntry" ); if ( m_pTextEntry ) { m_pTextEntry->RequestFocus(); m_pTextEntry->SetMultiline( true ); m_pTextEntry->SetCatchEnterKey( true ); m_pTextEntry->SetVerticalScrollbar( true ); m_pTextEntry->SetText( m_sText ); } if ( !m_bShowCancelButton ) { vgui::Panel *pButton = FindControl( "ButtonClose" ); if ( pButton ) { pButton->SetVisible( false ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportTextEditDialog::OnCommand( const char *command ) { if ( V_stricmp( command, "Done" ) == 0 ) { if ( m_sCommand.IsEmpty() ) { OnCommand( "Close" ); } else { GetParent()->OnCommand( m_sCommand ); } } else { BaseClass::OnCommand( command ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportTextEditDialog::SetText( const char *pszText ) { m_sText = pszText; if ( m_pTextEntry ) { m_pTextEntry->SetText( pszText ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportTextEditDialog::GetText( char *pszText, int nMaxSize ) { if ( m_pTextEntry ) { m_pTextEntry->GetText( pszText, nMaxSize ); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Import material edit dialog //----------------------------------------------------------------------------- class CTFImportMaterialEditDialog : public vgui::Frame { DECLARE_CLASS_SIMPLE( CTFImportMaterialEditDialog, Frame ); public: CTFImportMaterialEditDialog( vgui::Panel *parent, int nSkinIndex, int nMaterialIndex, KeyValues *pItemValues ); virtual ~CTFImportMaterialEditDialog() { } virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); virtual void OnCommand( const char *command ); MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); void SetVMTKeyValues( const char *pszRedVMTText, const char *pszBlueVMTText ); KeyValues* GetVMTKeyValues( int nSkinIndex ); const char* GetBaseTextureFile( int nSkinIndex ) const { return m_strBaseTextureFile[nSkinIndex].String(); } const char* GetNormalTextureFile() const { return m_strNormalTextureFile.String(); } const char* GetPhongExponentTextureFile() const { return m_strPhongExponentTextureFile.String(); } const char* GetSelfIllumTextureFile() const { return m_bSelfIllumEnabled ? m_strSelfIllumTextureFile.String() : ""; } private: void OnCommandEditSkin( int nSkinIndex ); void OnCommandBrowseMaterial( MATERIAL_FILE_TYPE fileType ); void SetColorTintBase( int nSkinIndex, const char* pszColorTintBase ); void SetSelfIllumTint( int nSkinIndex, const char* pszSelfIllumTint ); void UpdateBackgroundTexture( int nSkinIndex ); void UpdateBaseTexture( const char *pszBaseTextureFile ); void UpdateNormalTexture( const char *pszNormalTextureFile ); void UpdatePhongExponentTexture( const char* pszPhongExponentTextureFile ); void UpdateSelfIllumTexture( const char *pszSelfIllumTextureFile ); void UpdateBaseMapAlphaPhongMask(); void UpdateRimMask(); void UpdateRimMaskDisplay( bool bEnable ); void UpdateHalfLambert(); void UpdateBlendTintByBaseAlpha(); void UpdateBlendTintColorOverBaseDisplay( bool bEnable ); void UpdateColorTintBase( int nSkinIndex, const char* pszColor ); void UpdateAdditive(); void UpdateTranslucent(); void UpdateAlphaTest(); void UpdateAlphaTestDiaplay( bool bEnable ); void UpdateSelfIllum(); void UpdateSelfIllumDisplay( bool bEnable ); void UpdateSelfIllumTint( int nSkinIndex, const char* pszColor ); void UpdateEnvmapDisplay( bool bEnable ); void UpdateUniqueLabels(); CUtlString m_sCommand; KeyValuesAD m_VMTKeyValues; int m_nSkinIndex; int m_nMaterialIndex; KeyValues *m_pItemValues; // unique values per skin CUtlString m_strBaseTextureFile[NUM_IMPORT_MATERIALS_PER_TEAM]; CUtlString m_strColorTintBase[NUM_IMPORT_MATERIALS_PER_TEAM]; CUtlString m_strSelfIllumTint[NUM_IMPORT_MATERIALS_PER_TEAM]; CUtlString m_strNormalTextureFile; CUtlString m_strPhongExponentTextureFile; bool m_bSelfIllumEnabled; CUtlString m_strSelfIllumTextureFile; MATERIAL_FILE_TYPE m_browseMaterialFileType; vgui::Button *m_pRedTeamButton; vgui::Button *m_pBlueTeamButton; vgui::Label *m_pBaseTextureFileLabel; vgui::Label *m_pNormalTextureFileLabel; vgui::Label *m_pPhongExponentTextureFileLabel; vgui::Label *m_pSelfIllumTextureFileLabel; // Lighting vgui::ComboBox *m_pLightwarpComboBox; vgui::CheckButton *m_pBaseMapAlphaPhongMaskCheckButton; vgui::TextEntry *m_pPhongExponentTextEntry; vgui::TextEntry *m_pPhongBoostTextEntry; vgui::TextEntry *m_pRimLightExponentTextEntry; vgui::TextEntry *m_pRimLightBoostTextEntry; vgui::CheckButton *m_pRimMaskCheckButton; vgui::CheckButton *m_pHalfLambertCheckButton; // Paint vgui::CheckButton *m_pBlendTintByBaseAlphaCheckButton; vgui::TextEntry *m_pBlendTintColorOverBaseTextEntry; vgui::TextEntry *m_pColorTintBaseRedTextEntry; vgui::TextEntry *m_pColorTintBaseGreenTextEntry; vgui::TextEntry *m_pColorTintBaseBlueTextEntry; // Translucent vgui::CheckButton *m_pAdditiveCheckButton; vgui::CheckButton *m_pTranslucentCheckButton; vgui::CheckButton *m_pAlphaTestCheckButton; // Cube map vgui::ComboBox *m_pEnvmapComboBox; vgui::ComboBox *m_pEnvmapAlphaMaskComboBox; vgui::TextEntry *m_pCubemapTintRedTextEntry; vgui::TextEntry *m_pCubemapTintGreenTextEntry; vgui::TextEntry *m_pCubemapTintBlueTextEntry; // Self Illum vgui::CheckButton *m_pSelfIllumCheckButton; vgui::TextEntry *m_pSelfIllumTintRedTextEntry; vgui::TextEntry *m_pSelfIllumTintGreenTextEntry; vgui::TextEntry *m_pSelfIllumTintBlueTextEntry; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFImportMaterialEditDialog::CTFImportMaterialEditDialog( vgui::Panel *parent, int nSkinIndex, int nMaterialIndex, KeyValues* pItemValues ) : Frame( parent, "ImportMaterialEditDialog" ) , m_sCommand( CFmtStr( "EditMaterialDone%d,%d", nSkinIndex, nMaterialIndex ) ) , m_VMTKeyValues( "VMT" ) , m_nSkinIndex( nSkinIndex ) , m_nMaterialIndex( nMaterialIndex ) , m_pItemValues( pItemValues ) { vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); SetScheme(scheme); SetProportional( true ); SetDeleteSelfOnClose( true ); SetTitle( "", false ); SetSizeable( false ); bool bSetSharedTextures = false; for ( int nSkin=0; nSkinGetNumMaterialSkins(); ++nSkin ) { KeyValues* pMaterialKey = m_pItemValues->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), m_nMaterialIndex ) ); if ( pMaterialKey ) { m_strBaseTextureFile[nSkin] = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); if ( !bSetSharedTextures ) { m_strNormalTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_NORMAL] ) ); m_strPhongExponentTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_PHONGEXPONENT] ) ); m_strSelfIllumTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_SELFILLUM] ) ); bSetSharedTextures = true; } } } m_pRedTeamButton = NULL; m_pBlueTeamButton = NULL; m_pBaseTextureFileLabel = NULL; m_pNormalTextureFileLabel = NULL; m_pPhongExponentTextureFileLabel = NULL; m_bSelfIllumEnabled = false; m_pSelfIllumTextureFileLabel = NULL; m_pLightwarpComboBox = NULL; m_pBaseMapAlphaPhongMaskCheckButton = NULL; m_pPhongExponentTextEntry = NULL; m_pPhongBoostTextEntry = NULL; m_pRimLightExponentTextEntry = NULL; m_pRimLightBoostTextEntry = NULL; m_pRimMaskCheckButton = NULL; m_pHalfLambertCheckButton = NULL; m_pBlendTintByBaseAlphaCheckButton = NULL; m_pBlendTintColorOverBaseTextEntry = NULL; m_pColorTintBaseRedTextEntry = NULL; m_pColorTintBaseGreenTextEntry = NULL; m_pColorTintBaseBlueTextEntry = NULL; m_pAdditiveCheckButton = NULL; m_pTranslucentCheckButton = NULL; m_pAlphaTestCheckButton = NULL; m_pEnvmapComboBox = NULL; m_pEnvmapAlphaMaskComboBox = NULL; m_pCubemapTintRedTextEntry = NULL; m_pCubemapTintGreenTextEntry = NULL; m_pCubemapTintBlueTextEntry = NULL; m_pSelfIllumCheckButton = NULL; m_pSelfIllumTintRedTextEntry = NULL; m_pSelfIllumTintGreenTextEntry = NULL; m_pSelfIllumTintBlueTextEntry = NULL; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "Resource/UI/ImportMaterialEditDialog.res" ); bool bAllTeam = m_pItemValues->GetInt( kSkinType ) == 0; if ( !bAllTeam ) { m_pRedTeamButton = FindControl( "RedTeamButton" ); if ( m_pRedTeamButton ) { m_pRedTeamButton->SetVisible( true ); m_pRedTeamButton->SetEnabled( true ); } m_pBlueTeamButton = FindControl( "BlueTeamButton" ); if ( m_pBlueTeamButton ) { m_pBlueTeamButton->SetVisible( true ); m_pBlueTeamButton->SetEnabled( true ); } UpdateUniqueLabels(); } UpdateBackgroundTexture( m_nSkinIndex ); vgui::Label *pTitleLabel = FindControl( "TitleLabel" ); if ( pTitleLabel ) { pTitleLabel->SetText( CFmtStr( "#TF_ImportFile_EditVMT%d", m_nMaterialIndex ) ); } m_pBaseTextureFileLabel = FindControl( "BaseTextureFileLabel" ); m_pNormalTextureFileLabel = FindControl< vgui::Label >( "NormalTextureFileLabel" ); m_pPhongExponentTextureFileLabel = FindControl< vgui::Label >( "PhongExponentTextureFileLabel" ); m_pSelfIllumTextureFileLabel = FindControl< vgui::Label >( "SelfIllumTextureFileLabel" ); m_pLightwarpComboBox = FindControl( "LightwarpComboBox" ); if ( m_pLightwarpComboBox ) { m_pLightwarpComboBox->RemoveAll(); KeyValuesAD pKeyValues( "data" ); for ( int i=0; iSetString( kLightwarpPath, kLightwarps[i].pszPath ); m_pLightwarpComboBox->AddItem( kLightwarps[i].pszName, pKeyValues ); } m_pLightwarpComboBox->AddActionSignalTarget( this ); } // Lighting m_pBaseMapAlphaPhongMaskCheckButton = FindControl( "BaseMapAlphaPhongMaskCheckButton" ); if ( m_pBaseMapAlphaPhongMaskCheckButton ) { m_pBaseMapAlphaPhongMaskCheckButton->AddActionSignalTarget( this ); } m_pPhongExponentTextEntry = FindControl( "PhongExponentTextEntry" ); if ( m_pPhongExponentTextEntry ) { m_pPhongExponentTextEntry->AddActionSignalTarget( this ); } m_pPhongBoostTextEntry = FindControl( "PhongBoostTextEntry" ); if ( m_pPhongBoostTextEntry ) { m_pPhongBoostTextEntry->AddActionSignalTarget( this ); } m_pRimLightExponentTextEntry = FindControl( "RimLightExponentTextEntry" ); if ( m_pRimLightExponentTextEntry ) { m_pRimLightExponentTextEntry->AddActionSignalTarget( this ); } m_pRimLightBoostTextEntry = FindControl( "RimLightBoostTextEntry" ); if ( m_pRimLightBoostTextEntry ) { m_pRimLightBoostTextEntry->AddActionSignalTarget( this ); } m_pRimMaskCheckButton = FindControl( "RimMaskCheckButton" ); if ( m_pRimMaskCheckButton ) { m_pRimMaskCheckButton->AddActionSignalTarget( this ); m_pRimMaskCheckButton->SetCheckButtonCheckable( false ); } m_pHalfLambertCheckButton = FindControl( "HalfLambertCheckButton" ); if ( m_pHalfLambertCheckButton ) { m_pHalfLambertCheckButton->AddActionSignalTarget( this ); } // Paint m_pBlendTintByBaseAlphaCheckButton = FindControl( "BlendTintByBaseAlphaCheckButton" ); if ( m_pBlendTintByBaseAlphaCheckButton ) { m_pBlendTintByBaseAlphaCheckButton->AddActionSignalTarget( this ); m_pBlendTintByBaseAlphaCheckButton->SetCheckButtonCheckable( false ); } m_pBlendTintColorOverBaseTextEntry = FindControl( "BlendTintColorOverBaseTextEntry" ); if ( m_pBlendTintColorOverBaseTextEntry ) { m_pBlendTintColorOverBaseTextEntry->AddActionSignalTarget( this ); } m_pColorTintBaseRedTextEntry = FindControl( "ColorTintBaseRedTextEntry" ); if ( m_pColorTintBaseRedTextEntry ) { m_pColorTintBaseRedTextEntry->AddActionSignalTarget( this ); } m_pColorTintBaseGreenTextEntry = FindControl( "ColorTintBaseGreenTextEntry" ); if ( m_pColorTintBaseGreenTextEntry ) { m_pColorTintBaseGreenTextEntry->AddActionSignalTarget( this ); } m_pColorTintBaseBlueTextEntry = FindControl( "ColorTintBaseBlueTextEntry" ); if ( m_pColorTintBaseBlueTextEntry ) { m_pColorTintBaseBlueTextEntry->AddActionSignalTarget( this ); } // enable paintable UI const char* pszPaintable = CFmtStr( kItemPaintable, m_nMaterialIndex ); if ( m_pItemValues->GetBool( pszPaintable ) ) { m_pBlendTintByBaseAlphaCheckButton->SetEnabled( true ); m_pBlendTintByBaseAlphaCheckButton->SetCheckButtonCheckable( true ); m_pBlendTintColorOverBaseTextEntry->SetEnabled( true ); m_pColorTintBaseRedTextEntry->SetEnabled( true ); m_pColorTintBaseGreenTextEntry->SetEnabled( true ); m_pColorTintBaseBlueTextEntry->SetEnabled( true ); static const char* paintableUILabels[] = { "BlendTintByBaseAlphaLabel", "BlendTintColorOverBaseLabel", "ColorTintBaseLabel" }; for ( int i=0; i( paintableUILabels[i] ); if ( pLabel ) { pLabel->SetEnabled( true ); } } } // Translucent m_pAdditiveCheckButton = FindControl( "AdditiveCheckButton" ); if ( m_pAdditiveCheckButton ) { m_pAdditiveCheckButton->AddActionSignalTarget( this ); } m_pTranslucentCheckButton = FindControl( "TranslucentCheckButton" ); if ( m_pTranslucentCheckButton ) { m_pTranslucentCheckButton->AddActionSignalTarget( this ); } m_pAlphaTestCheckButton = FindControl( "AlphaTestCheckButton" ); if ( m_pAlphaTestCheckButton ) { m_pAlphaTestCheckButton->AddActionSignalTarget( this ); m_pAlphaTestCheckButton->SetCheckButtonCheckable( false ); } // Cube map m_pEnvmapComboBox = FindControl( "EnvmapComboBox" ); if ( m_pEnvmapComboBox ) { KeyValuesAD pKeyValues( "data" ); for ( int i=0; iSetString( kEnvmapPath, kEnvmaps[i].pszPath ); m_pEnvmapComboBox->AddItem( kEnvmaps[i].pszName, pKeyValues ); } m_pEnvmapComboBox->AddActionSignalTarget( this ); } m_pEnvmapAlphaMaskComboBox = FindControl( "EnvmapAlphaMaskComboBox" ); if ( m_pEnvmapAlphaMaskComboBox ) { KeyValuesAD pKeyValues( "data" ); for ( int i=0; iSetString( kEnvmapMaskVarName, kEnvmapMasks[i].pszVarName ); m_pEnvmapAlphaMaskComboBox->AddItem( kEnvmapMasks[i].pszDisplayName, pKeyValues ); } m_pEnvmapAlphaMaskComboBox->AddActionSignalTarget( this ); } m_pCubemapTintRedTextEntry = FindControl( "CubemapTintRedTextEntry" ); if ( m_pCubemapTintRedTextEntry ) { m_pCubemapTintRedTextEntry->AddActionSignalTarget( this ); } m_pCubemapTintGreenTextEntry = FindControl( "CubemapTintGreenTextEntry" ); if ( m_pCubemapTintGreenTextEntry ) { m_pCubemapTintGreenTextEntry->AddActionSignalTarget( this ); } m_pCubemapTintBlueTextEntry = FindControl( "CubemapTintBlueTextEntry" ); if ( m_pCubemapTintBlueTextEntry ) { m_pCubemapTintBlueTextEntry->AddActionSignalTarget( this ); } // Self Illum m_pSelfIllumCheckButton = FindControl( "SelfIllumCheckButton" ); if ( m_pSelfIllumCheckButton ) { m_pSelfIllumCheckButton->AddActionSignalTarget( this ); } m_pSelfIllumTintRedTextEntry = FindControl( "SelfIllumTintRedTextEntry" ); if ( m_pSelfIllumTintRedTextEntry ) { m_pSelfIllumTintRedTextEntry->AddActionSignalTarget( this ); } m_pSelfIllumTintGreenTextEntry = FindControl( "SelfIllumTintGreenTextEntry" ); if ( m_pSelfIllumTintGreenTextEntry ) { m_pSelfIllumTintGreenTextEntry->AddActionSignalTarget( this ); } m_pSelfIllumTintBlueTextEntry = FindControl( "SelfIllumTintBlueTextEntry" ); if ( m_pSelfIllumTintBlueTextEntry ) { m_pSelfIllumTintBlueTextEntry->AddActionSignalTarget( this ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::OnCommand( const char *command ) { if ( FStrEq( command, "Done" ) ) { if ( m_sCommand.IsEmpty() ) { OnCommand( "Close" ); } else if ( GetParent() ) { GetParent()->OnCommand( m_sCommand ); } } else if ( V_strncasecmp( command, "EditSkin", V_strlen( "EditSkin" ) ) == 0 ) { int index = V_atoi( &command[ V_strlen( "EditSkin" ) ] ); OnCommandEditSkin( index ); } else if ( FStrEq( command, "BrowseMaterial" ) ) { OnCommandBrowseMaterial( MATERIAL_FILE_BASETEXTURE ); } else if ( FStrEq( command, "BrowseNormalTexture" ) ) { OnCommandBrowseMaterial( MATERIAL_FILE_NORMAL ); } else if ( FStrEq( command, "BrowsePhongExponentTexture" ) ) { OnCommandBrowseMaterial( MATERIAL_FILE_PHONGEXPONENT ); } else if ( FStrEq( command, "BrowseSelfIllumTexture" ) ) { OnCommandBrowseMaterial( MATERIAL_FILE_SELFILLUM ); } else if ( FStrEq( command, "ClearNormalTexture" ) ) { UpdateNormalTexture( "" ); } else if ( FStrEq( command, "ClearPhongExponentTexture" ) ) { UpdatePhongExponentTexture( "" ); } else if ( FStrEq( command, "ClearSelfIllumTexture" ) ) { UpdateSelfIllumTexture( "" ); } else if ( FStrEq( command, "UpdateBaseMapAlphaPhongMask" ) ) { UpdateBaseMapAlphaPhongMask(); } else if ( FStrEq( command, "UpdateRimMask" ) ) { UpdateRimMask(); } else if ( FStrEq( command, "UpdateHalfLambert" ) ) { UpdateHalfLambert(); } else if ( FStrEq( command, "UpdateBlendTintByBaseAlpha" ) ) { UpdateBlendTintByBaseAlpha(); } else if ( FStrEq( command, "UpdateAdditive" ) ) { UpdateAdditive(); } else if ( FStrEq( command, "UpdateTranslucent" ) ) { UpdateTranslucent(); } else if ( FStrEq( command, "UpdateAlphaTest" ) ) { UpdateAlphaTest(); } else if ( FStrEq( command, "UpdateSelfIllum" ) ) { UpdateSelfIllum(); } else { BaseClass::OnCommand( command ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::OnCommandEditSkin( int nSkinIndex ) { if ( m_nSkinIndex == nSkinIndex ) { return; } m_nSkinIndex = nSkinIndex; UpdateBackgroundTexture( m_nSkinIndex ); UpdateBaseTexture( m_strBaseTextureFile[m_nSkinIndex] ); UpdateColorTintBase( m_nSkinIndex, m_strColorTintBase[m_nSkinIndex] ); UpdateSelfIllumTint( m_nSkinIndex, m_strSelfIllumTint[m_nSkinIndex] ); UpdateUniqueLabels(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::OnCommandBrowseMaterial( MATERIAL_FILE_TYPE fileType ) { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectMaterial", vgui::FOD_OPEN ); pDialog->AddFilter( "*.tga,*.psd", "#TF_ImportFile_MaterialFileType", true); pDialog->AddActionSignalTarget( this ); const char *pszStartPath = tf_steam_workshop_import_material_path.GetString(); if ( pszStartPath && *pszStartPath ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_browseMaterialFileType = fileType; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CheckImageSize( const char *fullpath, MATERIAL_FILE_TYPE materialFileType, KeyValues *pMessageVariables ) { CAssetTF asset; CTargetTGA image( &asset, NULL ); if ( !image.SetInputFile( fullpath ) ) { SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); return CTFFileImportDialog::BUILD_FAILED_IMAGEUNSUPPORTEDFILETYPE; } int nLimitWidth = 0; int nLimitHeight = 0; switch ( materialFileType ) { case MATERIAL_FILE_BASETEXTURE: { // 512x512 nLimitWidth = nLimitHeight = 512; } break; case MATERIAL_FILE_NORMAL: { // 512x512 nLimitWidth = nLimitHeight = 512; } break; case MATERIAL_FILE_PHONGEXPONENT: { // 256x256 nLimitWidth = nLimitHeight = 256; } break; case MATERIAL_FILE_SELFILLUM: { // 256x256 nLimitWidth = nLimitHeight = 256; } break; } if ( image.GetWidth() > nLimitWidth || image.GetHeight() > nLimitHeight ) { SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); pMessageVariables->SetInt( "width", nLimitWidth ); pMessageVariables->SetInt( "height", nLimitHeight ); return CTFFileImportDialog::BUILD_FAILED_IMAGERESOLUTIONOVERLIMIT; } if ( !IsPowerOfTwo( image.GetWidth() ) || !IsPowerOfTwo( image.GetHeight() ) ) { SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); return CTFFileImportDialog::BUILD_FAILED_IMAGERESOLUTIONNOTPOWEROF2; } return CTFFileImportDialog::BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::OnFileSelected( char const *fullpath ) { SaveBrowsePath( tf_steam_workshop_import_material_path, fullpath ); KeyValuesAD pKV("data"); CTFFileImportDialog::BUILD_RESULT result = CheckImageSize( fullpath, m_browseMaterialFileType, pKV ); if ( result != CTFFileImportDialog::BUILD_OKAY ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", kBuildResultMessages[result], pKV ); return; } switch ( m_browseMaterialFileType ) { case MATERIAL_FILE_BASETEXTURE: { UpdateBaseTexture( fullpath ); } break; case MATERIAL_FILE_NORMAL: { UpdateNormalTexture( fullpath ); } break; case MATERIAL_FILE_PHONGEXPONENT: { UpdatePhongExponentTexture( fullpath ); } break; case MATERIAL_FILE_SELFILLUM: { UpdateSelfIllumTexture( fullpath ); } break; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::OnTextChanged( KeyValues *data ) { Panel *pPanel = reinterpret_cast( data->GetPtr( "panel" ) ); vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); if ( pComboBox ) { if( pComboBox == m_pLightwarpComboBox ) { KeyValues *pData = m_pLightwarpComboBox->GetActiveItemUserData(); m_VMTKeyValues->SetString( "$lightwarptexture", pData->GetString( kLightwarpPath ) ); } else if ( pComboBox == m_pEnvmapComboBox ) { KeyValues *pData = m_pEnvmapComboBox->GetActiveItemUserData(); const char* pszEnvmapPath = pData->GetString( kEnvmapPath ); m_VMTKeyValues->SetString( "$envmap", pszEnvmapPath ); UpdateEnvmapDisplay( !FStrEq( pszEnvmapPath, "" ) ); } else if ( pComboBox == m_pEnvmapAlphaMaskComboBox ) { KeyValues *pData = m_pEnvmapAlphaMaskComboBox->GetActiveItemUserData(); const char* pszEnvmapMaskVarName = pData->GetString( kEnvmapMaskVarName ); for ( int i=0; iSetBool( pszCurrentVarName, bSet ); } // pop a warning static bool bWarned = false; if ( FStrEq( pszEnvmapMaskVarName, "$basealphaenvmapmask" ) ) { bool bHasNormal = !m_strNormalTextureFile.IsEmpty(); if ( !bWarned && bHasNormal ) { bWarned = true; ShowMessageBox( "#TF_ImportFile_Warning", kWarningMessages[ CTFFileImportDialog::WARNING_BASEALPHAMASK ] ); } } else { bWarned = false; } } return; } vgui::TextEntry *pTextEntry = dynamic_cast< vgui::TextEntry * >( pPanel ); if ( pTextEntry ) { if ( pTextEntry == m_pPhongExponentTextEntry ) { m_VMTKeyValues->SetFloat( "$phongexponent", m_pPhongExponentTextEntry->GetValueAsFloat() ); } else if ( pTextEntry == m_pPhongBoostTextEntry ) { m_VMTKeyValues->SetFloat( "$phongboost", m_pPhongBoostTextEntry->GetValueAsFloat() ); } else if ( pTextEntry == m_pRimLightExponentTextEntry ) { m_VMTKeyValues->SetFloat( "$rimlightexponent", m_pRimLightExponentTextEntry->GetValueAsFloat() ); } else if ( pTextEntry == m_pRimLightBoostTextEntry ) { m_VMTKeyValues->SetFloat( "$rimlightboost", m_pRimLightBoostTextEntry->GetValueAsFloat() ); } else if ( pTextEntry == m_pBlendTintColorOverBaseTextEntry ) { float flClampedValue = clamp( m_pBlendTintColorOverBaseTextEntry->GetValueAsFloat(), 0.f, 1.f ); m_VMTKeyValues->SetFloat( "$blendtintcoloroverbase", flClampedValue ); } else if ( pTextEntry == m_pColorTintBaseRedTextEntry || pTextEntry == m_pColorTintBaseGreenTextEntry || pTextEntry == m_pColorTintBaseBlueTextEntry ) { const char* pszColor = CFmtStr( "{ %d %d %d }", clamp( m_pColorTintBaseRedTextEntry->GetValueAsInt(), 0, 255 ), clamp( m_pColorTintBaseGreenTextEntry->GetValueAsInt(), 0, 255 ), clamp( m_pColorTintBaseBlueTextEntry->GetValueAsInt(), 0, 255 ) ); SetColorTintBase( m_nSkinIndex, pszColor ); } else if ( pTextEntry == m_pCubemapTintRedTextEntry || pTextEntry == m_pCubemapTintGreenTextEntry || pTextEntry == m_pCubemapTintBlueTextEntry ) { float flR = (float)clamp( m_pCubemapTintRedTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; float flG = (float)clamp( m_pCubemapTintGreenTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; float flB = (float)clamp( m_pCubemapTintBlueTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; const char* pszColor = CFmtStr( "[%f %f %f]", flR, flG, flB ); m_VMTKeyValues->SetString( "$envmaptint", pszColor ); } else if ( pTextEntry == m_pSelfIllumTintRedTextEntry || pTextEntry == m_pSelfIllumTintGreenTextEntry || pTextEntry == m_pSelfIllumTintBlueTextEntry ) { float flR = m_pSelfIllumTintRedTextEntry->GetValueAsFloat() / 255.f; float flG = m_pSelfIllumTintGreenTextEntry->GetValueAsFloat() / 255.f; float flB = m_pSelfIllumTintBlueTextEntry->GetValueAsFloat() / 255.f; const char* pszColor = CFmtStr( "[%f %f %f]", flR, flG, flB ); SetSelfIllumTint( m_nSkinIndex, pszColor ); } return; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::SetColorTintBase( int nSkinIndex, const char* pszColorTintBase ) { m_VMTKeyValues->SetString( "$colortint_base", pszColorTintBase ); m_VMTKeyValues->SetString( "$color2", pszColorTintBase ); m_strColorTintBase[nSkinIndex] = pszColorTintBase; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::SetSelfIllumTint( int nSkinIndex, const char* pszSelfIllumTint ) { m_VMTKeyValues->SetString( "$selfillumtint", pszSelfIllumTint ); m_strSelfIllumTint[nSkinIndex] = pszSelfIllumTint; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::SetVMTKeyValues( const char *pszRedVMTText, const char *pszBlueVMTText ) { m_VMTKeyValues->Clear(); // read the unique data const char* pszVMTs[NUM_IMPORT_MATERIALS_PER_TEAM] = { pszRedVMTText, pszBlueVMTText }; for ( int i=0; iLoadFromBuffer( "VMT", pszVMTs[i] ) ) { m_strColorTintBase[i] = pKV->GetString( "$colortint_base" ); m_strSelfIllumTint[i] = pKV->GetString( "$selfillumtint" ); } } const char* pszVMTText = m_nSkinIndex == 0 ? pszRedVMTText : pszBlueVMTText; if ( m_VMTKeyValues->LoadFromBuffer( "VMT", pszVMTText ) ) { // update the UI here UpdateBaseTexture( m_strBaseTextureFile[m_nSkinIndex].String() ); UpdateNormalTexture( m_strNormalTextureFile.String() ); UpdatePhongExponentTexture( m_strPhongExponentTextureFile.String() ); UpdateSelfIllumTexture( m_strSelfIllumTextureFile.String() ); if ( m_pLightwarpComboBox ) { const char* pszCurrentLightwarpPath = m_VMTKeyValues->GetString( "$lightwarptexture" ); for ( int i=0; iActivateItemByRow( i ); break; } } } const char* pszFloatFormat = "%.3f"; // Lighting if ( m_pBaseMapAlphaPhongMaskCheckButton ) { m_pBaseMapAlphaPhongMaskCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$basemapalphaphongmask" ) ); } if ( m_pPhongExponentTextEntry ) { m_pPhongExponentTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$phongexponent" ) ) ); } if ( m_pPhongBoostTextEntry ) { m_pPhongBoostTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$phongboost" ) ) ); } if ( m_pRimLightExponentTextEntry ) { m_pRimLightExponentTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$rimlightexponent" ) ) ); } if ( m_pRimLightBoostTextEntry ) { m_pRimLightBoostTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$rimlightboost" ) ) ); } if ( m_pRimMaskCheckButton ) { UpdateRimMaskDisplay( !m_strPhongExponentTextureFile.IsEmpty() ); m_pRimMaskCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$rimmask" ) ); } if ( m_pHalfLambertCheckButton ) { m_pHalfLambertCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$halflambert" ) ); } // Paint if ( m_pBlendTintByBaseAlphaCheckButton ) { m_pBlendTintByBaseAlphaCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$blendtintbybasealpha" ) ); } if ( m_pBlendTintColorOverBaseTextEntry ) { m_pBlendTintColorOverBaseTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$blendtintcoloroverbase" ) ) ); } UpdateColorTintBase( m_nSkinIndex, m_VMTKeyValues->GetString( "$colortint_base" ) ); // Translucent if ( m_pAdditiveCheckButton ) { m_pAdditiveCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$additive" ) ); } if ( m_pTranslucentCheckButton ) { m_pTranslucentCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$translucent" ) ); } if ( m_pAlphaTestCheckButton ) { bool bTranslucent = m_pTranslucentCheckButton->IsSelected(); UpdateAlphaTestDiaplay( bTranslucent ); m_pAlphaTestCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$alphatest" ) ); } // Cube map if ( m_pEnvmapComboBox ) { const char *pszEnvmap = m_VMTKeyValues->GetString( "$envmap" ); for ( int i=0; iGetItemCount(); ++i ) { KeyValues *pKey = m_pEnvmapComboBox->GetItemUserData( i ); const char *pszPath = pKey->GetString( kEnvmapPath ); if ( FStrEq( pszEnvmap, pszPath ) ) { m_pEnvmapComboBox->ActivateItemByRow( i ); break; } } } if ( m_pEnvmapAlphaMaskComboBox ) { int nRow = 0; for ( int i=0; iGetItemCount(); ++i ) { KeyValues *pKey = m_pEnvmapAlphaMaskComboBox->GetItemUserData( i ); const char *pszMask = pKey->GetString( kEnvmapMaskVarName ); if ( pKey && m_VMTKeyValues->GetBool( pszMask ) ) { nRow = i; break; } } m_pEnvmapAlphaMaskComboBox->ActivateItemByRow( nRow ); } const char *pszStrippedEnvmapTintColor = m_VMTKeyValues->GetString( "$envmaptint" ) + 1; float entmapTint[3]; UTIL_StringToFloatArray( entmapTint, ARRAYSIZE( entmapTint ), pszStrippedEnvmapTintColor ); if ( m_pCubemapTintRedTextEntry ) { m_pCubemapTintRedTextEntry->SetText( CFmtStr( "%d", int( entmapTint[0] * 255.f ) ) ); } if ( m_pCubemapTintGreenTextEntry ) { m_pCubemapTintGreenTextEntry->SetText( CFmtStr( "%d", int( entmapTint[1] * 255.f ) ) ); } if ( m_pCubemapTintBlueTextEntry ) { m_pCubemapTintBlueTextEntry->SetText( CFmtStr( "%d", int( entmapTint[2] * 255.f ) ) ); } // Self Illum bool bSelfIllum = m_VMTKeyValues->GetBool( ">=DX90/$selfillum" ); if ( m_pSelfIllumCheckButton ) { m_pSelfIllumCheckButton->SetSelected( bSelfIllum ); UpdateSelfIllumDisplay( bSelfIllum ); } UpdateSelfIllumTint( m_nSkinIndex, m_VMTKeyValues->GetString( "$selfillumtint" ) ); } else { Warning( "CTFImportMaterialEditDialog::SetKeyValues failed to LoadFromBuffer\n" ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- KeyValues* CTFImportMaterialEditDialog::GetVMTKeyValues( int nSkinIndex ) { //set unique values for the skin index here m_VMTKeyValues->SetString( "$colortint_base", m_strColorTintBase[nSkinIndex] ); m_VMTKeyValues->SetString( "$color2", m_strColorTintBase[nSkinIndex] ); m_VMTKeyValues->SetString( "$selfillumtint", m_strSelfIllumTint[nSkinIndex] ); return m_VMTKeyValues; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateBackgroundTexture( int nSkinIndex ) { static const char* pszBGs[] = { "RedBG", "BlueBG" }; for ( int i=0; i( pszBGs[i] ); if ( pBG ) { bool bVisible = nSkinIndex == i; pBG->SetVisible( bVisible ); pBG->SetEnabled( bVisible ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateBaseTexture( const char *pszBaseTextureFile ) { if ( m_pBaseTextureFileLabel && pszBaseTextureFile ) { m_pBaseTextureFileLabel->InvalidateLayout( true, true ); if ( *pszBaseTextureFile ) { char file[MAX_PATH]; V_FileBase( pszBaseTextureFile, file, sizeof(file) ); m_pBaseTextureFileLabel->SetText( file ); m_pBaseTextureFileLabel->SetFgColor( Color( 255, 255, 255, 255 ) ); } else { m_pBaseTextureFileLabel->SetText( "#TF_PublishFile_NoFileSelected" ); m_pBaseTextureFileLabel->SetFgColor( Color( 255, 0, 0, 255 ) ); } m_strBaseTextureFile[m_nSkinIndex] = pszBaseTextureFile; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateNormalTexture( const char *pszNormalTextureFile ) { if ( m_pNormalTextureFileLabel && pszNormalTextureFile ) { if ( *pszNormalTextureFile ) { char file[MAX_PATH]; V_FileBase( pszNormalTextureFile, file, sizeof(file) ); m_pNormalTextureFileLabel->SetText( file ); } else { m_pNormalTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); } m_strNormalTextureFile = pszNormalTextureFile; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdatePhongExponentTexture( const char* pszPhongExponentTextureFile ) { if ( m_pPhongExponentTextureFileLabel && pszPhongExponentTextureFile ) { if ( *pszPhongExponentTextureFile ) { char file[MAX_PATH]; V_FileBase( pszPhongExponentTextureFile, file, sizeof(file) ); m_pPhongExponentTextureFileLabel->SetText( file ); } else { m_pPhongExponentTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); } m_strPhongExponentTextureFile = pszPhongExponentTextureFile; UpdateRimMaskDisplay( !m_strPhongExponentTextureFile.IsEmpty() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateSelfIllumTexture( const char *pszSelfIllumTextureFile ) { if ( m_pSelfIllumTextureFileLabel && pszSelfIllumTextureFile ) { if ( *pszSelfIllumTextureFile ) { char file[MAX_PATH]; V_FileBase( pszSelfIllumTextureFile, file, sizeof(file) ); m_pSelfIllumTextureFileLabel->SetText( file ); } else { m_pSelfIllumTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); } m_strSelfIllumTextureFile = pszSelfIllumTextureFile; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateBaseMapAlphaPhongMask() { if ( m_pBaseMapAlphaPhongMaskCheckButton ) { m_VMTKeyValues->SetBool( "$basemapalphaphongmask", m_pBaseMapAlphaPhongMaskCheckButton->IsSelected() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateRimMask() { if ( m_pRimMaskCheckButton ) { m_VMTKeyValues->SetBool( "$rimmask", m_pRimMaskCheckButton->IsSelected() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateRimMaskDisplay( bool bEnable ) { if ( m_pRimMaskCheckButton ) { m_pRimMaskCheckButton->SetEnabled( bEnable ); m_pRimMaskCheckButton->SetCheckButtonCheckable( bEnable ); } vgui::Label* pLabel = FindControl< vgui::Label >( "RimMaskLabel" ); if ( pLabel ) { pLabel->SetEnabled( bEnable ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateHalfLambert() { if ( m_pHalfLambertCheckButton ) { m_VMTKeyValues->SetBool( "$halflambert", m_pHalfLambertCheckButton->IsSelected() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateBlendTintByBaseAlpha() { if ( m_pBlendTintByBaseAlphaCheckButton ) { bool bSelected = m_pBlendTintByBaseAlphaCheckButton->IsSelected(); m_VMTKeyValues->SetBool( "$blendtintbybasealpha", bSelected ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateBlendTintColorOverBaseDisplay( bool bEnable ) { if ( m_pBlendTintColorOverBaseTextEntry ) { if ( !bEnable ) { m_VMTKeyValues->SetFloat( "$blendtintcoloroverbase", 0.f ); } m_pBlendTintColorOverBaseTextEntry->SetText( CFmtStr( "%.3f", m_VMTKeyValues->GetFloat( "$blendtintcoloroverbase" ) ) ); m_pBlendTintColorOverBaseTextEntry->SetEnabled( bEnable ); vgui::Label *pLabel = FindControl( "BlendTintColorOverBaseLabel" ); if ( pLabel ) { pLabel->SetEnabled( bEnable ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateColorTintBase( int nSkinIndex, const char* pszColor ) { m_strColorTintBase[nSkinIndex] = pszColor; int colorTintBase[3]; // color string +2 to skip "{ " or "[ " const char *pszStrippedColorTintBase = pszColor + 2; UTIL_StringToIntArray( colorTintBase, 3, pszStrippedColorTintBase ); if ( m_pColorTintBaseRedTextEntry ) { m_pColorTintBaseRedTextEntry->SetText( CFmtStr( "%d", colorTintBase[0] ) ); } if ( m_pColorTintBaseGreenTextEntry ) { m_pColorTintBaseGreenTextEntry->SetText( CFmtStr( "%d", colorTintBase[1] ) ); } if ( m_pColorTintBaseBlueTextEntry ) { m_pColorTintBaseBlueTextEntry->SetText( CFmtStr( "%d", colorTintBase[2] ) ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateAdditive() { if ( m_pAdditiveCheckButton ) { m_VMTKeyValues->SetBool( "$additive", m_pAdditiveCheckButton->IsSelected() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateTranslucent() { if ( m_pTranslucentCheckButton ) { bool bSelected = m_pTranslucentCheckButton->IsSelected(); UpdateAlphaTestDiaplay( bSelected ); m_VMTKeyValues->SetBool( "$translucent", bSelected ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateAlphaTest() { if ( m_pAlphaTestCheckButton ) { m_VMTKeyValues->SetBool( "$alphatest", m_pAlphaTestCheckButton->IsSelected() ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateAlphaTestDiaplay( bool bEnable ) { if ( m_pAlphaTestCheckButton ) { m_pAlphaTestCheckButton->SetEnabled( bEnable ); m_pAlphaTestCheckButton->SetCheckButtonCheckable( bEnable ); } vgui::Label *pLabel = FindControl( "AlphaTestLabel" ); if ( pLabel ) { pLabel->SetEnabled( bEnable ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateSelfIllum() { if ( m_pSelfIllumCheckButton ) { bool bSelected = m_pSelfIllumCheckButton->IsSelected(); m_VMTKeyValues->SetBool( ">=DX90/$selfillum", bSelected ); UpdateSelfIllumDisplay( bSelected ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateSelfIllumDisplay( bool bEnable ) { m_bSelfIllumEnabled = bEnable; static const char* pszSelfIllumLabels[] = { "SelfIllumTintLabel", "SelfIllumTextureLabel" }; for ( int i=0; i( pszSelfIllumLabels[i] ); if ( pLabel ) { pLabel->SetEnabled( bEnable ); } } static const char* pszSelfIllumButtons[] = { "SelfIllumTextureBrowse", "SelfIllumTextureClear" }; for ( int i=0; i( pszSelfIllumButtons[i] ); if ( pButton ) { pButton->SetEnabled( bEnable ); } } m_pSelfIllumTextureFileLabel->SetEnabled( bEnable ); m_pSelfIllumTintRedTextEntry->SetEnabled( bEnable ); m_pSelfIllumTintGreenTextEntry->SetEnabled( bEnable ); m_pSelfIllumTintBlueTextEntry->SetEnabled( bEnable ); // blend tint color over base is not compatible with selfillum. must turn it off UpdateBlendTintColorOverBaseDisplay( !bEnable ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateSelfIllumTint( int nSkinIndex, const char* pszColor ) { m_strSelfIllumTint[nSkinIndex] = pszColor; // +1 to skip [ const char *pszStrippedSelfIllumTintColor = pszColor + 1; float selfIllumTint[3]; UTIL_StringToFloatArray( selfIllumTint, ARRAYSIZE( selfIllumTint ), pszStrippedSelfIllumTintColor ); if ( m_pSelfIllumTintRedTextEntry ) { m_pSelfIllumTintRedTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[0] * 255.f ) ) ); } if ( m_pSelfIllumTintGreenTextEntry ) { m_pSelfIllumTintGreenTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[1] * 255.f ) ) ); } if ( m_pSelfIllumTintBlueTextEntry ) { m_pSelfIllumTintBlueTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[2] * 255.f ) ) ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateEnvmapDisplay( bool bEnable ) { static const char* pszEnvmapLabels[] = { "EnvmapAlphaMaskLabel", "EnvmapTintLabel" }; for ( int i=0; i( pszEnvmapLabels[i] ); if ( pLabel ) { pLabel->SetEnabled( bEnable ); } } m_pEnvmapAlphaMaskComboBox->SetEnabled( bEnable ); m_pCubemapTintRedTextEntry->SetEnabled( bEnable ); m_pCubemapTintGreenTextEntry->SetEnabled( bEnable ); m_pCubemapTintBlueTextEntry->SetEnabled( bEnable ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFImportMaterialEditDialog::UpdateUniqueLabels() { static Color color[NUM_IMPORT_MATERIALS_PER_TEAM] = { Color( 189, 59, 59, 255 ), Color( 57, 92, 120, 255 ) }; static const char* pszLabelNames[] = { "BaseTextureLabel", "ColorTintBaseLabel", "SelfIllumTintLabel" }; for ( int i=0; i( pszLabelNames[i] ); if ( pLabel ) { pLabel->InvalidateLayout( true, true ); pLabel->SetFgColor( color[m_nSkinIndex] ); } } } //----------------------------------------------------------------------------- // Purpose: Preview an item after building it //----------------------------------------------------------------------------- class CImportPreviewItemPanel : public CTFStorePreviewItemPanel2 { DECLARE_CLASS_SIMPLE( CImportPreviewItemPanel, CTFStorePreviewItemPanel2 ); public: CImportPreviewItemPanel( vgui::Panel *parent, KeyValues *pItemValues, int nSelectedClass ); virtual ~CImportPreviewItemPanel(); virtual void PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry = NULL ) OVERRIDE; protected: void ResetHandles(); virtual void OnThink(); virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); virtual void OnCommand( const char *command ); virtual void OnKeyCodeTyped( KeyCode code ); virtual void PerformLayout( void ); virtual void OnClose(); virtual void UpdatePlayerModelButtons(); void UpdateActivityUI(); void UpdateActivity(); void UpdateMaterialButtons(); virtual bool AllowUnusualPreview() const { return true; } int GetSequence( const char *pszGesture = NULL ); void StartAction(); void StartGesture( const char *pszGesture ); void EndGestures(); bool ClassHasModels( int nClassIndex ) { for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) { if ( V_stricmp( m_pItemValues->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ), "" ) != 0 ) return true; } return false; } MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); MESSAGE_FUNC_PARAMS( OnClassIconSelected, "ClassIconSelected", data ); void ResetCamera(); vgui::ComboBox *m_pLODComboBox; vgui::ComboBox *m_pLoadoutComboBox; vgui::ComboBox *m_pPoseComboBox; vgui::ComboBox *m_pActionComboBox; vgui::ComboBox *m_pEffectComboBox; CUtlVector< vgui::Button* > m_pMaterialButtons; KeyValues *m_pItemValues; int m_nCurrentLOD; loadout_positions_t m_nCurrentLoadout; CUtlString m_sCurrentPose; CUtlString m_sCurrentAction; bool m_bIsVCDFileNameOnly; float m_flGestureEndTime; int m_nSelectedClass; int m_nCacheModelDetail; bool m_bIsTaunt; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CImportPreviewItemPanel::CImportPreviewItemPanel( vgui::Panel *parent, KeyValues *pItemValues, int nSelectedClass ) : CTFStorePreviewItemPanel2( parent, "resource/ui/ImportPreviewItemPanel.res", "importpreviewitem", NULL ) , m_pItemValues( pItemValues ) , m_nCurrentLOD( 0 ) , m_nCurrentLoadout( LOADOUT_POSITION_PRIMARY ) , m_sCurrentPose( kModelPoses[ kDefaultModelPoseIndex ] ) , m_bIsVCDFileNameOnly( true ) , m_flGestureEndTime( 0.0f ) , m_nSelectedClass( nSelectedClass ) { ResetHandles(); static ConVarRef r_rootlod( "r_rootlod" ); if ( r_rootlod.IsValid() ) { m_nCacheModelDetail = r_rootlod.GetInt(); r_rootlod.SetValue( 0 ); } m_bIsTaunt = FStrEq( m_pItemValues->GetString( kItemPrefab ), "taunt" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CImportPreviewItemPanel::~CImportPreviewItemPanel() { g_PlayerPreviewEffect.Reset(); static ConVarRef r_rootlod( "r_rootlod" ); if ( r_rootlod.IsValid() ) { r_rootlod.SetValue( m_nCacheModelDetail ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry ) { if ( m_pPlayerModelPanel && m_iState == PS_PLAYER ) { // Preserve state when refreshing the preview Vector vecSavedCameraOffset; Vector vecSavedCameraPos; QAngle angSavedCameraDir; m_pPlayerModelPanel->GetCameraOffset( vecSavedCameraOffset ); m_pPlayerModelPanel->GetCameraPositionAndAngles( vecSavedCameraPos, angSavedCameraDir ); int iSavedClass = m_iCurrentClass; BaseClass::PreviewItem( iClass, pItem, pEntry ); KeyValuesAD pKeyValues( "data" ); pKeyValues->SetInt( "class", iSavedClass ); OnClassIconSelected( pKeyValues ); m_pPlayerModelPanel->ResetCameraPivot(); m_pPlayerModelPanel->SetCameraOffset( vecSavedCameraOffset ); m_pPlayerModelPanel->SetCameraPositionAndAngles( vecSavedCameraPos, angSavedCameraDir ); m_pPlayerModelPanel->SetForcedCameraPosition( true ); m_pPlayerModelPanel->SetLOD( m_nCurrentLOD ); } else { BaseClass::PreviewItem( iClass, pItem, pEntry ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::ResetHandles() { m_pLODComboBox = NULL; m_pLoadoutComboBox = NULL; m_pPoseComboBox = NULL; m_pActionComboBox = NULL; m_pEffectComboBox = NULL; m_pMaterialButtons.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnThink() { // We want to skip CTFStorePreviewItemPanel2::OnThink() because it closes when the mouse is clicked outside the dialog. CTFStorePreviewItemPanelBase::OnThink(); // There's no event when the team color changes, but this is a super cheap call so we'll poll. g_PlayerPreviewEffect.SetTeam( GetPreviewTeam() ); if ( m_flGestureEndTime && gpGlobals->curtime >= m_flGestureEndTime ) { EndGestures(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { ResetHandles(); BaseClass::ApplySchemeSettings( pScheme ); // We don't use the scrollbar in this view if ( m_pScrollBar ) { m_pScrollBar->MarkForDeletion(); m_pScrollBar = NULL; } vgui::Button *pButton = FindControl( "AddToCartButton", true ); if ( pButton ) { pButton->SetVisible( false ); } m_pLODComboBox = FindControl( "LODComboBox", true ); if ( m_pLODComboBox ) { m_pLODComboBox->AddActionSignalTarget( this ); } m_pLoadoutComboBox = FindControl( "LoadoutComboBox", true ); if ( m_pLoadoutComboBox ) { m_pLoadoutComboBox->AddActionSignalTarget( this ); } m_pPoseComboBox = FindControl( "PoseComboBox", true ); if ( m_pPoseComboBox ) { m_pPoseComboBox->AddActionSignalTarget( this ); } m_pActionComboBox = FindControl( "ActionComboBox", true ); if ( m_pActionComboBox ) { m_pActionComboBox->AddActionSignalTarget( this ); } m_pEffectComboBox = FindControl( "EffectComboBox", true ); if ( m_pEffectComboBox ) { m_pEffectComboBox->RemoveAll(); KeyValuesAD pKeyValues( "data" ); for ( int iEffect = 0; iEffect < C_TFPlayerPreviewEffect::NUM_PREVIEW_EFFECTS; ++iEffect ) { pKeyValues->SetInt( "effect", iEffect ); int iRow = m_pEffectComboBox->AddItem( CFmtStr( "#TF_ImportPreview_Effect%d", iEffect ), pKeyValues ); if ( g_PlayerPreviewEffect.GetEffect() == iEffect ) { m_pEffectComboBox->ActivateItemByRow( iRow ); } } m_pEffectComboBox->AddActionSignalTarget( this ); } // Default to the character view, because that's the most valuable for preview here const CTFItemDefinition *pItemData = m_item.GetItemDefinition(); if ( pItemData ) { for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ ) { if ( !pItemData->CanBeUsedByClass(iClass) ) continue; KeyValuesAD pKeyValues( "data" ); pKeyValues->SetInt( "class", iClass ); OnClassIconSelected( pKeyValues ); break; } } pButton = FindControl( "ButtonAction", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( "ButtonEditQC", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } int nSkinType = m_pItemValues->GetInt( kSkinType ); m_pMaterialButtons.SetCount( MAX_MATERIAL_COUNT ); for ( int i = 0; i < MAX_MATERIAL_COUNT; ++i ) { m_pMaterialButtons[i] = FindControl( CFmtStr( "ButtonEditMaterial%d", i ), true ); if ( m_pMaterialButtons[i] ) { int nSkinIndex = i / NUM_IMPORT_MATERIALS_PER_TEAM; int nMaterialIndex = i % NUM_IMPORT_MATERIALS_PER_TEAM; const char* pszTeam; if ( nSkinType == 0 ) { pszTeam = "ALL"; } else { pszTeam = nSkinIndex == 0 ? "RED" : "BLU"; } m_pMaterialButtons[i]->SetText( CFmtStr( "Edit VMT%d %s", nMaterialIndex + 1, pszTeam ) ); m_pMaterialButtons[i]->AddActionSignalTarget( this ); } } // Fix up the fullscreen panel with our desired control set if ( m_pFullscreenPanel ) { pButton = m_pFullscreenPanel->FindControl( "RotateLeftButton", true ); if ( pButton ) { pButton->SetVisible( false ); } pButton = m_pFullscreenPanel->FindControl( "RotateRightButton", true ); if ( pButton ) { pButton->SetVisible( false ); } pButton = m_pFullscreenPanel->FindControl( "ZoomButton", true ); if ( pButton ) { pButton->SetVisible( false ); } } pButton = FindControl( "ButtonEditQCI", true ); if ( pButton ) { pButton->SetVisible( m_bIsTaunt ); } vgui::Label *pLabel = FindControl( "AdvancedLabel", true ); if ( pLabel ) { pLabel->SetVisible( !m_bIsTaunt ); } vgui::Panel *pPanel = FindControl( "AdvancedFrame", true ); if ( pPanel ) { pPanel->SetVisible( !m_bIsTaunt ); } UpdateActivityUI(); UpdateMaterialButtons(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnCommand( const char *command ) { if ( V_strcasecmp( command, "show_explanations" ) == 0 ) { CExplanationPopup *pPopup = dynamic_cast( FindChildByName("StartExplanation") ); if ( pPopup ) { pPopup->Popup(); } } else if ( V_strcasecmp( command, "action" ) == 0 ) { StartAction(); } else if ( V_strcasecmp( command, "BuildPreview" ) == 0 || V_strcasecmp( command, "EditQC" ) == 0 || V_strcasecmp( command, "EditQCI" ) == 0 || V_strncasecmp( command, "EditMaterial", V_strlen( "EditMaterial" ) ) == 0 ) { // Dispatch directly to our parent because the base class tries to run the command through the console interpreter GetParent()->OnCommand( command ); } else { BaseClass::OnCommand( command ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnKeyCodeTyped( KeyCode code ) { if ( code == KEY_F5 ) { OnCommand( "BuildPreview" ); return; } BaseClass::OnKeyCodeTyped( code ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::PerformLayout( void ) { CTFStorePreviewItemPanel2::PerformLayout(); PlaceControl( m_pDetailsViewChild, NULL, "UsedByLabel", m_iSmallVerticalBreakSize, true ); PlaceControl( m_pDetailsViewChild, "UsedByLabel", "UsedByTextLabel", m_iHorizontalBreakSize, false ); PlaceControl( m_pDetailsViewChild, "UsedByLabel", "SlotLabel", m_iSmallVerticalBreakSize, true ); PlaceControl( m_pDetailsViewChild, "SlotLabel", "SlotTextLabel", m_iHorizontalBreakSize, false ); PlaceControl( m_pDetailsViewChild, "SlotLabel", "AttributesLabel", m_iBigVerticalBreakSize, true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnClose() { GetParent()->OnCommand( "PreviewDone" ); MarkForDeletion(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::UpdatePlayerModelButtons() { BaseClass::UpdatePlayerModelButtons(); UpdateActivityUI(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::UpdateActivityUI() { if ( m_pLODComboBox ) { m_pLODComboBox->RemoveAll(); m_pLODComboBox->SetText( "" ); Assert( m_nSelectedClass != TF_CLASS_UNDEFINED ); if ( m_iState == PS_PLAYER ) { KeyValuesAD pKeyValues( "data" ); int nDefaultRow = -1; int nLastValidLOD = 0; for ( int nLOD = 0; nLOD < NUM_IMPORT_LODS; ++nLOD ) { KeyValues *pKey = m_pItemValues->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], nLOD ) ); if ( pKey && *pKey->GetString( "file" ) ) { nLastValidLOD = nLOD; } pKeyValues->SetInt( "LOD", nLOD ); int nRow = m_pLODComboBox->AddItem( CFmtStr( "LOD%d", nLOD ), pKeyValues ); if ( m_nCurrentLOD == nLOD ) { nDefaultRow = nRow; } } Assert( nDefaultRow >= 0 ); m_pLODComboBox->ActivateItemByRow( nDefaultRow ); } } if ( m_pLoadoutComboBox ) { m_pLoadoutComboBox->RemoveAll(); m_pLoadoutComboBox->SetText( "" ); if ( m_iState == PS_PLAYER ) { KeyValuesAD pKeyValues( "data" ); int nDefaultRow = -1; loadout_positions_t nFirstLoadout = LOADOUT_POSITION_INVALID; for ( int iLoadoutPosition = 0; iLoadoutPosition < CLASS_LOADOUT_POSITION_COUNT; ++iLoadoutPosition ) { CEconItemView *pItem = TFInventoryManager()->GetBaseItemForClass( m_iCurrentClass, iLoadoutPosition ); if ( pItem && pItem->IsValid() ) { const char *pszLabel = ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pItem->GetItemDefinition()->GetEquipType() )[ iLoadoutPosition ]; pKeyValues->SetInt( "loadout", iLoadoutPosition ); int nRow = m_pLoadoutComboBox->AddItem( pszLabel, pKeyValues ); if ( iLoadoutPosition == m_nCurrentLoadout ) { nDefaultRow = nRow; } if ( nFirstLoadout == LOADOUT_POSITION_INVALID ) { nFirstLoadout = (loadout_positions_t)iLoadoutPosition; } } } Assert(nFirstLoadout != LOADOUT_POSITION_INVALID); if (nDefaultRow < 0) { // Didn't find our current loadout position, pick the first one nDefaultRow = 0; m_nCurrentLoadout = nFirstLoadout; } m_pLoadoutComboBox->ActivateItemByRow( nDefaultRow ); } } if ( m_pPoseComboBox ) { m_pPoseComboBox->RemoveAll(); m_pPoseComboBox->SetText( "" ); if ( m_iState == PS_PLAYER ) { KeyValuesAD pKeyValues( "data" ); int nDefaultRow = -1; for ( int iPose = 0; iPose < ARRAYSIZE(kModelPoses); ++iPose ) { pKeyValues->SetString( "pose", kModelPoses[ iPose ] ); int nRow = m_pPoseComboBox->AddItem( CFmtStr( "#TF_ImportPreview_Pose%s", kModelPoses[ iPose ] ), pKeyValues ); if ( m_sCurrentPose == kModelPoses[ iPose ] ) { nDefaultRow = nRow; } } Assert( nDefaultRow >= 0 ); m_pPoseComboBox->ActivateItemByRow( nDefaultRow ); } } if ( m_pActionComboBox ) { m_pActionComboBox->RemoveAll(); m_pActionComboBox->SetText( "" ); if ( m_iState == PS_PLAYER ) { KeyValuesAD pKeyValues("data"); if ( m_bIsTaunt ) { CTFFileImportDialog *pFileImportDialog = dynamic_cast(GetParent()); if (pFileImportDialog) { KeyValuesAD pItemSchema(pFileImportDialog->BuildItemSchema("item_preview")); const CUtlVector&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); KeyValues *pTauntKey = pItemSchema->FindKey("taunt"); if (pTauntKey) { KeyValues *pCustomTauntPerClass = pTauntKey->FindKey("custom_taunt_scene_per_class"); if (pCustomTauntPerClass) { const char *pSceneName = pCustomTauntPerClass->GetString(vecUsabilityStrings[m_nSelectedClass]); if (pSceneName && *pSceneName) { pKeyValues->SetString("action", pSceneName); pKeyValues->SetBool("file_name_only", false); m_pActionComboBox->AddItem("#TF_ImportPreview_Taunt", pKeyValues); } } } } } else { for (int iAction = 0; iAction < ARRAYSIZE(kModelActions); ++iAction) { pKeyValues->SetString("action", kModelActions[iAction]); pKeyValues->SetBool("file_name_only", true); m_pActionComboBox->AddItem(CFmtStr("#TF_ImportPreview_Action%d", iAction), pKeyValues); } } Assert( m_pActionComboBox->GetItemCount() >= 0 ); m_pActionComboBox->ActivateItemByRow( 0 ); // init default value KeyValues *pData = m_pActionComboBox->GetActiveItemUserData(); m_sCurrentAction = pData->GetString( "action" ); m_bIsVCDFileNameOnly = pData->GetBool( "file_name_only" ); } } UpdateActivity(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::UpdateActivity() { if ( !m_pPlayerModelPanel || !m_pPlayerModelPanel->GetStudioHdr() || m_iState != PS_PLAYER ) { return; } static CEconItemView tempItem; if ( m_bIsTaunt && ClassHasModels( m_nSelectedClass ) ) { // use preview item if specified for taunt tempItem.Init( PREVIEW_ITEM_DEFINITION_INDEX, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); } else { // FIXME: Once we support weapons we'll need to check to see if we want to display the preview item here instead. CEconItemView *pItem = TFInventoryManager()->GetBaseItemForClass( m_iCurrentClass, m_nCurrentLoadout ); Assert( pItem && pItem->IsValid() ); tempItem = *pItem; } m_pPlayerModelPanel->SwitchHeldItemTo( &tempItem ); int iSequence = GetSequence(); if ( iSequence >= 0 ) { m_pPlayerModelPanel->SetSequence( iSequence ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CImportPreviewItemPanel::GetSequence( const char *pszGesture ) { if ( !m_pPlayerModelPanel || !m_pPlayerModelPanel->GetStudioHdr() ) { return -1; } CEconItemView *pItem = m_pPlayerModelPanel->GetHeldItem(); if ( !pItem ) { return -1; } int iAnimSlot = pItem->GetAnimationSlot(); if ( iAnimSlot < 0 ) { iAnimSlot = pItem->GetItemDefinition()->GetLoadoutSlot( m_iCurrentClass ); } if ( iAnimSlot < 0 ) { return -1; } CStudioHdr studioHdr( m_pPlayerModelPanel->GetStudioHdr(), g_pMDLCache ); // Look for the bind pose by label since it's not an activity if ( !pszGesture && V_strcasecmp( m_sCurrentPose.Get(), "ref" ) == 0 ) { for ( int iSeq = 0; iSeq < studioHdr.GetNumSeq(); ++iSeq ) { mstudioseqdesc_t &seqDesc = studioHdr.pSeqdesc( iSeq ); if ( V_strcasecmp( seqDesc.pszLabel(), m_sCurrentPose.Get() ) == 0 ) { return iSeq; } } return -1; } CUtlString sActivity; const char *pszActivityOverride; CUtlString sAnimSuffix = GetItemSchema()->GetWeaponTypeSubstrings()[ iAnimSlot ]; sAnimSuffix.ToUpper(); if ( pszGesture ) { CUtlString sGesture = pszGesture; sGesture.ToUpper(); sActivity.Format( "ACT_MP_%s_%s_%s", sGesture.Get(), m_sCurrentPose.Get(), sAnimSuffix.Get() ); } else { sActivity.Format( "ACT_MP_%s_%s", m_sCurrentPose.Get(), sAnimSuffix.Get() ); } pszActivityOverride = pItem->GetItemDefinition()->GetActivityOverride( GetPreviewTeam(), sActivity ); if ( pszActivityOverride ) { sActivity = pszActivityOverride; } return m_pPlayerModelPanel->FindSequenceFromActivity( &studioHdr, sActivity.Get() ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::UpdateMaterialButtons() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) return; KeyValues* pModelKey = m_pItemValues->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], 0 ) ); if ( !pModelKey) return; int nSkinType = m_pItemValues->GetInt( kSkinType ); int nMaterialCount = pModelKey->GetInt( "materialCount" ); for ( int i=0; iSetVisible( bVisible ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::StartAction() { const char *pszAction = m_sCurrentAction.String(); if ( !pszAction || !*pszAction ) { return; } if ( !m_pPlayerModelPanel ) { return; } if ( V_strncasecmp( pszAction, "gesture_", 8 ) == 0 ) { pszAction += 8; StartGesture( pszAction ); } else { m_pPlayerModelPanel->PlayVCD( pszAction, NULL, false, m_bIsVCDFileNameOnly ); UpdateActivity(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::StartGesture( const char *pszGesture ) { int iSequence = GetSequence( pszGesture ); if ( iSequence >= 0 ) { CStudioHdr studioHdr( m_pPlayerModelPanel->GetStudioHdr(), g_pMDLCache ); MDLSquenceLayer_t tmpSequenceLayers[1]; tmpSequenceLayers[0].m_nSequenceIndex = iSequence; tmpSequenceLayers[0].m_flWeight = 1.0; tmpSequenceLayers[0].m_bNoLoop = true; tmpSequenceLayers[0].m_flCycleBeganAt = 0.0f; m_pPlayerModelPanel->SetSequenceLayers( tmpSequenceLayers, 1 ); float flGestureDuration = Studio_Duration( &studioHdr, iSequence, NULL ); m_flGestureEndTime = gpGlobals->curtime + flGestureDuration; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::EndGestures() { Assert(m_pPlayerModelPanel); m_pPlayerModelPanel->SetSequenceLayers( NULL, 0 ); m_flGestureEndTime = 0.0f; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnTextChanged( KeyValues *data ) { Panel *pPanel = reinterpret_cast( data->GetPtr( "panel" ) ); vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); if ( pComboBox ) { if( pComboBox == m_pLODComboBox ) { KeyValues *pData = pComboBox->GetActiveItemUserData(); int nLOD = pData->GetInt( "LOD" ); if ( nLOD != m_nCurrentLOD ) { m_nCurrentLOD = nLOD; if ( m_pPlayerModelPanel ) { m_pPlayerModelPanel->SetLOD( m_nCurrentLOD ); } } } else if( pComboBox == m_pLoadoutComboBox ) { KeyValues *pData = pComboBox->GetActiveItemUserData(); loadout_positions_t nLoadout = (loadout_positions_t)pData->GetInt( "loadout" ); if ( nLoadout != m_nCurrentLoadout ) { m_nCurrentLoadout = nLoadout; UpdateActivity(); } } else if ( pComboBox == m_pPoseComboBox ) { KeyValues *pData = pComboBox->GetActiveItemUserData(); const char *pszPose = pData->GetString( "pose" ); if ( V_strcmp( pszPose, m_sCurrentPose ) != 0 ) { m_sCurrentPose = pszPose; UpdateActivity(); // Changing pose resets the camera ResetCamera(); } } else if ( pComboBox == m_pActionComboBox ) { KeyValues *pData = pComboBox->GetActiveItemUserData(); m_sCurrentAction = pData->GetString( "action" ); m_bIsVCDFileNameOnly = pData->GetBool( "file_name_only" ); } else if ( pComboBox == m_pEffectComboBox ) { KeyValues *pData = pComboBox->GetActiveItemUserData(); g_PlayerPreviewEffect.SetEffect( (C_TFPlayerPreviewEffect::PREVIEW_EFFECT)pData->GetInt("effect") ); } return; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::ResetCamera() { if ( m_pPlayerModelPanel ) { m_pPlayerModelPanel->SetForcedCameraPosition( false ); m_pPlayerModelPanel->InvalidateLayout( true, true ); m_pPlayerModelPanel->SetForcedCameraPosition( true ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CImportPreviewItemPanel::OnClassIconSelected( KeyValues *data ) { BaseClass::OnClassIconSelected( data ); m_nSelectedClass = data->GetInt( "class" ); // Clicking on a class icon resets the camera ResetCamera(); UpdateMaterialButtons(); } //----------------------------------------------------------------------------- // Purpose: Import file dialog //----------------------------------------------------------------------------- CTFFileImportDialog::CTFFileImportDialog( vgui::Panel *parent ) : Frame( parent, "ImportFileDialog" ), m_tempQC( 0, 0, CUtlBuffer::TEXT_BUFFER ) { vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); SetScheme(scheme); SetProportional( true ); m_nSelectedClass = TF_CLASS_UNDEFINED; m_nFileOpenMode = FILE_OPEN_NONE; m_pItemValues = new KeyValues( "ImportSession" ); m_pItemValues->UsesEscapeSequences( true ); m_pPreviewSchema = NULL; m_pNameTextEntry = NULL; m_pTypeComboBox = NULL; m_pSwapVMTButton = NULL; m_pSkinComboBox = NULL; m_pWorkshopIDTextEntry = NULL; m_pTFEnglishNameTextEntry = NULL; m_pPerforceCheckButton = NULL; m_pPartnerCheckButton = NULL; m_pEquipRegionPanel = NULL; m_pEquipRegionComboBox = NULL; m_pIconImagePanel = NULL; V_memset( m_pClassRadioButtons, 0, sizeof( m_pClassRadioButtons ) ); V_memset( m_pClassHighlights, 0, sizeof( m_pClassHighlights ) ); m_pBodygroupsPanel = NULL; m_pLODsPanel = NULL; m_pSkinsPanel = NULL; m_pTauntInputPanel = NULL; m_pAnimationSourceFile = NULL; m_pAnimationVCDFile = NULL; m_pAnimationDurationLabel = NULL; m_pAnimationPropLabel = NULL; m_pAnimationLoopCheckButton = NULL; m_pAnimationLoopStartTextEntry = NULL; m_pBuildButton = NULL; m_pTextEditDialog = NULL; m_pMaterialEditDialog = NULL; m_pPreviewDialog = NULL; m_pPlayerModelPanel = NULL; // force sv_cheats 1 so we can run some client command static ConVarRef sv_cheats("sv_cheats"); if ( sv_cheats.IsValid() ) { m_bWasCheatOn = sv_cheats.GetBool(); sv_cheats.SetValue( true ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::~CTFFileImportDialog() { m_pItemValues->deleteThis(); if ( m_pPreviewSchema ) { m_pPreviewSchema->deleteThis(); } // restore sv_cheats value before coming into the tool static ConVarRef sv_cheats("sv_cheats"); if ( sv_cheats.IsValid() ) { sv_cheats.SetValue( m_bWasCheatOn ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) { vgui::Button *pButton; BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "Resource/UI/ImportFileDialog.res" ); m_pNameTextEntry = FindControl( "Name" ); if ( m_pNameTextEntry ) { m_pNameTextEntry->AddActionSignalTarget( this ); } m_pTypeComboBox = FindControl( "TypeComboBox" ); if ( m_pTypeComboBox ) { m_pTypeComboBox->RemoveAll(); KeyValuesAD pKeyValues( "data" ); // Add all the public prefabs const CEconItemSchema::PrefabMap_t &prefabMap = ItemSystem()->GetItemSchema()->GetPrefabMap(); for ( int i = prefabMap.FirstInorder(); i != prefabMap.InvalidIndex(); i = prefabMap.NextInorder( i ) ) { KeyValues *pPrefabKeyValues = prefabMap [ i ]; if ( pPrefabKeyValues->GetBool( "public_prefab" ) ) { for ( int j=0; jGetName() ) == 0 ) { pKeyValues->SetString( kItemPrefab, pPrefabKeyValues->GetName() ); m_pTypeComboBox->AddItem( CFmtStr( "#TF_ItemPrefab_%s", pPrefabKeyValues->GetName() ), pKeyValues ); } } } } SetItemPrefab( kDefaultPrefab ); m_pTypeComboBox->AddActionSignalTarget( this ); } m_pEquipRegionPanel = FindControl( "EquipRegionPanel" ); m_pEquipRegionComboBox = FindControl( "EquipRegionComboBox", true ); if ( m_pEquipRegionComboBox ) { KeyValuesAD pKey( "data" ); const CEconItemSchema::EquipRegionsList_t& list = ItemSystem()->GetItemSchema()->GetEquipRegionsList(); CUtlStringList strEquipRegionNameList; for ( int j=0; jSetString( kEquipRegion, pszEquipRegion ); m_pEquipRegionComboBox->AddItem( pszEquipRegion, pKey ); } SetEquipRegion( kDefaultEquipRegion ); m_pEquipRegionComboBox->AddActionSignalTarget( this ); } if ( vgui::Label* pLabel = FindControl( "WorkshopIDLabel" ) ) { pLabel->SetVisible( p4 ); } m_pWorkshopIDTextEntry = FindControl( "WorkshopIDTextEntry" ); if ( m_pWorkshopIDTextEntry ) { m_pWorkshopIDTextEntry->SetVisible( p4 ); } if ( vgui::Label* pLabel = FindControl( "TFEnglishNameLabel" ) ) { pLabel->SetVisible( p4 ); } m_pTFEnglishNameTextEntry = FindControl( "TFEnglishNameTextEntry" ); if ( m_pTFEnglishNameTextEntry ) { m_pTFEnglishNameTextEntry->SetVisible( p4 ); } m_pPerforceCheckButton = FindControl( "PerforceCheckButton" ); if ( m_pPerforceCheckButton ) { m_pPerforceCheckButton->SetVisible( p4 ); } m_pPartnerCheckButton = FindControl( "PartnerCheckButton" ); if ( m_pPartnerCheckButton ) { m_pPartnerCheckButton->SetVisible( p4 ); } m_pIconImagePanel = FindControl( "Icon", true ); if ( m_pIconImagePanel ) { // Set black background, and center the 512x512 backpack icon m_pIconImagePanel->SetFillColor( Color(0, 0, 0, 255) ); } pButton = FindControl( "ButtonIconClear", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( "ButtonIconBrowse", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } m_pPaintableCheckButtons.SetCount( 2 ); for ( int i=0; i( CFmtStr( "Paintable%dCheckBox", i ), true ); if ( m_pPaintableCheckButtons[i] ) { m_pPaintableCheckButtons[i]->AddActionSignalTarget( this ); } } for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; ++i ) { m_pClassHighlights[ i ] = FindControl( CFmtStr( "ClassHighlight%d", i ), true ); m_pClassRadioButtons[i] = FindControl( CFmtStr( "ButtonSelectClass%d", i ), true ); if ( m_pClassRadioButtons[i] ) m_pClassRadioButtons[i]->AddActionSignalTarget( this ); } m_pBodygroupsPanel = FindControl( "BodygroupsPanel" ); m_pBodygroups.SetCount( ARRAYSIZE( kBodygroupArray ) ); for ( int i=0; i( CFmtStr( "Bodygroup%d", i ), true ); AssertMsg( m_pBodygroups[i], CFmtStr( "Missing Bodygroup%d CheckButton in ImportFileDialog.res", i ) ); if ( m_pBodygroups[i] ) { m_pBodygroups[i]->AddActionSignalTarget( this ); m_pBodygroups[i]->SetSelected( true ); m_pBodygroups[i]->SetCheckButtonCheckable( false ); m_pBodygroups[i]->SetText( kBodygroupArray[i] ); } } m_pLODsPanel = FindControl( "LODsPanel" ); m_pLODPanels.SetCount( NUM_IMPORT_LODS ); m_pLODFiles.SetCount( NUM_IMPORT_LODS ); m_pLODDetails.SetCount( NUM_IMPORT_LODS ); for ( int i = 0; i < NUM_IMPORT_LODS; ++i ) { m_pLODPanels[ i ] = FindControl( CFmtStr( "LOD%dPanel", i ), true ); m_pLODFiles[ i ] = FindControl( CFmtStr( "LOD%dFile", i ), true ); m_pLODDetails[ i ] = FindControl( CFmtStr( "LOD%dDetails", i ), true ); pButton = FindControl( CFmtStr( "ButtonLOD%dBrowse", i ), true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( CFmtStr( "ButtonLOD%dClear", i ), true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } } pButton = FindControl( "ButtonEditQC", true ); if (pButton) { pButton->AddActionSignalTarget(this); } m_pSkinsPanel = FindControl( "SkinsPanel" ); m_pSwapVMTButton = FindControl( "SwapVMTButton", true ); if ( m_pSwapVMTButton ) { m_pSwapVMTButton->AddActionSignalTarget( this ); } m_pSkinComboBox = FindControl( "SkinComboBox", true ); if ( m_pSkinComboBox ) { m_pSkinComboBox->RemoveAll(); KeyValuesAD pKeyValues( "data" ); for ( int j=0; jSetInt( kSkinType, j ); m_pSkinComboBox->AddItem( CFmtStr( "#TF_ItemSkinType_%d", j ), pKeyValues ); } m_pSkinComboBox->ActivateItemByRow( 0 ); m_pSkinComboBox->AddActionSignalTarget( this ); } m_pMaterialPanels.SetCount( MAX_MATERIAL_COUNT ); m_pMaterialLabels.SetCount( MAX_MATERIAL_COUNT ); m_pMaterialFiles.SetCount( MAX_MATERIAL_COUNT ); for ( int i = 0; i < MAX_MATERIAL_COUNT; ++i ) { m_pMaterialPanels[ i ] = FindControl( CFmtStr( "Material%dPanel", i ), true ); m_pMaterialLabels[ i ] = FindControl( CFmtStr( "Material%dLabel", i ), true ); m_pMaterialFiles[ i ] = FindControl( CFmtStr( "Material%dFile", i ), true ); pButton = FindControl( CFmtStr( "ButtonMaterial%dEdit", i ), true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( CFmtStr( "ButtonMaterial%dBrowse", i ), true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( CFmtStr( "ButtonMaterial%dClear", i ), true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } } m_pTauntInputPanel = FindControl( "TauntInputPanel" ); if ( m_pTauntInputPanel ) { m_pAnimationSourceFile = FindControl( "AnimationSourceFile", true ); pButton = FindControl( "ButtonAnimationSourceBrowse", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( "ButtonAnimationSourceClear", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } m_pAnimationVCDFile = FindControl( "AnimationVCDFile", true ); pButton = FindControl( "ButtonAnimationVCDBrowse", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } pButton = FindControl( "ButtonAnimationVCDClear", true ); if ( pButton ) { pButton->AddActionSignalTarget( this ); } m_pAnimationDurationLabel = FindControl( "AnimDurationLabel", true ); m_pAnimationLoopCheckButton = FindControl( "AnimationLoopCheckButton", true ); if ( m_pAnimationLoopCheckButton ) { m_pAnimationLoopCheckButton->AddActionSignalTarget( this ); } m_pAnimationLoopStartTextEntry = FindControl( "AnimationLoopStartTextEntry", true ); if ( m_pAnimationLoopStartTextEntry ) { m_pAnimationLoopStartTextEntry->AddActionSignalTarget( this ); } pButton = FindControl( "ButtonEditQCI", true ); if (pButton) { pButton->AddActionSignalTarget(this); } } m_pAnimationPropLabel = FindControl( "AnimationPropLabel" ); m_pBuildButton = FindControl( "ButtonBuild" ); if ( m_pBuildButton ) { m_pBuildButton->SetEnabled( false ); } m_pPlayerModelPanel = dynamic_cast( FindChildByName("classmodelpanel") ); OnOpen(); UpdateMaterialDisplay(); UpdateBodygroupsDisplay(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommand( const char *command ) { if ( V_stricmp( command, "Load" ) == 0 ) { OnCommandLoad(); } else if ( V_stricmp( command, "Save" ) == 0 ) { OnCommandSave(); } else if ( V_stricmp( command, "ClearIcon" ) == 0 ) { SetItemIcon( "" ); } else if ( V_stricmp( command, "BrowseIcon" ) == 0 ) { OnCommandBrowseIcon(); } else if ( V_stricmp( command, "UpdateBodygroup" ) == 0 ) { OnCommandUpdateBodygroup(); } else if ( V_strncasecmp( command, "UpdatePaintable", V_strlen( "UpdatePaintable" ) ) == 0 ) { int nMaterialIndex = V_atoi( &command[ V_strlen( "UpdatePaintable" ) ] ); SetPaintable( m_pPaintableCheckButtons[nMaterialIndex]->IsSelected(), nMaterialIndex ); } else if ( V_strncasecmp( command, "ClearLOD", V_strlen( "ClearLOD" ) ) == 0 ) { int index = V_atoi( &command[ V_strlen( "ClearLOD" ) ] ); SetLOD( m_nSelectedClass, index, "" ); } else if ( V_strncasecmp( command, "BrowseLOD", V_strlen( "BrowseLOD" ) ) == 0 ) { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); return; } int index = V_atoi( &command[ V_strlen( "BrowseLOD" ) ] ); OnCommandBrowseLOD( index ); } else if ( V_stricmp( command, "SwapVMT" ) == 0 ) { OnCommandSwapVMT(); } else if ( V_strncasecmp( command, "EditMaterialDone", V_strlen( "EditMaterialDone" ) ) == 0 ) { int nSkinIndex, nMaterialIndex; if ( sscanf( command + V_strlen( "EditMaterialDone" ), "%d,%d", &nSkinIndex, &nMaterialIndex ) == 2 ) { OnCommandEditMaterialDone( nSkinIndex, nMaterialIndex ); } } else if ( V_strncasecmp( command, "EditMaterial", V_strlen( "EditMaterial" ) ) == 0 ) { int nMaterialPanelIndex; if ( sscanf( command + V_strlen( "EditMaterial" ), "%d", &nMaterialPanelIndex ) == 1 ) { int nSkinIndex = nMaterialPanelIndex / NUM_IMPORT_MATERIALS_PER_TEAM; int nMaterialIndex = nMaterialPanelIndex % NUM_IMPORT_MATERIALS_PER_TEAM; OnCommandEditMaterial( nSkinIndex, nMaterialIndex ); } } else if ( V_stricmp( command, "UpdateAnimationLoopable" ) == 0 ) { SetLoopableTaunt( IsLoopableTaunt(), GetAnimationLoopStartTime() ); } else if ( V_stricmp( command, "ClearAnimationSource" ) == 0 ) { SetAnimationSource( m_nSelectedClass, NULL ); } else if ( V_stricmp( command, "ClearAnimationVCD" ) == 0 ) { SetAnimationVCD( m_nSelectedClass, NULL ); } else if ( V_stricmp( command, "BrowseAnimationSource" ) == 0 ) { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); return; } OnCommandBrowseAnimationSource(); } else if ( V_stricmp( command, "BrowseAnimationVCD" ) == 0 ) { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); return; } OnCommandBrowseAnimationVCD(); } else if ( V_stricmp( command, "EditQC" ) == 0 ) { OnCommandEditQC(); } else if ( V_stricmp( command, "EditQCI") == 0 ) { OnCommandEditQCI(); } else if ( V_stricmp( command, "EditQCDone" ) == 0 ) { OnCommandEditQCDone(); } else if ( V_stricmp( command, "EditQCIDone" ) == 0 ) { OnCommandEditQCIDone(); } else if ( V_stricmp( command, "BuildPreview" ) == 0 ) { OnCommandBuild( BUILD_PREVIEW ); } else if ( V_stricmp( command, "BuildVerify") == 0 ) { OnCommandBuild( BUILD_VERIFY ); } else if ( V_stricmp( command, "BuildFinal" ) == 0 ) { OnCommandBuild( BUILD_FINAL ); } else if ( V_stricmp( command, "PreviewDone" ) == 0 ) { CleanupPreviewData(); } else { BaseClass::OnCommand( command ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandLoad() { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectFile", vgui::FOD_OPEN ); pDialog->AddFilter( "*.txt,*.zip", "#TF_ImportFile_LoadSessionFileType", true); pDialog->AddActionSignalTarget( this ); char pszStartPath[ MAX_PATH ]; if ( g_pFullFileSystem->RelativePathToFullPath_safe( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), "GAME", pszStartPath ) ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = FILE_OPEN_LOAD; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandSave() { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectFile", vgui::FOD_SAVE ); pDialog->AddFilter( "*.txt", "#TF_ImportFile_SaveSessionFileType", true); pDialog->AddActionSignalTarget( this ); char pszStartPath[ MAX_PATH ]; if ( g_pFullFileSystem->RelativePathToFullPath_safe( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), "GAME", pszStartPath ) ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = FILE_OPEN_SAVE; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandBrowseIcon() { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectImage", vgui::FOD_OPEN ); pDialog->AddFilter( "*.tga,*.psd", "#TF_ImportFile_IconFileType", true); pDialog->AddActionSignalTarget( this ); const char *pszStartPath = tf_steam_workshop_import_icon_path.GetString(); if ( pszStartPath && *pszStartPath ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = FILE_OPEN_ICON; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandBrowseLOD( int index ) { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectModel", vgui::FOD_OPEN ); pDialog->AddFilter( "*.smd,*.dmx,*.fbx", "#TF_ImportFile_ModelFileType", true); pDialog->AddActionSignalTarget( this ); const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); if ( pszStartPath && *pszStartPath ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = static_cast( FILE_OPEN_LOD0 + index ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandBrowseAnimationSource() { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectAnimationSource", vgui::FOD_OPEN ); pDialog->AddFilter( "*.smd,*.dmx,*.fbx", "#TF_ImportFile_AnimationSourceFileType", true); pDialog->AddActionSignalTarget( this ); const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); if ( pszStartPath && *pszStartPath ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = static_cast( FILE_OPEN_ANIMATION_SOURCE ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandBrowseAnimationVCD() { vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectAnimationVCD", vgui::FOD_OPEN ); pDialog->AddFilter( "*.vcd", "#TF_ImportFile_AnimationVCDFileType", true); pDialog->AddActionSignalTarget( this ); const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); if ( pszStartPath && *pszStartPath ) { pDialog->SetStartDirectory( pszStartPath ); } pDialog->DoModal(); pDialog->Activate(); m_nFileOpenMode = static_cast( FILE_OPEN_ANIMATION_VCD ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandSwapVMT() { bool bSwapPaint = false; for ( int nSkin=0; nSkinGetNumMaterialSkins(); ++nSkin ) { KeyValues *pVMT0 = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), 0 ) ); KeyValues *pVMT1 = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), 1 ) ); if ( pVMT0 && pVMT1 ) { KeyValuesAD pTemp( pVMT0->MakeCopy() ); pVMT0->Clear(); pVMT1->CopySubkeys( pVMT0 ); pVMT1->Clear(); pTemp->CopySubkeys( pVMT1 ); if ( !bSwapPaint ) { bool bPaintable0 = IsPaintable( 0 ); bool bPaintable1 = IsPaintable( 1 ); SetPaintable( bPaintable1, 0 ); SetPaintable( bPaintable0, 1 ); bSwapPaint = true; } } } UpdateMaterialDisplay(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditMaterial( int nSkinIndex, int nMaterialIndex ) { CTFImportMaterialEditDialog *pDialog = new CTFImportMaterialEditDialog( this, nSkinIndex, nMaterialIndex, GetItemValues() ); pDialog->InvalidateLayout( true, true ); CUtlBuffer sRedMaterialText, sBlueMaterialText; pDialog->SetVMTKeyValues( GetMaterialText( 0, nMaterialIndex, sRedMaterialText ), GetMaterialText( 1, nMaterialIndex, sBlueMaterialText ) ); pDialog->DoModal(); pDialog->Activate(); m_pMaterialEditDialog = pDialog; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditMaterialDone( int nSkinIndex, int nMaterialIndex ) { if ( !m_pMaterialEditDialog ) { return; } CUtlStringList oldMaterials; CUtlStringList oldBaseTextures; CUtlStringList oldNormalTextures; CUtlStringList oldPhongExponentTextures; CUtlStringList oldSelfIllumTextures; bool bAllTeam = m_pItemValues->GetInt( kSkinType ) == 0; const int nNumSkin = bAllTeam ? 1 : CItemUpload::Manifest()->GetNumMaterialSkins(); for ( int nSkin=0; nSkin < nNumSkin; ++nSkin ) { KeyValuesAD pKV( m_pMaterialEditDialog->GetVMTKeyValues( nSkin )->MakeCopy() ); BUILD_RESULT nResult = ValidateMaterialValues( pKV, nMaterialIndex ); if ( nResult != BUILD_OKAY ) { ShowMessageBoxWithFile( "#TF_SteamWorkshop_Error", kBuildResultMessages[ nResult ], CFmtStr( "VMT%d", 1 + nMaterialIndex ) ); return; } CUtlBuffer sOldText; GetMaterialText( nSkin, nMaterialIndex, sOldText ); oldMaterials.CopyAndAddToTail( sOldText.String() ); oldBaseTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ) ); oldNormalTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_NORMAL ) ); oldPhongExponentTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_PHONGEXPONENT ) ); oldSelfIllumTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_SELFILLUM ) ); // set new material text CUtlBuffer sNewText; sNewText.SetBufferType( true, true ); pKV->RecursiveSaveToFile( sNewText, 0, false, true ); sNewText.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); SetMaterialText( nSkin, nMaterialIndex, sNewText.String() ); // set new textures SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetBaseTextureFile( nSkin ), MATERIAL_FILE_BASETEXTURE ); SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetNormalTextureFile(), MATERIAL_FILE_NORMAL ); SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetPhongExponentTextureFile(), MATERIAL_FILE_PHONGEXPONENT ); SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetSelfIllumTextureFile(), MATERIAL_FILE_SELFILLUM ); } if ( m_pPreviewDialog ) { // Refresh the preview and see if everything builds correctly if ( !OnCommandBuild( BUILD_PREVIEW ) ) { for ( int nSkin=0; nSkinOnCommand( "Close" ); m_pMaterialEditDialog.Set(INVALID_PANEL); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditQC() { // The QC template is dependent on the item type, so make sure that's set first if ( V_strcmp( GetItemPrefab(), "" ) == 0 ) { ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoType" ); return; } if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); return; } CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog( this, "#TF_ImportFile_EditQC", "EditQCDone" ); pDialog->SetText( GetQCTemplate( m_nSelectedClass ) ); pDialog->DoModal(); pDialog->Activate(); m_pTextEditDialog = pDialog; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditQCI() { // The QC template is dependent on the item type, so make sure that's set first if ( V_strcmp(GetItemPrefab(), "") == 0 ) { ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoType" ); return; } if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); return; } CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog(this, "#TF_ImportFile_EditQCI", "EditQCIDone"); pDialog->SetText( GetQCITemplate( m_nSelectedClass ) ); pDialog->DoModal(); pDialog->Activate(); m_pTextEditDialog = pDialog; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditQCDone() { if ( !m_pTextEditDialog ) { return; } char pszText[MAX_TEXT_EDIT_SIZE]; m_pTextEditDialog->GetText( pszText, sizeof(pszText) ); static const char *pszRequiredText[] = { "", "", "", }; for ( int i = 0; i < ARRAYSIZE(pszRequiredText); ++i ) { if ( !V_strstr( pszText, pszRequiredText[i] ) ) { KeyValuesAD pData( "Data" ); pData->SetString( "text", pszRequiredText[i] ); ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_QCMissingText", pData ); return; } } static const char *pszUnsupportedText[] = { "$keyvalues", }; for ( int i = 0; i < ARRAYSIZE(pszUnsupportedText); ++i ) { if ( V_strstr( pszText, pszUnsupportedText[i] ) ) { KeyValuesAD pData( "Data" ); pData->SetString( "text", pszUnsupportedText[i] ); ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_QCUnsupportedText", pData ); return; } } const char* pszQCKeyName = CFmtStr( kClassQC, kClassFolders[ m_nSelectedClass ] ); CUtlString sOldText = GetItemValues()->GetString( pszQCKeyName ); GetItemValues()->SetString( pszQCKeyName, pszText ); if ( m_pPreviewDialog ) { // Refresh the preview and see if everything builds correctly if ( !OnCommandBuild( BUILD_PREVIEW ) ) { GetItemValues()->SetString( pszQCKeyName, sOldText ); return; } } m_pTextEditDialog->OnCommand( "Close" ); m_pTextEditDialog.Set(INVALID_PANEL); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandEditQCIDone() { if ( !m_pTextEditDialog ) { return; } char pszText[MAX_TEXT_EDIT_SIZE]; m_pTextEditDialog->GetText( pszText, sizeof(pszText) ); const char* pszQCKeyName = CFmtStr( kClassQCI, kClassFolders[ m_nSelectedClass ] ); CUtlString sOldText = GetItemValues()->GetString( pszQCKeyName ); GetItemValues()->SetString( pszQCKeyName, pszText ); if ( m_pPreviewDialog ) { // Refresh the preview and see if everything builds correctly if ( !OnCommandBuild( BUILD_PREVIEW ) ) { GetItemValues()->SetString( pszQCKeyName, sOldText ); return; } } m_pTextEditDialog->OnCommand( "Close" ); m_pTextEditDialog.Set(INVALID_PANEL); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::OnCommandBuild( BUILD_STAGE buildStage ) { KeyValuesAD pBuildMessageVariables( "data" ); // this can take a while, put up a waiting cursor vgui::surface()->SetCursor( vgui::dc_hourglass ); // Set up Perforce integration CItemUpload::SetP4( ShouldP4AddOrEdit() ); if ( CItemUpload::GetP4() ) { CUtlString sChangeList( "imported - " ); sChangeList += GetItemName(); g_p4factory->SetOpenFileChangeList( NULL ); g_p4factory->SetOpenFileChangeList( sChangeList.String() ); } BUILD_RESULT nResult = Build( buildStage, pBuildMessageVariables ); if ( CItemUpload::GetP4() ) { g_p4factory->SetOpenFileChangeList( NULL ); } // change the cursor back to normal vgui::surface()->SetCursor( vgui::dc_user ); if ( nResult == BUILD_OKAY ) { switch ( buildStage ) { case BUILD_PREVIEW: { if ( !SetupPreviewData() ) { ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_PreviewFailed" ); return false; } m_pPreviewDialog->SetVisible( true ); } break; case BUILD_VERIFY: { SetDirty( false ); } break; case BUILD_FINAL: { const char *pszBuildOutput = V_GetFileName( GetItemValues()->GetString( kBuildOutput ) ); ShowMessageBoxWithFile( "#TF_ImportFile_ImportCompleteTitle", "#TF_ImportFile_ImportComplete", pszBuildOutput ); SetWorkshopData(); BaseClass::OnCommand( "Close" ); } break; default: Assert( 0 ); } return true; } // The build failed. SetDirty( true ); if ( nResult == BUILD_FAILED_COMPILE ) { CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog( this, "#TF_ImportFile_BuildFailed" ); pDialog->HideCancelButton(); pDialog->SetText( pBuildMessageVariables->GetString( "log" ) ); pDialog->DoModal(); pDialog->Activate(); } else { ShowMessageBox( "#TF_ImportFile_BuildFailed", kBuildResultMessages[ nResult ], pBuildMessageVariables ); } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnCommandUpdateBodygroup() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { return; } KeyValuesAD pBodygroupKey( kBodygroup ); for ( int i=0; iIsSelected() ) { pBodygroupKey->SetBool( kBodygroupArray[i], true ); } } SetBodygroup( pBodygroupKey ); SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnOpen() { // Make sure our workshop directory exists const char *pszWorkshopDir = CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ); g_pFullFileSystem->CreateDirHierarchy( pszWorkshopDir, "GAME" ); GetWorkshopData(); if ( !CheckSourceSDK() ) { ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoSDK" ); } CUtlString sName; if ( CItemUpload::SanitizeName( GetItemName(), sName ) ) { char pszSessionPath[ MAX_PATH ]; V_ComposeFileName( pszWorkshopDir, CFmtStr( "%s.txt", sName.Get() ), pszSessionPath, sizeof(pszSessionPath) ); CUtlString sFailedPath; LOAD_RESULT nResult = Load( pszSessionPath, "GAME", sFailedPath ); // We ignore a general load failed since it's okay if the file is missing, but if some of the internal // data is missing from a valid session we want to let the user know. if ( nResult == LOAD_FAILED_BADMODEL || nResult == LOAD_FAILED_BADMATERIAL ) { ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ nResult ], sFailedPath ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnClose() { CleanupPreviewData(); CUtlString sName; if ( CItemUpload::SanitizeName( GetItemName(), sName ) ) { char pszSessionPath[ MAX_PATH ]; V_ComposeFileName( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), CFmtStr( "%s.txt", sName.Get() ), pszSessionPath, sizeof(pszSessionPath) ); SAVE_RESULT nResult = Save( pszSessionPath, "GAME" ); if ( nResult != SAVE_OKAY ) { ShowMessageBoxWithFile( "#TF_ImportFile_SaveFailed", kSaveResultMessages[ nResult ], pszSessionPath ); } } BaseClass::OnClose(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnTextChanged( KeyValues *data ) { Panel *pPanel = reinterpret_cast( data->GetPtr( "panel" ) ); vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); if ( pComboBox ) { if( pComboBox == m_pTypeComboBox ) { KeyValues *pData = m_pTypeComboBox->GetActiveItemUserData(); SetItemPrefab( pData->GetString( kItemPrefab ) ); } else if ( pComboBox == m_pSkinComboBox ) { KeyValues *pData = m_pSkinComboBox->GetActiveItemUserData(); SetSkinType( pData->GetInt( kSkinType ) ); } else if ( pComboBox == m_pEquipRegionComboBox ) { KeyValues *pData = m_pEquipRegionComboBox->GetActiveItemUserData(); SetEquipRegion( pData->GetString( kEquipRegion ) ); } return; } vgui::TextEntry *pTextEntry = dynamic_cast< vgui::TextEntry * >( pPanel ); if ( pTextEntry ) { if ( pTextEntry == m_pNameTextEntry ) { char name[256]; m_pNameTextEntry->GetText( name, sizeof(name) ); GetItemValues()->SetString( kItemName, name ); } else if ( pTextEntry == m_pWorkshopIDTextEntry ) { char szID[256]; m_pWorkshopIDTextEntry->GetText( szID, ARRAYSIZE( szID ) ); GetItemValues()->SetString( kWorkshopID, szID ); } else if ( pTextEntry == m_pTFEnglishNameTextEntry ) { char name[256]; m_pTFEnglishNameTextEntry->GetText( name, sizeof(name) ); GetItemValues()->SetString( kTFEnglishName, name ); } else if ( pTextEntry == m_pAnimationLoopStartTextEntry ) { const float flAnimationLoopStartTime = m_pAnimationLoopStartTextEntry->GetValueAsFloat(); GetItemValues()->SetFloat( kAnimationLoopable, flAnimationLoopStartTime ); } return; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnFileSelected( char const *fullpath ) { switch ( m_nFileOpenMode ) { case FILE_OPEN_LOAD: { CUtlString sFailedPath; LOAD_RESULT nResult = Load( fullpath, NULL, sFailedPath ); if ( nResult != LOAD_OKAY ) { ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ nResult ], sFailedPath ); } } break; case FILE_OPEN_SAVE: { SAVE_RESULT nResult = Save( fullpath, NULL ); if ( nResult != SAVE_OKAY ) { ShowMessageBoxWithFile( "#TF_ImportFile_SaveFailed", kSaveResultMessages[ nResult ], fullpath ); } } break; case FILE_OPEN_ICON: { SetItemIcon( fullpath ); SaveBrowsePath( tf_steam_workshop_import_icon_path, fullpath ); } break; case FILE_OPEN_LOD0: case FILE_OPEN_LOD1: case FILE_OPEN_LOD2: { KeyValuesAD pKV( "data" ); LOAD_RESULT result = SetLOD( m_nSelectedClass, (m_nFileOpenMode - FILE_OPEN_LOD0), fullpath, pKV ); if ( result != LOAD_OKAY ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); } SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); } break; case FILE_OPEN_ANIMATION_SOURCE: { KeyValuesAD pKV( "data" ); LOAD_RESULT result = SetAnimationSource( m_nSelectedClass, fullpath, pKV ); if ( result != LOAD_OKAY ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); } SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); } break; case FILE_OPEN_ANIMATION_VCD: { KeyValuesAD pKV( "data" ); LOAD_RESULT result = SetAnimationVCD( m_nSelectedClass, fullpath, pKV ); if ( result != LOAD_OKAY ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); } SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); } break; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::OnRadioButtonChecked( Panel *panel ) { int i; for ( i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; ++i ) { if ( panel == m_pClassRadioButtons[i] ) { SelectClass( i ); return; } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetItemName( const char *pszName ) { if ( m_pNameTextEntry ) { m_pNameTextEntry->SetText( pszName ); } GetItemValues()->SetString( kItemName, pszName ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetItemName() { const char *pszName = GetItemValues()->GetString( kItemName ); // Skip "The " if someone put it into the item name const char *kSkip = "The "; if ( V_strncasecmp(pszName, kSkip, V_strlen( kSkip ) ) == 0 ) { pszName += V_strlen( kSkip ); } return pszName; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsValidPrefab( const char *pszPrefab ) { KeyValues *pPrefab = ItemSystem()->GetItemSchema()->FindDefinitionPrefabByName( GetItemPrefab() ); return pPrefab && pPrefab->GetBool( "public_prefab" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetItemPrefab( const char *pszPrefab ) { if ( m_pTypeComboBox ) { ImportPrefab_t nOldPrefab = m_nPrefab; bool bFound = false; for ( int i = 0; i < m_pTypeComboBox->GetItemCount(); ++i ) { KeyValues *pKeyValues = m_pTypeComboBox->GetItemUserData( m_pTypeComboBox->GetItemIDFromRow( i ) ); if ( V_strcasecmp( pszPrefab, pKeyValues->GetString( kItemPrefab ) ) == 0 ) { bFound = true; m_pTypeComboBox->ActivateItemByRow( i ); m_nPrefab = ImportPrefab_t(i); break; } } if ( ( nOldPrefab != PREFAB_TAUNT && m_nPrefab == PREFAB_TAUNT ) || ( nOldPrefab == PREFAB_TAUNT && m_nPrefab != PREFAB_TAUNT ) ) { ClearLODs(); } pszPrefab = bFound ? pszPrefab : ""; GetItemValues()->SetString( kItemPrefab, pszPrefab ); UpdateUIForPrefab( m_nPrefab ); } SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateUIForPrefab( ImportPrefab_t nPrefab ) { if ( nPrefab == PREFAB_TAUNT ) { if ( m_pEquipRegionPanel ) { m_pEquipRegionPanel->SetVisible( false ); } if ( m_pBodygroupsPanel ) { m_pBodygroupsPanel->SetVisible( false ); } if ( m_pTauntInputPanel ) { m_pTauntInputPanel->SetVisible( true ); } if ( m_pAnimationPropLabel ) { m_pAnimationPropLabel->SetVisible( true ); } UpdateAnimationSourceDisplay(); UpdateAnimationVCDDisplay(); UpdateAnimDurationDisplay(); } else { if ( m_pEquipRegionPanel ) { m_pEquipRegionPanel->SetVisible( true ); } if ( m_pBodygroupsPanel ) { m_pBodygroupsPanel->SetVisible( true ); } if ( m_pTauntInputPanel ) { m_pTauntInputPanel->SetVisible( false ); } if ( m_pAnimationPropLabel ) { m_pAnimationPropLabel->SetVisible( false ); } UpdateLODDisplay(); UpdateMaterialDisplay(); } InvalidateLayout(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetItemPrefab() { return GetItemValues()->GetString( kItemPrefab ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::GetItemPrefabValue( const char *pszPrefab, const char *pszName, CUtlString& strOutput ) { extern void MergeDefinitionPrefab( KeyValues *pKVWriteItem, KeyValues *pKVSourceItem ); KeyValues *pPrefab = ItemSystem()->GetItemSchema()->FindDefinitionPrefabByName( pszPrefab ); if ( !pPrefab ) { return false; } KeyValuesAD pKVUnpackedPrefab( "prefab" ); MergeDefinitionPrefab( pKVUnpackedPrefab, pPrefab ); strOutput = pKVUnpackedPrefab->GetString( pszName, NULL ); return !strOutput.IsEmpty(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SelectClass( int nClassIndex ) { m_nSelectedClass = nClassIndex; if ( m_nPrefab == PREFAB_TAUNT ) { UpdateAnimationSourceDisplay(); UpdateAnimationVCDDisplay(); UpdateAnimDurationDisplay(); UpdateLODDisplay(); UpdateMaterialDisplay(); } else { UpdateBodygroupsDisplay(); UpdateLODDisplay(); UpdateMaterialDisplay(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetItemIcon( const char *pszFilePath ) { if ( pszFilePath && *pszFilePath && m_pIconImagePanel ) { // clean up old image if there's one m_pIconImagePanel->EvictImage(); Bitmap_t image; ConversionErrorType nErrorCode = ImgUtl_LoadBitmap( pszFilePath, image ); if ( nErrorCode != CE_SUCCESS ) { m_pIconImagePanel->SetImage( (vgui::IImage *)0 ); ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadFile", pszFilePath ); return; } if ( image.Width() != 512 || image.Height() != 512 ) { ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadIconResolution", pszFilePath ); return; } if ( image.Format() != IMAGE_FORMAT_RGBA8888 ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedImageNot32Bits" ); return; } int badPixelCount = 0; static const int startSafeZoneY = 91; static const int endSafeZoneY = 420; for ( int y=0; y<512; ++y ) { bool bSafeZone = y >= startSafeZoneY && y < endSafeZoneY; // check if icon is outside the safezone for ( int x=0; x<512; ++x ) { RGBA8888_t* pPixel = (RGBA8888_t*)image.GetPixel( x, y ); if ( bSafeZone ) { // in the safezone, check if background is black if ( pPixel->a == 0 && ( pPixel->r || pPixel->g || pPixel->b ) ) { badPixelCount++; } } else { if ( pPixel->r || pPixel->g || pPixel->b || pPixel->a ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedImageDoesNotFitInsideSafeZone" ); return; } } } } static const int nTotalSafeZonePixels = 512 * ( endSafeZoneY - startSafeZoneY ); float flBadPercentage = (float)badPixelCount / nTotalSafeZonePixels; if ( flBadPercentage > 0.05f ) { ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadIconBackground" ); return; } int wide, tall; BitmapImage *pBitmapImage = new BitmapImage; pBitmapImage->SetBitmap( image ); pBitmapImage->GetSize( wide, tall ); // The ImagePanel needs to know the scaling factor for the BitmapImage, to // center it when it's going to be rendered, and then the BitmapImage needs // to know how big it should be rendered. float fScaleAmount = static_cast( m_pIconImagePanel->GetWide() ) / wide; m_pIconImagePanel->SetShouldCenterImage( true ); m_pIconImagePanel->SetShouldScaleImage( true ); m_pIconImagePanel->SetScaleAmount( fScaleAmount ); pBitmapImage->SetRenderSize( m_pIconImagePanel->GetWide(), static_cast( tall * fScaleAmount ) ); m_pIconImagePanel->SetImage( pBitmapImage ); } GetItemValues()->SetString( kItemIcon, pszFilePath ); SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetItemIcon() { return GetItemValues()->GetString( kItemIcon ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetPaintable( bool bPaintable, int nMaterialIndex ) { const char* pszPaintable = CFmtStr( kItemPaintable, nMaterialIndex ); GetItemValues()->SetBool( pszPaintable, bPaintable ); if ( m_pPaintableCheckButtons[nMaterialIndex] ) { m_pPaintableCheckButtons[nMaterialIndex]->SetSelected( bPaintable ); } // You should check out how paints look on the item SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsPaintable( int nMaterialIndex ) { const char* pszPaintable = CFmtStr( kItemPaintable, nMaterialIndex ); return GetItemValues()->GetBool( pszPaintable ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsAnyVMTPaintable() { for ( int nMaterialIndex=0; nMaterialIndex pQC = asset.GetTargetQC(); const char *pszCustomRelativeDir = CFmtStr( "%s/player/animations", GetWorkshopFolder() ); pQC->SetCustomRelativeDir( pszCustomRelativeDir ); // use class_workshop_animations as shipping QC const char *pszCustomQCOutputName = CFmtStr( "%s_workshop_animations", pszClassFolder ); pQC->SetCustomOutputName( pszCustomQCOutputName ); pQC->SetQCITemplate( GetQCTemplate( nSelectedClass ) ); // add temp DMX to get QC path const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ) ); asset.AddTargetDMX( pszFilePath ); m_tempQC.Clear(); if ( pQC->GetOutputPath( strQCTemplateFile, 0 ) ) { // if the QC was checked out, revert it first char szCorrectCaseFilePath[MAX_PATH]; g_pFullFileSystem->GetCaseCorrectFullPath( strQCTemplateFile.String(), szCorrectCaseFilePath ); CP4AutoRevertFile revertFile( szCorrectCaseFilePath ); if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, NULL, m_tempQC ) ) { m_tempQC.PutString( "\n" ); m_tempQC.PutString( "$pushd \"../../../\"\n" ); m_tempQC.PutString( "$include \"../../../\"\n" ); m_tempQC.PutString( "$popd\n" ); return (char *)m_tempQC.Base(); } } } else if ( GetItemPrefabValue( GetItemPrefab(), "qc_template", strQCTemplateFile ) ) { m_tempQC.Clear(); if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, "MOD", m_tempQC ) ) { return (char *)m_tempQC.Base(); } } Warning( "Failed to load specified QC template '%s'.\n", strQCTemplateFile.String() ); return NULL; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetQCTemplate( int nSelectedClass ) { const char *pszQCText = GetItemValues()->GetString( CFmtStr( kClassQC, kClassFolders[nSelectedClass] ) ); if ( V_strlen(pszQCText) == 0 ) { CUtlString strQCTemplateFile; if ( GetItemPrefabValue( m_nPrefab == PREFAB_TAUNT ? "misc" : GetItemPrefab(), "qc_template", strQCTemplateFile ) ) { m_tempQC.Clear(); if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, "MOD", m_tempQC ) ) { return (char *)m_tempQC.Base(); } else { Warning( "Failed to load specified QC template '%s'.\n", strQCTemplateFile.String() ); } } return CAssetTF().GetTargetQC()->GetQCTemplate(); } return pszQCText; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetQCITemplate( int nSelectedClass ) { const char *pszQCText = GetItemValues()->GetString( CFmtStr( kClassQCI, kClassFolders[nSelectedClass] ) ); if ( V_strlen(pszQCText) == 0 ) { CUtlString strQCITemplateFile = CItemUpload::Manifest()->GetQCITemplate(); CAssetTF asset; m_tempQC.Clear(); if ( g_pFullFileSystem->ReadFile( strQCITemplateFile.String(), "MOD", m_tempQC ) ) { return (char *)m_tempQC.Base(); } else { Warning( "Failed to load specified QCI template '%s'.\n", strQCITemplateFile.String() ); } } return pszQCText; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::ShouldP4AddOrEdit() const { return p4 && m_pPerforceCheckButton && m_pPerforceCheckButton->IsSelected(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsPartnerContent() const { return m_pPartnerCheckButton && m_pPartnerCheckButton->IsVisible() && m_pPartnerCheckButton->IsSelected(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char* CTFFileImportDialog::GetWorkshopFolder() const { return IsPartnerContent() ? "workshop_partner" : "workshop"; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CTFFileImportDialog::GetCustomBones( int selectedClass, const char* pszFileName, CUtlStringList& strBoneList ) { strBoneList.PurgeAndDeleteElements(); CUtlBuffer hdrBuf; const studiohdr_t *pItemStudioHdr = NULL; if ( g_pFullFileSystem->ReadFile( pszFileName, NULL, hdrBuf ) ) { pItemStudioHdr = reinterpret_cast< const studiohdr_t * >( hdrBuf.Base() ); } if ( pItemStudioHdr == NULL ) { return false; } if ( pItemStudioHdr ) { m_pPlayerModelPanel->SetToPlayerClass( selectedClass, false ); const studiohdr_t* pClassStudioHdr = m_pPlayerModelPanel->GetStudioHdr(); for ( int iItemBone=0; iItemBonenumbones; ++iItemBone ) { const char* pszItemBoneName = pItemStudioHdr->pBone( iItemBone )->pszName(); bool bCustomBone = true; for ( int iClassBone=0; iClassBonenumbones; ++iClassBone ) { const char* pszClassBoneName = pClassStudioHdr->pBone( iClassBone )->pszName(); if ( FStrEq( pszItemBoneName, pszClassBoneName ) ) { bCustomBone = false; break; } } if ( bCustomBone ) { strBoneList.CopyAndAddToTail( pszItemBoneName ); } } } return strBoneList.Count(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::ClearLODs() { for ( int iClassIndex=TF_FIRST_NORMAL_CLASS; iClassIndexFindKey( CFmtStr( kClassLODN, kClassFolders[ iClassIndex ], iLOD ) ); if ( pKey ) { pKey->Clear(); } } if ( m_pClassHighlights[ iClassIndex ] ) { m_pClassHighlights[ iClassIndex ]->SetVisible( false ); } } Assert( !AnyClassHasModels() ); ClearMaterials(); SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetLOD( int selectedClass, int nModelIndex, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) { if ( selectedClass == TF_CLASS_UNDEFINED ) { return LOAD_FAILED; } // Make sure we can load the model first if ( *pszFilePath ) { CAssetTF asset; if ( asset.AddTargetDMX( pszFilePath ) < 0 ) { return LOAD_FAILED_BADMODEL; } int nMaxTris = GetModelTriangleBudget( selectedClass, nModelIndex ); int nTriCount = asset.GetTargetDMX( 0 )->GetTriangleCount(); if ( nTriCount > nMaxTris ) { pKV->SetInt( "count", nTriCount ); pKV->SetInt( "limit", nMaxTris ); SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED_COMPLEXMODEL; } CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); pQC->SetQCTemplate( GetQCTemplate( m_nSelectedClass ) ); // need to compile dmx to output mdl file to get studiohdr_t for bone name list asset.SetName( "temp" ); asset.SetClass( kClassFolders[ selectedClass ] ); if ( asset.CompilePreview() ) { const CUtlVector< CUtlString >& strBuiltFiles = asset.GetBuiltFiles(); CUtlString strMDLPath; for ( int i=0; iRemoveFile( strBuiltFiles[i] ); } const int nCustomBoneLimit = GetModelBoneBudget(); if ( nCustomBones > nCustomBoneLimit ) { CUtlString strCustomBones = strBoneList[0]; for ( int i=1; iSetInt( "count", nCustomBones ); pKV->SetInt( "limit", nCustomBoneLimit ); pKV->SetString( "custom_bones", strCustomBones.String() ); SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED_TOOMANYBONES; } } int nMaterialCount = asset.GetTargetVMTCount(); if ( nMaterialCount > NUM_IMPORT_MATERIALS_PER_TEAM ) { pKV->SetInt( "count", nMaterialCount ); pKV->SetInt( "limit", NUM_IMPORT_MATERIALS_PER_TEAM ); SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED_TOOMANYMATERIALS; } // check if material count is not more than the higher LOD if ( nModelIndex > 0 ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], nModelIndex - 1 ) ); Assert( pKey ); if ( pKey ) { int nHigherLODMaterialCount = pKey->GetInt( "materialCount" ); if ( nHigherLODMaterialCount < nMaterialCount ) { SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED_MATERIALCOUNTMISMATCH; } } } for ( int i = 0; i < nMaterialCount; ++i ) { CFmtStr sMaterialName( kMaterialN, i ); if ( !GetItemValues()->GetString( sMaterialName, NULL ) ) { char pszMaterialId[MAX_PATH]; V_FileBase( asset.GetTargetVMT( i )->GetMaterialId(), pszMaterialId, sizeof(pszMaterialId) ); GetItemValues()->SetString( sMaterialName, pszMaterialId ); } } KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], nModelIndex ), true ); pKey->SetString( "file", pszFilePath ); pKey->SetInt( "polyCount", asset.GetTargetDMX( 0 )->GetPolyCount() ); pKey->SetInt( "triangleCount", nTriCount ); pKey->SetInt( "vertexCount", asset.GetTargetDMX( 0 )->GetVertexCount() ); pKey->SetInt( "materialCount", nMaterialCount ); // if we're already under the lowest budget, no need for more LODs if ( nTriCount <= GetModelTriangleBudget( selectedClass, NUM_IMPORT_LODS - 1 ) ) { for ( int i=nModelIndex+1; iFindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], i ) ); if ( pKeyLOD ) { pKeyLOD->Clear(); } } } } else { for ( int i=nModelIndex; iFindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], i ) ); if ( pKey ) { pKey->Clear(); } } if ( !AnyClassHasModels() ) { ClearMaterials(); } } SetDirty( true ); if ( selectedClass == m_nSelectedClass ) { UpdateLODDisplay(); } UpdateMaterialDisplay(); // Show a highlight for classes that have models if ( m_pClassHighlights[ selectedClass ] ) { m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasModels( selectedClass ) ); } return LOAD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateLODDisplay() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { return; } int nMinTriRequirement = GetModelTriangleBudget( m_nSelectedClass, NUM_IMPORT_LODS - 1 ); int nPreviousTriCount = INT_MAX; for ( int i=0; iFindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], i ) ); if ( pKey ) { pszFilePath = pKey->GetString( "file" ); nTriCount = pKey->GetInt( "triangleCount" ); } if ( nPreviousTriCount != 0 && nPreviousTriCount > nMinTriRequirement ) { SetLODPanelEnable( true, i ); } else { SetLODPanelEnable( false, i ); } vgui::Label *pFileLabel = m_pLODFiles[ i ]; if ( pFileLabel ) { if ( *pszFilePath ) { char file[MAX_PATH]; V_FileBase( pszFilePath, file, sizeof(file) ); pFileLabel->SetText( file ); } else { pFileLabel->SetText( "#TF_PublishFile_NoFileSelected" ); } } vgui::Label *pDetailsLabel = m_pLODDetails[ i ]; if ( pDetailsLabel ) { if ( *pszFilePath ) { wchar_t details[1024]; g_pVGuiLocalize->ConstructString_safe( details, "#TF_ImportFile_ModelDetails", pKey ); pDetailsLabel->SetText( details, true ); } else { pDetailsLabel->SetText( "" ); } } nPreviousTriCount = nTriCount; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CTFFileImportDialog::GetModelTriangleBudget( int selectedClass, int nModelIndex ) { // Return the budget for this item type if ( nModelIndex >= NUM_IMPORT_LODS ) { Warning( "GetModelTriangleBudget: bad model index\n" ); return 0; } int nTriangleBudget = kDefaultTriangleBudget[nModelIndex]; CUtlString strTriangleBudget; if ( GetItemPrefabValue( GetItemPrefab(), CFmtStr( "triangle_budget_lod%d", nModelIndex ), strTriangleBudget ) ) { nTriangleBudget = V_atoi( strTriangleBudget.String() ); } return nTriangleBudget; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CTFFileImportDialog::GetModelBoneBudget() { int nBoneBudget = kDefaultBoneBudget; CUtlString strBoneBudget; if ( GetItemPrefabValue( GetItemPrefab(), "custom_bone_budget", strBoneBudget ) ) { nBoneBudget = V_atoi( strBoneBudget.String() ); } return nBoneBudget; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::SetMaterial( int nMaterialPanelIndex, const char* pszFilePath, MATERIAL_FILE_TYPE fileType ) { int selectedSkin = nMaterialPanelIndex / NUM_IMPORT_MATERIALS_PER_TEAM; int nMaterialIndex = nMaterialPanelIndex % NUM_IMPORT_MATERIALS_PER_TEAM; return SetMaterial( selectedSkin, nMaterialIndex, pszFilePath, fileType ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::SetMaterial( int selectedSkin, int nMaterialIndex, const char *pszFilePath, MATERIAL_FILE_TYPE fileType ) { if ( *pszFilePath ) { CAssetTF asset; CTargetTGA image( &asset, NULL ); if ( !image.SetInputFile( pszFilePath ) ) { return false; } const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ), true ); pKey->SetString( CFmtStr( "%s_texture_file", pszMaterialFilePrefix ), pszFilePath ); pKey->SetInt( CFmtStr( "%s_texture_width", pszMaterialFilePrefix ), image.GetWidth() ); pKey->SetInt( CFmtStr( "%s_texture_height", pszMaterialFilePrefix ), image.GetHeight() ); pKey->SetInt( CFmtStr( "%s_texture_channels", pszMaterialFilePrefix ), image.GetChannelCount() ); pKey->SetBool( CFmtStr( "%s_texture_alpha", pszMaterialFilePrefix ), image.HasAlpha() ); } else { static const char* s_removeKeyNames[] = { "%s_texture_file", "%s_texture_width", "%s_texture_height", "%s_texture_channels", "%s_texture_alpha" }; KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ) ); if ( pKey ) { const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; for ( int i=0; iFindKey( CFmtStr( s_removeKeyNames[i], pszMaterialFilePrefix ) ); if ( pSubKey ) { pKey->RemoveSubKey( pSubKey ); } } } } SetDirty( true ); UpdateMaterialDisplay( selectedSkin, nMaterialIndex ); return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char* CTFFileImportDialog::GetMaterialTextureFile( int selectedSkin, int nMaterialIndex, MATERIAL_FILE_TYPE fileType ) { KeyValues* pMaterialKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ) ); if ( pMaterialKey ) { const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; return pMaterialKey->GetString( CFmtStr( "%s_texture_file", pszMaterialFilePrefix ) ); } return ""; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CUtlString CTFFileImportDialog::GetMaterialName( int selectedSkin, int nMaterialIndex ) { const char* pszFilePath = GetMaterialTextureFile( selectedSkin, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ); if ( FStrEq( pszFilePath, "" ) ) { return ""; } // Turn the texture name into vmt name CUtlString strMaterialName = V_GetFileName( pszFilePath ); strMaterialName += ".vmt"; return strMaterialName; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::ClearMaterials() { KeyValues *pKeyParent = GetItemValues()->FindKey( "Materials" ); if ( pKeyParent ) { for ( int nMaterialIndex = 0; nMaterialIndex < NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) { KeyValues *pKey = pKeyParent->FindKey( CFmtStr( "Material%d", nMaterialIndex ) ); if ( pKey ) { pKeyParent->RemoveSubKey( pKey ); pKey->deleteThis(); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::ClearMaterial( int nSkinIndex, int nMaterialIndex ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ) ); if ( pKey ) { pKey->Clear(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateMaterialDisplay() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { return; } int nModelMaterials = 0; KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], 0 ) ); if ( pKey ) { nModelMaterials = pKey->GetInt( "materialCount" ); } if ( m_pSwapVMTButton ) { m_pSwapVMTButton->SetVisible( nModelMaterials > 1 ); } int nSkinType = GetItemValues()->GetInt( kSkinType ); for ( int nMaterialPaneIndex = 0; nMaterialPaneIndex < MAX_MATERIAL_COUNT; ++nMaterialPaneIndex ) { vgui::Panel *pMaterialPanel = m_pMaterialPanels[ nMaterialPaneIndex ]; if (!pMaterialPanel) { continue; } int nSkinIndex = nMaterialPaneIndex / NUM_IMPORT_MATERIALS_PER_TEAM; int nMaterialIndex = nMaterialPaneIndex % NUM_IMPORT_MATERIALS_PER_TEAM; bool bWasVisible = pMaterialPanel->IsVisible(); bool bVisible = nSkinIndex <= nSkinType && nMaterialIndex < nModelMaterials; pMaterialPanel->SetVisible( bVisible ); if ( bVisible ) { if ( !bWasVisible ) { pMaterialPanel->InvalidateLayout( true, true ); } UpdateMaterialDisplay( nSkinIndex, nMaterialIndex ); } } // update paintable buttons for ( int nMaterialIndex=0; nMaterialIndexSetVisible( bVisible ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateMaterialDisplay( int nSkinIndex, int nMaterialIndex ) { int nMaterialPanelIndex = nSkinIndex * NUM_IMPORT_MATERIALS_PER_TEAM + nMaterialIndex; if ( nMaterialPanelIndex >= MAX_MATERIAL_COUNT ) { // nSkinIndex could be 2 for Preview Image return; } vgui::Label *pLabel = m_pMaterialLabels[ nMaterialPanelIndex ]; if ( pLabel ) { const char* pszInputName = "Input"; if ( GetItemValues()->GetInt( kSkinType ) ) { pszInputName = ( nSkinIndex == 0 ) ? "Red Input" : "Blue Input"; } pLabel->SetText( CFmtStr( "%s: \"%s\"", pszInputName, GetItemValues()->GetString( CFmtStr( kMaterialN, nMaterialIndex ) ) ) ); } pLabel = m_pMaterialFiles[ nMaterialPanelIndex ]; if ( pLabel ) { const char *pszFilePath = GetMaterialTextureFile( nSkinIndex, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ); if ( *pszFilePath ) { char file[MAX_PATH]; V_FileBase( pszFilePath, file, sizeof(file) ); pLabel->SetText( file ); pLabel->SetFgColor( Color( 255, 255, 255, 255 ) ); } else { pLabel->SetText( "#TF_PublishFile_NoFileSelected" ); pLabel->SetFgColor( Color( 255, 0, 0, 255 ) ); } } } const char *CTFFileImportDialog::GetMaterialText( int nSkinIndex, int nMaterialIndex, CUtlBuffer &sMaterialText ) { sMaterialText.Clear(); sMaterialText.SetBufferType( true, true ); if ( !sMaterialText.TellPut() ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ) ); if ( pKey ) { KeyValuesAD pVMTKey( "VMT" ); if ( pVMTKey->LoadFromBuffer( "VMT", pKey->GetString( "vmt" ) ) ) { if ( ValidateMaterialValues( pVMTKey, nMaterialIndex ) == BUILD_OKAY ) { sMaterialText.PutString( pKey->GetString( "vmt" ) ); } else { // HACK! We had proxies bug that will invalidate the material // Try to update the proxies from the template to see if this fixes the issue KeyValues *pCurrentProxies = pVMTKey->FindKey( "Proxies" ); if ( pCurrentProxies ) { KeyValuesAD pKVTemplate( "Template" ); if ( pKVTemplate->LoadFromFile( g_pFullFileSystem, "materials/models/player/items/templates/standard.vmt", "GAME" ) ) { KeyValues *pTemplateProxiesKey = pKVTemplate->FindKey( "Proxies" ); if ( pTemplateProxiesKey ) { // clear old proxies and copy a new one pCurrentProxies->Clear(); pCurrentProxies->RecursiveMergeKeyValues( pTemplateProxiesKey ); // try again if ( ValidateMaterialValues( pVMTKey, nMaterialIndex ) == BUILD_OKAY ) { sMaterialText.SetBufferType( true, true ); pVMTKey->RecursiveSaveToFile( sMaterialText, 0, false, true ); sMaterialText.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); } } } } } } } } if ( !sMaterialText.TellPut() ) { g_pFullFileSystem->ReadFile( "materials/models/player/items/templates/standard.vmt", "GAME", sMaterialText ); } if ( !sMaterialText.TellPut() ) { return NULL; } return sMaterialText.String(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::SetMaterialText( int nSkinIndex, int nMaterialIndex, const char* pszMaterialText ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ), true ); if ( pKey ) { pKey->SetString( "vmt", pszMaterialText ); return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::ValidateMaterialValues( KeyValues *pKV, int nMaterialIndex ) { static const char *MATERIAL_SHADER = "VertexlitGeneric"; static const int CONDITION_PAINTABLE = 0x01; static const int CONDITION_NOTPAINTABLE = 0x02; static const int MAX_MATERIAL_VARIABLES = 8; static struct MaterialCheck { BUILD_RESULT nErrorResult; int nCondition; const char *vecVariables[MAX_MATERIAL_VARIABLES]; } sVecMaterialChecks[] = { { BUILD_FAILED_MATERIALMISSINGCLOAK, 0, { "$cloakPassEnabled", "Proxies/invis" } }, { BUILD_FAILED_MATERIALMISSINGBURNING, 0, { "$detail", "$detailscale", "$detailblendfactor", "$detailblendmode", "Proxies/AnimatedTexture", "Proxies/BurnLevel" } }, { BUILD_FAILED_MATERIALMISSINGJARATE, CONDITION_NOTPAINTABLE, { "$yellow", "Proxies/YellowLevel", "Proxies/Equals" } }, { BUILD_FAILED_MATERIALMISSINGJARATE, CONDITION_PAINTABLE, { "$yellow", "Proxies/YellowLevel", "Proxies/Multiply" } }, { BUILD_FAILED_MATERIALMISSINGPAINTABLE, CONDITION_PAINTABLE, { "$blendtintbybasealpha", "$blendtintcoloroverbase", "$colortint_base", "$color2", "$colortint_tmp", "Proxies/ItemTintColor", "Proxies/SelectFirstIfNonZero" } }, }; if ( V_strcasecmp( pKV->GetName(), MATERIAL_SHADER ) != 0 ) { return BUILD_FAILED_MATERIALMISSINGSHADER; } for ( int iCheck = 0; iCheck < ARRAYSIZE(sVecMaterialChecks); ++iCheck ) { const MaterialCheck &check = sVecMaterialChecks[ iCheck ]; bool bIsPaintable = IsPaintable( nMaterialIndex ); if ( ( check.nCondition & CONDITION_PAINTABLE ) && !bIsPaintable ) { continue; } if ( ( check.nCondition & CONDITION_NOTPAINTABLE ) && bIsPaintable ) { continue; } for ( int i = 0; i < ARRAYSIZE(check.vecVariables) && check.vecVariables[i]; ++i ) { if ( !pKV->FindKey( check.vecVariables[i] ) ) { return check.nErrorResult; } } } // Ugh, terrible hack... // If a KeyValues key doesn't have a value or subkeys, it won't get written out. // Unfortunately we need Proxies/invis to be written out as an empty set, // so it needs to have _something_ in it to force it to be written to disk. const char *kSubkeyHack = "hack_not_written_to_disk"; KeyValues *pSubKey = pKV->FindKey( "Proxies/invis" ); Assert(pSubKey); if ( !pSubKey->FindKey( kSubkeyHack ) ) { pSubKey->AddSubKey( new KeyValues( kSubkeyHack ) ); } return BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemoveUnnecessaryParametersFromVMT( KeyValues *pKV, int nMaterialIndex ) { RemoveLightParameters( pKV, nMaterialIndex ); RemovePaintParameters( pKV, nMaterialIndex ); RemoveTranslucentParameters( pKV ); RemoveCubeMapParameters( pKV ); RemoveSelfIllumParameters( pKV ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemoveLightParameters( KeyValues *pKV, int nMaterialIndex ) { static const char *vecLightingKeys[] = { "$basemapalphaphongmask", "$halflambert" }; for ( int i=0; iGetBool( pszLightKeyName ) ) { KeyValues *pSubKey = pKV->FindKey( pszLightKeyName ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } } if ( FStrEq( GetMaterialTextureFile( 0, nMaterialIndex, MATERIAL_FILE_PHONGEXPONENT ), "" ) ) { KeyValues* pSubKey = pKV->FindKey( "$rimmask" ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemovePaintParameters( KeyValues *pKV, int nMaterialIndex ) { if ( IsPaintable( nMaterialIndex ) ) { static const char *vecNonPaintableProxyKeys[] = { "Equals" }; // Now remove proxies KeyValues *pProxyKV = pKV->FindKey( "Proxies" ); if ( pProxyKV ) { for ( int iProxyKey = 0; iProxyKey < ARRAYSIZE(vecNonPaintableProxyKeys); ++iProxyKey ) { KeyValues *pKey = pProxyKV->FindKey( vecNonPaintableProxyKeys[ iProxyKey ] ); if ( pKey ) { pProxyKV->RemoveSubKey( pKey ); pKey->deleteThis(); } } } return; } static const char *vecPaintableKeys[] = { "$blendtintbybasealpha", "$blendtintcoloroverbase", "$colortint_base", "$colortint_tmp" }; static const char *vecPaintableProxyKeys[] = { "ItemTintColor", "SelectFirstIfNonZero", "Multiply" }; // First remove all the variables for ( int iKey = 0; iKey < ARRAYSIZE(vecPaintableKeys); ++iKey ) { KeyValues *pKey = pKV->FindKey( vecPaintableKeys[ iKey ] ); if ( pKey ) { pKV->RemoveSubKey( pKey ); pKey->deleteThis(); } } // Now remove proxies KeyValues *pProxyKV = pKV->FindKey( "Proxies" ); if ( pProxyKV ) { for ( int iProxyKey = 0; iProxyKey < ARRAYSIZE(vecPaintableProxyKeys); ++iProxyKey ) { KeyValues *pKey = pProxyKV->FindKey( vecPaintableProxyKeys[ iProxyKey ] ); if ( pKey ) { pProxyKV->RemoveSubKey( pKey ); pKey->deleteThis(); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemoveTranslucentParameters( KeyValues *pKV ) { if ( !pKV->GetBool( "$additive" ) ) { KeyValues *pSubKey = pKV->FindKey( "$additive" ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } if ( !pKV->GetBool( "$translucent" ) ) { KeyValues *pSubKey = pKV->FindKey( "$translucent" ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } pSubKey = pKV->FindKey( "$alphatest" ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemoveCubeMapParameters( KeyValues *pKV ) { static const char* vecEnvmapKeys[] = { "$envmap", "$basealphaenvmapmask", "$normalmapalphaenvmapmask", "$envmaptint" }; const char* pszEnvmapName = pKV->GetString( "$envmap" ); if ( FStrEq( pszEnvmapName, "" ) ) { for ( int i=0; iFindKey( pszEnvmapKey ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::RemoveSelfIllumParameters( KeyValues *pKV ) { static const char* vecSelfIllumKeys[] = { "$selfillum", "$selfillumtint", "$selfillummask" }; bool bSelfIllum = false; KeyValues *pDX9Key = pKV->FindKey( ">=DX90" ); if ( pDX9Key ) { bSelfIllum = pDX9Key->GetBool( "$selfillum" ); } if ( !bSelfIllum ) { for ( int i=0; iFindKey( vecSelfIllumKeys[i] ); if ( pSubKey ) { pKV->RemoveSubKey( pSubKey ); pSubKey->deleteThis(); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateBodygroupsDisplay() { KeyValues *pKey = GetItemValues()->FindKey( kBodygroup ); for ( int i=0; iSetCheckButtonCheckable( true ); pButton->SetSelected( !pKey || !pKey->GetBool( pszBodygroupName ) ); if ( m_nSelectedClass != TF_CLASS_UNDEFINED ) { m_pPlayerModelPanel->SetToPlayerClass( m_nSelectedClass, false ); const studiohdr_t* pMDL = m_pPlayerModelPanel->GetStudioHdr(); bool bEnabled = false; for ( int iBodygroup=0; iBodygroupnumbodyparts; ++iBodygroup ) { const char* pszValidBodygroup = pMDL->pBodypart( iBodygroup )->pszName(); if ( FStrEq( pszValidBodygroup, pszBodygroupName ) ) { bEnabled = true; break; } } pButton->SetEnabled( bEnabled ); } pButton->SetCheckButtonCheckable( pButton->IsEnabled() ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetBodygroup( KeyValues* pBodygroupKey ) { if ( !pBodygroupKey ) { return; } KeyValues *pKey = GetItemValues()->FindKey( kBodygroup, true ); if ( pKey ) { pKey->Clear(); for ( int i=0; iGetBool( pszBodygroup ) ) { pKey->SetBool( pszBodygroup, true ); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetAnimationSource( int selectedClass, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) { if ( selectedClass == TF_CLASS_UNDEFINED ) { SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED; } // Make sure we can load the model first if ( pszFilePath && *pszFilePath ) { CAssetTF asset; CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); pQC->SetQCTemplate( GetUserAnimationQCTemplate( selectedClass ) ); pQC->SetQCITemplate( GetQCTemplate( selectedClass ) ); if ( asset.AddTargetDMX( pszFilePath ) < 0 ) { SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED_BADMODEL; } CSmartPtr< CTargetDMX > pDMX = pQC->GetTargetDMX( 0 ); float flFrameRate; int nFrameCount; float flAnimDuration = 0.f; if ( pDMX.IsValid() && pDMX->GetAnimationFrameInfo( flFrameRate, nFrameCount ) ) { flAnimDuration = (float)nFrameCount/flFrameRate; if ( flAnimDuration > GetMaxTauntDuration() ) { if ( pKV ) { pKV->SetFloat( "current_anim_duration", flAnimDuration ); pKV->SetInt( "max_anim_duration", GetMaxTauntDuration() ); } SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAIL_ANIMATIONTOOLONG; } } KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ), true ); pKey->SetString( "source_file", pszFilePath ); SetAnimationDuration( selectedClass, flAnimDuration ); } else { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); if ( pKey ) { KeyValues *pVCDKey = pKey->FindKey( "source_file" ); if ( pVCDKey ) { pKey->RemoveSubKey( pVCDKey ); pVCDKey->deleteThis(); } } } SetDirty( true ); if ( selectedClass == m_nSelectedClass ) { UpdateAnimationSourceDisplay(); } // Show a highlight for classes that have models if ( m_pClassHighlights[ selectedClass ] ) { m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasTauntSources( selectedClass ) ); } return LOAD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetAnimationVCD( int selectedClass, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) { if ( selectedClass == TF_CLASS_UNDEFINED ) { SetMessageFileVariable( pKV, pszFilePath ); return LOAD_FAILED; } if ( pszFilePath && *pszFilePath ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ), true ); pKey->SetString( "vcd_file", pszFilePath ); } else { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); if ( pKey ) { KeyValues *pVCDKey = pKey->FindKey( "vcd_file" ); if ( pVCDKey ) { pKey->RemoveSubKey( pVCDKey ); pVCDKey->deleteThis(); } } } SetDirty( true ); if ( selectedClass == m_nSelectedClass ) { UpdateAnimationVCDDisplay(); } // Show a highlight for classes that have models if ( m_pClassHighlights[ selectedClass ] ) { m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasTauntSources( selectedClass ) ); } return LOAD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetAnimationDuration( int selectedClass, float flDuration ) { if ( selectedClass == TF_CLASS_UNDEFINED ) { return; } float flClampedDuration = clamp( flDuration, 0.f, GetMaxTauntDuration() ); KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); if ( pKey ) { pKey->SetFloat( "taunt_duration", flClampedDuration ); } UpdateAnimDurationDisplay(); } extern CChoreoScene *LoadSceneForModel( const char *filename, IChoreoEventCallback *pCallback, float *flSceneEndTime ); //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::VerifyVCD( const CAssetTF &asset ) { if ( m_nPrefab != PREFAB_TAUNT ) return BUILD_OKAY; // force reload scene cache scenefilecache->Reload(); CUtlVector< int > vcdFileIndices; const CUtlVector< CUtlString > &builtFiles = asset.GetBuiltFiles(); const CUtlVector< CUtlString > &relPathBuiltFiles = asset.GetRelativePathBuiltFiles(); for ( int iFile=0; iFileGetNumEvents() && !pEventSequence; ++iEvent ) { CChoreoEvent *pEvent = pScene->GetEvent( iEvent ); if ( pEvent && pEvent->GetType() == CChoreoEvent::EVENTTYPE::SEQUENCE ) { pEventSequence = pEvent; } } if ( !pEventSequence ) { delete pScene; return BUILD_FAILED_VCD_MISSING_EVENT_SEQUENCE; } if ( pEventSequence->GetEndTime() > GetMaxTauntDuration() ) { delete pScene; return BUILD_FAILED_VCD_EVENT_SEQUENCE_TOO_LONG; } char szFileName[MAX_PATH]; V_FileBase( pszRelPath, szFileName, sizeof( szFileName ) ); pEventSequence->SetParameters( szFileName ); pScene->SaveToFile( pszFullPath ); vcdFileIndices.AddToTail( iFile ); delete pScene; } } const char *pszArchiveName = asset.GetArchivePath(); if ( pszArchiveName && *pszArchiveName ) { CUtlBuffer buf; if ( !g_pFullFileSystem->ReadFile( pszArchiveName, NULL, buf ) ) { // failed to parse zip file return BUILD_FAILED_BAD_VCD_FILE; } IZip *pZip = IZip::CreateZip(); if ( pZip ) { pZip->ParseFromBuffer( buf.Base(), buf.Size() ); for ( int i=0; iAddFileToZip( pszRelPath, pszFullPath ); } pZip->SaveToBuffer( buf ); IZip::ReleaseZip( pZip ); g_pFullFileSystem->WriteFile( pszArchiveName, NULL, buf ); } else { // failed to parse zip file return BUILD_FAILED_BAD_VCD_FILE; } } return BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateAnimationSourceDisplay() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { return; } if ( m_pAnimationSourceFile ) { const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, kClassFolders[ m_nSelectedClass ] ) ); if ( pszFilePath && *pszFilePath ) { char file[MAX_PATH]; V_FileBase( pszFilePath, file, sizeof(file) ); m_pAnimationSourceFile->SetText( file ); } else { m_pAnimationSourceFile->SetText( "#TF_PublishFile_NoFileSelected" ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateAnimationVCDDisplay() { if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) { return; } if ( m_pAnimationVCDFile ) { const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationVCDFile, kClassFolders[ m_nSelectedClass ] ) ); if ( pszFilePath && *pszFilePath ) { char file[MAX_PATH]; V_FileBase( pszFilePath, file, sizeof(file) ); m_pAnimationVCDFile->SetText( file ); } else { m_pAnimationVCDFile->SetText( "#TF_PublishFile_NoFileSelected" ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::UpdateAnimDurationDisplay() { if ( m_pAnimationDurationLabel ) { float flDuration = GetItemValues()->GetFloat( CFmtStr( kClassAnimationDuration, kClassFolders[ m_nSelectedClass ] ) ); wchar_t wszTemp[256]; wchar_t wszCount[10]; _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%.4f", flDuration ); g_pVGuiLocalize->ConstructString_safe( wszTemp, g_pVGuiLocalize->Find("#TF_ImportFile_AnimationDuration"), 1, wszCount ); m_pAnimationDurationLabel->SetText( wszTemp ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetDirty( bool bDirty ) { if ( m_pBuildButton ) { m_pBuildButton->SetEnabled( !bDirty ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- static int FindSuffix( const char *pszString, const char *pszSuffix ) { int nStringLen = V_strlen(pszString); int nSuffixLen = V_strlen(pszSuffix); int nSuffixOffset = nStringLen - nSuffixLen; if ( nSuffixOffset >= 0 && V_strcasecmp( (pszString + nSuffixOffset), pszSuffix ) == 0 ) { return nSuffixOffset; } return -1; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- static bool FindTexture( const char *pszStrippedPath, const char *pszSuffix, CUtlString &sOutputPath ) { static const char *vecTextureExtensions[] = { ".tga", ".psd" }; for ( int i = 0; i < ARRAYSIZE(vecTextureExtensions); ++i ) { char pszFullPath[MAX_PATH]; V_snprintf(pszFullPath, sizeof(pszFullPath), "%s%s%s", pszStrippedPath, pszSuffix, vecTextureExtensions[ i ]); if ( CItemUpload::FileExists( pszFullPath ) ) { sOutputPath = pszFullPath; return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SetLoopableTaunt( bool bLoopable, float flLoopStartTime ) { GetItemValues()->SetFloat( kAnimationLoopable, flLoopStartTime ); if ( m_pAnimationLoopCheckButton ) { m_pAnimationLoopCheckButton->SetSelected( bLoopable ); } if ( m_pAnimationLoopStartTextEntry ) { m_pAnimationLoopStartTextEntry->SetEnabled( bLoopable ); m_pAnimationLoopStartTextEntry->SetText( CFmtStr( "%f", bLoopable ? flLoopStartTime : -1.f ) ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsLoopableTaunt() const { return m_pAnimationLoopCheckButton && m_pAnimationLoopCheckButton->IsSelected(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- float CTFFileImportDialog::GetAnimationLoopStartTime() const { if ( m_pAnimationLoopStartTextEntry ) { return m_pAnimationLoopStartTextEntry->GetValueAsFloat(); } return 0.f; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddTauntToAsset( CAssetTF &asset, int nClassIndex, bool bIsMulticlass, BUILD_STAGE buildStage, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) { const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; const CUtlVector&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); bool bPreview = buildStage == BUILD_PREVIEW; asset.AddModel(); const char *pszClassFolder = kClassFolders[ nClassIndex ]; CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); asset.ExcludeFileExtension( "qc" ); asset.ExcludeFileExtension( "mdl" ); // Are we checking out files to perforce? bool bPerforce = !bPreview && ShouldP4AddOrEdit(); pQC->GetCustomKeyValues()->SetString( "", pszClassFolder ); pQC->SetQCTemplate( GetUserAnimationQCTemplate( nClassIndex, bPerforce ) ); pQC->SetQCITemplate( GetQCITemplate( nClassIndex ) ); const char *pszVCDFile = GetItemValues()->GetString( CFmtStr( kClassAnimationVCDFile, pszClassFolder ) ); CSmartPtr< CTargetVCD > pVCD = pQC->GetTargetVCD(); pVCD->SetInputFile( pszVCDFile ); const char *pszCustomRelativeDir = CFmtStr( "%s/player/%s/low", GetWorkshopFolder(), vecUsabilityStrings[nClassIndex] ); pVCD->SetCustomRelativeDir( pszCustomRelativeDir ); if ( bPreview ) { pVCD->SetCustomModPath( "custom/workshop" ); } // Dir for MDL pszCustomRelativeDir = bPerforce ? CFmtStr( "%s/player/animations", GetWorkshopFolder() ) : "player"; const char *pszAnimMDLMiddleName = bPerforce ? "workshop" : "user"; // use class_user_animations as temp MDL and class_workshop_animations as shipping MDL const char *pszCustomMDLOutputName = CFmtStr( "%s_%s_animations", pszClassFolder, pszAnimMDLMiddleName ); CSmartPtr< CTargetMDL > pMDL = asset.GetTargetMDL(); pMDL->SetCustomRelativeDir( pszCustomRelativeDir ); pMDL->SetCustomOutputName( pszCustomMDLOutputName ); if ( bPreview ) { pMDL->SetCustomModPath( "custom/workshop" ); } // Dir for QC pszCustomRelativeDir = bPerforce ? CFmtStr( "%s/player/animations", GetWorkshopFolder() ) : CFmtStr( "player/%s", pszClassFolder ); const char *pszAnimQCMiddleName = bPerforce ? "workshop" : "preview"; // use class_preview_animations as temp QC and class_workshop_animations as shipping QC const char *pszCustomQCOutputName = CFmtStr( "%s_%s_animations", pszClassFolder, pszAnimQCMiddleName ); pQC->SetCustomRelativeDir( pszCustomRelativeDir ); pQC->SetCustomOutputName( pszCustomQCOutputName ); pQC->SetIgnoreP4( !bPerforce ); const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ) ); if ( pszFilePath && *pszFilePath ) { int nLOD = asset.AddTargetDMX( pszFilePath ); if ( nLOD < 0 ) { SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); return BUILD_FAILED_BADMODEL; } CSmartPtr< CTargetDMX > pTargetDMX = asset.GetTargetDMX( nLOD ); if ( bIsMulticlass ) { pTargetDMX->SetNameSuffix( CFmtStr( "_%s", pszClassFolder ) ); } // Update the item data for the path inside the asset archive CUtlString sOutputPath; pTargetDMX->GetOutputPath( sOutputPath, 0, nPathFlags ); pItemData->SetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ), sOutputPath ); CUtlString sSequenceName; pTargetDMX->GetOutputPath( sSequenceName, 0, CTargetBase::PATH_FLAG_FILE ); float flFrameRate; int nFrameCount; pTargetDMX->GetAnimationFrameInfo( flFrameRate, nFrameCount ); float flTotalAnimTime = (float)nFrameCount / flFrameRate; // set custom keys for DMX pTargetDMX->GetCustomKeyValues()->SetString( "", sSequenceName.String() ); pTargetDMX->GetCustomKeyValues()->SetString( "", pszClassFolder ); pTargetDMX->GetCustomKeyValues()->SetFloat( "", flTotalAnimTime ); if ( IsLoopableTaunt() ) { float flStartTime = Clamp( GetAnimationLoopStartTime(), 0.f, flTotalAnimTime ); pTargetDMX->SetAnimationLoopStartTime( flStartTime ); } pTargetDMX->SetSoundScriptFilePath( kWorkshopSoundScriptFile ); if ( bPreview ) { pTargetDMX->SetCustomModPath( "custom/workshop" ); } } // check out files before compiling (INTERNAL ONLY) if ( p4 ) { CUtlString sMDLAbsPath; pMDL->GetOutputPath( sMDLAbsPath, 0 ); char szCorrectCaseFilePath[MAX_PATH]; g_pFullFileSystem->GetCaseCorrectFullPath( sMDLAbsPath.String(), szCorrectCaseFilePath ); CP4AutoEditAddFile editMDL( szCorrectCaseFilePath, "binary" ); // check out class_workshop_animation.qc to submit the final workshop if ( bPerforce ) { CUtlString sQCAbsPath; pQC->GetOutputPath( sQCAbsPath, 0 ); g_pFullFileSystem->GetCaseCorrectFullPath( sQCAbsPath.String(), szCorrectCaseFilePath ); CP4AutoEditAddFile editQC( szCorrectCaseFilePath ); } const char *pszSoundScriptFile = GetWorkshopSoundScriptFile(); if ( pszSoundScriptFile ) { CP4AutoEditAddFile editSoundScript( pszSoundScriptFile ); } } return BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddModelToAsset( CAssetTF &asset, int nClassIndex, bool bIsMulticlass, BUILD_STAGE buildStage, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) { const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; bool bPreview = buildStage == BUILD_PREVIEW; asset.AddModel(); const char *pszClassFolder = kClassFolders[ nClassIndex ]; if ( bIsMulticlass ) { asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", pszClassFolder ) ); } CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); pQC->SetQCTemplate( GetQCTemplate( nClassIndex ) ); int nLastSpecifiedTriCount = 0; int nLastSpecifiedLOD = 0; for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) { const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, pszClassFolder, nModelIndex ) ); if ( *pszFilePath ) { int nLOD = asset.AddTargetDMX( pszFilePath ); if ( nLOD < 0 ) { SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); return BUILD_FAILED_BADMODEL; } CSmartPtr< CTargetDMX > pTargetDMX = asset.GetTargetDMX( nLOD ); const int nMaxTris = GetModelTriangleBudget( nClassIndex, nModelIndex ); const int nTriCount = pTargetDMX->GetTriangleCount(); if ( !bPreview && nTriCount > nMaxTris ) { pBuildMessageVariables->SetInt( "count", nTriCount ); pBuildMessageVariables->SetInt( "limit", nMaxTris ); SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); return BUILD_FAILED_COMPLEXMODEL; } // Update the item data for the path inside the asset archive CUtlString sOutputPath; pTargetDMX->GetOutputPath( sOutputPath, 0, nPathFlags ); pItemData->SetString( CFmtStr( kClassLODNFile, pszClassFolder, nModelIndex ), sOutputPath ); nLastSpecifiedLOD = nModelIndex; nLastSpecifiedTriCount = nTriCount; } else if ( !bPreview && nModelIndex == 0 ) { // We need LOD0... pBuildMessageVariables->SetString( "class", pszClassFolder ); return BUILD_FAILED_MISSINGMODEL; } } // for each LOD if ( !bPreview && nLastSpecifiedTriCount > GetModelTriangleBudget( nClassIndex, NUM_IMPORT_LODS - 1 ) ) { pBuildMessageVariables->SetString( "lod", kLODLevels[ nLastSpecifiedLOD + 1 ] ); const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, pszClassFolder, nLastSpecifiedLOD ) ); SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); return BUILD_FAILED_NEEDMORELOD; } return BUILD_OKAY; } CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddMaterialsToAsset( CAssetTF &asset, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) { const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; int nValidVMTIndex = 0; CUtlVector< CUtlString > vecMaterialFiles; for ( int nVMT = 0; nVMT < asset.GetTargetVMTCount(); nVMT++ ) { CTargetVMT *pVMT = asset.GetTargetVMT( nVMT ); if ( pVMT ) { if ( pVMT->GetDuplicate() ) { continue; } if ( pVMT->GetMaterialType() == kInvalidMaterialType ) { SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); return BUILD_FAILED_BADMATERIALTYPE; } for ( int nSkinIndex = 0; nSkinIndex < CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkinIndex ) { CUtlString strMaterialName = GetMaterialName( nSkinIndex, nValidVMTIndex ); if ( strMaterialName.IsEmpty() ) { continue; } KeyValuesAD pKV( "VMT" ); CUtlBuffer sMaterialText; if ( !GetMaterialText( nSkinIndex, nValidVMTIndex, sMaterialText ) || !pKV->LoadFromBuffer( pVMT->GetMaterialId(), sMaterialText ) ) { if ( !strMaterialName.IsEmpty() ) { SetMessageFileVariable( pBuildMessageVariables, strMaterialName ); } else { SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); } return BUILD_FAILED_BADMATERIAL; } BUILD_RESULT nMaterialResult = ValidateMaterialValues( pKV, nValidVMTIndex ); if ( nMaterialResult != BUILD_OKAY ) { if ( !strMaterialName.IsEmpty() ) { SetMessageFileVariable( pBuildMessageVariables, strMaterialName ); } else { SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); } return nMaterialResult; } RemoveUnnecessaryParametersFromVMT( pKV, nValidVMTIndex ); pVMT->SetVMTKV( pKV, nSkinIndex ); bool bSelfIllum = pKV->GetBool( ">=DX90/$selfillum" ); bool bBaseAlphaMask = pKV->GetBool( "$basealphaenvmapmask" ); Assert( CItemUpload::Manifest()->GetNumTextureTypes() == NUM_MATERIAL_TEXTURE_FILE_TYPE ); for ( int nTextureType = 0; nTextureType < CItemUpload::Manifest()->GetNumTextureTypes(); ++nTextureType ) { MATERIAL_FILE_TYPE materialFileType = (MATERIAL_FILE_TYPE)nTextureType; const char *pszTexturePath = GetMaterialTextureFile( nSkinIndex, nValidVMTIndex, materialFileType ); if ( V_strlen( pszTexturePath ) == 0 ) { continue; } BUILD_RESULT checkImageResult = CheckImageSize( pszTexturePath, materialFileType, pBuildMessageVariables ); if ( checkImageResult != BUILD_OKAY ) { return checkImageResult; } const char *pszTextureType = CItemUpload::Manifest()->GetTextureType( materialFileType ); if ( bBaseAlphaMask && FStrEq( pszTextureType, "_normal" ) ) { Assert( materialFileType == MATERIAL_FILE_NORMAL ); // Base alpha mask will not work in materials using a normal map, use normal map alpha mask instead continue; } else if ( !bSelfIllum && FStrEq( pszTextureType, "_illum" ) ) { Assert( materialFileType == MATERIAL_FILE_SELFILLUM ); // no need to output illum if self illum is not set continue; } if ( !pVMT->SetTargetVTF( pszTextureType, pszTexturePath, nSkinIndex ) ) { SetMessageFileVariable( pBuildMessageVariables, pszTexturePath ); return BUILD_FAILED_BADIMAGE; } } for ( int iVTF=0; iVTFGetNumTargetVTFS( nSkinIndex ); ++iVTF ) { // Update the item data for the path inside the asset archive CUtlString sOutputPath; CTargetVTF *pVTF = pVMT->GetTargetVTF( iVTF, nSkinIndex ); if ( pVTF ) { pVTF->GetTargetTGA()->GetOutputPath( sOutputPath, 0, nPathFlags ); sOutputPath = asset.CheckRedundantOutputFilePath( pVTF->GetTargetTGA()->GetInputFile().String(), "", sOutputPath.String() ); pItemData->SetString( CFmtStr( kMaterialSkinNFile, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nValidVMTIndex, s_pszMaterialFilePrefixes[iVTF] ), sOutputPath ); } } } ++nValidVMTIndex; } } return BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::CheckSourceSDK() { CUtlString sDummy; return CItemUpload::GetContentDir( sDummy ) && CItemUpload::GetBinDirectory( sDummy ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::Build( BUILD_STAGE buildStage, KeyValues *pBuildMessageVariables ) { const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; bool bPreview = buildStage == BUILD_PREVIEW; if ( !CheckSourceSDK() ) { return BUILD_FAILED_NOSDK; } // check for build errors if ( !bPreview ) { if ( V_strcmp( GetItemName(), "" ) == 0 ) { return BUILD_FAILED_NONAME; } if ( V_strcmp( GetItemPrefab(), "" ) == 0 ) { return BUILD_FAILED_NOTYPE; } if ( !IsValidPrefab( GetItemPrefab() ) ) { return BUILD_FAILED_BADTYPE; } if ( m_nPrefab == PREFAB_TAUNT ) { if ( !AnyClassHasTauntSources() ) { return BUILD_FAILED_NO_TAUNT_SOURCES; } } else { if ( !AnyClassHasModels() ) { return BUILD_FAILED_NOMODELS; } if ( !AreClassesLODCountMatch() ) { return BUILD_FAILED_LODCOUNTMISMATCH; } if ( !AreClassesMaterialCountMatch() ) { return BUILD_FAILED_MATERIALCOUNTMISMATCH; } if ( !DidSpecifyAllMaterials() ) { return BUILD_FAILED_NOMATERIALS; } } if ( V_strcmp( GetItemIcon(), "" ) == 0 ) { return BUILD_FAILED_NOBACKPACKICON; } } bool bPartnerContent = IsPartnerContent(); // override the manifest data for partner content CItemUpload::Manifest()->SetItemDirectoryOverride( bPartnerContent ? "workshop_partner/player/items/" : "" ); CItemUpload::Manifest()->SetAnimationDirectoryOverride( bPartnerContent ? "workshop_partner/player/animations/" : "" ); CItemUpload::Manifest()->SetIconDirectoryOverride( bPartnerContent ? "backpack/workshop_partner/player/items/" : "" ); CAssetTF asset; CBuildLog buildLog; asset.SetItemLog( &buildLog ); CUtlString sName = GetItemName(); if ( bPreview ) { sName = "item_preview"; } // get rid of leading/trailing white spaces char szTempName[MAX_PATH]; V_strcpy_safe( szTempName, sName.String() ); Q_StripPrecedingAndTrailingWhitespace( szTempName ); sName = szTempName; if ( !asset.SetName( sName ) ) { return BUILD_FAILED_BADNAME; } asset.SetClass( GetClassFolder() ); KeyValuesAD pSessionData( BuildSessionData( sName ) ); KeyValues *pItemData = pSessionData->FindKey( GetItemValues()->GetName() ); Assert( pItemData != NULL ); const char *pszIcon = GetItemIcon(); if ( V_strlen( pszIcon ) > 0 ) { int nNumIconTypes = CItemUpload::Manifest()->GetNumIconTypes(); if ( nNumIconTypes > 0 ) { for ( int nIcon = 0; nIcon < nNumIconTypes; ++nIcon ) { if ( !asset.SetTargetIcon( nIcon, pszIcon ) ) { SetMessageFileVariable( pBuildMessageVariables, pszIcon ); return BUILD_FAILED_BADIMAGE; } } // Get the filename from the last (largest) icon type CSmartPtr< CTargetIcon > pTargetIcon = asset.GetTargetIcon( nNumIconTypes - 1 ); CUtlString sOutputPath; pTargetIcon->GetTargetVTF( 0 )->GetTargetTGA()->GetOutputPath( sOutputPath, 0, nPathFlags ); pItemData->SetString( kItemIcon, sOutputPath ); } } // clean up "blue" materials if needed if ( GetItemValues()->GetInt( kSkinType ) == 0 ) { for ( int nMaterialIndex = 0; nMaterialIndexGetUint64( kWorkshopID ) == 0 ) { return BUILD_FAILED_NO_WORKSHOP_ID; } } if ( CItemUpload::GetP4() ) { KeyValues *pItemSchema = pSessionData->FindKey( CFmtStr( "%s/%s", GetItemValues()->GetName(), kItemSchema ) ); if ( pItemSchema ) { item_definition_index_t defIndex = AddKeyValuesToItemWorkshopSchema( pItemSchema ); if ( !IsTFEnglishNameValid( defIndex ) ) { return BUILD_FAILED_BADTFENGLISHNAME; } } } } asset.SetAdditionalManifestData( pSessionData ); if ( m_nPrefab == PREFAB_TAUNT ) { asset.SetBuildScenesImage( true ); if ( bPreview ) { asset.SetCustomModPath( "custom/workshop" ); } } if ( bPreview ) { if ( !asset.CompilePreview() ) { pBuildMessageVariables->SetString( "log", buildLog.Get() ); return BUILD_FAILED_COMPILE; } buildResult = VerifyVCD( asset ); if ( buildResult != BUILD_OKAY ) { return buildResult; } SavePreviewData( asset ); } else { CUtlString sAssetName; char pszSessionPath[ MAX_PATH ]; char pszArchivePath[ MAX_PATH ]; asset.GetName( sAssetName ); const char *pszWorkshopDir = CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ); if ( !g_pFullFileSystem->RelativePathToFullPath_safe( pszWorkshopDir, "GAME", pszSessionPath ) ) { SetMessageFileVariable( pBuildMessageVariables, pszWorkshopDir ); return BUILD_FAILED_COMPILE; } V_ComposeFileName( pszSessionPath, CFmtStr( "%s.zip", sAssetName.Get() ), pszArchivePath, sizeof(pszArchivePath) ); asset.SetArchivePath( pszArchivePath ); if ( !asset.Compile() ) { pBuildMessageVariables->SetString( "log", buildLog.Get() ); return BUILD_FAILED_COMPILE; } buildResult = VerifyVCD( asset ); if ( buildResult != BUILD_OKAY ) { return buildResult; } GetItemValues()->SetString( kBuildOutput, pszArchivePath ); } return BUILD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- KeyValues *CTFFileImportDialog::BuildSessionData( const char *pszItemName ) { KeyValues *pData = new KeyValues( "Data" ); KeyValues *pItemData = GetItemValues()->MakeCopy(); pItemData->AddSubKey( BuildItemSchema( pszItemName ) ); pData->AddSubKey( pItemData ); return pData; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- KeyValues *CTFFileImportDialog::BuildItemSchema( const char *pszItemName ) { const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE); KeyValues *pData = new KeyValues( kItemSchema ); KeyValues *pKey; int nClassIndex; pData->UsesEscapeSequences( true ); // Get the sanitized name for item schema tokens CUtlString sName; CAssetTF asset; asset.SetName( pszItemName ); asset.GetName( sName ); asset.SetClass( GetClassFolder() ); const char* pszTFEnglishName = GetItemValues()->GetString( kTFEnglishName ); pData->SetString( kWorkshopName, GetItemValues()->GetString( kItemName ) ); pData->SetString( "name", pszTFEnglishName ); // TODO: Change this when we add a ship panel to fill in name from tf_english.txt const char *pszForcePrefab = "no_craft"; pData->SetString( "prefab", CFmtStr( "%s %s", pszForcePrefab, GetItemPrefab() ) ); pData->SetString( "item_name", CFmtStr( "#TF_%s", sName.Get() ) ); pData->SetString( "item_description", CFmtStr( "#TF_%s_Desc", sName.Get() ) ); if ( m_nPrefab != PREFAB_TAUNT ) { pData->SetString( "equip_region", GetItemValues()->GetString( kEquipRegion ) ); } const char *kThe = "The "; if ( V_strncasecmp( pszTFEnglishName, kThe, V_strlen( kThe ) ) == 0 ) { pData->SetBool( "propername", true ); } if ( m_nPrefab != PREFAB_TAUNT ) { KeyValues *pItemBodygroups = GetItemValues()->FindKey( kBodygroup ); if ( pItemBodygroups ) { CUtlVector bodygroupIDs; for ( int i=0; iGetBool( kBodygroupArray[i] ) ) { bodygroupIDs.AddToTail(i); } } if ( bodygroupIDs.Count() > 0 ) { KeyValues *pSchemaVisualsKey = pData->FindKey( "visuals", true ); if ( pSchemaVisualsKey ) { KeyValues *pSchemaBodygroupsKey = pSchemaVisualsKey->FindKey( "player_bodygroups", true ); if ( pSchemaBodygroupsKey ) { for ( int i=0; iSetBool( kBodygroupArray[nBodygroupIndex], true ); } } } } } } else if ( IsLoopableTaunt() ) { KeyValues *pAttributesKey = pData->FindKey( "attributes", true ); if ( pAttributesKey ) { KeyValues *pLoopAttrKey = pAttributesKey->FindKey( "taunt is press and hold", true ); if ( pLoopAttrKey ) { pLoopAttrKey->SetString( "attribute_class", "enable_misc2_holdtaunt" ); pLoopAttrKey->SetInt( "value", 1 ); } } } const char *pszIcon = GetItemIcon(); if ( V_strlen( pszIcon ) > 0 ) { if ( asset.SetTargetIcon( 0, pszIcon ) ) { CSmartPtr< CTargetIcon > pTargetIcon = asset.GetTargetIcon( 0 ); CUtlString sOutputPath; if ( pTargetIcon->GetOutputPath( sOutputPath, 0, nPathFlags ) ) { const char *pszMaterialsPrefix = "materials/"; char *pszOutputPath = sOutputPath.GetForModify(); V_FixSlashes( pszOutputPath, '/' ); if ( V_strncmp( pszOutputPath, pszMaterialsPrefix, V_strlen( pszMaterialsPrefix ) ) == 0 ) { pszOutputPath += V_strlen( pszMaterialsPrefix ); } V_StripExtension( pszOutputPath, pszOutputPath, V_strlen( pszOutputPath ) + 1 ); pData->SetString( "image_inventory", pszOutputPath ); } else { Warning( "Couldn't get output path for icon %s", pszIcon ); } } else { Warning( "Couldn't load icon %s", pszIcon ); } } // always add can_craft_count even if the item is not craftable in case we want to make it craftable in the future pKey = pData->FindKey( "capabilities", true ); pKey->SetInt( "can_craft_count", 1 ); if ( IsAnyVMTPaintable() ) { pKey->SetBool( "paintable", true ); } const CUtlVector&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); if ( m_nPrefab != PREFAB_TAUNT ) { bool bIsMulticlass = IsMulticlass(); asset.RemoveModels(); for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( !ClassHasModels( nClassIndex ) ) continue; asset.AddModel(); if ( bIsMulticlass ) { asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", kClassFolders[ nClassIndex ] ) ); } const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], 0 ) ); if ( *pszFilePath ) { int nLOD = asset.AddTargetDMX( pszFilePath ); if ( nLOD < 0 ) { Warning( "Couldn't load model %s", pszFilePath ); continue; } // Update the item data for the path inside the asset archive CUtlString sOutputPath; if ( asset.GetTargetMDL()->GetOutputPath( sOutputPath, 0, nPathFlags ) ) { sOutputPath.FixSlashes( '/' ); if ( bIsMulticlass ) { pKey = pData->FindKey( "model_player_per_class", true ); const char* pszClassName = vecUsabilityStrings[ nClassIndex ]; pKey->SetString( pszClassName, sOutputPath ); } else { pData->SetString( "model_player", sOutputPath ); } } else { Warning( "Couldn't get output path for model %s", pszFilePath ); } } } } KeyValues *pUsedByClass = pData->FindKey( "used_by_classes", true ); for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( !ClassHasModels( nClassIndex ) && !ClassHasTauntSources( nClassIndex ) ) continue; pUsedByClass->SetBool( vecUsabilityStrings[ nClassIndex ], true ); } // add "taunt" block here if ( m_nPrefab == PREFAB_TAUNT ) { KeyValues *pTauntKey = pData->FindKey( "taunt", true ); KeyValues *pCustomTauntPerClass = pTauntKey->FindKey( "custom_taunt_scene_per_class", true ); CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); CSmartPtr< CTargetVCD > pVCD = pQC->GetTargetVCD(); bool bIsMulticlass = IsMulticlass(); for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { const char *pszClass = vecUsabilityStrings[nClassIndex]; if ( pUsedByClass->GetBool( pszClass ) ) { pVCD->SetCustomRelativeDir( CFmtStr( "%s/player/%s/low", GetWorkshopFolder(), pszClass ) ); CUtlString sTauntOutputPath; pVCD->GetOutputPath( sTauntOutputPath, 0, nPathFlags ); sTauntOutputPath.FixSlashes( '/' ); pCustomTauntPerClass->SetString( pszClass, sTauntOutputPath.String() ); // should we add prop? if ( !ClassHasModels( nClassIndex ) ) continue; asset.AddModel(); if ( bIsMulticlass ) { asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", kClassFolders[ nClassIndex ] ) ); } const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], 0 ) ); if ( *pszFilePath ) { int nLOD = asset.AddTargetDMX( pszFilePath ); if ( nLOD < 0 ) { Warning( "Couldn't load model %s", pszFilePath ); continue; } // Update the item data for the path inside the asset archive CUtlString sPropOutputPath; if ( asset.GetTargetMDL()->GetOutputPath( sPropOutputPath, 0, nPathFlags ) ) { sPropOutputPath.FixSlashes( '/' ); KeyValues *pCustomPropPerClass = pTauntKey->FindKey( "custom_taunt_prop_per_class", true ); pCustomPropPerClass->SetString( pszClass, sPropOutputPath.String() ); } else { Warning( "Couldn't get output path for model %s", pszFilePath ); } } } } } return pData; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::Load( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) { const char *pszExtension = V_GetFileExtension( pszFilePath ); if ( V_strcasecmp( pszExtension, "txt" ) == 0 ) { return LoadTxt( pszFilePath, pathID, sFailedPath ); } if ( V_strcasecmp( pszExtension, "zip" ) == 0 ) { return LoadZip( pszFilePath, pathID, sFailedPath ); } sFailedPath = pszFilePath; return LOAD_FAILED; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadTxt( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) { char pszBasePath[MAX_PATH]; char pszLoadPath[MAX_PATH]; V_ExtractFilePath( pszFilePath, pszBasePath, sizeof(pszBasePath) ); KeyValuesAD pData( "Data" ); pData->UsesEscapeSequences( true ); if ( !pData->LoadFromFile( g_pFullFileSystem, pszFilePath, pathID ) ) { sFailedPath = pszFilePath; return LOAD_FAILED; } KeyValues *pItemData = pData->FindKey( GetItemValues()->GetName() ); if ( !pItemData ) { sFailedPath = pszFilePath; return LOAD_FAILED; } SetItemName( pItemData->GetString( kItemName) ); SetItemPrefab( pItemData->GetString( kItemPrefab ) ); SetSkinType( pItemData->GetInt( kSkinType ) ); SetEquipRegion( pItemData->GetString( kEquipRegion ) ); SetWorkshopID( pItemData->GetString( kWorkshopID ) ); SetTFEnglishName( pItemData->GetString( kTFEnglishName ) ); KeyValues *pBodygroup = pItemData->FindKey( kBodygroup ); if ( pBodygroup ) { SetBodygroup( pBodygroup ); } const char *pszIconFile = pItemData->GetString( kItemIcon ); if ( *pszIconFile && !V_IsAbsolutePath( pszIconFile) ) { V_ComposeFileName( pszBasePath, pszIconFile, pszLoadPath, sizeof(pszLoadPath) ); pszIconFile = pszLoadPath; } SetItemIcon( pszIconFile ); for ( int nMaterialIndex=0; nMaterialIndexGetBool( pszPaintable ), nMaterialIndex ); } bool bSelected = false; for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { const char* pszQCKeyName = CFmtStr( kClassQC, kClassFolders[ nClassIndex ] ); GetItemValues()->SetString( pszQCKeyName, pItemData->GetString( pszQCKeyName ) ); for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) { const char *pszModelFile = pItemData->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ); if ( *pszModelFile ) { if ( !V_IsAbsolutePath( pszModelFile) ) { V_ComposeFileName( pszBasePath, pszModelFile, pszLoadPath, sizeof(pszLoadPath) ); pszModelFile = pszLoadPath; } // set default selected class if ( !bSelected ) { m_nSelectedClass = nClassIndex; if ( m_pClassRadioButtons[ nClassIndex ] ) { m_pClassRadioButtons[ nClassIndex ]->SetSelected( true ); bSelected = true; } } } LOAD_RESULT result = SetLOD( nClassIndex, nModelIndex, pszModelFile ); if ( result != LOAD_OKAY ) { sFailedPath = pszModelFile; return result; } } } const float flAnimationLoopStartTime = pItemData->GetFloat( kAnimationLoopable, -1.f ); SetLoopableTaunt( flAnimationLoopStartTime >= 0.f, flAnimationLoopStartTime ); // Load animation files for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { const char* pszQCIKeyName = CFmtStr( kClassQCI, kClassFolders[ nClassIndex ] ); GetItemValues()->SetString( pszQCIKeyName, pItemData->GetString( pszQCIKeyName ) ); const char *pszSourceFile = pItemData->GetString( CFmtStr( kClassAnimationSourceFile, kClassFolders[ nClassIndex ] ) ); if ( *pszSourceFile ) { if ( !V_IsAbsolutePath( pszSourceFile) ) { V_ComposeFileName( pszBasePath, pszSourceFile, pszLoadPath, sizeof(pszLoadPath) ); pszSourceFile = pszLoadPath; } // set default selected class if ( !bSelected ) { m_nSelectedClass = nClassIndex; if ( m_pClassRadioButtons[ nClassIndex ] ) { m_pClassRadioButtons[ nClassIndex ]->SetSelected( true ); bSelected = true; } } } LOAD_RESULT result = SetAnimationSource( nClassIndex, pszSourceFile ); if ( result != LOAD_OKAY ) { sFailedPath = pszSourceFile; return result; } const char *pszVCDFile = pItemData->GetString( CFmtStr( kClassAnimationVCDFile, kClassFolders[ nClassIndex ] ) ); if ( *pszVCDFile ) { if ( !V_IsAbsolutePath( pszVCDFile) ) { V_ComposeFileName( pszBasePath, pszVCDFile, pszLoadPath, sizeof(pszLoadPath) ); pszVCDFile = pszLoadPath; } } result = SetAnimationVCD( nClassIndex, pszVCDFile ); if ( result != LOAD_OKAY ) { sFailedPath = pszVCDFile; return result; } } Assert( CItemUpload::Manifest()->GetNumTextureTypes() == NUM_MATERIAL_TEXTURE_FILE_TYPE ); for ( int nSkinIndex = 0; nSkinIndex < CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkinIndex ) { for ( int nMaterialIndex = 0; nMaterialIndex < NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) { const char *pszMaterialSkin = CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ); const char *pszMaterialVMT = pItemData->GetString( CFmtStr( kMaterialSkinNVMT, pszMaterialSkin, nMaterialIndex ) ); const char* pszMaterialFile = pItemData->GetString( CFmtStr( kMaterialSkinNFile, pszMaterialSkin, nMaterialIndex, s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); if ( *pszMaterialFile && !V_IsAbsolutePath( pszMaterialFile) ) { V_ComposeFileName( pszBasePath, pszMaterialFile, pszLoadPath, sizeof(pszLoadPath) ); pszMaterialFile = pszLoadPath; } CUtlBuffer sMaterialText; if ( FStrEq( pszMaterialVMT, "" ) ) { sMaterialText.SetBufferType( true, true ); g_pFullFileSystem->ReadFile( pszMaterialFile, NULL, sMaterialText ); pszMaterialVMT = sMaterialText.String(); } if ( !SetMaterialText( nSkinIndex, nMaterialIndex, pszMaterialVMT ) ) { sFailedPath = pszMaterialFile; return LOAD_FAILED_BADMATERIAL; } for ( int nTextureType = 0; nTextureType < CItemUpload::Manifest()->GetNumTextureTypes(); ++nTextureType ) { const char *pszMaterialTextureFile = pItemData->GetString( CFmtStr( kMaterialSkinNFile, pszMaterialSkin, nMaterialIndex, s_pszMaterialFilePrefixes[nTextureType] ) ); if ( *pszMaterialTextureFile && !V_IsAbsolutePath( pszMaterialTextureFile) ) { V_ComposeFileName( pszBasePath, pszMaterialTextureFile, pszLoadPath, sizeof(pszLoadPath) ); pszMaterialTextureFile = pszLoadPath; } if ( !SetMaterial( nSkinIndex, nMaterialIndex, pszMaterialTextureFile, (MATERIAL_FILE_TYPE)nTextureType ) ) { sFailedPath = pszMaterialTextureFile; return LOAD_FAILED_BADMATERIAL; } } } } return LOAD_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadZip( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) { // Unzip the file into the temporary directory char pszZipName[MAX_PATH]; V_FileBase( pszFilePath, pszZipName, sizeof(pszZipName) ); char pszTempPath[MAX_PATH]; V_StripExtension( pszFilePath, pszTempPath, sizeof(pszTempPath) ); if ( ShouldP4AddOrEdit() ) { char szCorrectCaseFilePath[MAX_PATH]; g_pFullFileSystem->GetCaseCorrectFullPath( pszFilePath, szCorrectCaseFilePath ); CP4AutoEditFile a( szCorrectCaseFilePath ); } if ( !g_pFullFileSystem->UnzipFile( pszFilePath, pathID, pszTempPath ) ) { sFailedPath = pszFilePath; return LOAD_FAILED; } char pszManifest[MAX_PATH]; V_ComposeFileName( pszTempPath, "manifest.txt", pszManifest, sizeof(pszManifest) ); return LoadTxt( pszManifest, pathID, sFailedPath ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFFileImportDialog::SAVE_RESULT CTFFileImportDialog::Save( const char *pszFilePath, const char *pathID ) { KeyValuesAD pData( BuildSessionData( GetItemName() ) ); CUtlBuffer sNewText; sNewText.SetBufferType( true, true ); pData->RecursiveSaveToFile( sNewText, 0, false, true ); if ( !pData->SaveToFile( g_pFullFileSystem, pszFilePath, pathID ) ) { return SAVE_FAILED; } return SAVE_OKAY; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::SavePreviewData( CAssetTF &asset ) { KeyValues *pSessionData = asset.GetAdditionalManifestData(); if ( m_pPreviewSchema ) { m_pPreviewSchema->deleteThis(); m_pPreviewSchema = NULL; } KeyValues *pItemSchema = pSessionData->FindKey( CFmtStr( "%s/%s", GetItemValues()->GetName(), kItemSchema ) ); if ( pItemSchema ) { m_pPreviewSchema = pItemSchema->MakeCopy(); } Assert(m_pPreviewSchema); // Save the files that were built so we can remove them later m_vecPreviewFiles = asset.GetBuiltFiles(); m_vecCustomModFiles = asset.GetModFiles(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::SetupPreviewData() { KeyValuesAD pPreviewSchema( m_pPreviewSchema->MakeCopy() ); pPreviewSchema->SetString( "item_name", pPreviewSchema->GetString( "name" ) ); if ( !ItemSystem()->GetItemSchema()->SetupPreviewItemDefinition( pPreviewSchema ) ) { return false; } // must call this to flush old model and force load new model with the same name engine->ExecuteClientCmd( "r_flushlod" ); engine->ExecuteClientCmd( "mat_reloadallmaterials" ); engine->ExecuteClientCmd( "cl_soundemitter_flush" ); if ( !m_pPreviewDialog ) { m_pPreviewDialog = new CImportPreviewItemPanel( this, GetItemValues(), m_nSelectedClass ); m_pPreviewDialog->MakePopup( false ); } CEconItemView itemData; itemData.Init( PREVIEW_ITEM_DEFINITION_INDEX, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); itemData.SetClientItemFlags( kEconItemFlagClient_Preview ); m_pPreviewDialog->PreviewItem( 0, &itemData ); return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::CleanupPreviewData() { m_pPreviewDialog.Set( INVALID_PANEL ); FOR_EACH_VEC( m_vecPreviewFiles, i ) { const char *pszFileName = m_vecPreviewFiles[ i ].String(); if ( p4 && V_strstr( pszFileName, "_user_animations.mdl" ) ) { char szCorrectCaseFilePath[MAX_PATH]; g_pFullFileSystem->GetCaseCorrectFullPath( pszFileName, szCorrectCaseFilePath ); CP4AutoRevertFile revert( szCorrectCaseFilePath ); } else { g_pFullFileSystem->RemoveFile( pszFileName ); } } m_vecPreviewFiles.RemoveAll(); FOR_EACH_VEC( m_vecCustomModFiles, i ) { g_pFullFileSystem->RemoveFile( m_vecCustomModFiles[ i ] ); } m_vecCustomModFiles.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::IsMulticlass() { int nClasses = 0; for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( ClassHasModels( nClassIndex ) || ClassHasTauntSources( nClassIndex ) ) ++nClasses; } return (nClasses > 1); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CTFFileImportDialog::GetClassFolder() { const char *pszClassName = NULL; for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( ClassHasModels( nClassIndex ) || ClassHasTauntSources( nClassIndex ) ) { if ( pszClassName ) { pszClassName = kClassFolderMulticlass; } else { pszClassName = kClassFolders[ nClassIndex ]; } } } return pszClassName; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::AnyClassHasModels() { for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( ClassHasModels( nClassIndex ) ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::ClassHasModels( int nClassIndex ) { for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) { if ( V_stricmp( GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ), "" ) != 0 ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::DidSpecifyAllMaterials() { for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], 0 ) ); if ( pKey ) { int nSkinType = GetItemValues()->GetInt( kSkinType ); int nMaterialCount = pKey->GetInt( "materialCount" ); for ( int nSkinIndex=0; nSkinIndex<=nSkinType; ++nSkinIndex ) { for ( int nMaterialIndex=0; nMaterialIndexGetString( CFmtStr( kMaterialSkinNFile, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex, s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); if ( FStrEq( pszMaterialFile, "" ) ) { return false; } } } // only need to check materials for one class because we already check AreClassesMaterialCountMatch break; } } // for each LOD return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::AreClassesLODCountMatch() { int nCurrentLODCount = 0; for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { int nNumClassLOD = 0; for ( int nLOD=0; nLODFindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], nLOD ) ); if ( pKey ) { if ( !FStrEq( pKey->GetString( "file" ), "" ) ) { nNumClassLOD++; } } } // for each LOD if ( nCurrentLODCount == 0 ) { nCurrentLODCount = nNumClassLOD; } else if ( nNumClassLOD != 0 && nCurrentLODCount != nNumClassLOD ) { return false; } } // for each class return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::AreClassesMaterialCountMatch() { for ( int nLOD=0; nLODFindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], nLOD ) ); if ( pKey ) { if ( !FStrEq( pKey->GetString( "file" ), "" ) ) { int nMaterialCount = pKey->GetInt( "materialCount" ); if ( nCurrentMaterialCount == -1 ) { nCurrentMaterialCount = nMaterialCount; } else if ( nCurrentMaterialCount != nMaterialCount ) { return false; } } } } // for each class } // for each LOD return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::AnyClassHasTauntSources() { for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) { if ( ClassHasTauntSources( nClassIndex ) ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFFileImportDialog::ClassHasTauntSources( int nClassIndex ) { if ( nClassIndex == TF_CLASS_UNDEFINED ) return false; KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ nClassIndex ] ) ); if ( pKey ) { const char *pszSource = pKey->GetString( "source_file" ); if ( pszSource && *pszSource ) { return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFileImportDialog::GetWorkshopData() { CFilePublishDialog *pPublishDialog = dynamic_cast< CFilePublishDialog * >( GetParent() ); if ( !pPublishDialog ) return; vgui::TextEntry *pTextEntry = pPublishDialog->FindControl( "FileTitle" ); if ( pTextEntry ) { char pszName[1024]; pTextEntry->GetText( pszName, sizeof(pszName) ); SetItemName( pszName ); } } void CTFFileImportDialog::SetWorkshopData() { CFilePublishDialog *pPublishDialog = dynamic_cast< CFilePublishDialog * >( GetParent() ); if ( !pPublishDialog ) return; pPublishDialog->SetFile( GetItemValues()->GetString( kBuildOutput ), true ); vgui::TextEntry *pTextEntry = pPublishDialog->FindControl( "FileTitle" ); if ( pTextEntry ) { pTextEntry->SetText( GetItemValues()->GetString( kItemName ) ); } vgui::EditablePanel* pClassUsagePanel = pPublishDialog->FindControl( "ClassUsagePanel" ); if ( pClassUsagePanel ) { for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; nClassIndex++ ) { SetChildButtonSelected( pClassUsagePanel, VarArgs( "ClassCheckBox%d", nClassIndex ), ClassHasModels( nClassIndex ) ); } } } void CTFFileImportDialog::SetLODPanelEnable( bool bEnable, int nModelIndex ) { vgui::Panel *pLODPanel = m_pLODPanels[nModelIndex]; if ( pLODPanel ) { for ( int i=0; iGetChildCount(); ++i ) { pLODPanel->GetChild(i)->SetEnabled( bEnable ); } } } void CTFFileImportDialog::SetSkinType( int nSkinType ) { if ( m_pSkinComboBox && nSkinType < m_pSkinComboBox->GetItemCount() ) { m_pSkinComboBox->ActivateItemByRow( nSkinType ); } GetItemValues()->SetInt( kSkinType, nSkinType ); UpdateMaterialDisplay(); SetDirty( true ); } void CTFFileImportDialog::SetEquipRegion( const char* pszEquipRegion ) { if ( m_pEquipRegionComboBox ) { bool bFound = false; for ( int i = 0; i < m_pEquipRegionComboBox->GetItemCount(); ++i ) { KeyValues *pKeyValues = m_pEquipRegionComboBox->GetItemUserData( m_pEquipRegionComboBox->GetItemIDFromRow( i ) ); if ( V_strcasecmp( pszEquipRegion, pKeyValues->GetString( kEquipRegion ) ) == 0 ) { bFound = true; m_pEquipRegionComboBox->ActivateItemByRow( i ); break; } } GetItemValues()->SetString( kEquipRegion, bFound ? pszEquipRegion : "" ); } SetDirty( true ); } void CTFFileImportDialog::SetWorkshopID( const char* pszWorkshopID ) { if ( m_pWorkshopIDTextEntry->IsVisible() ) { GetItemValues()->SetString( kWorkshopID, pszWorkshopID ); m_pWorkshopIDTextEntry->SetText( GetItemValues()->GetString( kWorkshopID ) ); } SetDirty( true ); } bool CTFFileImportDialog::IsTFEnglishNameValid( item_definition_index_t defIndex ) { // check if the name already exist in item schema if ( m_pTFEnglishNameTextEntry->IsVisible() ) { if ( defIndex == INVALID_ITEM_DEF_INDEX ) { return false; } const char* pszTFEnglishName = GetItemValues()->GetString( kTFEnglishName ); const CEconItemSchema::ItemDefinitionMap_t& mapItemDefs = ItemSystem()->GetItemSchema()->GetItemDefinitionMap(); FOR_EACH_MAP_FAST( mapItemDefs, i ) { CEconItemDefinition *pData = mapItemDefs[i]; const char *pszExistingItemName = pData->GetDefinitionName(); item_definition_index_t existingItemDefIndex = pData->GetDefinitionIndex(); if ( existingItemDefIndex != 0 && existingItemDefIndex != defIndex && FStrEq( pszExistingItemName, pszTFEnglishName ) ) { return false; } } } return true; } void CTFFileImportDialog::SetTFEnglishName( const char* pszTFEnglishName ) { if ( m_pTFEnglishNameTextEntry->IsVisible() ) { GetItemValues()->SetString( kTFEnglishName, pszTFEnglishName ); m_pTFEnglishNameTextEntry->SetText( GetItemValues()->GetString( kTFEnglishName ) ); } SetDirty( true ); } //----------------------------------------------------------------------------- item_definition_index_t CTFFileImportDialog::AddKeyValuesToItemWorkshopSchema( KeyValues *pKV ) { char szItemWorkshopAbsPath[MAX_PATH]; if ( !GenerateFullPath( kWorkshopSchemaFile, "MOD", szItemWorkshopAbsPath, ARRAYSIZE( szItemWorkshopAbsPath ) ) ) { Warning( "Failed to GenerateFullPath %s\n", kWorkshopSchemaFile ); return INVALID_ITEM_DEF_INDEX; } char szCorrectCaseFilePath[MAX_PATH]; g_pFullFileSystem->GetCaseCorrectFullPath( szItemWorkshopAbsPath, szCorrectCaseFilePath ); CP4AutoEditAddFile a( szCorrectCaseFilePath ); KeyValuesAD pWorkshopSchema( "WorkshopSchema" ); // This file should force a cache refresh of this specific file otherwise we won't write stuff out. if ( !pWorkshopSchema->LoadFromFile( g_pFullFileSystem, kWorkshopSchemaFile, "MOD", true ) ) { Warning( "Failed to load %s\n", kWorkshopSchemaFile ); return INVALID_ITEM_DEF_INDEX; } int nNewItemIndex = kStartWorkshopItemIndex; const char* pszNewItemName = pKV->GetString( kWorkshopName ); KeyValues *pNewItemKey = NULL; KeyValues *pLastKey = NULL; KeyValues *pItemKey = pWorkshopSchema; while ( pItemKey ) { const char* pszItemName = pItemKey->GetString( kWorkshopName ); nNewItemIndex = atoi( pItemKey->GetName() ); if ( FStrEq( pszItemName, pszNewItemName ) ) { pNewItemKey = pItemKey; break; } pLastKey = pItemKey; pItemKey = pItemKey->GetNextKey(); } if ( !pNewItemKey ) { pNewItemKey = pKV->MakeCopy(); pNewItemKey->SetName( CFmtStr( "%d", nNewItemIndex + 1 ) ); pLastKey->SetNextKey( pNewItemKey ); } else { KeyValuesAD temp( pNewItemKey->MakeCopy() ); pKV->CopySubkeys( pNewItemKey ); pNewItemKey->RecursiveMergeKeyValues( temp ); } KeyValues* pPaymentKey = pNewItemKey->FindKey( "payment_rules/0", true ); pPaymentKey->SetFloat( "workshop_revenue_share", 0.25f ); pPaymentKey->SetString( "target", GetItemValues()->GetString( kWorkshopID ) ); pPaymentKey->SetString( "payment_rule_for_itemdef", pNewItemKey->GetName() ); pItemKey = pWorkshopSchema; CUtlBuffer buffer; while ( pItemKey ) { pItemKey->RecursiveSaveToFile( buffer, 2, false, true ); pItemKey = pItemKey->GetNextKey(); } if ( !g_pFullFileSystem->WriteFile( szItemWorkshopAbsPath, NULL, buffer ) ) { Warning( "Failed to save new item to %s", szItemWorkshopAbsPath ); } item_definition_index_t defIndex = atoi( pNewItemKey->GetName() ); return defIndex; }