HAxis sos
This commit is contained in:
21
Plugins/Mantis/Mantis.uplugin
Normal file
21
Plugins/Mantis/Mantis.uplugin
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "1.0",
|
||||
"FriendlyName": "Mantis Plugin",
|
||||
"Description": "A plugin to add an interface in Unreal for Mantis bug reports.",
|
||||
"Category": "Bugs",
|
||||
"CreatedBy": "Yoshi van Belkom",
|
||||
"CreatedByURL": "http://www.yoshivanbelkom.com/",
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "Mantis",
|
||||
"Type": "Developer",
|
||||
"LoadingPhase": "PreDefault"
|
||||
}
|
||||
],
|
||||
"EnabledByDefault": true,
|
||||
"CanContainContent": true,
|
||||
"IsBetaVersion": true,
|
||||
"Installed": false
|
||||
}
|
||||
BIN
Plugins/Mantis/Resources/Icon128.png
Normal file
BIN
Plugins/Mantis/Resources/Icon128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
70
Plugins/Mantis/Source/Mantis/Classes/MantisSettings.h
Normal file
70
Plugins/Mantis/Source/Mantis/Classes/MantisSettings.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "MantisSettings.generated.h"
|
||||
|
||||
USTRUCT()
|
||||
struct FBatchBinding
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/* Initialize the struct using a string from the config file. */
|
||||
FBatchBinding( FString& InString )
|
||||
{
|
||||
FString CleanString = InString.Mid( 1, InString.Len() - 2 );
|
||||
|
||||
TArray<FString> VariableStrings;
|
||||
CleanString.ParseIntoArray( VariableStrings, TEXT(",") );
|
||||
|
||||
TMap<FString, FString> Variables;
|
||||
for ( int32 i = 0; i < VariableStrings.Num(); i++ )
|
||||
{
|
||||
TArray<FString> VariableString;
|
||||
VariableStrings[i].ParseIntoArray( VariableString, TEXT( "=" ) );
|
||||
if ( VariableString.Num() != 2 ) continue;
|
||||
Variables.Add( VariableString[0], VariableString[1].TrimQuotes() );
|
||||
}
|
||||
|
||||
FString* FieldIDValue = Variables.Find( "FieldID" );
|
||||
if ( FieldIDValue != nullptr ) FieldID = *FieldIDValue;
|
||||
FString* BatchPathValue = Variables.Find( "BatchPath" );
|
||||
if ( BatchPathValue != nullptr ) BatchPath = *BatchPathValue;
|
||||
}
|
||||
|
||||
/* Default constructor. */
|
||||
FBatchBinding() {}
|
||||
|
||||
/*
|
||||
* The ID of the field.
|
||||
* e.g. category_id
|
||||
*/
|
||||
UPROPERTY( Config, EditAnywhere )
|
||||
FString FieldID;
|
||||
|
||||
/*
|
||||
* The path to the batch script. This is can be a relative path from the project folder (where the .uproject is located) or an absolute path.
|
||||
* Relative e.g. /Scripts/GetCategory.bat
|
||||
* Absolute e.g. C:/Perforce/Scripts/GetCategory.bat
|
||||
*/
|
||||
UPROPERTY( Config, EditAnywhere )
|
||||
FString BatchPath;
|
||||
};
|
||||
|
||||
UCLASS(config=Engine)
|
||||
class UMantisSettings : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
public:
|
||||
/*
|
||||
* This is the root url of the Mantis.
|
||||
* e.g. if the login url is: http://bugs.yourdomain.com/login_page.php
|
||||
* this would be http://bugs.youdomain.com/
|
||||
*/
|
||||
UPROPERTY( Config, EditAnywhere, Category = General )
|
||||
FString HostURL;
|
||||
|
||||
/*
|
||||
* A list of batch scrips you want to use to load data for certain fields in the crash report.
|
||||
*/
|
||||
UPROPERTY( Config, EditAnywhere, Category = Advanced )
|
||||
TArray<FBatchBinding> ScriptBindings;
|
||||
};
|
||||
29
Plugins/Mantis/Source/Mantis/Mantis.Build.cs
Normal file
29
Plugins/Mantis/Source/Mantis/Mantis.Build.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
//////////////////////////////////////////
|
||||
// Author: Yoshi van Belkom - 130118
|
||||
//////////////////////////////////////////
|
||||
// The Mantis Editor Module Settings.
|
||||
//////////////////////////////////////////
|
||||
|
||||
namespace UnrealBuildTool.Rules
|
||||
{
|
||||
public class Mantis : ModuleRules
|
||||
{
|
||||
public Mantis(TargetInfo Target)
|
||||
{
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[] {
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"UnrealEd"
|
||||
}
|
||||
);
|
||||
|
||||
PrivateIncludePathModuleNames.AddRange(
|
||||
new string[] {
|
||||
"Settings"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
332
Plugins/Mantis/Source/Mantis/Private/Mantis.cpp
Normal file
332
Plugins/Mantis/Source/Mantis/Private/Mantis.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
// Project Lab - NHTV IGAD
|
||||
//////////////////////////////////////////
|
||||
// Author: Yoshi van Belkom - 130118
|
||||
//////////////////////////////////////////
|
||||
|
||||
#include "MantisPrivatePCH.h"
|
||||
#include "ISettingsModule.h"
|
||||
#include "MantisSettings.h"
|
||||
#include "Runtime/Launch/Resources/Version.h"
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <Winver.h>
|
||||
#pragma comment( lib, "version.lib" )
|
||||
#endif
|
||||
|
||||
//defines
|
||||
#define LOCTEXT_NAMESPACE "Mantis"
|
||||
#define STRINGIZE_(x) #x
|
||||
#define STRINGIZE(x) STRINGIZE_(x)
|
||||
#define PlatformFile FPlatformFileManager::Get().GetPlatformFile()
|
||||
|
||||
class FMantis : public IMantis
|
||||
{
|
||||
public:
|
||||
/* IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
/* End IModuleInterface implementation */
|
||||
FString GetEngineCrashClientPath();
|
||||
FString GetMantisCrashClientPath();
|
||||
void RegisterSettings();
|
||||
void UnregisterSettings();
|
||||
int32 IsMantisExe( FString FilePath );
|
||||
void UpdateMantis();
|
||||
bool MakeBackup( FString Original, FString Backup, bool bOverwrite = false );
|
||||
};
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogMantis);
|
||||
|
||||
//Get the path of the Engine Crash Report
|
||||
FString FMantis::GetEngineCrashClientPath()
|
||||
{
|
||||
//Get Engine root path.
|
||||
FString EnginePath = FPaths::RootDir();
|
||||
FPaths::NormalizeDirectoryName(EnginePath);
|
||||
TArray< FString > EnginePathDirs;
|
||||
EnginePath.ParseIntoArray(EnginePathDirs, TEXT("/"), 1);
|
||||
|
||||
//Get the path to the CrashReportClient.exe
|
||||
FString EngineCrashClientPath;
|
||||
EnginePathDirs.Push(TEXT("Engine"));
|
||||
EnginePathDirs.Push(TEXT("Binaries"));
|
||||
EnginePathDirs.Push(TEXT("Win64"));
|
||||
EnginePathDirs.Push(TEXT("CrashReportClient.exe"));
|
||||
EngineCrashClientPath = FString::Join(EnginePathDirs, TEXT("/"));
|
||||
|
||||
//Check if file exists.
|
||||
if (FPaths::FileExists(EngineCrashClientPath))
|
||||
{
|
||||
UE_LOG(LogMantis, Log, TEXT("Engine Crash Report file found!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogMantis, Warning, TEXT("Engine Crash Report file not found!"));
|
||||
}
|
||||
|
||||
return EngineCrashClientPath;
|
||||
}
|
||||
|
||||
FString FMantis::GetMantisCrashClientPath()
|
||||
{
|
||||
//Get the path of the Project File
|
||||
FString ProjectPath = FPaths::GetPath( FPaths::GetProjectFilePath() );
|
||||
FPaths::NormalizeDirectoryName( ProjectPath );
|
||||
//Get the path to the Mantis Crash Report
|
||||
TArray< FString > ProjectPathDirs;
|
||||
ProjectPath.ParseIntoArray( ProjectPathDirs, TEXT( "/" ), 1 );
|
||||
FString MantisCrashClientPath;
|
||||
ProjectPathDirs.Push( TEXT( "Plugins" ) );
|
||||
ProjectPathDirs.Push( TEXT( "Mantis" ) );
|
||||
ProjectPathDirs.Push( TEXT( "Resources" ) );
|
||||
ProjectPathDirs.Push( TEXT( "CrashReporter" ) );
|
||||
ProjectPathDirs.Push( TEXT( STRINGIZE( ENGINE_MAJOR_VERSION ) "." STRINGIZE( ENGINE_MINOR_VERSION ) ) );
|
||||
#if PLATFORM_64BITS
|
||||
ProjectPathDirs.Push( TEXT( "Win64" ) );
|
||||
#else
|
||||
ProjectPathDirs.Push( TEXT( "Win32" ) );
|
||||
#endif
|
||||
ProjectPathDirs.Push( TEXT( "CrashReportClient.exe" ) );
|
||||
MantisCrashClientPath = FString::Join( ProjectPathDirs, TEXT( "/" ) );
|
||||
return MantisCrashClientPath;
|
||||
}
|
||||
|
||||
void FMantis::RegisterSettings()
|
||||
{
|
||||
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
|
||||
|
||||
if (SettingsModule != nullptr)
|
||||
{
|
||||
SettingsModule->RegisterSettings("Project", "Plugins", "MantisPlugin",
|
||||
LOCTEXT("MantisSettingsName", "Mantis Plugin"),
|
||||
LOCTEXT("MantisSettingsDescription", "Set the setting for the Mantis Plugin."),
|
||||
GetMutableDefault<UMantisSettings>()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogMantis, Log, TEXT("SettingsModule is null!"));
|
||||
}
|
||||
}
|
||||
|
||||
void FMantis::UnregisterSettings()
|
||||
{
|
||||
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
|
||||
if (SettingsModule != nullptr)
|
||||
{
|
||||
SettingsModule->UnregisterSettings("Project", "Plugins", "MantisPlugin");
|
||||
}
|
||||
}
|
||||
|
||||
void FMantis::UpdateMantis()
|
||||
{
|
||||
//Get the path of the Engine Crash Report
|
||||
FString EngineCrashClientPath = GetEngineCrashClientPath();
|
||||
FString EngineCrashClientBackupPath = EngineCrashClientPath + ".ue";
|
||||
FString EngineCrashClientTmpPath = EngineCrashClientPath + ".tmp";
|
||||
|
||||
//Get the path to the Mantis Crash Report
|
||||
FString MantisCrashClientPath = GetMantisCrashClientPath();
|
||||
UE_LOG( LogMantis, Log, TEXT( "MantisCrashClientPath: %s" ), *MantisCrashClientPath );
|
||||
if ( FPaths::FileExists( MantisCrashClientPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Mantis Crash Report file found!" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Mantis Crash Report file not found!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Removing the read-only tag
|
||||
PlatformFile.SetReadOnly( *EngineCrashClientPath, false );
|
||||
|
||||
if ( IsMantisExe( EngineCrashClientPath ) == 1 )
|
||||
{
|
||||
FDateTime EngineTimestamp = PlatformFile.GetTimeStamp( *EngineCrashClientPath );
|
||||
FDateTime MantisTimestamp = PlatformFile.GetTimeStamp( *MantisCrashClientPath );
|
||||
if ( EngineTimestamp >= MantisTimestamp )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Crash Report Client is up-to-date!" ) );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Crash Report Client is out-of-date!" ) );
|
||||
}
|
||||
}
|
||||
|
||||
//Make temporary backup
|
||||
if ( !MakeBackup( EngineCrashClientPath, EngineCrashClientTmpPath, true ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Couldn't make temporary Crash Report Client backup!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Delete current file.
|
||||
if ( !PlatformFile.DeleteFile( *EngineCrashClientPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Failed to delete the current Crash Report Client." ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Copy file if out of date.
|
||||
if ( PlatformFile.CopyFile( *EngineCrashClientPath, *MantisCrashClientPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Crash Report Client is updated!" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 errorNum = FPlatformMisc::GetLastError();
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Failed to update Crash Report Client! (Error: %i)" ), errorNum );
|
||||
|
||||
if ( PlatformFile.CopyFile( *EngineCrashClientPath, *EngineCrashClientPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Restored Crash Report Client." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
errorNum = FPlatformMisc::GetLastError();
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Failed to restore Crash Report Client! (Error: %i)" ), errorNum );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Delete temporary backup file.
|
||||
if ( !PlatformFile.DeleteFile( *EngineCrashClientTmpPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Failed to delete the current Crash Report Client." ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Removing the read-only tag
|
||||
PlatformFile.SetReadOnly( *EngineCrashClientPath, false );
|
||||
}
|
||||
|
||||
bool FMantis::MakeBackup( FString Original, FString Backup, bool bOverwrite )
|
||||
{
|
||||
//Delete backup if it already exists.
|
||||
if ( bOverwrite && FPaths::FileExists( Backup ) )
|
||||
{
|
||||
PlatformFile.DeleteFile( *Backup );
|
||||
}
|
||||
|
||||
//Make backup.
|
||||
if ( PlatformFile.CopyFile( *Backup, *Original ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Made a backup." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 errorNum = FPlatformMisc::GetLastError();
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Original path: %s" ), *Original );
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Backup path: %s" ), *Backup );
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Failed to make a backup! (Error: %i)" ), errorNum );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FMantis::StartupModule()
|
||||
{
|
||||
//Register the settings in the editor.
|
||||
RegisterSettings();
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
//Get the path of the Engine Crash Report
|
||||
FString EngineCrashClientPath = GetEngineCrashClientPath();
|
||||
FString EngineCrashClientBackupPath = EngineCrashClientPath + ".ue";
|
||||
|
||||
int32 Result = IsMantisExe( EngineCrashClientPath );
|
||||
if ( Result == 1 )
|
||||
{
|
||||
UpdateMantis();
|
||||
}
|
||||
else if ( Result == 0 )
|
||||
{
|
||||
MakeBackup( EngineCrashClientPath, EngineCrashClientBackupPath, true );
|
||||
UpdateMantis();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void FMantis::ShutdownModule()
|
||||
{
|
||||
//Unregister the settings in the editor.
|
||||
UnregisterSettings();
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
//Get the path of the Engine Crash Report
|
||||
FString EngineCrashClientPath = GetEngineCrashClientPath();
|
||||
FString EngineCrashClientBackupPath = EngineCrashClientPath + ".ue";
|
||||
|
||||
//Can't restore if there is no backup.
|
||||
if ( !FPaths::FileExists( EngineCrashClientBackupPath ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Backup file not found!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if backup is valid
|
||||
if ( IsMantisExe( EngineCrashClientBackupPath ) == 1 )
|
||||
{
|
||||
UE_LOG( LogMantis, Warning, TEXT( "Backup file is not from Unreal!" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if client is valid
|
||||
int32 Result = IsMantisExe( EngineCrashClientPath );
|
||||
if ( Result == 1 )
|
||||
{
|
||||
MakeBackup( EngineCrashClientBackupPath, EngineCrashClientPath, true );
|
||||
}
|
||||
#endif
|
||||
// This function may be called during shutdown to clean up the module. For modules that support dynamic reloading,
|
||||
// this function gets called before unloading the module.
|
||||
}
|
||||
|
||||
int32 FMantis::IsMantisExe( FString FilePath )
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
// get the filename of the executable containing the version resource
|
||||
LPWSTR FilePathW = (WCHAR*) *FilePath;
|
||||
|
||||
// allocate a block of memory for the version info
|
||||
uint32 dummy;
|
||||
uint32 dwSize = GetFileVersionInfoSize( FilePathW, (LPDWORD)&dummy );
|
||||
if ( dwSize == 0 )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "GetFileVersionInfoSize failed with error %d\n" ), FPlatformMisc::GetLastError() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
TArray<BYTE> data;
|
||||
data.SetNum( dwSize );
|
||||
// load the version info
|
||||
if ( !GetFileVersionInfo( FilePathW, NULL, dwSize, &data[0] ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "GetFileVersionInfo failed with error %d\n" ), FPlatformMisc::GetLastError() );
|
||||
return -1;
|
||||
}
|
||||
|
||||
LPVOID pvFileDescription = NULL;
|
||||
uint32 FileDescriptionLen = 0;
|
||||
|
||||
if ( !VerQueryValue( &data[0], _T( "\\StringFileInfo\\040904b0\\FileDescription" ), &pvFileDescription, &FileDescriptionLen ) )
|
||||
{
|
||||
UE_LOG( LogMantis, Log, TEXT( "Can't obtain ProductName and ProductVersion from resources\n" ) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
FString MantisClientName = TEXT( "MantisCrashReportClient" );
|
||||
TCHAR* ClientNameW = (TCHAR*)pvFileDescription;
|
||||
FString ClientName = ClientNameW;
|
||||
return ( ClientName == MantisClientName ) ? 1 : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
IMPLEMENT_MODULE( FMantis, Mantis )
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
12
Plugins/Mantis/Source/Mantis/Private/MantisPrivatePCH.h
Normal file
12
Plugins/Mantis/Source/Mantis/Private/MantisPrivatePCH.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// Project Lab - NHTV IGAD
|
||||
//////////////////////////////////////////
|
||||
// Author: Yoshi van Belkom - 130118
|
||||
//////////////////////////////////////////
|
||||
// The Mantis Module Pre Compiled Header.
|
||||
//////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IMantis.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogMantis, Log, All);
|
||||
7
Plugins/Mantis/Source/Mantis/Private/MantisSettings.cpp
Normal file
7
Plugins/Mantis/Source/Mantis/Private/MantisSettings.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "MantisPrivatePCH.h"
|
||||
#include "MantisSettings.h"
|
||||
|
||||
UMantisSettings::UMantisSettings(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer), HostURL(TEXT(""))
|
||||
{}
|
||||
27
Plugins/Mantis/Source/Mantis/Public/IMantis.h
Normal file
27
Plugins/Mantis/Source/Mantis/Public/IMantis.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Project Lab - NHTV IGAD
|
||||
//////////////////////////////////////////
|
||||
// Author: Yoshi van Belkom - 130118
|
||||
//////////////////////////////////////////
|
||||
// The Mantis Editor Module Interface.
|
||||
//////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModuleManager.h"
|
||||
|
||||
class IMantis : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
//Function to Get the Singleton of this Module if it's loaded.
|
||||
static inline IMantis& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked< IMantis >( "Mantis" );
|
||||
}
|
||||
|
||||
//Function to check if the Module is loaded.
|
||||
static inline bool IsAvailable()
|
||||
{
|
||||
return FModuleManager::Get().IsModuleLoaded( "Mantis" );
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user