You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1646 lines
48 KiB
1646 lines
48 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
#include "cbase.h" |
|
|
|
#include "imageutils.h" |
|
#include "econ_controls.h" |
|
#include "econ/confirm_dialog.h" |
|
#include "game/client/iviewport.h" |
|
#include "ienginevgui.h" |
|
#include "tf_hud_mainmenuoverride.h" |
|
#include "vgui/ILocalize.h" |
|
#include "vgui/ISurface.h" |
|
#include "vgui/ISystem.h" |
|
#include "vgui_bitmappanel.h" |
|
#include <vgui_controls/FileOpenDialog.h> |
|
|
|
#ifdef WORKSHOP_IMPORT_ENABLED |
|
#include "itemtest/itemtest.h" |
|
#include "workshop/item_import.h" |
|
#endif |
|
|
|
#include "steampublishedfiles/publish_file_dialog.h" |
|
|
|
#include "tier1/checksum_crc.h" |
|
|
|
// for hud element |
|
#include "iclientmode.h" |
|
#include "tf_gamerules.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
#define TF2_PREVIEW_IMAGE_HEIGHT 512 |
|
#define TF2_PREVIEW_IMAGE_WIDTH 512 |
|
|
|
#define COMMUNITY_DEV_HOST "http://localhost/" |
|
|
|
extern ConVar publish_file_last_dir; |
|
|
|
// milliseconds |
|
ConVar tf_steam_workshop_query_timeout( "tf_steam_workshop_query_timeout", "10", FCVAR_CLIENTDLL, "Time in seconds to allow communication with the Steam Workshop server." ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Utility function |
|
//----------------------------------------------------------------------------- |
|
static void MakeModalAndBringToFront( vgui::EditablePanel *dialog ) |
|
{ |
|
dialog->SetVisible( true ); |
|
if ( dialog->GetParent() == NULL ) |
|
{ |
|
dialog->MakePopup(); |
|
} |
|
dialog->SetZPos( 10000 ); |
|
dialog->MoveToFront(); |
|
dialog->SetKeyBoardInputEnabled( true ); |
|
dialog->SetMouseInputEnabled( true ); |
|
TFModalStack()->PushModal( dialog ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: helper class that contains the list of published files for a user |
|
//----------------------------------------------------------------------------- |
|
class CPublishedFiles |
|
{ |
|
public: |
|
enum |
|
{ |
|
kState_Initialized, |
|
kState_PopulatingFileList, |
|
kState_ErrorOccurred, |
|
kState_DeletingFile, |
|
kState_ErrorCannotDeleteFile, |
|
kState_Timeout, |
|
kState_Done, |
|
}; |
|
|
|
CPublishedFiles(); |
|
~CPublishedFiles(); |
|
|
|
bool QueryHasTimedOut( void ); |
|
void PopulateFileList( void ); |
|
bool EnumerateUserPublishedFiles( uint32 unPage ); |
|
void RefreshPublishedFileDetails( uint64 nPublishedFileID ); |
|
void DeletePublishedFile( uint64 nPublishedFileID ); |
|
void ViewPublishedFile( uint64 nPublishedFileID ); |
|
const SteamUGCDetails_t *GetPublishedFileDetails( uint64 nPublishedFileID ) const; |
|
|
|
// Enumerate subscribed files |
|
CCallResult<CPublishedFiles, SteamUGCQueryCompleted_t> m_callbackEnumeratePublishedFiles; |
|
void Steam_OnEnumeratePublishedFiles( SteamUGCQueryCompleted_t *pResult, bool bError ); |
|
|
|
// Callback for deleting files |
|
CCallResult<CPublishedFiles, RemoteStorageDeletePublishedFileResult_t> m_callbackDeletePublishedFile; |
|
void Steam_OnDeletePublishedFile( RemoteStorageDeletePublishedFileResult_t *pResult, bool bError ); |
|
|
|
unsigned int m_nTotalFilesToQuery; |
|
CUtlQueue< PublishedFileId_t > m_FilesToQuery; |
|
CUtlMap< PublishedFileId_t, SteamUGCDetails_t > m_FileDetails; |
|
|
|
long m_nFileQueryTime; |
|
bool m_bQueryErrorOccurred; |
|
uint32 m_state; |
|
uint32 m_unEnumerateStartPage; |
|
PublishedFileId_t m_nCurrentQueryPublishedFileID; |
|
}; |
|
|
|
CPublishedFiles::CPublishedFiles() |
|
: m_nTotalFilesToQuery( 0 ) |
|
, m_nFileQueryTime( 0 ) |
|
, m_bQueryErrorOccurred( false ) |
|
, m_state( kState_Initialized ) |
|
, m_unEnumerateStartPage( 0 ) |
|
, m_nCurrentQueryPublishedFileID( 0 ) |
|
{ |
|
m_FileDetails.SetLessFunc( DefLessFunc( PublishedFileId_t ) ); |
|
} |
|
|
|
CPublishedFiles::~CPublishedFiles() |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determine if our file query has timed out |
|
//----------------------------------------------------------------------------- |
|
bool CPublishedFiles::QueryHasTimedOut( void ) |
|
{ |
|
return ( ( system()->GetTimeMillis() - m_nFileQueryTime ) > tf_steam_workshop_query_timeout.GetInt() * 1000 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::PopulateFileList( void ) |
|
{ |
|
// Start the process of showing all of our published files |
|
if ( EnumerateUserPublishedFiles( 1 ) ) |
|
{ |
|
m_unEnumerateStartPage = 1; |
|
|
|
// Get our starting tick |
|
m_nFileQueryTime = system()->GetTimeMillis(); |
|
|
|
m_state = kState_PopulatingFileList; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Wrapper for creating and sending a CreateQueryUserUGCRequest for this user's published files |
|
//----------------------------------------------------------------------------- |
|
bool CPublishedFiles::EnumerateUserPublishedFiles( uint32 unPage ) |
|
{ |
|
ISteamUGC *pUGC = steamapicontext->SteamUGC(); |
|
ISteamUser *pUser = steamapicontext->SteamUser(); |
|
if ( pUGC && pUser ) |
|
{ |
|
AccountID_t nAccountID = pUser->GetSteamID().GetAccountID(); |
|
|
|
UGCQueryHandle_t ugcHandle = pUGC->CreateQueryUserUGCRequest( nAccountID, |
|
k_EUserUGCList_Published, |
|
k_EUGCMatchingUGCType_Items, |
|
k_EUserUGCListSortOrder_CreationOrderDesc, |
|
engine->GetAppID(), engine->GetAppID(), unPage ); |
|
|
|
// make sure we get the entire description and not a truncated version |
|
pUGC->SetReturnLongDescription( ugcHandle, true ); |
|
|
|
SteamAPICall_t hSteamAPICall = pUGC->SendQueryUGCRequest( ugcHandle ); |
|
m_callbackEnumeratePublishedFiles.Set( hSteamAPICall, this, &CPublishedFiles::Steam_OnEnumeratePublishedFiles ); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::DeletePublishedFile( uint64 nPublishedFileID ) |
|
{ |
|
m_state = kState_DeletingFile; |
|
SteamAPICall_t hSteamAPICall = steamapicontext->SteamRemoteStorage()->DeletePublishedFile( nPublishedFileID ); |
|
m_callbackDeletePublishedFile.Set( hSteamAPICall, this, &CPublishedFiles::Steam_OnDeletePublishedFile ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const SteamUGCDetails_t *CPublishedFiles::GetPublishedFileDetails( uint64 nPublishedFileID ) const |
|
{ |
|
int idx = m_FileDetails.Find( nPublishedFileID ); |
|
if ( idx != m_FileDetails.InvalidIndex() ) |
|
{ |
|
return &m_FileDetails[idx]; |
|
} |
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::ViewPublishedFile( uint64 nPublishedFileID ) |
|
{ |
|
EUniverse universe = GetUniverse(); |
|
switch ( universe ) |
|
{ |
|
case k_EUniversePublic: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
case k_EUniverseBeta: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
case k_EUniverseDev: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( COMMUNITY_DEV_HOST "sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::RefreshPublishedFileDetails( uint64 nPublishedFileID ) |
|
{ |
|
if ( m_state != kState_Done ) |
|
{ |
|
// Would confuse the refresh in progress |
|
AssertMsg( m_state == kState_Done, "Shouldn't be refreshing file details while other operations are already happening" ); |
|
return; |
|
} |
|
|
|
ISteamUGC *pUGC = steamapicontext->SteamUGC(); |
|
Assert( pUGC ); |
|
if ( pUGC ) |
|
{ |
|
UGCQueryHandle_t ugcHandle = pUGC->CreateQueryUGCDetailsRequest( &nPublishedFileID, 1 ); |
|
SteamAPICall_t hSteamAPICall = pUGC->SendQueryUGCRequest( ugcHandle ); |
|
m_callbackEnumeratePublishedFiles.Set( hSteamAPICall, this, &CPublishedFiles::Steam_OnEnumeratePublishedFiles ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::Steam_OnDeletePublishedFile( RemoteStorageDeletePublishedFileResult_t *pResult, bool bError ) |
|
{ |
|
if ( pResult && !bError ) |
|
{ |
|
if ( pResult->m_eResult != k_EResultOK ) |
|
{ |
|
m_state = kState_ErrorOccurred; |
|
if ( pResult->m_eResult == k_EResultAccessDenied ) |
|
{ |
|
m_state = kState_ErrorCannotDeleteFile; |
|
} |
|
} |
|
else |
|
{ |
|
m_state = kState_Done; |
|
m_FileDetails.Remove( pResult->m_nPublishedFileId ); |
|
} |
|
} |
|
else |
|
{ |
|
m_state = kState_ErrorOccurred; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPublishedFiles::Steam_OnEnumeratePublishedFiles( SteamUGCQueryCompleted_t *pResult, bool bError ) |
|
{ |
|
// Make sure we succeeded |
|
if ( bError || pResult->m_eResult != k_EResultOK ) |
|
{ |
|
m_state = kState_ErrorOccurred; |
|
return; |
|
} |
|
|
|
if ( m_state == kState_PopulatingFileList && m_unEnumerateStartPage == 1 ) |
|
{ |
|
// Start from scratch |
|
m_FilesToQuery.Purge(); |
|
m_FileDetails.Purge(); |
|
} |
|
|
|
const int nNumFiles = pResult->m_unNumResultsReturned; |
|
for ( int i = 0; i < nNumFiles; i++ ) |
|
{ |
|
SteamUGCDetails_t sDetails = { 0 }; |
|
steamapicontext->SteamUGC()->GetQueryUGCResult( pResult->m_handle, i, &sDetails ); |
|
m_FileDetails.InsertOrReplace( sDetails.m_nPublishedFileId, sDetails ); |
|
} |
|
|
|
if ( m_state == kState_Done ) |
|
{ |
|
// This was a one-off request from e.g. RefreshPublishedFileDetails |
|
return; |
|
} |
|
|
|
if ( !nNumFiles || m_FileDetails.Count() >= pResult->m_unTotalMatchingResults ) |
|
{ |
|
m_state = kState_Done; |
|
return; |
|
} |
|
|
|
EnumerateUserPublishedFiles( ++m_unEnumerateStartPage ); |
|
} |
|
|
|
// Tags |
|
static const char *kClassTags[TF_LAST_NORMAL_CLASS] = { |
|
"", // TF_CLASS_UNDEFINED |
|
"Scout", // TF_CLASS_SCOUT |
|
"Sniper", // TF_CLASS_SNIPER, |
|
"Soldier", // TF_CLASS_SOLDIER, |
|
"Demoman", // TF_CLASS_DEMOMAN, |
|
"Medic", // TF_CLASS_MEDIC, |
|
"Heavy", //TF_CLASS_HEAVYWEAPONS, |
|
"Pyro", // TF_CLASS_PYRO, |
|
"Spy", // TF_CLASS_SPY, |
|
"Engineer", // TF_CLASS_ENGINEER, |
|
}; |
|
|
|
struct TagPair_t |
|
{ |
|
const char *pCheckboxElementName; |
|
const char *pTag; |
|
}; |
|
static TagPair_t kOtherTags[] = { |
|
{ "TagCheckbox_Headgear", "Headgear" }, |
|
{ "TagCheckbox_Weapon", "Weapon" }, |
|
{ "TagCheckbox_Misc", "Misc" }, |
|
{ "TagCheckbox_SoundDevice", "Sound Device" }, |
|
{ "TagCheckbox_Halloween", "Halloween" }, |
|
{ "TagCheckbox_Taunt", "Taunt" }, |
|
{ "TagCheckbox_UnusualEffect", "Unusual Effect" }, |
|
{ "TagCheckbox_Jungle", "Jungle" }, |
|
}; |
|
static uint32 kNumOtherTags = ARRAYSIZE( kOtherTags ); |
|
|
|
// Map Tags |
|
static TagPair_t kMapTags[] = { |
|
{ "MapsCheckBox_CTF", "Capture the Flag" }, |
|
{ "MapsCheckBox_CP", "Control Point" }, |
|
{ "MapsCheckBox_Escort", "Payload" }, |
|
{ "MapsCheckBox_EscortRace", "Payload Race" }, |
|
{ "MapsCheckBox_Arena", "Arena" }, |
|
{ "MapsCheckBox_Koth", "King of the Hill" }, |
|
{ "MapsCheckBox_AttackDefense", "Attack / Defense" }, |
|
{ "MapsCheckBox_SD", "Special Delivery" }, |
|
{ "MapsCheckBox_RobotDestruction", "Robot Destruction" }, |
|
{ "MapsCheckBox_MVM", "Mann vs. Machine" }, |
|
{ "MapsCheckBox_Powerup", "Mannpower" }, |
|
{ "MapsCheckBox_Medieval", "Medieval" }, |
|
{ "MapsCheckBox_PassTime", "PASS Time" }, |
|
{ "MapsCheckBox_Specialty", "Specialty" }, |
|
{ "MapsCheckBox_Halloween", "Halloween" }, |
|
{ "MapsCheckbox_Smissmas", "Smissmas" }, |
|
{ "MapsCheckbox_Night", "Night" }, |
|
{ "MapsCheckbox_Jungle", "Jungle" }, |
|
}; |
|
static uint32 kNumMapTags = ARRAYSIZE( kMapTags ); |
|
|
|
static const char *kImportedTag = "Certified Compatible"; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Publish file dialog |
|
//----------------------------------------------------------------------------- |
|
class CTFFilePublishDialog : public CFilePublishDialog |
|
{ |
|
DECLARE_CLASS_SIMPLE( CTFFilePublishDialog, CFilePublishDialog ); |
|
public: |
|
CTFFilePublishDialog( Panel *parent, const char *name, PublishedFileDetails_t *pDetails ) : CFilePublishDialog( parent, name, pDetails ), m_bImported(false) {} |
|
|
|
virtual ErrorCode_t ValidateFile( const char *lpszFilename ) |
|
{ |
|
if( !g_pFullFileSystem->FileExists( lpszFilename ) ) |
|
return kFailedFileNotFound; |
|
|
|
// TODO This is the nominal max of SteamUGC, but should be found dynamically |
|
const uint32 kMaxFileSize = 400 * 1024 * 1024; |
|
unsigned int unFileSize = g_pFullFileSystem->Size( lpszFilename ); |
|
if ( unFileSize == 0 || unFileSize > kMaxFileSize ) |
|
{ |
|
return kFailedFileTooLarge; |
|
} |
|
return kNoError; |
|
} |
|
virtual AppId_t GetTargetAppID( void ) { return engine->GetAppID(); } |
|
virtual unsigned int DesiredPreviewHeight( void ) { return TF2_PREVIEW_IMAGE_HEIGHT; } |
|
virtual unsigned int DesiredPreviewWidth( void ) { return TF2_PREVIEW_IMAGE_WIDTH; } |
|
virtual bool BForceSquarePreviewImage( void ) { return true; } |
|
virtual EWorkshopFileType WorkshipFileTypeForFile( const char *pszFileName ) { |
|
const char *pExt = V_GetFileExtension( pszFileName ); |
|
if ( pExt && V_strcmp( pExt, "bsp" ) == 0 ) |
|
{ |
|
return k_EWorkshopFileTypeCommunity; |
|
} |
|
|
|
AssertMsg( pExt && V_strcmp( pExt, "zip" ) == 0, "Unrecognized file type, defaulting to microtransaction\n" ); |
|
return k_EWorkshopFileTypeMicrotransaction; |
|
} |
|
virtual const char *GetPreviewFileTypes( void ) { return "*.tga,*.jpg,*.png"; } |
|
virtual const char *GetPreviewFileTypeDescriptions( void ) { return "#TF_SteamWorkshop_Images"; } |
|
virtual const char *GetFileTypes( eFilterType_t eType = IMPORT_FILTER_NONE ) OVERRIDE |
|
{ |
|
if ( eType == IMPORT_FILTER_MAP ) |
|
{ |
|
return "*.bsp"; |
|
} |
|
return "*.zip"; |
|
} |
|
virtual const char *GetFileTypeDescriptions( eFilterType_t eType = IMPORT_FILTER_NONE ) OVERRIDE |
|
{ |
|
if ( eType == IMPORT_FILTER_MAP ) |
|
{ |
|
return "#TF_SteamWorkshop_AcceptableFilesMaps"; |
|
} |
|
return "#TF_SteamWorkshop_AcceptableFiles"; |
|
} |
|
virtual const char *GetResFile() const { return "Resource/UI/PublishFileDialog.res"; } |
|
|
|
virtual void SetFile( const char *lpszFilename, bool bImported ) |
|
{ |
|
BaseClass::SetFile( lpszFilename, bImported ); |
|
SetTagsVisible( true, WorkshipFileTypeForFile( lpszFilename ) ); |
|
|
|
m_sFilePath = lpszFilename; |
|
|
|
CUtlBuffer buffer; |
|
g_pFullFileSystem->ReadFile( lpszFilename, NULL, buffer ); |
|
m_fileCRC = CRC32_ProcessSingleBuffer( buffer.Base(), buffer.Size() ); |
|
|
|
m_bImported = bImported; |
|
} |
|
|
|
void SetTagsVisible( bool visible, EWorkshopFileType eFileType = k_EWorkshopFileTypeCommunity ) |
|
{ |
|
uint32 i; |
|
vgui::CheckButton *pButton; |
|
|
|
vgui::Label *pLabel = FindControl<vgui::Label>( "TagsTitle", true ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetVisible( visible ); |
|
} |
|
|
|
if ( !visible ) |
|
{ |
|
// no tags visible, so hide everything |
|
// class tags |
|
for ( i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( VarArgs( "ClassCheckBox%d", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( visible ); |
|
} |
|
} |
|
|
|
// other tags |
|
for ( i = 0; i < kNumOtherTags; ++i ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( kOtherTags[i].pCheckboxElementName, true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( visible ); |
|
} |
|
} |
|
|
|
// map tags |
|
for ( i = 0; i < kNumMapTags; ++i ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( kMapTags[i].pCheckboxElementName, true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( visible ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
bool bIsMap = ( eFileType == k_EWorkshopFileTypeCommunity ); |
|
|
|
// class tags |
|
for ( i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( VarArgs( "ClassCheckBox%d", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( !bIsMap ); |
|
|
|
if ( bIsMap && pButton->IsSelected() ) |
|
{ |
|
pButton->SetSelected( false ); // reset this button if we're using the maps tags |
|
} |
|
} |
|
} |
|
|
|
// other tags |
|
for ( i = 0; i < kNumOtherTags; ++i ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( kOtherTags[i].pCheckboxElementName, true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( !bIsMap ); |
|
|
|
if ( bIsMap && pButton->IsSelected() ) |
|
{ |
|
pButton->SetSelected( false ); // reset this button if we're using the maps tags |
|
} |
|
} |
|
} |
|
|
|
// map tags |
|
for ( i = 0; i < kNumMapTags; ++i ) |
|
{ |
|
pButton = FindControl<vgui::CheckButton>( kMapTags[i].pCheckboxElementName, true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( bIsMap ); |
|
|
|
if ( !bIsMap && pButton->IsSelected() ) |
|
{ |
|
pButton->SetSelected( false ); // reset this button if we're not using the maps tags |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
virtual void PopulateTags( SteamParamStringArray_t &strArray ) |
|
{ |
|
m_vecTags.RemoveAll(); |
|
|
|
// class tags |
|
vgui::EditablePanel* pClassUsagePanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName( "ClassUsagePanel" ) ); |
|
if ( pClassUsagePanel ) |
|
{ |
|
for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ ) |
|
{ |
|
if ( IsChildButtonSelected( pClassUsagePanel, VarArgs("ClassCheckBox%d",i), false ) ) |
|
{ |
|
m_vecTags.AddToTail( kClassTags[i] ); |
|
} |
|
} |
|
} |
|
|
|
// other tags |
|
for ( uint32 i = 0; i < kNumOtherTags; ++i ) |
|
{ |
|
if ( IsChildButtonSelected( this, kOtherTags[i].pCheckboxElementName, true ) ) |
|
{ |
|
m_vecTags.AddToTail( kOtherTags[i].pTag ); |
|
} |
|
} |
|
|
|
// map tags |
|
for ( uint32 i = 0; i < kNumMapTags; ++i ) |
|
{ |
|
if ( IsChildButtonSelected( this, kMapTags[i].pCheckboxElementName, true ) ) |
|
{ |
|
m_vecTags.AddToTail( kMapTags[i].pTag ); |
|
} |
|
} |
|
|
|
if ( m_bImported ) |
|
{ |
|
m_vecTags.AddToTail( kImportedTag ); |
|
} |
|
|
|
strArray.m_ppStrings = m_vecTags.Base(); |
|
strArray.m_nNumStrings = m_vecTags.Count(); |
|
} |
|
|
|
virtual void PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
// Center it, keeping requested size |
|
int x, y, ww, wt, wide, tall; |
|
vgui::surface()->GetWorkspaceBounds( x, y, ww, wt ); |
|
GetSize(wide, tall); |
|
SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2)); |
|
} |
|
|
|
virtual bool PrepSteamCloudFilePath( const char *lpszFileName, CUtlString &steamCloudFileName ) |
|
{ |
|
char szShortName[ MAX_PATH ]; |
|
Q_FileBase( lpszFileName, szShortName, sizeof( szShortName ) ); |
|
const char *szExt = Q_GetFileExtension( lpszFileName ); |
|
Q_SetExtension( szShortName, CFmtStr( ".%s", szExt ).Access(), sizeof(szShortName ) ); |
|
steamCloudFileName.Format( "steamworkshop/tf2/%s", szShortName ); |
|
return true; |
|
} |
|
|
|
virtual void ErrorMessage( ErrorCode_t errorCode, KeyValues *pkvTokens ) |
|
{ |
|
switch ( errorCode ) |
|
{ |
|
case kFailedToPublishFile: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedToPublishFile", "#GameUI_OK" ); |
|
break; |
|
case kFailedToPrepareFile: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedToPrepareFile", "#GameUI_OK" ); |
|
break; |
|
case kFailedToUpdateFile: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedToUpdateFile", "#GameUI_OK" ); |
|
break; |
|
case kSteamCloudNotAvailable: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kSteamCloudNotAvailable", "#GameUI_OK" ); |
|
break; |
|
case kSteamExceededCloudQuota: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kSteamExceededCloudQuota", "#GameUI_OK" ); |
|
break; |
|
case kFailedToWriteToSteamCloud: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedToWriteToSteamCloud", "#GameUI_OK" ); |
|
break; |
|
case kFileNotFound: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFileNotFound", "#GameUI_OK" ); |
|
break; |
|
case kNeedTitleAndDescription: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kNeedTitleAndDescription", "#GameUI_OK" ); |
|
break; |
|
case kFailedFileValidation: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedFileValidation", "#GameUI_OK" ); |
|
break; |
|
case kFailedFileTooLarge: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedFileTooLarge", "#GameUI_OK" ); |
|
break; |
|
case kFailedFileNotFound: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedFileNotFound", "#GameUI_OK" ); |
|
break; |
|
case kFailedUserModifiedFile: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kFailedUserModifiedFile", "#GameUI_OK" ); |
|
break; |
|
case kInvalidMapName: |
|
ShowMessageBox( "#TF_PublishFile_Error", "#TF_PublishFile_kInvalidMapName", "#GameUI_OK" ); |
|
break; |
|
default: |
|
Assert( false ); // Unhandled enum value |
|
break; |
|
} |
|
if ( pkvTokens ) |
|
{ |
|
pkvTokens->deleteThis(); |
|
} |
|
} |
|
|
|
void ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
if ( !m_bAddingNewFile ) |
|
{ |
|
bool bIsMap = ( m_FileDetails.publishedFileDetails.m_eFileType == k_EWorkshopFileTypeCommunity ); |
|
|
|
CExImageButton *pImageButton = FindControl<CExImageButton>( "ButtonSourceCosmetics", true ); |
|
if ( pImageButton ) |
|
{ |
|
pImageButton->SetVisible( !bIsMap ); |
|
} |
|
|
|
vgui::Button *pButton = FindControl<Button>( "ButtonSourceOther", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( !bIsMap ); |
|
} |
|
|
|
pImageButton = FindControl<CExImageButton>( "ButtonSourceMaps", true ); |
|
if ( pImageButton ) |
|
{ |
|
pImageButton->SetVisible( bIsMap ); |
|
} |
|
} |
|
} |
|
|
|
protected: |
|
|
|
virtual void PopulateEditFields( void ) |
|
{ |
|
BaseClass::PopulateEditFields(); |
|
|
|
// class tags |
|
vgui::EditablePanel* pClassUsagePanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName( "ClassUsagePanel" ) ); |
|
if ( pClassUsagePanel ) |
|
{ |
|
for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ ) |
|
{ |
|
bool bHasTag = Q_strstr( m_FileDetails.publishedFileDetails.m_rgchTags, kClassTags[i] ) != 0; |
|
SetChildButtonSelected( pClassUsagePanel, VarArgs("ClassCheckBox%d",i), bHasTag ); |
|
} |
|
} |
|
|
|
// other tags |
|
for ( uint32 i = 0; i < kNumOtherTags; ++i ) |
|
{ |
|
bool bHasTag = Q_strstr( m_FileDetails.publishedFileDetails.m_rgchTags, kOtherTags[i].pTag ) != 0; |
|
SetChildButtonSelected( this, kOtherTags[i].pCheckboxElementName, bHasTag, true ); |
|
} |
|
|
|
// map tags |
|
for ( uint32 i = 0; i < kNumMapTags; ++i ) |
|
{ |
|
bool bHasTag = Q_strstr( m_FileDetails.publishedFileDetails.m_rgchTags, kMapTags[i].pTag ) != 0; |
|
SetChildButtonSelected( this, kMapTags[i].pCheckboxElementName, bHasTag, true ); |
|
} |
|
|
|
if ( Q_strstr( m_FileDetails.publishedFileDetails.m_rgchTags, kImportedTag ) ) |
|
{ |
|
m_bImported = true; |
|
} |
|
else |
|
{ |
|
m_bImported = false; |
|
} |
|
|
|
// Default the tags hidden until there is a file set |
|
if ( !m_FileDetails.lpszFilename ) |
|
{ |
|
SetTagsVisible( false ); |
|
} |
|
else |
|
{ |
|
SetTagsVisible( true, m_FileDetails.publishedFileDetails.m_eFileType ); |
|
} |
|
|
|
#ifndef WORKSHOP_IMPORT_ENABLED |
|
vgui::Button *pImportButton = FindControl<vgui::Button>( "ButtonSourceCosmetics" ); |
|
if ( pImportButton ) |
|
pImportButton->SetVisible( false ); |
|
#endif |
|
} |
|
|
|
const char* GetStatusString( StatusCode_t statusCode ) |
|
{ |
|
switch ( statusCode ) |
|
{ |
|
case kPublishing: |
|
return "#TF_PublishFile_Publishing"; |
|
break; |
|
case kUpdating: |
|
return "#TF_PublishFile_Updating"; |
|
break; |
|
} |
|
return ""; |
|
} |
|
|
|
void ShowStatusWindow( StatusCode_t statusCode ) |
|
{ |
|
ShowWaitingDialog( new CGenericWaitingDialog( this ), GetStatusString( statusCode ), true, false, 0.0f ); |
|
} |
|
|
|
void HideStatusWindow( void ) |
|
{ |
|
CloseWaitingDialog(); |
|
} |
|
|
|
virtual void OnCommand( const char *command ) |
|
{ |
|
if ( V_stricmp( command, "MainFileCosmetics" ) == 0 ) |
|
{ |
|
#ifdef WORKSHOP_IMPORT_ENABLED |
|
if ( CItemUpload::InitManifest() ) |
|
{ |
|
CTFFileImportDialog *pImportDialog = new CTFFileImportDialog( this ); |
|
pImportDialog->SetDeleteSelfOnClose( true ); |
|
pImportDialog->SetSizeable( false ); |
|
MakeModalAndBringToFront( pImportDialog ); |
|
} |
|
else |
|
{ |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_InvalidManifest" ); |
|
} |
|
#endif |
|
} |
|
else if ( V_stricmp( command, "Publish" ) == 0 || V_stricmp( command, "Update" ) == 0 ) |
|
{ |
|
if ( m_bImported ) |
|
{ |
|
CUtlBuffer buffer; |
|
g_pFullFileSystem->ReadFile( m_sFilePath, NULL, buffer ); |
|
CRC32_t crc = CRC32_ProcessSingleBuffer( buffer.Base(), buffer.Size() ); |
|
if ( crc != m_fileCRC ) |
|
{ |
|
ErrorMessage( kFailedUserModifiedFile, NULL ); |
|
m_bImported = false; |
|
return; |
|
} |
|
} |
|
|
|
BaseClass::OnCommand( command ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
private: |
|
CUtlVector< const char* > m_vecTags; |
|
|
|
CRC32_t m_fileCRC; |
|
CUtlString m_sFilePath; |
|
bool m_bImported; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class CUGCFileRequestCache |
|
{ |
|
public: |
|
CUGCFileRequestCache() |
|
{ |
|
m_mapPreviewFileRequests.SetLessFunc( DefLessFunc( UGCHandle_t ) ); |
|
} |
|
|
|
~CUGCFileRequestCache() |
|
{ |
|
m_mapPreviewFileRequests.PurgeAndDeleteElements(); |
|
} |
|
|
|
CUGCFileRequest *GetFileRequest( UGCHandle_t fileHandle ) |
|
{ |
|
int idx = m_mapPreviewFileRequests.Find( fileHandle ); |
|
if ( idx == m_mapPreviewFileRequests.InvalidIndex() ) |
|
{ |
|
idx = m_mapPreviewFileRequests.Insert( fileHandle, new CUGCFileRequest() ); |
|
} |
|
return m_mapPreviewFileRequests[idx]; |
|
} |
|
|
|
private: |
|
CUtlMap< UGCHandle_t, CUGCFileRequest* > m_mapPreviewFileRequests; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class CSteamWorkshopItemPanel : public vgui::EditablePanel |
|
{ |
|
DECLARE_CLASS_SIMPLE( CSteamWorkshopItemPanel, vgui::EditablePanel ); |
|
public: |
|
CSteamWorkshopItemPanel( vgui::Panel *parent, const char *panelName, CUGCFileRequestCache &previewFileCache ) |
|
: vgui::EditablePanel( parent, panelName ) |
|
, m_bSelected( false ) |
|
, m_bPreviewDownloadPending( false ) |
|
, m_pUGCPreviewFileRequest( NULL ) |
|
, m_previewFileCache( previewFileCache ) |
|
|
|
{ |
|
memset( &m_FileDetails, 0, sizeof( m_FileDetails ) ); |
|
m_pCroppedTextureImagePanel = new CBitmapPanel( this, "PreviewImage" ); |
|
m_pHighlightPanel = new vgui::EditablePanel( this, "HighlightPanel" ); |
|
vgui::ivgui()->AddTickSignal( GetVPanel(), 100 ); |
|
} |
|
|
|
void SetPublishedFileDetails( const SteamUGCDetails_t *pDetails ) |
|
{ |
|
if ( pDetails ) |
|
{ |
|
m_FileDetails = *pDetails; |
|
|
|
SetDialogVariable( "title", m_FileDetails.m_rgchTitle ); |
|
DownloadPreviewImage(); |
|
|
|
SetVisible( true ); |
|
InvalidateLayout( true ); |
|
} |
|
else |
|
{ |
|
m_bPreviewDownloadPending = false; |
|
SetVisible( false ); |
|
m_pUGCPreviewFileRequest = NULL; |
|
} |
|
|
|
m_bSelected = false; |
|
UpdateBorder(); |
|
} |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
LoadControlSettings( "Resource/UI/SteamWorkshopItem.res" ); |
|
} |
|
|
|
virtual void PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
} |
|
|
|
virtual void OnTick() |
|
{ |
|
BaseClass::OnTick(); |
|
|
|
if ( m_bPreviewDownloadPending && m_pUGCPreviewFileRequest ) |
|
{ |
|
UGCFileRequestStatus_t ugcStatus = m_pUGCPreviewFileRequest->Update(); |
|
switch ( ugcStatus ) |
|
{ |
|
case UGCFILEREQUEST_ERROR: |
|
m_bPreviewDownloadPending = false; |
|
break; |
|
|
|
case UGCFILEREQUEST_FINISHED: |
|
SetPreviewImage(); |
|
m_bPreviewDownloadPending = false; |
|
break; |
|
|
|
default: |
|
// Working, continue to wait... |
|
return; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
virtual void OnCursorEntered() |
|
{ |
|
m_pHighlightPanel->SetVisible( true ); |
|
} |
|
|
|
virtual void OnCursorExited() |
|
{ |
|
UpdateBorder(); |
|
} |
|
|
|
virtual void OnMousePressed(vgui::MouseCode code) |
|
{ |
|
if ( code != MOUSE_LEFT ) |
|
return; |
|
|
|
PostActionSignal( new KeyValues( "ItemPanelMousePressed" ) ); |
|
} |
|
|
|
void UpdateBorder() |
|
{ |
|
m_pHighlightPanel->SetVisible( m_bSelected ); |
|
} |
|
|
|
void SetSelected( bool bSelected ) { m_bSelected = bSelected; } |
|
bool GetSelected() const { return m_bSelected; } |
|
|
|
uint64 GetPublishedFileID() const { return m_FileDetails.m_nPublishedFileId; } |
|
|
|
protected: |
|
void DownloadPreviewImage() |
|
{ |
|
m_pCroppedTextureImagePanel->SetImage( NULL ); |
|
m_pUGCPreviewFileRequest = m_previewFileCache.GetFileRequest( m_FileDetails.m_hPreviewFile ); |
|
|
|
switch ( m_pUGCPreviewFileRequest->GetStatus() ) |
|
{ |
|
case UGCFILEREQUEST_READY: |
|
{ |
|
// Start off our download |
|
char szTargetFilename[MAX_PATH]; |
|
V_snprintf( szTargetFilename, sizeof(szTargetFilename), "%llu_thumb.jpg", m_FileDetails.m_nPublishedFileId ); |
|
m_pUGCPreviewFileRequest->StartDownload( m_FileDetails.m_hPreviewFile, "downloads", szTargetFilename ); |
|
m_bPreviewDownloadPending = true; |
|
} |
|
break; |
|
|
|
case UGCFILEREQUEST_DOWNLOADING: |
|
case UGCFILEREQUEST_DOWNLOAD_WRITING: |
|
{ |
|
// download already going for another preview panel |
|
m_bPreviewDownloadPending = true; |
|
} |
|
break; |
|
|
|
case UGCFILEREQUEST_FINISHED: |
|
{ |
|
SetPreviewImage(); |
|
} |
|
break; |
|
|
|
default: |
|
{ |
|
m_pCroppedTextureImagePanel->SetVisible( false ); |
|
} |
|
break; |
|
} // switch |
|
} |
|
|
|
void SetPreviewImage() |
|
{ |
|
// Update our image preview |
|
char szLocalFilename[MAX_PATH]; |
|
m_pUGCPreviewFileRequest->GetLocalFileName( szLocalFilename, sizeof(szLocalFilename) ); |
|
char szLocalPath[ _MAX_PATH ]; |
|
g_pFullFileSystem->GetLocalPath( szLocalFilename, szLocalPath, sizeof(szLocalPath) ); |
|
SetPreviewImage( szLocalPath ); |
|
} |
|
|
|
void SetPreviewImage( const char *lpszFilename ) |
|
{ |
|
if ( lpszFilename == NULL ) |
|
return; |
|
|
|
ConversionErrorType nErrorCode = ImgUtl_LoadBitmap( lpszFilename, m_imgSource ); |
|
if ( nErrorCode == CE_SUCCESS ) |
|
{ |
|
m_pCroppedTextureImagePanel->SetBitmap( m_imgSource ); |
|
m_pCroppedTextureImagePanel->SetVisible( true ); |
|
} |
|
} |
|
|
|
// data |
|
bool m_bSelected; |
|
bool m_bPreviewDownloadPending; |
|
Bitmap_t m_imgSource; // original resolution and aspect |
|
CBitmapPanel *m_pCroppedTextureImagePanel; |
|
vgui::EditablePanel *m_pHighlightPanel; |
|
CUGCFileRequest *m_pUGCPreviewFileRequest; |
|
SteamUGCDetails_t m_FileDetails; |
|
CUGCFileRequestCache &m_previewFileCache; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
#define MAX_ITEMS_VIEWABLE 4 |
|
|
|
class CSteamWorkshopDialog : public vgui::EditablePanel |
|
{ |
|
DECLARE_CLASS_SIMPLE( CSteamWorkshopDialog, vgui::EditablePanel ); |
|
public: |
|
CSteamWorkshopDialog( vgui::Panel *parent ) |
|
: vgui::EditablePanel( parent, "SteamWorkshopDialog" ) |
|
, m_lastPublishedFilesState( CPublishedFiles::kState_Initialized ) |
|
{ |
|
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); |
|
SetScheme(scheme); |
|
SetProportional( true ); |
|
|
|
m_pContainer = new vgui::EditablePanel( this, "Container" ); |
|
m_pItemsContainer = new vgui::EditablePanel( m_pContainer, "ItemsContainer" ); |
|
|
|
vgui::ivgui()->AddTickSignal( GetVPanel(), 0 ); |
|
|
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
m_items[i] = new CSteamWorkshopItemPanel( m_pItemsContainer, VarArgs("SteamWorkshopItem%d", i ), m_previewFileCache ); |
|
m_items[i]->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
virtual ~CSteamWorkshopDialog() |
|
{ |
|
} |
|
|
|
virtual void OnTick( void ) |
|
{ |
|
BaseClass::OnTick(); |
|
|
|
if ( m_lastPublishedFilesState != m_publishedFiles.m_state ) |
|
{ |
|
CloseWaitingDialog(); |
|
switch ( m_publishedFiles.m_state ) |
|
{ |
|
case CPublishedFiles::kState_PopulatingFileList: |
|
ShowWaitingDialog( new CGenericWaitingDialog( this ), "#TF_SteamWorkshop_PopulatingList", true, false, 30.0f ); |
|
break; |
|
case CPublishedFiles::kState_ErrorOccurred: |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_SteamWorkshop_ErrorText", "#GameUI_OK" ); |
|
break; |
|
case CPublishedFiles::kState_DeletingFile: |
|
ShowWaitingDialog( new CGenericWaitingDialog( this ), "#TF_SteamWorkshop_DeletingFile", true, false, 30.0f ); |
|
break; |
|
case CPublishedFiles::kState_ErrorCannotDeleteFile: |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_SteamWorkshop_CannotDeleteFile", "#GameUI_OK" ); |
|
break; |
|
case CPublishedFiles::kState_Timeout: |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_SteamWorkshop_Timeout", "#GameUI_OK" ); |
|
break; |
|
case CPublishedFiles::kState_Done: |
|
RefreshItemsUI(); |
|
break; |
|
} |
|
m_lastPublishedFilesState = m_publishedFiles.m_state; |
|
} |
|
} |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/ui/SteamWorkshopDialog.res" ); |
|
|
|
SetupButton( "LearnMoreButton" ); |
|
SetupButton( "LearnMore2Button" ); |
|
SetupButton( "BrowseButton" ); |
|
SetupButton( "PublishButton" ); |
|
SetupButton( "ViewPublishedButton" ); |
|
SetupButton( "LoadTestMapButton" ); |
|
SetupButton( "ViewLegalAgreementButton" ); |
|
|
|
SetupButton( "PrevPageButton" ); |
|
SetupButton( "NextPageButton" ); |
|
SetupButton( "ViewButton" ); |
|
SetupButton( "EditButton" ); |
|
SetupButton( "DeleteButton" ); |
|
|
|
SetupButton( "CancelButton" ); |
|
|
|
SetChildPanelEnabled( this, "LoadTestMapButton", !engine->IsInGame() || !FStrEq( engine->GetLevelName(), "maps/itemtest.bsp" ), true ); |
|
} |
|
|
|
virtual void PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
// Center it, keeping requested size |
|
int x, y, ww, wt, wide, tall; |
|
vgui::surface()->GetWorkspaceBounds( x, y, ww, wt ); |
|
GetSize(wide, tall); |
|
SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2)); |
|
} |
|
|
|
virtual void Show() |
|
{ |
|
TFModalStack()->PushModal( this ); |
|
|
|
// Make sure we're signed on |
|
if ( !CheckSteamSignOn() ) |
|
{ |
|
Close(); |
|
return; |
|
} |
|
|
|
SetVisible( true ); |
|
MakePopup(); |
|
MoveToFront(); |
|
SetKeyBoardInputEnabled( true ); |
|
SetMouseInputEnabled( true ); |
|
|
|
// start download |
|
m_publishedFiles.PopulateFileList(); |
|
} |
|
|
|
virtual void OnCommand( const char *pCommand ) |
|
{ |
|
if ( FStrEq( pCommand, "cancel" ) ) |
|
{ |
|
Close(); |
|
} |
|
else if ( FStrEq( pCommand, "publish" ) ) |
|
{ |
|
ShowPublishFileDialog(); |
|
} |
|
else if ( FStrEq( pCommand, "learn_more" ) ) |
|
{ |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://www.teamfortress.com/contribute/" ); |
|
} |
|
else if ( FStrEq( pCommand, "view_files" ) ) |
|
{ |
|
EUniverse universe = GetUniverse(); |
|
uint64 ulSteamID = steamapicontext->SteamUser()->GetSteamID().ConvertToUint64(); |
|
switch ( universe ) |
|
{ |
|
case k_EUniversePublic: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/profiles/%llu/mysharedfiles/", ulSteamID ) ); |
|
break; |
|
case k_EUniverseBeta: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/profiles/%llu/mysharedfiles/", ulSteamID ) ); |
|
break; |
|
case k_EUniverseDev: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( COMMUNITY_DEV_HOST "profiles/%llu/mysharedfiles/", ulSteamID ) ); |
|
break; |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "view_legal_agreement" ) ) |
|
{ |
|
EUniverse universe = GetUniverse(); |
|
switch ( universe ) |
|
{ |
|
case k_EUniversePublic: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/workshop/workshoplegalagreement/?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
case k_EUniverseBeta: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/workshop/workshoplegalagreement/?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
case k_EUniverseDev: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( COMMUNITY_DEV_HOST "workshop/workshoplegalagreement/?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "browse" ) ) |
|
{ |
|
EUniverse universe = GetUniverse(); |
|
switch ( universe ) |
|
{ |
|
case k_EUniversePublic: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/workshop/browse?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
case k_EUniverseBeta: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/workshop/browse?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
case k_EUniverseDev: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( COMMUNITY_DEV_HOST "workshop/browse?appid=%d", engine->GetAppID() ) ); |
|
break; |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "itemtest" ) ) |
|
{ |
|
Close(); |
|
engine->ClientCmd_Unrestricted( "disconnect\nwait\nwait\n\nprogress_enable\nmap itemtest\n" ); |
|
} |
|
else if ( FStrEq( pCommand, "prevpage" ) ) |
|
{ |
|
if ( m_unCurrentPage > 0 ) |
|
{ |
|
--m_unCurrentPage; |
|
} |
|
PopulatePublishedFilesUI(); |
|
} |
|
else if ( FStrEq( pCommand, "nextpage" ) ) |
|
{ |
|
uint32 unNumPages = ceil( (float)m_publishedFiles.m_FileDetails.Count() / (float)MAX_ITEMS_VIEWABLE ); |
|
if ( m_unCurrentPage < unNumPages ) |
|
{ |
|
++m_unCurrentPage; |
|
PopulatePublishedFilesUI(); |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "view" ) ) |
|
{ |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
if ( m_items[i]->GetSelected() ) |
|
{ |
|
ViewPublishedFile( m_items[i]->GetPublishedFileID() ); |
|
break; |
|
} |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "edit" ) ) |
|
{ |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
if ( m_items[i]->GetSelected() ) |
|
{ |
|
EditPublishedFile( m_items[i]->GetPublishedFileID() ); |
|
break; |
|
} |
|
} |
|
} |
|
else if ( FStrEq( pCommand, "delete_item" ) ) |
|
{ |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
if ( m_items[i]->GetSelected() ) |
|
{ |
|
DeletePublishedFile( m_items[i]->GetPublishedFileID() ); |
|
break; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( pCommand ); |
|
} |
|
} |
|
|
|
virtual void OnKeyCodeTyped( vgui::KeyCode code ) |
|
{ |
|
if( code == KEY_ESCAPE ) |
|
{ |
|
OnCommand( "cancel" ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnKeyCodeTyped( code ); |
|
} |
|
} |
|
|
|
virtual void OnKeyCodePressed( vgui::KeyCode code ) |
|
{ |
|
if( GetBaseButtonCode( code ) == KEY_XBUTTON_B ) |
|
{ |
|
OnCommand( "cancel" ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
} |
|
|
|
MESSAGE_FUNC_PTR( OnItemPanelMousePressed, "ItemPanelMousePressed", panel ) |
|
{ |
|
CSteamWorkshopItemPanel *pItemPanel = static_cast< CSteamWorkshopItemPanel * >( panel ); |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
m_items[i]->SetSelected( m_items[i] == pItemPanel ); |
|
m_items[i]->UpdateBorder(); |
|
} |
|
|
|
// enable per item controls |
|
SetChildPanelEnabled( m_pItemsContainer, "ViewButton", true ); |
|
SetChildPanelEnabled( m_pItemsContainer, "EditButton", true ); |
|
SetChildPanelEnabled( m_pItemsContainer, "DeleteButton", true ); |
|
} |
|
|
|
MESSAGE_FUNC_UINT64( OnChangedFile, "ChangedFile", nPublishedFileID ) |
|
{ |
|
m_publishedFiles.RefreshPublishedFileDetails( nPublishedFileID ); |
|
} |
|
|
|
protected: |
|
|
|
bool CheckSteamSignOn() |
|
{ |
|
// Make sure we are connected to steam, or they are going to be disappointed |
|
if ( steamapicontext == NULL |
|
|| steamapicontext->SteamUtils() == NULL |
|
|| steamapicontext->SteamMatchmakingServers() == NULL |
|
|| steamapicontext->SteamUser() == NULL |
|
|| !steamapicontext->SteamUser()->BLoggedOn() |
|
) { |
|
Warning( "Steam not properly initialized or connected.\n" ); |
|
ShowMessageBox( "#TF_MM_GenericFailure_Title", "#TF_MM_GenericFailure", "#GameUI_OK" ); |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
void RefreshItemsUI() |
|
{ |
|
SetChildPanelVisible( m_pContainer, "NoItemsContainer", m_publishedFiles.m_FileDetails.Count() == 0 ); |
|
SetChildPanelVisible( m_pContainer, "ItemsContainer", m_publishedFiles.m_FileDetails.Count() != 0 ); |
|
SetChildPanelVisible( m_pContainer, "LearnMore2Button", m_publishedFiles.m_FileDetails.Count() != 0 ); |
|
SetChildPanelVisible( m_pContainer, "BrowseButton", m_publishedFiles.m_FileDetails.Count() == 0 ); |
|
|
|
m_unCurrentPage = 0; |
|
PopulatePublishedFilesUI(); |
|
} |
|
|
|
void PopulatePublishedFilesUI() |
|
{ |
|
if ( m_publishedFiles.m_FileDetails.Count() != 0 ) |
|
{ |
|
uint32 unIndex = m_unCurrentPage * MAX_ITEMS_VIEWABLE; |
|
int nFileIdx = m_publishedFiles.m_FileDetails.FirstInorder(); |
|
for ( uint32 i = 0; i < unIndex && nFileIdx != m_publishedFiles.m_FileDetails.InvalidIndex(); ++i ) |
|
{ |
|
nFileIdx = m_publishedFiles.m_FileDetails.NextInorder( nFileIdx ); |
|
} |
|
bool bSelected = false; |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
CSteamWorkshopItemPanel *pItemPanel = m_items[i]; |
|
if ( nFileIdx != m_publishedFiles.m_FileDetails.InvalidIndex() ) |
|
{ |
|
SteamUGCDetails_t &details = m_publishedFiles.m_FileDetails[ nFileIdx ]; |
|
pItemPanel->SetPublishedFileDetails( &details ); |
|
if ( !bSelected ) |
|
{ |
|
pItemPanel->SetSelected( true ); |
|
pItemPanel->UpdateBorder(); |
|
bSelected = true; |
|
} |
|
nFileIdx = m_publishedFiles.m_FileDetails.NextInorder( nFileIdx ); |
|
} |
|
else |
|
{ |
|
pItemPanel->SetPublishedFileDetails( NULL ); |
|
} |
|
} |
|
|
|
// paging |
|
uint32 unNumPages = ceil( (float)m_publishedFiles.m_FileDetails.Count() / (float)MAX_ITEMS_VIEWABLE ); |
|
bool bMultiplePages = ( unNumPages > 1 ); |
|
if ( bMultiplePages ) |
|
{ |
|
m_pItemsContainer->SetDialogVariable( "page", CFmtStr( "%d/%d", m_unCurrentPage + 1, unNumPages ) ); |
|
} |
|
else |
|
{ |
|
m_pItemsContainer->SetDialogVariable( "page", "" ); |
|
} |
|
SetChildPanelVisible( m_pItemsContainer, "NextPageButton", bMultiplePages ); |
|
SetChildPanelVisible( m_pItemsContainer, "PrevPageButton", bMultiplePages ); |
|
SetChildPanelEnabled( m_pItemsContainer, "NextPageButton", m_unCurrentPage < unNumPages - 1 ); |
|
SetChildPanelEnabled( m_pItemsContainer, "PrevPageButton", m_unCurrentPage > 0 ); |
|
|
|
// other controls |
|
SetChildPanelEnabled( m_pItemsContainer, "ViewButton", bSelected ); |
|
SetChildPanelEnabled( m_pItemsContainer, "EditButton", bSelected ); |
|
SetChildPanelEnabled( m_pItemsContainer, "DeleteButton", bSelected ); |
|
} |
|
else |
|
{ |
|
SetChildPanelEnabled( m_pItemsContainer, "ViewButton", false ); |
|
SetChildPanelEnabled( m_pItemsContainer, "EditButton", false ); |
|
SetChildPanelEnabled( m_pItemsContainer, "DeleteButton", false ); |
|
} |
|
} |
|
|
|
void ShowPublishFileDialog() |
|
{ |
|
CTFFilePublishDialog *pPublishDialog = new CTFFilePublishDialog( this, "PublishFileDialog", NULL ); |
|
pPublishDialog->AddActionSignalTarget( this ); |
|
pPublishDialog->SetDeleteSelfOnClose( true ); |
|
pPublishDialog->SetSizeable( false ); |
|
MakeModalAndBringToFront( pPublishDialog ); |
|
} |
|
|
|
void ViewPublishedFile( uint64 nPublishedFileID ) |
|
{ |
|
EUniverse universe = GetUniverse(); |
|
switch ( universe ) |
|
{ |
|
case k_EUniversePublic: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
case k_EUniverseBeta: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
case k_EUniverseDev: |
|
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( COMMUNITY_DEV_HOST "sharedfiles/filedetails/?id=%llu", nPublishedFileID ) ); |
|
break; |
|
} |
|
} |
|
|
|
void EditPublishedFile( uint64 nPublishedFileID ) |
|
{ |
|
const SteamUGCDetails_t *pDetails = m_publishedFiles.GetPublishedFileDetails( nPublishedFileID ); |
|
if ( pDetails ) |
|
{ |
|
|
|
PublishedFileDetails_t fileDetails; |
|
fileDetails.publishedFileDetails = *pDetails; |
|
fileDetails.lpszFilename = pDetails->m_pchFileName; |
|
|
|
CTFFilePublishDialog *pPublishDialog = new CTFFilePublishDialog( this, "PublishFileDialog", &fileDetails ); |
|
pPublishDialog->AddActionSignalTarget( this ); |
|
pPublishDialog->SetDeleteSelfOnClose( true ); |
|
pPublishDialog->SetSizeable( false ); |
|
MakeModalAndBringToFront( pPublishDialog ); |
|
|
|
if ( fileDetails.publishedFileDetails.m_eFileType == k_EWorkshopFileTypeMicrotransaction && |
|
!Q_strstr( fileDetails.publishedFileDetails.m_rgchTags, kImportedTag ) ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_Warning", "#TF_ImportFile_NotCompatible" ); |
|
} |
|
} |
|
} |
|
|
|
static void ConfirmDeletePublishedFile( bool bConfirmed, void *pContext ) |
|
{ |
|
if ( bConfirmed ) |
|
{ |
|
CSteamWorkshopDialog *pDialog = static_cast< CSteamWorkshopDialog* >( pContext ); |
|
uint64 nPublishedFileID = 0; |
|
for ( uint32 i = 0; i < MAX_ITEMS_VIEWABLE; ++i ) |
|
{ |
|
if ( pDialog->m_items[i]->GetSelected() ) |
|
{ |
|
nPublishedFileID = pDialog->m_items[i]->GetPublishedFileID(); |
|
break; |
|
} |
|
} |
|
if ( nPublishedFileID != 0 ) |
|
{ |
|
const SteamUGCDetails_t *pDetails = pDialog->m_publishedFiles.GetPublishedFileDetails( nPublishedFileID ); |
|
if ( pDetails ) |
|
{ |
|
pDialog->m_publishedFiles.DeletePublishedFile( nPublishedFileID ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void DeletePublishedFile( uint64 nPublishedFileID ) |
|
{ |
|
ShowConfirmDialog( "#TF_SteamWorkshop_DeleteConfirmTitle", "#TF_SteamWorkshop_DeleteConfirmText", "#GameUI_OK", "#GameuI_CancelBold", &ConfirmDeletePublishedFile, this, this ); |
|
} |
|
|
|
void SetupButton( const char *pPanelName ) |
|
{ |
|
vgui::Panel *pPanel = m_pContainer->FindChildByName( pPanelName, true ); |
|
if ( pPanel ) |
|
{ |
|
pPanel->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
// called when the Cancel button is pressed |
|
void Close() |
|
{ |
|
SetVisible( false ); |
|
TFModalStack()->PopModal( this ); |
|
MarkForDeletion(); |
|
} |
|
|
|
vgui::EditablePanel *m_pContainer; |
|
vgui::EditablePanel *m_pItemsContainer; |
|
CPublishedFiles m_publishedFiles; |
|
uint32 m_lastPublishedFilesState; |
|
uint32 m_unCurrentPage; |
|
CSteamWorkshopItemPanel *m_items[MAX_ITEMS_VIEWABLE]; |
|
CUGCFileRequestCache m_previewFileCache; |
|
}; |
|
static vgui::DHANDLE<CSteamWorkshopDialog> g_pSteamWorkshopDialog; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Callback to open the game menus |
|
//----------------------------------------------------------------------------- |
|
static void CL_OpenSteamWorkshopDialog( const CCommand &args ) |
|
{ |
|
if ( g_pSteamWorkshopDialog.Get() == NULL ) |
|
{ |
|
IViewPortPanel *pMMOverride = ( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) ); |
|
g_pSteamWorkshopDialog = vgui::SETUP_PANEL( new CSteamWorkshopDialog( (CHudMainMenuOverride*)pMMOverride ) ); |
|
} |
|
engine->ExecuteClientCmd( "gameui_activate" ); |
|
g_pSteamWorkshopDialog->Show(); |
|
} |
|
|
|
// the console commands |
|
static ConCommand steamworkshopdialog( "OpenSteamWorkshopDialog", &CL_OpenSteamWorkshopDialog, "" ); |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
class CItemTestHUDPanel : public CHudElement, public vgui::EditablePanel |
|
{ |
|
DECLARE_CLASS_SIMPLE( CItemTestHUDPanel, vgui::EditablePanel ); |
|
public: |
|
CItemTestHUDPanel( const char *pElementName ) |
|
: CHudElement( pElementName ) |
|
, BaseClass( NULL, "ItemTestHUDPanel" ) |
|
{ |
|
vgui::Panel *pParent = g_pClientMode->GetViewport(); |
|
SetParent( pParent ); |
|
|
|
SetHiddenBits( HIDEHUD_MISCSTATUS ); |
|
} |
|
|
|
virtual ~CItemTestHUDPanel() |
|
{ |
|
|
|
} |
|
|
|
virtual bool ShouldDraw( void ) |
|
{ |
|
if ( !CHudElement::ShouldDraw() ) |
|
return false; |
|
|
|
if ( !engine->IsInGame() ) |
|
return false; |
|
|
|
if ( TFGameRules() && TFGameRules()->IsInItemTestingMode() ) |
|
return true; |
|
|
|
return FStrEq( engine->GetLevelName(), "maps/itemtest.bsp" ); |
|
} |
|
|
|
virtual void PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
if ( m_pBGPanel_Blue && m_pBGPanel_Red && C_TFPlayer::GetLocalTFPlayer() ) |
|
{ |
|
bool bRed = ( C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber() == TF_TEAM_RED ); |
|
m_pBGPanel_Blue->SetVisible( !bRed ); |
|
m_pBGPanel_Red->SetVisible( bRed ); |
|
} |
|
} |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *scheme ) |
|
{ |
|
if ( g_pFullFileSystem->FileExists( "resource/UI/ItemTestHUDPanel.res" ) ) |
|
{ |
|
LoadControlSettings( "resource/UI/ItemTestHUDPanel.res" ); |
|
} |
|
|
|
BaseClass::ApplySchemeSettings( scheme ); |
|
|
|
m_pBGPanel_Blue = FindChildByName("Background_Blue"); |
|
m_pBGPanel_Red = FindChildByName("Background_Red"); |
|
|
|
if ( m_pBGPanel_Blue ) |
|
{ |
|
m_pBGPanel_Blue->SetVisible( true ); |
|
} |
|
} |
|
|
|
int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) |
|
{ |
|
if ( !IsVisible() ) |
|
return 1; // key not handled |
|
|
|
if ( !down ) |
|
return 1; // key not handled |
|
|
|
switch ( keynum ) |
|
{ |
|
case KEY_F7: |
|
{ |
|
engine->ClientCmd_Unrestricted( "itemtest" ); |
|
return 0; |
|
} |
|
break; |
|
case KEY_F8: |
|
{ |
|
engine->ClientCmd_Unrestricted( "itemtest_botcontrols" ); |
|
return 0; |
|
} |
|
break; |
|
case KEY_F9: |
|
{ |
|
InvalidateLayout( true, true ); |
|
return 0; |
|
} |
|
break; |
|
} |
|
|
|
return 1; // key not handled |
|
} |
|
|
|
protected: |
|
vgui::Panel *m_pBGPanel_Blue; |
|
vgui::Panel *m_pBGPanel_Red; |
|
}; |
|
|
|
DECLARE_HUDELEMENT( CItemTestHUDPanel ); |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
// @return true if the item test HUD handled the input, false otherwise |
|
bool ItemTestHandlesKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) |
|
{ |
|
CItemTestHUDPanel *pItemTestHUDPanel = ( CItemTestHUDPanel * )GET_HUDELEMENT( CItemTestHUDPanel ); |
|
if ( pItemTestHUDPanel ) |
|
{ |
|
return pItemTestHUDPanel->HudElementKeyInput( down, keynum, pszCurrentBinding ) == 0; |
|
} |
|
return false; |
|
} |
|
|
|
|