Files
UnrealEngineUWP/Engine/Source/Developer/Windows/LiveCoding/Private/LiveCodingModule.cpp

362 lines
8.7 KiB
C++
Raw Normal View History

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "LiveCodingModule.h"
#include "Modules/ModuleManager.h"
#include "Features/IModularFeatures.h"
#include "HAL/IConsoleManager.h"
#include "Misc/CoreDelegates.h"
#include "LiveCodingLog.h"
#include "External/LC_EntryPoint.h"
#include "Misc/App.h"
#include "Misc/Paths.h"
#include "Misc/ConfigCacheIni.h"
#include "LiveCodingSettings.h"
#include "ISettingsModule.h"
#include "ISettingsSection.h"
#include "Windows/WindowsHWrapper.h"
IMPLEMENT_MODULE(FLiveCodingModule, LiveCoding)
#define LOCTEXT_NAMESPACE "LiveCodingModule"
bool GIsCompileActive = false;
FString GLiveCodingConsolePath;
FString GLiveCodingConsoleArguments;
FLiveCodingModule::FLiveCodingModule()
: bEnabledLastTick(false)
, bEnabledForSession(false)
, bStarted(false)
, FullEnginePluginsDir(FPaths::ConvertRelativePathToFull(FPaths::EnginePluginsDir()))
, FullProjectDir(FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()))
, FullProjectPluginsDir(FPaths::ConvertRelativePathToFull(FPaths::ProjectPluginsDir()))
{
}
void FLiveCodingModule::StartupModule()
{
Settings = GetMutableDefault<ULiveCodingSettings>();
IConsoleManager& ConsoleManager = IConsoleManager::Get();
EnableCommand = ConsoleManager.RegisterConsoleCommand(
TEXT("LiveCoding"),
TEXT("Enables live coding support"),
FConsoleCommandDelegate::CreateRaw(this, &FLiveCodingModule::EnableForSession, true),
ECVF_Cheat
);
ConsolePathVariable = ConsoleManager.RegisterConsoleVariable(
TEXT("LiveCoding.ConsolePath"),
FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/Win64/LiveCodingConsole.exe")),
TEXT("Path to the live coding console application"),
ECVF_Cheat
);
EndFrameDelegateHandle = FCoreDelegates::OnEndFrame.AddRaw(this, &FLiveCodingModule::Tick);
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule != nullptr)
{
SettingsSection = SettingsModule->RegisterSettings("Editor", "General", "Live Coding",
LOCTEXT("LiveCodingSettingsName", "Live Coding"),
LOCTEXT("LiveCodintSettingsDescription", "Settings for recompiling C++ code while the engine is running."),
GetMutableDefault<ULiveCodingSettings>()
);
}
extern void Startup(Windows::HINSTANCE hInstance);
Startup(hInstance);
if (Settings->bEnabled)
{
if(Settings->Startup == ELiveCodingStartupMode::Automatic)
{
StartLiveCoding();
ShowConsole();
}
else if(Settings->Startup == ELiveCodingStartupMode::AutomaticButHidden)
{
GLiveCodingConsoleArguments = L"-Hidden";
StartLiveCoding();
}
}
if(FParse::Param(FCommandLine::Get(), TEXT("LiveCoding")))
{
StartLiveCoding();
}
bEnabledLastTick = Settings->bEnabled;
}
void FLiveCodingModule::ShutdownModule()
{
extern void Shutdown();
Shutdown();
FCoreDelegates::OnEndFrame.Remove(EndFrameDelegateHandle);
IConsoleManager& ConsoleManager = IConsoleManager::Get();
ConsoleManager.UnregisterConsoleObject(ConsolePathVariable);
ConsoleManager.UnregisterConsoleObject(EnableCommand);
}
void FLiveCodingModule::EnableByDefault(bool bEnable)
{
if(Settings->bEnabled != bEnable)
{
Settings->bEnabled = bEnable;
if(SettingsSection.IsValid())
{
SettingsSection->Save();
}
}
EnableForSession(bEnable);
}
bool FLiveCodingModule::IsEnabledByDefault() const
{
return Settings->bEnabled;
}
void FLiveCodingModule::EnableForSession(bool bEnable)
{
if (bEnable)
{
if(!bStarted)
{
StartLiveCoding();
ShowConsole();
}
}
else
{
if(bStarted)
{
UE_LOG(LogLiveCoding, Display, TEXT("Console will be hidden but remain running in the background. Restart to disable completely."));
LppSetActive(false);
LppSetVisible(false);
}
}
bEnabledForSession = bEnable;
}
bool FLiveCodingModule::IsEnabledForSession() const
{
return bEnabledForSession;
}
bool FLiveCodingModule::HasStarted() const
{
return bStarted;
}
void FLiveCodingModule::ShowConsole()
{
if (bStarted)
{
LppSetVisible(true);
LppSetActive(true);
LppShowConsole();
}
}
void FLiveCodingModule::Compile()
{
if(!GIsCompileActive)
{
EnableForSession(true);
if(bStarted)
{
LppTriggerRecompile();
GIsCompileActive = true;
}
}
}
bool FLiveCodingModule::IsCompiling() const
{
return GIsCompileActive;
}
void FLiveCodingModule::Tick()
{
if (Settings->bEnabled != bEnabledLastTick && Settings->Startup != ELiveCodingStartupMode::Manual)
{
EnableForSession(Settings->bEnabled);
bEnabledLastTick = Settings->bEnabled;
}
}
bool FLiveCodingModule::StartLiveCoding()
{
if(!bStarted)
{
// Setup the console path
GLiveCodingConsolePath = ConsolePathVariable->GetString();
if (!FPaths::FileExists(GLiveCodingConsolePath))
{
UE_LOG(LogLiveCoding, Error, TEXT("Unable to start live coding session. Missing executable '%s'. Use the LiveCoding.ConsolePath console variable to modify."), *GLiveCodingConsolePath);
return false;
}
UE_LOG(LogLiveCoding, Display, TEXT("Starting LiveCoding"));
// Enable external build system
LppUseExternalBuildSystem();
// Enable the server
FString ProcessGroup = FString::Printf(TEXT("UE4_%s_0x%08x"), FApp::GetProjectName(), GetTypeHash(FPaths::ProjectDir()));
LppRegisterProcessGroup(TCHAR_TO_ANSI(*ProcessGroup));
// Build the command line
FString Arguments;
Arguments += FString::Printf(TEXT("%s"), FPlatformMisc::GetUBTPlatform());
Arguments += FString::Printf(TEXT(" %s"), EBuildConfigurations::ToString(FApp::GetBuildConfiguration()));
Arguments += FString::Printf(TEXT(" -TargetType=%s"), FPlatformMisc::GetUBTTarget());
if(FPaths::IsProjectFilePathSet())
{
Arguments += FString::Printf(TEXT(" -Project=\"%s\""), *FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath()));
}
LppSetBuildArguments(*Arguments);
// Configure all the current modules
UpdateModules();
// Register a delegate to listen for new modules loaded from this point onwards
ModulesChangedDelegateHandle = FModuleManager::Get().OnModulesChanged().AddRaw(this, &FLiveCodingModule::OnModulesChanged);
// Mark it as started
bStarted = true;
bEnabledForSession = true;
}
return true;
}
void FLiveCodingModule::UpdateModules()
{
#if IS_MONOLITHIC
wchar_t FullFilePath[WINDOWS_MAX_PATH];
verify(GetModuleFileName(hInstance, FullFilePath, ARRAY_COUNT(FullFilePath)));
EnableModule(FullFilePath);
#else
TArray<FModuleStatus> ModuleStatuses;
FModuleManager::Get().QueryModules(ModuleStatuses);
extern void BeginCommandBatch();
BeginCommandBatch();
for (const FModuleStatus& ModuleStatus : ModuleStatuses)
{
if (ModuleStatus.bIsLoaded)
{
FString FullFilePath = FPaths::ConvertRelativePathToFull(ModuleStatus.FilePath);
ConfigureModule(FName(*ModuleStatus.Name), FullFilePath);
}
}
extern void EndCommandBatch();
EndCommandBatch();
#endif
}
void FLiveCodingModule::EnableModule(const FString& FullFilePath)
{
if (!EnabledModules.Contains(FullFilePath))
{
LppEnableModule(*FullFilePath);
EnabledModules.Add(FullFilePath);
}
}
void FLiveCodingModule::DisableModule(const FString& FullFilePath)
{
if(EnabledModules.Contains(FullFilePath))
{
LppDisableModule(*FullFilePath);
EnabledModules.Remove(FullFilePath);
}
}
void FLiveCodingModule::OnModulesChanged(FName ModuleName, EModuleChangeReason Reason)
{
#if !IS_MONOLITHIC
if (Reason == EModuleChangeReason::ModuleLoaded)
{
FModuleStatus Status;
if (FModuleManager::Get().QueryModule(ModuleName, Status))
{
FString FullFilePath = FPaths::ConvertRelativePathToFull(Status.FilePath);
ConfigureModule(ModuleName, FullFilePath);
}
}
#endif
}
void FLiveCodingModule::ConfigureModule(const FName& Name, const FString& FullFilePath)
{
#if !IS_MONOLITHIC
if (ShouldEnableModule(Name, FullFilePath))
{
EnableModule(FullFilePath);
}
else
{
DisableModule(FullFilePath);
}
#endif
}
bool FLiveCodingModule::ShouldEnableModule(const FName& Name, const FString& FullFilePath) const
{
if (Settings->ExcludeSpecificModules.Contains(Name))
{
return false;
}
if (Settings->IncludeSpecificModules.Contains(Name))
{
return true;
}
if (FullFilePath.StartsWith(FullProjectDir))
{
if (Settings->bIncludeProjectModules == Settings->bIncludeProjectPluginModules)
{
return Settings->bIncludeProjectModules;
}
if(FullFilePath.StartsWith(FullProjectPluginsDir))
{
return Settings->bIncludeProjectPluginModules;
}
else
{
return Settings->bIncludeProjectModules;
}
}
else
{
if (FApp::IsEngineInstalled())
{
return false;
}
if (Settings->bIncludeEngineModules == Settings->bIncludeEnginePluginModules)
{
return Settings->bIncludeEngineModules;
}
if(FullFilePath.StartsWith(FullEnginePluginsDir))
{
return Settings->bIncludeEnginePluginModules;
}
else
{
return Settings->bIncludeEngineModules;
}
}
}
#undef LOCTEXT_NAMESPACE