Skip to content
Snippets Groups Projects
Commit a4247b20 authored by Jonathan Ehret's avatar Jonathan Ehret
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request VR-Group/unreal-development/plugins/universallogging!16
parents 4bb373d3 d7257923
No related branches found
No related tags found
1 merge request!16Develop
Showing
with 521 additions and 94 deletions
#-------------------------------------------------------------------------------
# Copyright (c) 2020 RWTH Aachen University, Germany,
# Virtual Reality & Immersive Visualisation Group.
#-------------------------------------------------------------------------------
# The include file can be change to either be removed or reference a specific commit.
include:
- project: 'vr-group/unreal-development/unreal-ci'
ref: master
file: '/shared_scripts.yml'
# In this file you are able to configure your plugins pipeline.
# If you want to customize something, either overwrite things that are defined in the shared_scripts repository,
# or remove the "extends" and write your own scripts
#
# If you want your pipeline to run on every commit, just remove the "only" blocks. Keep in mind, that a build
# can take some time.
#
# If you want to alter the unreal-building process two variables are defined for either changing the CLIENT_CONFIG or
# for adding EXTRA_ARGS to the building process
#
# For the generate stage, you can specify needed dependencies in GEN_DEPENDENCIES with [Branch@PluginFolder] as key
# Example:
#
# Generate_Project:
# only: ['web', 'schedules']
# extends: .Generate_Project_
# variables:
# GEN_TEMPLATE_REPO: "https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unrealprojecttemplate.git"
# GEN_TEMPLATE_BRANCH: "develop"
# GEN_DEPENDENCIES: "(
# [master@nDisplayExtensions]='https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/ndisplayextensions.git'
# [master@CaveOverlay]='https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unreal-cave-overlay.git'
# )"
#
# You can uncomment the deploy lines to deploy your project to the CAVE/VRDev. This only makes sense, if your plugin works
# with a generated project.
stages:
- generate
- build
# - deploy
Generate_Project:
only: ['web', 'schedules']
extends: .Generate_Project_
variables:
GEN_TEMPLATE_REPO: "https://devhub.vr.rwth-aachen.de/VR-Group/unreal-development/unrealprojecttemplate.git"
GEN_TEMPLATE_BRANCH: "4.26"
GEN_DEPENDENCIES: "(
)"
Build_Windows:
only: ['web', 'schedules']
extends: .Build_Windows_
tags:
- windows
- unreal-4.26
variables:
GIT_STRATEGY: none
GIT_CHECKOUT: "false"
CLIENT_CONFIG: "DebugGame"
needs:
- job: "Generate_Project"
artifacts: true
Build_CentOS:
only: ['web', 'schedules']
extends: .Build_CentOS_
tags:
- centos
- unreal-4.26
variables:
GIT_STRATEGY: none
GIT_CHECKOUT: "false"
CLIENT_CONFIG: "DebugGame"
needs:
- job: "Generate_Project"
artifacts: true
#Deploy_CAVE:
# only: ['web', 'schedules']
# extends: .Deploy_CAVE_
# needs:
# - job: "Build_CentOS"
# artifacts: true
#
#Deploy_Windows:
# only: ['web', 'schedules']
# extends: .Deploy_VRDev_
# needs:
# - job: "Build_Windows"
# artifacts: true
LICENSE 0 → 100644
BSD 3-Clause License
Copyright (c) 2020, Virtual Reality & Immersive Visualization Group at RWTH Aachen University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
...@@ -75,6 +75,16 @@ UniLog.Log("Message", "StreamName"); ...@@ -75,6 +75,16 @@ UniLog.Log("Message", "StreamName");
UniLog.LogF("StreamName", "Message %s", *variable); UniLog.LogF("StreamName", "Message %s", *variable);
``` ```
### Send Multiple LogStreams to the Same File
You can simply specify the same file name and file path in multiple LogStreams. The output of both streams will be written to this file. This can be useful to have separate streams for errors or warnings. To distinguish the streams, you can use
```cpp
stream->SetPrefix("Warning: "); // No additional space will be added after the prefix, so make sure to add one if you want that
```
to set a prefix that will automatically be added to every message that is written to the file (this will not show up in the on screen log).
### On Screen Logging ### On Screen Logging
You can also display the log messages on screen. This can even be enabled/disabled during runtime. To do this, use the ILogStream interface: You can also display the log messages on screen. This can even be enabled/disabled during runtime. To do this, use the ILogStream interface:
......
#include "LogFileManager.h"
LogFileStream* LogFileManager::GetLogFileStream(FString FilePath, FString FileName)
{
FString Full_Path = FPaths::Combine(FilePath, FileName);
if (Streams.Contains(Full_Path))
return Streams[Full_Path].Get();
else
Streams.Add(Full_Path, MakeUnique<LogFileStream>(FilePath, FileName));
return Streams[Full_Path].Get();
}
LogFileManager::LogFileManager()
{
}
LogFileManager::~LogFileManager()
{
}
#pragma once
#include "LogFileStream.h"
class LogFileManager
{
public:
LogFileStream* GetLogFileStream(FString FilePath, FString FileName);
private:
friend class UniversalLoggingImpl;
LogFileManager();
virtual ~LogFileManager();
private:
TMap<FString, TUniquePtr<LogFileStream>> Streams;
};
\ No newline at end of file
#include "LogFileStream.h"
#include "HAL/PlatformFilemanager.h"
#include "LogStream.h"
#include "Misc/Paths.h"
LogFileStream::LogFileStream(const FString Filepath, const FString Filename)
: Filepath(Filepath)
, Filename(Filename)
, bIs_Open(false)
, File_Handle(nullptr)
{
}
LogFileStream::~LogFileStream()
{
Close();
}
void LogFileStream::Open()
{
IPlatformFile& platform_file = FPlatformFileManager::Get().GetPlatformFile();
FString file_path = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir() + Filepath);
platform_file.CreateDirectoryTree(*file_path);
file_path = FPaths::Combine(file_path, Filename);
File_Handle.Reset(platform_file.OpenWrite(*file_path));
if (!File_Handle)
{
UE_LOG(LogUni, Error, TEXT("Universal Logging: The file %s could not be opened for writing."), *file_path);
bIs_Open = false;
return;
}
bIs_Open = true;
}
void LogFileStream::Close()
{
File_Handle.Reset();
bIs_Open = false;
}
bool LogFileStream::GetIsOpen() const
{
return bIs_Open;
}
void LogFileStream::Write(const FString Text)
{
if (!bIs_Open)
Open();
const FTCHARToUTF8 StringUTF8(*Text);
File_Handle->Write(reinterpret_cast<const uint8*>(StringUTF8.Get()), StringUTF8.Length());
}
#pragma once
class LogFileStream
{
public:
LogFileStream(const FString Filepath, const FString Filename);
virtual ~LogFileStream();
void Open();
void Close();
bool GetIsOpen() const;
void Write(const FString Text);
private:
const FString Filepath;
const FString Filename;
bool bIs_Open;
TUniquePtr <IFileHandle> File_Handle;
};
\ No newline at end of file
#include "UniversalLoggingPrivatePCH.h"
#include "LogStream.h" #include "LogStream.h"
#include "UniversalLogging.h" #include "UniversalLogging.h"
#include "HAL/PlatformFilemanager.h"
#include "Misc/Paths.h" #include "Misc/Paths.h"
#include "HAL/IPlatformFileProfilerWrapper.h"
DEFINE_LOG_CATEGORY(LogUni);
LogStreamImpl::LogStreamImpl(const FString Filepath, const FString Filename, const bool bPer_Session, const bool bLogOnMaster, const bool bLogOnSlaves) LogStreamImpl::LogStreamImpl(const FString Filepath, const FString Filename, const bool bPer_Session, const bool bLogOnMaster, const bool bLogOnSlaves)
: Filepath(Filepath) : Filepath(Filepath)
, Filename(Filename) , Filename(Filename)
, bPer_Session(bPer_Session) , bPer_Session(bPer_Session)
, bOnScreen(false) , bOnScreen(false)
, OnScreenColor(0, 0, 255, 255) , OnScreenColor(255, 255, 255, 255)
, OnScreenBackgroundColor(0, 0, 0, 128)
, OnScreenSize(1.0)
, OnScreenDuration(5.0)
, bLogToDefaultLog(false)
, bLogOnMaster(bLogOnMaster) , bLogOnMaster(bLogOnMaster)
, bLogOnSlaves(bLogOnSlaves) , bLogOnSlaves(bLogOnSlaves)
, bLogOnScreenOnMaster(true) , bLogOnScreenOnMaster(true)
, bLogOnScreenOnSlaves(false) , bLogOnScreenOnSlaves(false)
, bIs_Open(false)
, bIs_Valid(false) , bIs_Valid(false)
, File_Handle(nullptr) , Log_File_Stream(nullptr)
{ {
if ((bLogOnMaster && UniversalLoggingImpl::IsClusterMaster()) || (bLogOnSlaves && !UniversalLoggingImpl::IsClusterMaster())) if ((bLogOnMaster && UniversalLoggingImpl::IsClusterMaster()) || (bLogOnSlaves && !UniversalLoggingImpl::IsClusterMaster()))
{ {
Open(); Open();
if (bIs_Open) if (GetIsOpen())
bIs_Valid = true; bIs_Valid = true;
Close(); Close();
} }
...@@ -49,6 +51,16 @@ FString LogStreamImpl::GetFilename() ...@@ -49,6 +51,16 @@ FString LogStreamImpl::GetFilename()
return Filename; return Filename;
} }
void LogStreamImpl::SetPrefix(FString Prefix)
{
MessagePrefix = Prefix;
}
FString LogStreamImpl::GetPrefix() const
{
return MessagePrefix;
}
void LogStreamImpl::SetOnScreen(const bool Val) void LogStreamImpl::SetOnScreen(const bool Val)
{ {
bOnScreen = Val; bOnScreen = Val;
...@@ -69,6 +81,46 @@ FColor LogStreamImpl::GetOnScreenColor() const ...@@ -69,6 +81,46 @@ FColor LogStreamImpl::GetOnScreenColor() const
return OnScreenColor; return OnScreenColor;
} }
void LogStreamImpl::SetOnScreenBackgroundColor(const FColor Color)
{
OnScreenBackgroundColor = Color;
}
FColor LogStreamImpl::GetOnScreenBackgroundColor() const
{
return OnScreenBackgroundColor;
}
void LogStreamImpl::SetOnScreenSize(const float Scale)
{
OnScreenSize = Scale;
}
float LogStreamImpl::GetOnScreenSize() const
{
return OnScreenSize;
}
void LogStreamImpl::SetOnScreenDuration(const float Seconds)
{
OnScreenDuration = Seconds;
}
float LogStreamImpl::GetOnScreenDuration() const
{
return OnScreenDuration;
}
void LogStreamImpl::SetLogToDefaultLog(const bool Val)
{
bLogToDefaultLog = Val;
}
bool LogStreamImpl::GetLogToDefaultLog() const
{
return bLogToDefaultLog;
}
bool LogStreamImpl::GetLogOnMaster() const bool LogStreamImpl::GetLogOnMaster() const
{ {
return bLogOnMaster; return bLogOnMaster;
...@@ -81,6 +133,8 @@ bool LogStreamImpl::GetLogOnSlaves() const ...@@ -81,6 +133,8 @@ bool LogStreamImpl::GetLogOnSlaves() const
void LogStreamImpl::SetLogOnScreenOnMaster(const bool Val) void LogStreamImpl::SetLogOnScreenOnMaster(const bool Val)
{ {
if(Val) // to avoid confusion, this also enables logging
SetOnScreen(true);
bLogOnScreenOnMaster = Val; bLogOnScreenOnMaster = Val;
} }
...@@ -91,6 +145,8 @@ bool LogStreamImpl::GetLogOnScreenOnMaster() const ...@@ -91,6 +145,8 @@ bool LogStreamImpl::GetLogOnScreenOnMaster() const
void LogStreamImpl::SetLogOnScreenOnSlaves(const bool Val) void LogStreamImpl::SetLogOnScreenOnSlaves(const bool Val)
{ {
if (Val) // to avoid confusion, this also enables logging
SetOnScreen(true);
bLogOnScreenOnSlaves = Val; bLogOnScreenOnSlaves = Val;
} }
...@@ -106,40 +162,33 @@ bool LogStreamImpl::GetIsValid() ...@@ -106,40 +162,33 @@ bool LogStreamImpl::GetIsValid()
void LogStreamImpl::Open() void LogStreamImpl::Open()
{ {
IPlatformFile& platform_file = FPlatformFileManager::Get().GetPlatformFile(); FString File_Path = Filepath;
FString file_path = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir() + Filepath);
if(bPer_Session) if(bPer_Session)
file_path += "/" + UniLog.GetSessionIdentifier(); File_Path = FPaths::Combine(File_Path, UniLog.GetSessionIdentifier());
platform_file.CreateDirectoryTree(*file_path); Log_File_Stream = UniversalLoggingImpl::GetLogFileManager()->GetLogFileStream(File_Path, Filename); // this will not stay like this, as LogFileStreams will be managed by LogFileManager
file_path += "/" + Filename; Log_File_Stream->Open();
File_Handle = platform_file.OpenWrite(*file_path); if (!Log_File_Stream->GetIsOpen())
if (!File_Handle) {
{
UE_LOG(LogTemp, Error, TEXT("Universal Logging: The file %s could not be opened for writing."), *file_path);
bIs_Open = false;
bIs_Valid = false; bIs_Valid = false;
return; return;
} }
bIs_Open = true;
} }
void LogStreamImpl::Close() void LogStreamImpl::Close()
{ {
delete File_Handle; Log_File_Stream->Close();
File_Handle = nullptr;
bIs_Open = false;
} }
bool LogStreamImpl::GetIsOpen() const bool LogStreamImpl::GetIsOpen() const
{ {
return bIs_Open; return Log_File_Stream->GetIsOpen();
} }
void LogStreamImpl::Write(const FString Text) void LogStreamImpl::Write(const FString Text)
{ {
if (!bIs_Valid) if (!bIs_Valid)
return; return;
if (!bIs_Open) if (!Log_File_Stream->GetIsOpen())
Open(); Open();
File_Handle->Write(reinterpret_cast<const uint8*>(TCHAR_TO_ANSI(*Text)), Text.Len()); Log_File_Stream->Write(MessagePrefix + Text);
} }
\ No newline at end of file
#pragma once #pragma once
#include "ILogStream.h"
#include "LogFileStream.h"
#include "Math/Color.h" #include "Math/Color.h"
DECLARE_LOG_CATEGORY_EXTERN(LogUni, Log, All);
class LogStreamImpl : public ILogStream class LogStreamImpl : public ILogStream
{ {
public: public:
...@@ -11,10 +18,22 @@ public: ...@@ -11,10 +18,22 @@ public:
FString GetFilepath() override; FString GetFilepath() override;
FString GetFilename() override; FString GetFilename() override;
void SetPrefix(FString Prefix) override;
FString GetPrefix() const override;
void SetOnScreen(const bool Val) override; void SetOnScreen(const bool Val) override;
bool GetOnScreen() const override; bool GetOnScreen() const override;
void SetOnScreenColor(const FColor Color) override; void SetOnScreenColor(const FColor Color) override;
FColor GetOnScreenColor() const override; FColor GetOnScreenColor() const override;
void SetOnScreenBackgroundColor(const FColor Color) override;
FColor GetOnScreenBackgroundColor() const override;
void SetOnScreenSize(const float Scale) override;
float GetOnScreenSize() const override;
void SetOnScreenDuration(const float Seconds) override;
float GetOnScreenDuration() const override;
void SetLogToDefaultLog(const bool Val) override;
bool GetLogToDefaultLog() const override;
bool GetLogOnMaster() const override; bool GetLogOnMaster() const override;
bool GetLogOnSlaves() const override; bool GetLogOnSlaves() const override;
...@@ -34,10 +53,16 @@ public: ...@@ -34,10 +53,16 @@ public:
private: private:
const FString Filepath; const FString Filepath;
const FString Filename; const FString Filename;
FString MessagePrefix;
bool bPer_Session; bool bPer_Session;
bool bOnScreen; bool bOnScreen;
FColor OnScreenColor; FColor OnScreenColor;
FColor OnScreenBackgroundColor;
float OnScreenSize;
float OnScreenDuration;
bool bLogToDefaultLog;
bool bLogOnMaster; bool bLogOnMaster;
bool bLogOnSlaves; bool bLogOnSlaves;
...@@ -45,8 +70,7 @@ private: ...@@ -45,8 +70,7 @@ private:
bool bLogOnScreenOnMaster; bool bLogOnScreenOnMaster;
bool bLogOnScreenOnSlaves; bool bLogOnScreenOnSlaves;
bool bIs_Open;
bool bIs_Valid; bool bIs_Valid;
IFileHandle* File_Handle; LogFileStream* Log_File_Stream;
}; };
...@@ -12,12 +12,15 @@ AOnScreenLog::AOnScreenLog() ...@@ -12,12 +12,15 @@ AOnScreenLog::AOnScreenLog()
} }
void AOnScreenLog::EnqueueMessage(const FString Text, const FColor Color) void AOnScreenLog::EnqueueMessage(const FString Text, const FColor Color, const FColor BackgroundColor, const float Scale, const float Duration)
{ {
FMessage Message; FMessage Message;
Message.Text = Text; Message.Text = Text;
Message.Color = Color; Message.Color = Color;
Message.TimeToLive = 5.0; Message.BackgroundColor = BackgroundColor;
Message.AlphaFactor = 1.0;
Message.Scale = Scale;
Message.TimeToLive = Duration;
Message_Queue.Insert(Message, 0); Message_Queue.Insert(Message, 0);
} }
...@@ -32,18 +35,17 @@ void AOnScreenLog::BeginPlay() ...@@ -32,18 +35,17 @@ void AOnScreenLog::BeginPlay()
void AOnScreenLog::Tick(float DeltaTime) void AOnScreenLog::Tick(float DeltaTime)
{ {
Super::Tick(DeltaTime); Super::Tick(DeltaTime);
for (int i = 0; i < Message_Queue.Num(); i++) for (int i = Message_Queue.Num(); i--;)
{ {
Message_Queue[i].TimeToLive -= DeltaTime; Message_Queue[i].TimeToLive -= DeltaTime;
if(Message_Queue[i].TimeToLive < 1.0) // Fade out if(Message_Queue[i].TimeToLive < 1.0) // Fade out
{ {
Message_Queue[i].Color.A = Message_Queue[i].TimeToLive * 255; Message_Queue[i].AlphaFactor = Message_Queue[i].TimeToLive;
} }
} if(Message_Queue[i].TimeToLive <= 0.0) // Remove (works because array is traversed backwards)
FMessage LastMessage;
while (Message_Queue.Num() > 0 && Message_Queue.Top().TimeToLive <= 0)
{ {
Message_Queue.Pop(); Message_Queue.RemoveAt(i);
}
} }
} }
...@@ -52,8 +54,20 @@ void AOnScreenLog::PostRenderFor(APlayerController* PC, UCanvas* Canvas, FVector ...@@ -52,8 +54,20 @@ void AOnScreenLog::PostRenderFor(APlayerController* PC, UCanvas* Canvas, FVector
float YOffset = 50; float YOffset = 50;
for (auto Message : Message_Queue) for (auto Message : Message_Queue)
{ {
Canvas->DrawColor = Message.Color; int Height;
YOffset += Canvas->DrawText(myFont.Object, Message.Text, 10, YOffset); int Width;
myFont.Object->GetStringHeightAndWidth(Message.Text, Height, Width);
FVector2D BoxPosition(10, YOffset);
FVector2D BoxSize(Width * Message.Scale, Height * Message.Scale);
FLinearColor BoxColor = FLinearColor(Message.BackgroundColor);
BoxColor.A *= Message.AlphaFactor;
FCanvasTileItem Box(BoxPosition, BoxSize, BoxColor);
Box.BlendMode = ESimpleElementBlendMode::SE_BLEND_Translucent;
Canvas->DrawItem(Box);
FColor TextColor = Message.Color;
TextColor.A *= Message.AlphaFactor;
Canvas->DrawColor = TextColor;
YOffset += Canvas->DrawText(myFont.Object, Message.Text, 10, YOffset, Message.Scale, Message.Scale);
} }
} }
...@@ -19,7 +19,7 @@ public: ...@@ -19,7 +19,7 @@ public:
// Sets default values for this actor's properties // Sets default values for this actor's properties
AOnScreenLog(); AOnScreenLog();
void EnqueueMessage(const FString Text, const FColor Color); void EnqueueMessage(const FString Text, const FColor Color, const FColor BackgroundColor, const float Scale, const float Duration);
protected: protected:
// Called when the game starts or when spawned // Called when the game starts or when spawned
...@@ -35,6 +35,9 @@ private: ...@@ -35,6 +35,9 @@ private:
{ {
FString Text; FString Text;
FColor Color; FColor Color;
FColor BackgroundColor;
float AlphaFactor;
float Scale;
float TimeToLive; float TimeToLive;
}; };
TArray<FMessage> Message_Queue; TArray<FMessage> Message_Queue;
......
...@@ -26,26 +26,39 @@ FString UUniLogBlueprintFunctionLibrary::GetSessionIdentifier() ...@@ -26,26 +26,39 @@ FString UUniLogBlueprintFunctionLibrary::GetSessionIdentifier()
} }
void UUniLogBlueprintFunctionLibrary::NewLogStream(const FString StreamName, const FString Filepath, void UUniLogBlueprintFunctionLibrary::NewLogStream(const FString StreamName, const FString Filepath,
const FString Filename, bool bPer_Session, bool bOnScreen/* = false*/, const FString Filename, FString Prefix, bool bPer_Session, bool bOnScreen/* = false*/,
FColor OnScreenColor/* = FColor(0, 0, 255, 0)*/, FColor OnScreenColor/* = FColor(0, 0, 255, 0)*/,
bool bLogOnMaster/* = true*/, bool bLogOnSlaves/* = false*/, FColor OnScreenBackgroundColor, float OnScreenSize,
float OnScreenDuration,
bool bLogToDefaultLog, bool bLogOnMaster/* = true*/,
bool bLogOnSlaves/* = false*/,
bool bLogOnScreenOnMaster/* = true*/, bool bLogOnScreenOnMaster/* = true*/,
bool bLogOnScreenOnSlaves/* = false*/) bool bLogOnScreenOnSlaves/* = false*/)
{ {
auto LogStream = UniLog.NewLogStream(StreamName, Filepath, Filename, bPer_Session, bLogOnMaster, bLogOnSlaves); auto LogStream = UniLog.NewLogStream(StreamName, Filepath, Filename, bPer_Session, bLogOnMaster, bLogOnSlaves);
LogStream->SetPrefix(Prefix);
LogStream->SetOnScreen(bOnScreen); LogStream->SetOnScreen(bOnScreen);
LogStream->SetOnScreenColor(OnScreenColor); LogStream->SetOnScreenColor(OnScreenColor);
LogStream->SetOnScreenBackgroundColor(OnScreenBackgroundColor);
LogStream->SetOnScreenSize(OnScreenSize);
LogStream->SetOnScreenDuration(OnScreenDuration);
LogStream->SetLogToDefaultLog(bLogToDefaultLog);
LogStream->SetLogOnScreenOnMaster(bLogOnScreenOnMaster); LogStream->SetLogOnScreenOnMaster(bLogOnScreenOnMaster);
LogStream->SetLogOnScreenOnSlaves(bLogOnScreenOnSlaves); LogStream->SetLogOnScreenOnSlaves(bLogOnScreenOnSlaves);
} }
void UUniLogBlueprintFunctionLibrary::ModifyLogStream(const FString StreamName, bool bOnScreen, FColor OnScreenColor, void UUniLogBlueprintFunctionLibrary::ModifyLogStream(const FString StreamName, bool bOnScreen, FColor OnScreenColor,
bool bLogOnScreenOnMaster/* = true*/, FColor OnScreenBackgroundColor,
float OnScreenSize, float OnScreenDuration, bool bLogToDefaultLog, bool bLogOnScreenOnMaster/* = true*/,
bool bLogOnScreenOnSlaves/* = false*/) bool bLogOnScreenOnSlaves/* = false*/)
{ {
auto LogStream = UniLog.GetLogStream(StreamName); auto LogStream = UniLog.GetLogStream(StreamName);
LogStream->SetOnScreen(bOnScreen); LogStream->SetOnScreen(bOnScreen);
LogStream->SetOnScreenColor(OnScreenColor); LogStream->SetOnScreenColor(OnScreenColor);
LogStream->SetOnScreenBackgroundColor(OnScreenBackgroundColor);
LogStream->SetOnScreenSize(OnScreenSize);
LogStream->SetOnScreenDuration(OnScreenDuration);
LogStream->SetLogToDefaultLog(bLogToDefaultLog);
LogStream->SetLogOnScreenOnMaster(bLogOnScreenOnMaster); LogStream->SetLogOnScreenOnMaster(bLogOnScreenOnMaster);
LogStream->SetLogOnScreenOnSlaves(bLogOnScreenOnSlaves); LogStream->SetLogOnScreenOnSlaves(bLogOnScreenOnSlaves);
} }
#include "UniversalLogging.h" #include "UniversalLogging.h"
#include "UniversalLoggingPrivatePCH.h"
#include "LogStream.h" #include "LogStream.h"
#include "GameFramework/PlayerController.h" #include "GameFramework/PlayerController.h"
#include "GameFramework/HUD.h" #include "GameFramework/HUD.h"
#if PLATFORM_WINDOWS || PLATFORM_LINUX
#include "IDisplayCluster.h" #include "IDisplayCluster.h"
#include "Cluster/IDisplayClusterClusterManager.h" #include "Cluster/IDisplayClusterClusterManager.h"
#endif
#if WITH_EDITOR
#include "Editor.h"
#endif
#include "Misc/CommandLine.h" #include "Misc/CommandLine.h"
LogFileManager UniversalLoggingImpl::Log_File_Manager{};
void UniversalLoggingImpl::StartupModule() void UniversalLoggingImpl::StartupModule()
{ {
Streams.Add("", MakeUnique<LogStreamImpl>()); Streams.Add("", MakeUnique<LogStreamImpl>());
On_Post_World_Initialization_Delegate.BindRaw(this, &UniversalLoggingImpl::OnSessionStart); FWorldDelegates::OnPostWorldInitialization.AddRaw(this, &UniversalLoggingImpl::OnWorldStart);
FWorldDelegates::OnPostWorldInitialization.Add(On_Post_World_Initialization_Delegate); FWorldDelegates::OnWorldPostActorTick.AddRaw(this, &UniversalLoggingImpl::OnPostActorTick);
On_Pre_World_Finish_Destroy_Delegate.BindRaw(this, &UniversalLoggingImpl::OnSessionEnd);
FWorldDelegates::OnPreWorldFinishDestroy.Add(On_Pre_World_Finish_Destroy_Delegate);
On_World_Post_Actor_Tick_Delegate.BindRaw(this, &UniversalLoggingImpl::OnPostActorTick); #if WITH_EDITOR
FWorldDelegates::OnWorldPostActorTick.Add(On_World_Post_Actor_Tick_Delegate); FEditorDelegates::BeginPIE.AddRaw(this, &UniversalLoggingImpl::OnSessionStart);
FEditorDelegates::EndPIE.AddRaw(this, &UniversalLoggingImpl::OnSessionEnd);
#endif
Session_ID = ""; Session_ID = "";
} }
...@@ -30,24 +33,32 @@ void UniversalLoggingImpl::ShutdownModule() ...@@ -30,24 +33,32 @@ void UniversalLoggingImpl::ShutdownModule()
{ {
} }
void UniversalLoggingImpl::OnSessionStart(UWorld* World, const UWorld::InitializationValues) void UniversalLoggingImpl::OnWorldStart(UWorld* World, const UWorld::InitializationValues)
{ {
if (!World->IsGameWorld()) if (!World->IsGameWorld())
return; return;
On_Screen_Log_Actor = dynamic_cast<AOnScreenLog*>(World->SpawnActor(AOnScreenLog::StaticClass()));
//only set Session_ID on the first world of this session
if(Session_ID != "")
return;
if (World->IsPlayInEditor()) if (World->IsPlayInEditor())
ResetSessionId("PlayInEditor"); ResetSessionId("PlayInEditor");
else if (World->IsPlayInPreview()) else if (World->IsPlayInPreview())
ResetSessionId("PlayInPreview"); ResetSessionId("PlayInPreview");
else else
ResetSessionId("Play"); ResetSessionId("Play");
}
On_Screen_Log_Actor = dynamic_cast<AOnScreenLog*>(World->SpawnActor(AOnScreenLog::StaticClass())); void UniversalLoggingImpl::OnSessionStart(const bool)
{
Session_ID = "";
} }
void UniversalLoggingImpl::OnSessionEnd(UWorld* World) void UniversalLoggingImpl::OnSessionEnd(const bool)
{ {
if (!World->IsGameWorld())
return;
ResetSessionId("Stopped"); ResetSessionId("Stopped");
for (auto& Elem : Streams) for (auto& Elem : Streams)
...@@ -62,9 +73,12 @@ void UniversalLoggingImpl::OnPostActorTick(UWorld* World, ELevelTick LevelTick, ...@@ -62,9 +73,12 @@ void UniversalLoggingImpl::OnPostActorTick(UWorld* World, ELevelTick LevelTick,
if (!PlayerController) if (!PlayerController)
return; return;
auto HUD = PlayerController->GetHUD(); auto HUD = PlayerController->GetHUD();
if (HUD)
{
HUD->AddPostRenderedActor(On_Screen_Log_Actor); // Doing this every tick seems excessive (AddPostRenderActor checks for duplicates, though) HUD->AddPostRenderedActor(On_Screen_Log_Actor); // Doing this every tick seems excessive (AddPostRenderActor checks for duplicates, though)
HUD->bShowOverlays = true; // Yuck, but necessary as otherwise the Actor's PostRenderFor method is not called. HUD->bShowOverlays = true; // Yuck, but necessary as otherwise the Actor's PostRenderFor method is not called.
} }
}
ILogStream* UniversalLoggingImpl::NewLogStream(const FString StreamName) ILogStream* UniversalLoggingImpl::NewLogStream(const FString StreamName)
{ {
...@@ -122,7 +136,14 @@ void UniversalLoggingImpl::Log(const FString Text, const FString Stream /*= ""*/ ...@@ -122,7 +136,14 @@ void UniversalLoggingImpl::Log(const FString Text, const FString Stream /*= ""*/
if(Stream_OBJ->GetOnScreen() && On_Screen_Log_Actor) if(Stream_OBJ->GetOnScreen() && On_Screen_Log_Actor)
{ {
if ((Stream_OBJ->GetLogOnScreenOnMaster() && IsClusterMaster()) || (Stream_OBJ->GetLogOnScreenOnSlaves() && !IsClusterMaster())) if ((Stream_OBJ->GetLogOnScreenOnMaster() && IsClusterMaster()) || (Stream_OBJ->GetLogOnScreenOnSlaves() && !IsClusterMaster()))
On_Screen_Log_Actor->EnqueueMessage(Full_Text, Stream_OBJ->GetOnScreenColor()); On_Screen_Log_Actor->EnqueueMessage(Full_Text, Stream_OBJ->GetOnScreenColor(),
Stream_OBJ->GetOnScreenBackgroundColor(), Stream_OBJ->GetOnScreenSize(),
Stream_OBJ->GetOnScreenDuration());
}
if(Stream_OBJ->GetLogToDefaultLog())
{
UE_LOG(LogUni, Log, TEXT("[%s] %s"), *Stream, *Full_Text);
} }
} }
...@@ -150,6 +171,7 @@ void UniversalLoggingImpl::ResetSessionId(FString Prefix) ...@@ -150,6 +171,7 @@ void UniversalLoggingImpl::ResetSessionId(FString Prefix)
bool UniversalLoggingImpl::IsClusterMaster() bool UniversalLoggingImpl::IsClusterMaster()
{ {
#if PLATFORM_WINDOWS || PLATFORM_LINUX
if (!IDisplayCluster::IsAvailable()) if (!IDisplayCluster::IsAvailable())
{ {
return true; return true;
...@@ -159,15 +181,27 @@ bool UniversalLoggingImpl::IsClusterMaster() ...@@ -159,15 +181,27 @@ bool UniversalLoggingImpl::IsClusterMaster()
{ {
return true; // if we are not in cluster mode, we are always the master return true; // if we are not in cluster mode, we are always the master
} }
return Manager->IsMaster(); return Manager->IsMaster() || !Manager->IsSlave();
#else
return true;
#endif
} }
FString UniversalLoggingImpl::GetNodeName() FString UniversalLoggingImpl::GetNodeName()
{ {
#if PLATFORM_WINDOWS || PLATFORM_LINUX
if (IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster) if (IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster)
return IDisplayCluster::Get().GetClusterMgr()->GetNodeId(); return IDisplayCluster::Get().GetClusterMgr()->GetNodeId();
else else
return FString(TEXT("Localhost")); return FString(TEXT("Localhost"));
#else
return FString(TEXT("Localhost"));
#endif
}
LogFileManager* UniversalLoggingImpl::GetLogFileManager()
{
return &Log_File_Manager;
} }
IMPLEMENT_MODULE(UniversalLoggingImpl, UniversalLogging) IMPLEMENT_MODULE(UniversalLoggingImpl, UniversalLogging)
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include "LogStream.h" #include "LogStream.h"
#include "OnScreenLog.h" #include "OnScreenLog.h"
#include "IUniversalLogging.h"
#include "LogFileManager.h"
#include "Engine/World.h" #include "Engine/World.h"
...@@ -12,8 +14,9 @@ public: ...@@ -12,8 +14,9 @@ public:
void StartupModule() override; void StartupModule() override;
void ShutdownModule() override; void ShutdownModule() override;
void OnSessionStart(UWorld*, const UWorld::InitializationValues); void OnWorldStart(UWorld*, const UWorld::InitializationValues);
void OnSessionEnd(UWorld*); void OnSessionStart(const bool);
void OnSessionEnd(const bool);
void OnPostActorTick(UWorld*, ELevelTick, float); void OnPostActorTick(UWorld*, ELevelTick, float);
...@@ -31,11 +34,11 @@ public: ...@@ -31,11 +34,11 @@ public:
static bool IsClusterMaster(); static bool IsClusterMaster();
static FString GetNodeName(); static FString GetNodeName();
static LogFileManager* GetLogFileManager();
private: private:
static LogFileManager Log_File_Manager;
TMap<FString, TUniquePtr<LogStreamImpl>> Streams; TMap<FString, TUniquePtr<LogStreamImpl>> Streams;
FString Session_ID; FString Session_ID;
TBaseDelegate<void, UWorld*, const UWorld::InitializationValues> On_Post_World_Initialization_Delegate;
TBaseDelegate<void, UWorld*> On_Pre_World_Finish_Destroy_Delegate;
TBaseDelegate<void, UWorld*, ELevelTick, float> On_World_Post_Actor_Tick_Delegate;
AOnScreenLog* On_Screen_Log_Actor; AOnScreenLog* On_Screen_Log_Actor;
}; };
\ No newline at end of file
...@@ -7,10 +7,22 @@ public: ...@@ -7,10 +7,22 @@ public:
virtual FString GetFilename() = 0; virtual FString GetFilename() = 0;
virtual bool GetIsValid() = 0; virtual bool GetIsValid() = 0;
virtual void SetPrefix(FString Prefix) = 0;
virtual FString GetPrefix() const = 0;
virtual void SetOnScreen(const bool Val) = 0; virtual void SetOnScreen(const bool Val) = 0;
virtual bool GetOnScreen() const = 0; virtual bool GetOnScreen() const = 0;
virtual void SetOnScreenColor(const FColor Color) = 0; virtual void SetOnScreenColor(const FColor Color) = 0;
virtual FColor GetOnScreenColor() const = 0; virtual FColor GetOnScreenColor() const = 0;
virtual void SetOnScreenBackgroundColor(const FColor Color) = 0;
virtual FColor GetOnScreenBackgroundColor() const = 0;
virtual void SetOnScreenSize(const float Scale) = 0;
virtual float GetOnScreenSize() const = 0;
virtual void SetOnScreenDuration(const float Seconds) = 0;
virtual float GetOnScreenDuration() const = 0;
virtual void SetLogToDefaultLog(const bool Val) = 0;
virtual bool GetLogToDefaultLog() const = 0;
virtual bool GetLogOnMaster() const = 0; virtual bool GetLogOnMaster() const = 0;
virtual bool GetLogOnSlaves() const = 0; virtual bool GetLogOnSlaves() const = 0;
......
#pragma once #pragma once
#if PLATFORM_WINDOWS || PLATFORM_LINUX
#include "IDisplayCluster.h" #include "IDisplayCluster.h"
#endif
#include "Modules/ModuleManager.h" #include "Modules/ModuleManager.h"
#include "ILogStream.h" #include "ILogStream.h"
...@@ -72,10 +75,12 @@ public: ...@@ -72,10 +75,12 @@ public:
* Advanced logging with printf like syntax. * Advanced logging with printf like syntax.
* Note: Does not automatically add newline! * Note: Does not automatically add newline!
*/ */
template<typename... TArgs> template<typename FmtType, typename... TArgs>
void LogF(const FString Stream, const FString Format, TArgs&&... Args) void LogF(const FString Stream, const FmtType& Format, TArgs&&... Args)
{ {
const FString Out = FString::Printf(*Format, Args...); static_assert(TIsArrayOrRefOfType<FmtType, TCHAR>::Value, "Format must be a TCHAR string literal, i.e., only ever call this function with TEXT(\"...\") as the second parameter.");
const FString Out = FString::Printf(Format, Args...);
Log(Out, Stream, true); Log(Out, Stream, true);
} }
}; };
......
...@@ -23,13 +23,18 @@ class UUniLogBlueprintFunctionLibrary : public UBlueprintFunctionLibrary ...@@ -23,13 +23,18 @@ class UUniLogBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
static FString GetSessionIdentifier(); static FString GetSessionIdentifier();
UFUNCTION(BlueprintCallable, Category = "UniLog") UFUNCTION(BlueprintCallable, Category = "UniLog")
static void NewLogStream(const FString StreamName, const FString Filepath, const FString Filename, static void NewLogStream(const FString StreamName, const FString Filepath, const FString Filename, FString Prefix,
bool bPer_Session = false, bool bOnScreen = false, bool bPer_Session = false, bool bOnScreen = false,
FColor OnScreenColor = FColor(0, 0, 255, 0), bool bLogOnMaster = true, FColor OnScreenColor = FColor(255, 255, 255, 255),
bool bLogOnSlaves = false, bool bLogOnScreenOnMaster = true, bool bLogOnScreenOnSlaves = false); FColor OnScreenBackgroundColor = FColor(0, 0, 0, 128),
float OnScreenSize = 1.0, float OnScreenDuration = 5.0, bool bLogToDefaultLog = false, bool bLogOnMaster = true,
bool bLogOnSlaves = false, bool bLogOnScreenOnMaster = true,
bool bLogOnScreenOnSlaves = false);
UFUNCTION(BlueprintCallable, Category = "UniLog") UFUNCTION(BlueprintCallable, Category = "UniLog")
static void ModifyLogStream(const FString StreamName, bool bOnScreen = false, static void ModifyLogStream(const FString StreamName, bool bOnScreen = false,
FColor OnScreenColor = FColor(0, 0, 255, 0), bool bLogOnScreenOnMaster = true, FColor OnScreenColor = FColor(255, 255, 255, 255),
FColor OnScreenBackgroundColor = FColor(0, 0, 0, 128), float OnScreenSize = 1.0,
float OnScreenDuration = 5.0, bool bLogToDefaultLog = false, bool bLogOnScreenOnMaster = true,
bool bLogOnScreenOnSlaves = false); bool bLogOnScreenOnSlaves = false);
}; };
...@@ -5,9 +5,24 @@ public class UniversalLogging : ModuleRules ...@@ -5,9 +5,24 @@ public class UniversalLogging : ModuleRules
{ {
public UniversalLogging(ReadOnlyTargetRules Target) : base(Target) public UniversalLogging(ReadOnlyTargetRules Target) : base(Target)
{ {
PrivateIncludePaths.AddRange(new string[] { "UniversalLogging/Private" }); bLegacyPublicIncludePaths = false;
PublicIncludePaths.AddRange(new string[] { "UniversalLogging/Public" });
PublicDependencyModuleNames.AddRange(new string[] { "CoreUObject", "Engine", "Core", "DisplayCluster" }); PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PrivateIncludePaths.AddRange(new string[] { });
PublicIncludePaths.AddRange(new string[] { });
PublicDependencyModuleNames.AddRange(new string[] { "CoreUObject", "Engine", "Core" });
if (Target.Platform == UnrealTargetPlatform.Linux || Target.Platform == UnrealTargetPlatform.Win64)
{
PublicDependencyModuleNames.AddRange(new string[] { "DisplayCluster" });
}
//this is needed to register on Editor delegates, i.e., BeginPIE and EndPIE, but only in Editor builds
if (Target.Type == TargetRules.TargetType.Editor)
{
PrivateDependencyModuleNames.AddRange(new string[] { "UnrealEd" });
}
} }
} }
\ No newline at end of file
...@@ -10,12 +10,21 @@ ...@@ -10,12 +10,21 @@
"CreatedByURL": "https://bird.lol", "CreatedByURL": "https://bird.lol",
"CanContainContent": "true", "CanContainContent": "true",
"Modules" : "Modules": [
[
{ {
"Name": "UniversalLogging", "Name": "UniversalLogging",
"Type": "Runtime", "Type": "Runtime",
"LoadingPhase": "PreDefault" "LoadingPhase": "PreDefault"
} }
],
"Plugins": [
{
"Name": "nDisplay",
"Enabled": true,
"WhitelistPlatforms": [
"Win64",
"Linux"
]
}
] ]
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment