mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,985 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Dialog for selecting game configurations
|
||||
//
|
||||
//=====================================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#include <vgui/IVGui.h>
|
||||
#include <vgui/IInput.h>
|
||||
#include <vgui/ISystem.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui_controls/Button.h>
|
||||
#include <vgui_controls/TextEntry.h>
|
||||
#include <vgui_controls/MessageBox.h>
|
||||
#include <vgui_controls/ImagePanel.h>
|
||||
#include <vgui_controls/FileOpenDialog.h>
|
||||
#include "vgui_bitmappanel.h"
|
||||
#include <KeyValues.h>
|
||||
#include "imageutils.h"
|
||||
#include "bsp_utils.h"
|
||||
|
||||
#include "icommandline.h"
|
||||
#include "publish_file_dialog.h"
|
||||
#include "workshop/ugc_utils.h"
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
#include "../server/tf/workshop/maps_workshop.h"
|
||||
#endif // TF_CLIENT_DLL
|
||||
|
||||
#include "steam/steam_api.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
static CUtlString g_MapFilename;
|
||||
static CUtlString g_PreviewFilename;
|
||||
|
||||
ConVar publish_file_last_dir( "publish_file_last_dir", "", FCVAR_ARCHIVE | FCVAR_CLIENTDLL | FCVAR_HIDDEN | FCVAR_DONTRECORD );
|
||||
|
||||
CFilePublishDialog *g_pSteamFilePublishDialog = NULL;
|
||||
|
||||
#define WORKSHOP_TEMP_UPLOAD_DIR "workshop/upload"
|
||||
|
||||
class CPrepareFileThread : public CThread
|
||||
{
|
||||
public:
|
||||
CPrepareFileThread( const char *pszInputFile, const char *pszOutputFile )
|
||||
: m_strInput( pszInputFile )
|
||||
, m_strOutput( pszOutputFile )
|
||||
{}
|
||||
|
||||
// Return 0 for success
|
||||
virtual int Run()
|
||||
{
|
||||
if ( V_strcasecmp( V_GetFileExtension( m_strInput.Get() ), "bsp" ) == 0 )
|
||||
{
|
||||
return BSP_SyncRepack( m_strInput.Get(), m_strOutput.Get() ) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just copy file to prepared location
|
||||
return engine->CopyLocalFile( m_strInput.Get(), m_strOutput.Get() ) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlString m_strInput;
|
||||
CUtlString m_strOutput;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFilePublishDialog::CFilePublishDialog( Panel *parent, const char *name, PublishedFileDetails_t *pDetails ) : BaseClass( parent, name )
|
||||
{
|
||||
m_pPrepareFileThread = NULL;
|
||||
|
||||
g_pSteamFilePublishDialog = this;
|
||||
|
||||
// These must be supplied
|
||||
m_bValidFile = false;
|
||||
m_bValidJpeg = false;
|
||||
|
||||
vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
|
||||
|
||||
// Save this for later
|
||||
if ( pDetails != NULL )
|
||||
{
|
||||
m_FileDetails = *pDetails;
|
||||
m_bAddingNewFile = false;
|
||||
g_MapFilename = m_FileDetails.lpszFilename;
|
||||
m_nFileID = m_FileDetails.publishedFileDetails.m_nPublishedFileId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear it out
|
||||
m_FileDetails.lpszFilename = NULL;
|
||||
m_FileDetails.publishedFileDetails.m_eVisibility = k_ERemoteStoragePublishedFileVisibilityPublic;
|
||||
m_FileDetails.publishedFileDetails.m_hFile = k_UGCHandleInvalid;
|
||||
m_FileDetails.publishedFileDetails.m_hPreviewFile = k_UGCHandleInvalid;
|
||||
m_FileDetails.publishedFileDetails.m_nConsumerAppID = k_uAppIdInvalid;
|
||||
m_FileDetails.publishedFileDetails.m_nCreatorAppID = k_uAppIdInvalid;
|
||||
m_FileDetails.publishedFileDetails.m_nPublishedFileId = 0; // FIXME: Need a real "invalid" value
|
||||
m_FileDetails.publishedFileDetails.m_rtimeCreated = 0;
|
||||
m_FileDetails.publishedFileDetails.m_rtimeUpdated = 0;
|
||||
m_FileDetails.publishedFileDetails.m_ulSteamIDOwner = 0; // FIXME: Need a real "invalid" value
|
||||
memset( m_FileDetails.publishedFileDetails.m_rgchDescription, 0, k_cchPublishedDocumentDescriptionMax );
|
||||
memset( m_FileDetails.publishedFileDetails.m_rgchTitle, 0, k_cchPublishedDocumentTitleMax );
|
||||
|
||||
m_bAddingNewFile = true;
|
||||
g_MapFilename = "";
|
||||
m_nFileID = k_PublishedFileIdInvalid;
|
||||
}
|
||||
|
||||
m_nFileDetailsChanges = 0;
|
||||
|
||||
m_fileOpenMode = FILEOPEN_NONE;
|
||||
|
||||
// Setup our image panel
|
||||
m_pCroppedTextureImagePanel = new CBitmapPanel( this, "PreviewImage" );
|
||||
m_pCroppedTextureImagePanel->SetSize( DesiredPreviewWidth(), DesiredPreviewHeight() );
|
||||
m_pCroppedTextureImagePanel->SetVisible( true );
|
||||
|
||||
m_pStatusBox = NULL;
|
||||
|
||||
// Start downloading our preview image
|
||||
m_bPreviewDownloadPending = false;
|
||||
DownloadPreviewImage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFilePublishDialog::~CFilePublishDialog()
|
||||
{
|
||||
//delete m_pConfigCombo;
|
||||
g_pSteamFilePublishDialog = NULL;
|
||||
|
||||
// We should be in a modal dialog when this is running, not closable
|
||||
Assert( !m_pPrepareFileThread );
|
||||
if ( m_pPrepareFileThread )
|
||||
{
|
||||
m_pPrepareFileThread->Stop();
|
||||
delete m_pPrepareFileThread;
|
||||
m_pPrepareFileThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CFilePublishDialog::ErrorMessage( ErrorCode_t errorCode, KeyValues *pkvTokens )
|
||||
{
|
||||
switch ( errorCode )
|
||||
{
|
||||
case kFailedToPublishFile:
|
||||
ErrorMessage( "Failed to publish file!" );
|
||||
break;
|
||||
case kFailedToUpdateFile:
|
||||
ErrorMessage( "Failed to update file!" );
|
||||
break;
|
||||
case kFailedToPrepareFile:
|
||||
ErrorMessage( "Failed to prepare file!" );
|
||||
break;
|
||||
case kSteamCloudNotAvailable:
|
||||
ErrorMessage( "Steam Cloud is not available." );
|
||||
break;
|
||||
case kSteamExceededCloudQuota:
|
||||
ErrorMessage( "Exceed Steam Cloud quota." );
|
||||
break;
|
||||
case kFailedToWriteToSteamCloud:
|
||||
ErrorMessage( "Failed to write to Steam cloud!" );
|
||||
break;
|
||||
case kFileNotFound:
|
||||
ErrorMessage( "File not found!" );
|
||||
break;
|
||||
case kNeedTitleAndDescription:
|
||||
ErrorMessage( "Need to have a title and description!" );
|
||||
break;
|
||||
case kFailedFileValidation:
|
||||
ErrorMessage( "File failed to validate!" );
|
||||
break;
|
||||
case kFailedUserModifiedFile:
|
||||
ErrorMessage( "File was manually modified after verifying process" );
|
||||
break;
|
||||
case kInvalidMapName:
|
||||
ErrorMessage( "Invalid name for map. Map names must be lowercase and of the form cp_foo.bsp." );
|
||||
break;
|
||||
default:
|
||||
Assert( false ); // Unhandled enum value
|
||||
break;
|
||||
}
|
||||
if ( pkvTokens )
|
||||
{
|
||||
pkvTokens->deleteThis();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::ErrorMessage( const char *lpszText )
|
||||
{
|
||||
vgui::MessageBox *pBox = new vgui::MessageBox( "", lpszText, this );
|
||||
pBox->SetPaintBorderEnabled( false );
|
||||
pBox->SetPaintBackgroundEnabled( true );
|
||||
pBox->SetBgColor( Color(0,0,0,255) );
|
||||
pBox->DoModal();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* CFilePublishDialog::GetStatusString( StatusCode_t statusCode )
|
||||
{
|
||||
switch ( statusCode )
|
||||
{
|
||||
case kPublishing:
|
||||
return "Publishing, please wait...";
|
||||
break;
|
||||
case kUpdating:
|
||||
return "Publishing, please wait...";
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Show our modal status window to cover asynchronous tasks
|
||||
// TODO: Pull this out into a more generalized solution across dialogs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::ShowStatusWindow( StatusCode_t statusCode )
|
||||
{
|
||||
// Throw up our status box
|
||||
if ( m_pStatusBox )
|
||||
{
|
||||
m_pStatusBox->CloseModal();
|
||||
m_pStatusBox = NULL; // FIXME: Does this clear up the memory?
|
||||
}
|
||||
|
||||
const char *lpszText = GetStatusString( statusCode );
|
||||
|
||||
// Pop a message to the user so they know to wait
|
||||
m_pStatusBox = new vgui::MessageBox( "", lpszText, this );
|
||||
m_pStatusBox->SetPaintBorderEnabled( false );
|
||||
m_pStatusBox->SetPaintBackgroundEnabled( true );
|
||||
m_pStatusBox->SetBgColor( Color(0,0,0,255) );
|
||||
m_pStatusBox->SetOKButtonVisible( false );
|
||||
m_pStatusBox->DoModal();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hide our modal status window
|
||||
// TODO: Pull this out into a more generalized solution across dialogs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::HideStatusWindow( void )
|
||||
{
|
||||
m_pStatusBox->CloseModal();
|
||||
m_pStatusBox = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::DownloadPreviewImage( void )
|
||||
{
|
||||
// TODO: We need a generic "no image" image
|
||||
if ( m_bAddingNewFile )
|
||||
return;
|
||||
|
||||
// Start off our download
|
||||
char szTargetFilename[MAX_PATH];
|
||||
V_snprintf( szTargetFilename, sizeof(szTargetFilename), "%llu_thumb.jpg", m_FileDetails.publishedFileDetails.m_nPublishedFileId );
|
||||
m_UGCPreviewFileRequest.StartDownload( m_FileDetails.publishedFileDetails.m_hPreviewFile, "downloads", szTargetFilename );
|
||||
m_bPreviewDownloadPending = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::OnTick( void )
|
||||
{
|
||||
BaseClass::OnTick();
|
||||
|
||||
if ( m_pPrepareFileThread )
|
||||
{
|
||||
if ( !m_pPrepareFileThread->IsAlive() )
|
||||
{
|
||||
// Finished, trigger handler
|
||||
int result = m_pPrepareFileThread->GetResult();
|
||||
delete m_pPrepareFileThread;
|
||||
m_pPrepareFileThread = NULL;
|
||||
OnFilePrepared( result == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_bPreviewDownloadPending )
|
||||
{
|
||||
UGCFileRequestStatus_t ugcStatus = m_UGCPreviewFileRequest.Update();
|
||||
switch ( ugcStatus )
|
||||
{
|
||||
case UGCFILEREQUEST_ERROR:
|
||||
Warning("An error occurred while attempting to download a file from the UGC server!\n");
|
||||
m_bPreviewDownloadPending = false;
|
||||
break;
|
||||
|
||||
case UGCFILEREQUEST_FINISHED:
|
||||
// Update our image preview
|
||||
char szLocalFilename[MAX_PATH];
|
||||
m_UGCPreviewFileRequest.GetLocalFileName( szLocalFilename, sizeof(szLocalFilename) );
|
||||
char szLocalPath[ _MAX_PATH ];
|
||||
g_pFullFileSystem->GetLocalPath( szLocalFilename, szLocalPath, sizeof(szLocalPath) );
|
||||
SetPreviewImage( szLocalPath );
|
||||
m_bPreviewDownloadPending = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Working, continue to wait...
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::SetPreviewImage( const char *lpszFilename )
|
||||
{
|
||||
if ( lpszFilename == NULL )
|
||||
return;
|
||||
|
||||
// Retain this
|
||||
g_PreviewFilename = lpszFilename;
|
||||
|
||||
m_bValidJpeg = false;
|
||||
|
||||
ConversionErrorType nErrorCode = ImgUtl_LoadBitmap( lpszFilename, m_imgSource );
|
||||
if ( nErrorCode != CE_SUCCESS )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bValidJpeg = true;
|
||||
PerformSquarize();
|
||||
m_pCroppedTextureImagePanel->SetBitmap( GetPreviewBitmap() );
|
||||
}
|
||||
|
||||
// Update the state of our publish button
|
||||
SetPublishButtonState();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::PerformSquarize()
|
||||
{
|
||||
if ( !BForceSquarePreviewImage() )
|
||||
return;
|
||||
|
||||
const Bitmap_t *pResizeSrc = &m_imgSource;
|
||||
if ( !IsSourceImageSquare() )
|
||||
{
|
||||
// Select the smaller dimension as the size
|
||||
int nSize = MIN( m_imgSource.Width(), m_imgSource.Height() );
|
||||
|
||||
// Crop it.
|
||||
// Yeah, the crop and resize could be done all in one step.
|
||||
// And...I don't care.
|
||||
int x0 = ( m_imgSource.Width() - nSize ) / 2;
|
||||
int y0 = ( m_imgSource.Height() - nSize ) / 2;
|
||||
m_imgTemp.Crop( x0, y0, nSize, nSize, &m_imgSource );
|
||||
|
||||
pResizeSrc = &m_imgTemp;
|
||||
}
|
||||
|
||||
// resize
|
||||
ImgUtl_ResizeBitmap( m_imgSquare, DesiredPreviewWidth(), DesiredPreviewHeight(), pResizeSrc );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
Bitmap_t &CFilePublishDialog::GetPreviewBitmap()
|
||||
{
|
||||
return BForceSquarePreviewImage() ? m_imgSquare : m_imgSource;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Setup our edit fields with the appropriate information
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::PopulateEditFields( void )
|
||||
{
|
||||
m_pFileTitle->SetText( m_FileDetails.publishedFileDetails.m_rgchTitle );
|
||||
m_pFileDescription->SetText( m_FileDetails.publishedFileDetails.m_rgchDescription );
|
||||
|
||||
if ( m_FileDetails.lpszFilename && !FStrEq( m_FileDetails.lpszFilename, "" ) )
|
||||
{
|
||||
char szShortName[ MAX_PATH ];
|
||||
Q_FileBase( m_FileDetails.lpszFilename, szShortName, sizeof(szShortName) );
|
||||
const char *szExt = Q_GetFileExtension( m_FileDetails.lpszFilename );
|
||||
Q_SetExtension( szShortName, CFmtStr( ".%s", szExt ).Access(), sizeof(szShortName ) );
|
||||
m_pFilename->SetText( szShortName );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||||
{
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
|
||||
LoadControlSettings( GetResFile() );
|
||||
|
||||
m_pFileTitle = dynamic_cast< vgui::TextEntry * >( FindChildByName( "FileTitle" ) );
|
||||
if ( m_pFileTitle )
|
||||
{
|
||||
m_pFileTitle->AddActionSignalTarget( this );
|
||||
}
|
||||
|
||||
m_pFileDescription = dynamic_cast< vgui::TextEntry * >( FindChildByName( "FileDesc" ) );
|
||||
if ( m_pFileDescription )
|
||||
{
|
||||
m_pFileDescription->SetMultiline( true );
|
||||
m_pFileDescription->SetCatchEnterKey( true );
|
||||
m_pFileDescription->SetVerticalScrollbar( true );
|
||||
}
|
||||
|
||||
m_pFilename = dynamic_cast< vgui::Label * >( FindChildByName( "SourceFile" ) );
|
||||
if ( !g_MapFilename.IsEmpty() )
|
||||
{
|
||||
m_pFilename->SetText( g_MapFilename );
|
||||
}
|
||||
|
||||
m_pPublishButton = dynamic_cast< vgui::Button * >( FindChildByName( "ButtonPublish" ) );
|
||||
|
||||
// If we're updating, change the context of the button
|
||||
if ( !m_bAddingNewFile )
|
||||
{
|
||||
m_pPublishButton->SetText( "Update" );
|
||||
m_pPublishButton->SetCommand( "Update" );
|
||||
}
|
||||
|
||||
// Setup our initial state for the edit fields
|
||||
PopulateEditFields();
|
||||
SetPublishButtonState();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper to build thumbnail name
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::GetPreviewFilename( char *szOut, size_t outLen )
|
||||
{
|
||||
char szMapShortName[MAX_PATH];
|
||||
Q_FileBase( g_MapFilename, szMapShortName, sizeof(szMapShortName) );
|
||||
Q_snprintf( szOut, outLen, "%s_thumb.jpg", szMapShortName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Callback when our create item has completed. Need to do initial update.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::Steam_OnCreateItem( CreateItemResult_t *pResult, bool bError )
|
||||
{
|
||||
bError = bError || pResult->m_eResult != k_EResultOK;
|
||||
m_nFileID = pResult->m_nPublishedFileId;
|
||||
|
||||
if ( bError )
|
||||
{
|
||||
HideStatusWindow();
|
||||
ErrorMessage( kFailedToPublishFile );
|
||||
if ( m_nFileID != k_PublishedFileIdInvalid )
|
||||
{
|
||||
// TODO ISteamUGC is conspicuously missing a delete call, but shares IDs with SteamRemoteStorage.
|
||||
// Once this is fixed in steam, this call should probably be moved
|
||||
steamapicontext->SteamRemoteStorage()->DeletePublishedFile( m_nFileID );
|
||||
m_nFileID = k_PublishedFileIdInvalid;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StartPrepareFile();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Callback from our map compression thread finishing
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::OnFilePrepared( bool bSucceeded )
|
||||
{
|
||||
if ( bSucceeded )
|
||||
{
|
||||
// Move on to final publishing
|
||||
bSucceeded = UpdateFileInternal();
|
||||
}
|
||||
|
||||
if ( bSucceeded )
|
||||
{
|
||||
// Done, waiting on file publish callback
|
||||
return;
|
||||
}
|
||||
|
||||
// Failure
|
||||
|
||||
// This is after OnCreateItem for new files, so cleanup the incomplete item on failure from either the compress or
|
||||
// kicking off the update.
|
||||
if ( m_bAddingNewFile && m_nFileID != k_PublishedFileIdInvalid )
|
||||
{
|
||||
// TODO ISteamUGC is conspicuously missing a delete call, but shares IDs with SteamRemoteStorage.
|
||||
// Once this is fixed in steam, this call should probably be moved
|
||||
steamapicontext->SteamRemoteStorage()->DeletePublishedFile( m_nFileID );
|
||||
m_nFileID = k_PublishedFileIdInvalid;
|
||||
}
|
||||
|
||||
HideStatusWindow();
|
||||
ErrorMessage( kFailedToUpdateFile );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Callback when our publish call has completed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::Steam_OnPublishFile( SubmitItemUpdateResult_t *pResult, bool bError )
|
||||
{
|
||||
// Remove prepared map
|
||||
char szPreparedMap[MAX_PATH] = { 0 };
|
||||
V_ComposeFileName( WORKSHOP_TEMP_UPLOAD_DIR, V_GetFileName( g_MapFilename ),
|
||||
szPreparedMap, sizeof( szPreparedMap ) );
|
||||
g_pFullFileSystem->RemoveFile( szPreparedMap, UGC_PATHID );
|
||||
|
||||
// Remove local thumbnail
|
||||
CUtlBuffer bufData;
|
||||
char szPreviewFilename[MAX_PATH];
|
||||
GetPreviewFilename( szPreviewFilename, sizeof( szPreviewFilename ) );
|
||||
g_pFullFileSystem->RemoveFile( szPreviewFilename, UGC_PATHID );
|
||||
|
||||
HideStatusWindow();
|
||||
|
||||
if ( bError || pResult->m_eResult != k_EResultOK )
|
||||
{
|
||||
if ( m_bAddingNewFile && m_nFileID != k_PublishedFileIdInvalid )
|
||||
{
|
||||
// TODO ISteamUGC is conspicuously missing a delete call, but shares IDs with SteamRemoteStorage.
|
||||
// Once this is fixed in steam, this call should probably be moved
|
||||
steamapicontext->SteamRemoteStorage()->DeletePublishedFile( m_nFileID );
|
||||
m_nFileID = k_PublishedFileIdInvalid;
|
||||
}
|
||||
ErrorMessage( kFailedToPublishFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
EUniverse universe = GetUniverse();
|
||||
switch ( universe )
|
||||
{
|
||||
case k_EUniversePublic:
|
||||
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://steamcommunity.com/sharedfiles/filedetails/?id=%llu&requirelogin=true", m_nFileID ) );
|
||||
break;
|
||||
case k_EUniverseBeta:
|
||||
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://beta.steamcommunity.com/sharedfiles/filedetails/?id=%llu&requirelogin=true", m_nFileID ) );
|
||||
break;
|
||||
case k_EUniverseDev:
|
||||
steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStrMax( "http://localhost/community/sharedfiles/filedetails/?id=%llu&requirelogin=true", m_nFileID ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Tell our parent what happened
|
||||
KeyValues *pkvActionSignal = new KeyValues( "ChangedFile" );
|
||||
pkvActionSignal->SetUint64( "nPublishedFileID", m_nFileID );
|
||||
PostActionSignal( pkvActionSignal );
|
||||
|
||||
// Close down the window
|
||||
CloseModal();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Share the file with Steam Cloud and return the handle for later usage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFilePublishDialog::PublishFile()
|
||||
{
|
||||
// Must be a valid file
|
||||
ErrorCode_t errorCode = ValidateFile( g_MapFilename );
|
||||
#ifdef TF_CLIENT_DLL
|
||||
const char *pExt = V_GetFileExtension( g_MapFilename );
|
||||
if ( errorCode == kNoError && pExt && V_strcmp( pExt, "bsp" ) == 0 )
|
||||
{
|
||||
if ( !CTFMapsWorkshop::IsValidOriginalFileNameForMap( CUtlString( V_GetFileName( g_MapFilename ) ) ) )
|
||||
{
|
||||
errorCode = kInvalidMapName;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ( errorCode != kNoError )
|
||||
{
|
||||
ErrorMessage( errorCode );
|
||||
return false;
|
||||
}
|
||||
|
||||
ShowStatusWindow( kPublishing );
|
||||
|
||||
EWorkshopFileType eFileType = WorkshipFileTypeForFile( g_MapFilename );
|
||||
|
||||
// Create file on UGC
|
||||
SteamAPICall_t hSteamAPICall = steamapicontext->SteamUGC()->CreateItem( GetTargetAppID(), eFileType );
|
||||
|
||||
// Set the callback
|
||||
m_callbackCreateItem.Set( hSteamAPICall, this, &CFilePublishDialog::Steam_OnCreateItem );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Kick off the map compression thread
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::StartPrepareFile( void )
|
||||
{
|
||||
// Ensure temp dir exists
|
||||
g_pFullFileSystem->CreateDirHierarchy( WORKSHOP_TEMP_UPLOAD_DIR, UGC_PATHID );
|
||||
|
||||
char szOutPath[MAX_PATH] = { 0 };
|
||||
V_ComposeFileName( WORKSHOP_TEMP_UPLOAD_DIR, V_GetFileName( g_MapFilename ),
|
||||
szOutPath, sizeof( szOutPath ) );
|
||||
|
||||
// Ensure this file isn't leftover in output dir
|
||||
g_pFullFileSystem->RemoveFile( szOutPath, UGC_PATHID );
|
||||
|
||||
// Start thread
|
||||
Assert( !m_pPrepareFileThread );
|
||||
m_pPrepareFileThread = new CPrepareFileThread( g_MapFilename, szOutPath );
|
||||
m_pPrepareFileThread->Start();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parse commands coming in from the VGUI dialog
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::SetPublishButtonState( void )
|
||||
{
|
||||
if ( m_bAddingNewFile )
|
||||
{
|
||||
if ( m_bValidFile && m_bValidJpeg )
|
||||
{
|
||||
m_pPublishButton->SetEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPublishButton->SetEnabled( false );
|
||||
}
|
||||
}
|
||||
else // Updating a previous entry
|
||||
{
|
||||
// m_pPublishButton->SetEnabled( (m_nFileDetailsChanges!=0) );
|
||||
m_pPublishButton->SetEnabled( true ); // For now, always allow it. Worst case it's a no-op
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parse commands coming in from the VGUI dialog
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFilePublishDialog::UpdateFile( void )
|
||||
{
|
||||
// We should have been created for an existing file or published already, both of which set our ID.
|
||||
Assert( m_nFileID != k_PublishedFileIdInvalid );
|
||||
ShowStatusWindow( kUpdating );
|
||||
|
||||
if ( m_bAddingNewFile || m_nFileDetailsChanges & PFILE_FIELD_FILE )
|
||||
{
|
||||
StartPrepareFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not updating map, go straight to update step
|
||||
if ( !UpdateFileInternal() )
|
||||
{
|
||||
HideStatusWindow();
|
||||
ErrorMessage( kFailedToUpdateFile );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update a file, used by the create and update pathways to fill in a UGC item
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFilePublishDialog::UpdateFileInternal()
|
||||
{
|
||||
ISteamUGC *pUGC = steamapicontext->SteamUGC();
|
||||
|
||||
UGCUpdateHandle_t hItem = pUGC->StartItemUpdate( GetTargetAppID(), m_nFileID );
|
||||
if ( hItem == k_UGCUpdateHandleInvalid )
|
||||
{
|
||||
UGCWarning( "StartItemUpdate failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bError = false;
|
||||
|
||||
// create thumbnail
|
||||
CUtlBuffer bufData;
|
||||
char szPreviewFilename[MAX_PATH];
|
||||
GetPreviewFilename( szPreviewFilename, sizeof( szPreviewFilename ) );
|
||||
|
||||
if ( !bError && ImgUtl_SaveBitmapToBuffer( bufData, GetPreviewBitmap(), kImageFileFormat_JPG ) == CE_SUCCESS )
|
||||
{
|
||||
bError = !g_pFullFileSystem->WriteFile( szPreviewFilename, UGC_PATHID, bufData );
|
||||
|
||||
// Get full path to give steam
|
||||
g_pFullFileSystem->RelativePathToFullPath( szPreviewFilename, UGC_PATHID, szPreviewFilename, sizeof( szPreviewFilename ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
bError = true;
|
||||
}
|
||||
|
||||
// Get the compressed map out of the upload directory
|
||||
char szPreparedMap[MAX_PATH] = { 0 };
|
||||
char szFullPreparedPath[MAX_PATH] = { 0 };
|
||||
if ( m_bAddingNewFile || m_nFileDetailsChanges & PFILE_FIELD_FILE )
|
||||
{
|
||||
V_ComposeFileName( WORKSHOP_TEMP_UPLOAD_DIR, V_GetFileName( g_MapFilename ),
|
||||
szPreparedMap, sizeof( szPreparedMap ) );
|
||||
|
||||
g_pFullFileSystem->RelativePathToFullPath( szPreparedMap, UGC_PATHID,
|
||||
szFullPreparedPath,
|
||||
sizeof( szFullPreparedPath ) );
|
||||
|
||||
bError |= !*szFullPreparedPath;
|
||||
}
|
||||
|
||||
if ( !bError )
|
||||
{
|
||||
// Set title
|
||||
char szTitle[k_cchPublishedDocumentTitleMax];
|
||||
m_pFileTitle->GetText( szTitle, sizeof(szTitle) );
|
||||
Q_AggressiveStripPrecedingAndTrailingWhitespace( szTitle );
|
||||
|
||||
bError |= !pUGC->SetItemTitle( hItem, szTitle );
|
||||
|
||||
// Set descriptor
|
||||
char szDesc[k_cchPublishedDocumentDescriptionMax];
|
||||
m_pFileDescription->GetText( szDesc, sizeof(szDesc) );
|
||||
Q_AggressiveStripPrecedingAndTrailingWhitespace( szDesc );
|
||||
|
||||
bError |= !pUGC->SetItemDescription( hItem, szDesc );
|
||||
|
||||
// Set thumbnail
|
||||
if ( m_bAddingNewFile || m_nFileDetailsChanges & PFILE_FIELD_PREVIEW )
|
||||
{
|
||||
bError |= !pUGC->SetItemPreview( hItem, szPreviewFilename );
|
||||
}
|
||||
|
||||
// Set file
|
||||
if ( m_bAddingNewFile || m_nFileDetailsChanges & PFILE_FIELD_FILE )
|
||||
{
|
||||
if ( *szFullPreparedPath )
|
||||
{
|
||||
bError |= !pUGC->SetItemContent( hItem, szFullPreparedPath );
|
||||
// Metadata for our files is just the original filename, since they are currently all single files
|
||||
bError |= !pUGC->SetItemMetadata( hItem, V_GetFileName( g_MapFilename.Get() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
UGCWarning( "Prepared map does not appear to exist\n" );
|
||||
bError = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Tags
|
||||
SteamParamStringArray_t strArray;
|
||||
PopulateTags( strArray );
|
||||
bError |= !pUGC->SetItemTags( hItem, &strArray );
|
||||
|
||||
// Visibility
|
||||
bError |= !pUGC->SetItemVisibility( hItem, k_ERemoteStoragePublishedFileVisibilityPublic );
|
||||
}
|
||||
else
|
||||
{
|
||||
bError = true;
|
||||
}
|
||||
|
||||
if ( !bError )
|
||||
{
|
||||
SteamAPICall_t hSteamAPICall = steamapicontext->SteamUGC()->SubmitItemUpdate( hItem, NULL );
|
||||
m_callbackPublishFile.Set( hSteamAPICall, this, &CFilePublishDialog::Steam_OnPublishFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Failed, cleanup prepared map
|
||||
g_pFullFileSystem->RemoveFile( szPreparedMap, UGC_PATHID );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::PerformLayout()
|
||||
{
|
||||
BaseClass::PerformLayout();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parse commands coming in from the VGUI dialog
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::OnCommand( const char *command )
|
||||
{
|
||||
if ( Q_stricmp( command, "Publish" ) == 0 )
|
||||
{
|
||||
// Verify they've filled everything out properly
|
||||
bool bHasTitle = ( m_pFileTitle->GetTextLength() > 0 );
|
||||
bool bHasDesc = ( m_pFileDescription->GetTextLength() > 0 );
|
||||
if ( !bHasTitle || !bHasDesc )
|
||||
{
|
||||
ErrorMessage( kNeedTitleAndDescription );
|
||||
return;
|
||||
}
|
||||
|
||||
// Get our title
|
||||
char szTitle[k_cchPublishedDocumentTitleMax];
|
||||
m_pFileTitle->GetText( szTitle, sizeof(szTitle) );
|
||||
Q_AggressiveStripPrecedingAndTrailingWhitespace( szTitle );
|
||||
|
||||
// Get our descriptor
|
||||
char szDesc[k_cchPublishedDocumentDescriptionMax];
|
||||
m_pFileDescription->GetText( szDesc, sizeof(szDesc) );
|
||||
Q_AggressiveStripPrecedingAndTrailingWhitespace( szDesc );
|
||||
|
||||
bHasTitle = Q_strlen( szTitle ) != 0;
|
||||
bHasDesc = Q_strlen( szDesc ) != 0;
|
||||
if ( !bHasTitle || !bHasDesc )
|
||||
{
|
||||
ErrorMessage( kNeedTitleAndDescription );
|
||||
return;
|
||||
}
|
||||
|
||||
PublishFile();
|
||||
}
|
||||
else if ( Q_stricmp( command, "Update" ) == 0 )
|
||||
{
|
||||
UpdateFile();
|
||||
}
|
||||
else if ( Q_stricmp( command, "MainFileMaps" ) == 0 )
|
||||
{
|
||||
m_fileOpenMode = FILEOPEN_MAIN_FILE;
|
||||
|
||||
// Create a new dialog
|
||||
vgui::FileOpenDialog *pDlg = new vgui::FileOpenDialog( NULL, "Select File", true );
|
||||
pDlg->AddFilter( GetFileTypes( IMPORT_FILTER_MAP ), GetFileTypeDescriptions( IMPORT_FILTER_MAP ), true );
|
||||
if ( !FStrEq( publish_file_last_dir.GetString(), "" ) )
|
||||
{
|
||||
pDlg->SetStartDirectory( publish_file_last_dir.GetString() );
|
||||
}
|
||||
|
||||
char textBuffer[1024];
|
||||
m_pFilename->GetText( textBuffer, sizeof( textBuffer ) );
|
||||
|
||||
char szFilePath[MAX_PATH];
|
||||
g_pFullFileSystem->GetCurrentDirectory( szFilePath, sizeof(szFilePath) );
|
||||
|
||||
strcat( szFilePath, "/" );
|
||||
strcat( szFilePath, textBuffer );
|
||||
|
||||
// Get the currently set dir and use that as the start
|
||||
// pDlg->ExpandTreeToPath( szFilePath );
|
||||
pDlg->MoveToCenterOfScreen();
|
||||
pDlg->AddActionSignalTarget( this );
|
||||
pDlg->SetDeleteSelfOnClose( true );
|
||||
pDlg->DoModal();
|
||||
pDlg->Activate();
|
||||
}
|
||||
else if ( Q_stricmp( command, "MainFileOther" ) == 0 )
|
||||
{
|
||||
m_fileOpenMode = FILEOPEN_MAIN_FILE;
|
||||
|
||||
// Create a new dialog
|
||||
vgui::FileOpenDialog *pDlg = new vgui::FileOpenDialog( NULL, "Select File", true );
|
||||
pDlg->AddFilter( GetFileTypes( IMPORT_FILTER_OTHER ), GetFileTypeDescriptions( IMPORT_FILTER_OTHER ), true );
|
||||
if ( !FStrEq( publish_file_last_dir.GetString(), "" ) )
|
||||
{
|
||||
pDlg->SetStartDirectory( publish_file_last_dir.GetString() );
|
||||
}
|
||||
|
||||
char textBuffer[1024];
|
||||
m_pFilename->GetText( textBuffer, sizeof( textBuffer ) );
|
||||
|
||||
char szFilePath[MAX_PATH];
|
||||
g_pFullFileSystem->GetCurrentDirectory( szFilePath, sizeof( szFilePath ) );
|
||||
|
||||
strcat( szFilePath, "/" );
|
||||
strcat( szFilePath, textBuffer );
|
||||
|
||||
// Get the currently set dir and use that as the start
|
||||
// pDlg->ExpandTreeToPath( szFilePath );
|
||||
pDlg->MoveToCenterOfScreen();
|
||||
pDlg->AddActionSignalTarget( this );
|
||||
pDlg->SetDeleteSelfOnClose( true );
|
||||
pDlg->DoModal();
|
||||
pDlg->Activate();
|
||||
}
|
||||
else if ( Q_stricmp( command, "PreviewBrowse" ) == 0 )
|
||||
{
|
||||
m_fileOpenMode = FILEOPEN_PREVIEW;
|
||||
|
||||
// Create a new dialog
|
||||
vgui::FileOpenDialog *pDlg = new vgui::FileOpenDialog( NULL, "Select File", true );
|
||||
pDlg->AddFilter( GetPreviewFileTypes(), GetPreviewFileTypeDescriptions(), true );
|
||||
if ( !FStrEq( publish_file_last_dir.GetString(), "" ) )
|
||||
{
|
||||
pDlg->SetStartDirectory( publish_file_last_dir.GetString() );
|
||||
}
|
||||
|
||||
char szFilePath[MAX_PATH];
|
||||
g_pFullFileSystem->GetCurrentDirectory( szFilePath, sizeof(szFilePath) );
|
||||
|
||||
strcat( szFilePath, "/" );
|
||||
strcat( szFilePath, g_PreviewFilename );
|
||||
|
||||
// Get the currently set dir and use that as the start
|
||||
// pDlg->ExpandTreeToPath( szFilePath );
|
||||
pDlg->MoveToCenterOfScreen();
|
||||
pDlg->AddActionSignalTarget( this );
|
||||
pDlg->SetDeleteSelfOnClose( true );
|
||||
pDlg->DoModal();
|
||||
pDlg->Activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::OnCommand( command );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Take a filename, shorten it for display but retain the full path internally
|
||||
//-----------------------------------------------------------------------------
|
||||
CFilePublishDialog::ErrorCode_t CFilePublishDialog::ValidateFile( const char *lpszFilename )
|
||||
{
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Take a filename, shorten it for display but retain the full path internally
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::SetFile( const char *lpszFilename, bool bImported )
|
||||
{
|
||||
// Must be a valid file
|
||||
ErrorCode_t errorCode = ValidateFile( lpszFilename );
|
||||
if ( errorCode != kNoError )
|
||||
{
|
||||
ErrorMessage( errorCode );
|
||||
return;
|
||||
}
|
||||
|
||||
m_bValidFile = true;
|
||||
g_MapFilename = lpszFilename;
|
||||
char szShortName[ MAX_PATH ];
|
||||
Q_FileBase( g_MapFilename, szShortName, sizeof(szShortName) );
|
||||
const char *szExt = Q_GetFileExtension( lpszFilename );
|
||||
Q_SetExtension( szShortName, CFmtStr( ".%s", szExt ).Access(), sizeof(szShortName ) );
|
||||
m_pFilename->SetText( szShortName );
|
||||
|
||||
// Notify of the change
|
||||
m_nFileDetailsChanges |= PFILE_FIELD_FILE;
|
||||
|
||||
SetPublishButtonState();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Notify us that the directory dialog has returned a new entry
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFilePublishDialog::OnFileSelected( const char *fullPath )
|
||||
{
|
||||
char basepath[ MAX_PATH ];
|
||||
Q_ExtractFilePath( fullPath, basepath, sizeof( basepath ) );
|
||||
publish_file_last_dir.SetValue( basepath );
|
||||
|
||||
if ( m_fileOpenMode == FILEOPEN_MAIN_FILE )
|
||||
{
|
||||
SetFile( fullPath );
|
||||
}
|
||||
else if ( m_fileOpenMode == FILEOPEN_PREVIEW )
|
||||
{
|
||||
// Notify of the change
|
||||
m_nFileDetailsChanges |= PFILE_FIELD_PREVIEW;
|
||||
|
||||
SetPreviewImage( fullPath );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef PUBLISH_FILE_DIALOG_H
|
||||
#define PUBLISH_FILE_DIALOG_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vgui_controls/Frame.h>
|
||||
#include <vgui_controls/ImageList.h>
|
||||
#include <vgui_controls/SectionedListPanel.h>
|
||||
#include <vgui_controls/PHandle.h>
|
||||
#include <vgui_controls/BitmapImagePanel.h>
|
||||
#include <filesystem.h>
|
||||
#include "vgui/MouseCode.h"
|
||||
#include "vgui/IScheme.h"
|
||||
#include "steam/steam_api.h"
|
||||
#include "utlmap.h"
|
||||
#include "bitmap/bitmap.h"
|
||||
#include "workshop/ugc_utils.h"
|
||||
|
||||
struct PublishedFileDetails_t
|
||||
{
|
||||
SteamUGCDetails_t publishedFileDetails;
|
||||
const char *lpszFilename;
|
||||
};
|
||||
|
||||
#define APPID_PORTAL2 852
|
||||
|
||||
using namespace vgui;
|
||||
|
||||
class CBitmapPanel;
|
||||
|
||||
enum FileOpenMode_t {
|
||||
FILEOPEN_NONE,
|
||||
FILEOPEN_MAIN_FILE,
|
||||
FILEOPEN_PREVIEW
|
||||
};
|
||||
|
||||
struct EntityToTagMap_t
|
||||
{
|
||||
const char *lpszEntityName;
|
||||
const char *lpszTagName;
|
||||
const char *lpszKey;
|
||||
const char *lpszValue;
|
||||
};
|
||||
|
||||
enum PublishedFileDetailsField_t
|
||||
{
|
||||
PFILE_FIELD_TITLE = (1<<0),
|
||||
PFILE_FIELD_DESCRIPTION = (1<<1),
|
||||
PFILE_FIELD_FILE = (1<<2),
|
||||
PFILE_FIELD_PREVIEW = (1<<3),
|
||||
};
|
||||
|
||||
enum eFilterType_t
|
||||
{
|
||||
IMPORT_FILTER_NONE = 0,
|
||||
IMPORT_FILTER_COSMETIC,
|
||||
IMPORT_FILTER_OTHER,
|
||||
IMPORT_FILTER_MAP,
|
||||
};
|
||||
|
||||
// TODO: Move to P2 version
|
||||
#define TAG_GAME_MODE_SINGLEPLAYER "Singleplayer"
|
||||
#define TAG_GAME_MODE_COOP "Co-Op"
|
||||
//
|
||||
|
||||
// This is the size for the preview for P2 map preview images
|
||||
#define PREVIEW_WIDTH 225
|
||||
#define PREVIEW_HEIGHT 152
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Main dialog for media browser
|
||||
//-----------------------------------------------------------------------------
|
||||
class CPrepareFileThread;
|
||||
class CFilePublishDialog : public Frame
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( CFilePublishDialog, Frame );
|
||||
|
||||
public:
|
||||
|
||||
enum ErrorCode_t
|
||||
{
|
||||
kNoError,
|
||||
kFailedToPublishFile,
|
||||
kFailedToUpdateFile,
|
||||
kFailedToPrepareFile,
|
||||
kSteamCloudNotAvailable,
|
||||
kSteamExceededCloudQuota,
|
||||
kFailedToWriteToSteamCloud,
|
||||
kFileNotFound,
|
||||
kNeedTitleAndDescription,
|
||||
kFailedFileValidation,
|
||||
kFailedFileTooLarge,
|
||||
kFailedFileNotFound,
|
||||
kFailedUserModifiedFile,
|
||||
kInvalidMapName
|
||||
};
|
||||
|
||||
enum StatusCode_t
|
||||
{
|
||||
kPublishing,
|
||||
kUpdating,
|
||||
};
|
||||
|
||||
CFilePublishDialog( Panel *parent, const char *name, PublishedFileDetails_t *pDetails );
|
||||
virtual ~CFilePublishDialog();
|
||||
|
||||
virtual void PerformLayout();
|
||||
|
||||
virtual void SetFile( const char *lpszFilename, bool bImported = false );
|
||||
|
||||
protected:
|
||||
virtual void OnCommand( const char *command );
|
||||
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||||
virtual void OnTick( void );
|
||||
|
||||
// Override these functions to publish files for different app types
|
||||
virtual ErrorCode_t ValidateFile( const char *lpszFilename );
|
||||
virtual AppId_t GetTargetAppID( void ) { return APPID_PORTAL2; }
|
||||
virtual unsigned int DesiredPreviewHeight( void ) { return PREVIEW_HEIGHT; }
|
||||
virtual unsigned int DesiredPreviewWidth( void ) { return PREVIEW_WIDTH; }
|
||||
// Decides which type to use for publishing this file
|
||||
virtual EWorkshopFileType WorkshipFileTypeForFile( const char *pszFileName ) { return k_EWorkshopFileTypeCommunity; }
|
||||
virtual bool BForceSquarePreviewImage( void ) { return false; } // Force preview images to be square
|
||||
virtual const char *GetPreviewFileTypes( void ) { return "*.jpg"; }
|
||||
virtual const char *GetPreviewFileTypeDescriptions( void ) { return "JPEG Files (*.jpg)"; }
|
||||
virtual const char *GetFileTypes( eFilterType_t eType = IMPORT_FILTER_NONE ) { return "*.bsp"; }
|
||||
virtual const char *GetFileTypeDescriptions( eFilterType_t eType = IMPORT_FILTER_NONE ) { return "BSP Files (*.bsp)"; }
|
||||
virtual const char *GetResFile() const { return "PublishFileDialog.res"; }
|
||||
virtual void ErrorMessage( ErrorCode_t errorCode, KeyValues *pkvTokens = NULL );
|
||||
virtual void PopulateTags( SteamParamStringArray_t &strArray ) {}
|
||||
virtual const char* GetStatusString( StatusCode_t statusCode );
|
||||
virtual void ShowStatusWindow( StatusCode_t statusCode );
|
||||
virtual void HideStatusWindow( void );
|
||||
|
||||
virtual void PopulateEditFields( void );
|
||||
void DownloadPreviewImage( void );
|
||||
|
||||
void SetPublishButtonState( void );
|
||||
|
||||
bool UpdateFile( void );
|
||||
bool UpdateFileInternal( void );
|
||||
void GetPreviewFilename( char *szOut, size_t outLen );
|
||||
|
||||
bool PublishFile();
|
||||
void SetPreviewImage( const char *lpszFilename );
|
||||
|
||||
void PerformSquarize();
|
||||
Bitmap_t &GetPreviewBitmap();
|
||||
|
||||
void ErrorMessage( const char *lpszText );
|
||||
|
||||
void StartPrepareFile();
|
||||
|
||||
void OnFilePrepared( bool bSucceeded );
|
||||
|
||||
inline bool IsSourceImageSquare() const
|
||||
{
|
||||
// We must know the size
|
||||
Assert( m_imgSource.IsValid() );
|
||||
return
|
||||
m_imgSource.Width()*99 < m_imgSource.Height()*100
|
||||
&& m_imgSource.Height()*99 < m_imgSource.Width()*100;
|
||||
}
|
||||
|
||||
FileOpenMode_t m_fileOpenMode;
|
||||
|
||||
bool m_bValidFile;
|
||||
bool m_bValidJpeg;
|
||||
|
||||
CBitmapPanel *m_pCroppedTextureImagePanel;
|
||||
|
||||
Bitmap_t m_imgSource; // original resolution and aspect
|
||||
Bitmap_t m_imgSquare;
|
||||
Bitmap_t m_imgTemp;
|
||||
|
||||
PublishedFileId_t m_nFileID;
|
||||
PublishedFileDetails_t m_FileDetails;
|
||||
unsigned int m_nFileDetailsChanges;
|
||||
|
||||
vgui::MessageBox *m_pStatusBox;
|
||||
vgui::TextEntry *m_pFileTitle;
|
||||
vgui::TextEntry *m_pFileDescription;
|
||||
vgui::Label *m_pFilename;
|
||||
vgui::Button *m_pPublishButton;
|
||||
|
||||
CCallResult<CFilePublishDialog, CreateItemResult_t> m_callbackCreateItem;
|
||||
void Steam_OnCreateItem( CreateItemResult_t *pResult, bool bError );
|
||||
|
||||
CCallResult<CFilePublishDialog, SubmitItemUpdateResult_t> m_callbackPublishFile;
|
||||
void Steam_OnPublishFile( SubmitItemUpdateResult_t *pResult, bool bError );
|
||||
|
||||
// TODO Switch to using the auto-downloaded ISteamUGC previews
|
||||
CUGCFileRequest m_UGCPreviewFileRequest;
|
||||
bool m_bPreviewDownloadPending;
|
||||
bool m_bAddingNewFile;
|
||||
|
||||
CPrepareFileThread *m_pPrepareFileThread;
|
||||
|
||||
MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
|
||||
};
|
||||
|
||||
|
||||
extern CFilePublishDialog *g_pSteamFilePublishDialog;
|
||||
|
||||
|
||||
#endif // PUBLISH_FILE_DIALOG_H
|
||||
Reference in New Issue
Block a user