removed unused methods(BeginPlay, Tick) and added rider plugin

This commit is contained in:
Caleb Buhungiro
2025-07-05 15:04:21 +08:00
parent a98fd4b2a7
commit 58a7fc2f55
416 changed files with 64917 additions and 16 deletions

View File

@@ -0,0 +1,142 @@
#include "RiderLogging.hpp"
#include "BlueprintProvider.hpp"
#include "IRiderLink.hpp"
#include "Model/Library/UE4Library/LogMessageInfo.Pregenerated.h"
#include "Model/Library/UE4Library/StringRange.Pregenerated.h"
#include "Model/Library/UE4Library/UnrealLogEvent.Pregenerated.h"
#include "Internationalization/Regex.h"
#include "Misc/DateTime.h"
#include "Modules/ModuleManager.h"
#define LOCTEXT_NAMESPACE "RiderLogging"
DEFINE_LOG_CATEGORY(FLogRiderLoggingModule);
IMPLEMENT_MODULE(FRiderLoggingModule, RiderLogging);
namespace LoggingExtensionImpl
{
static TArray<rd::Wrapper<JetBrains::EditorPlugin::StringRange>> GetPathRanges(
const FRegexPattern& Pattern,
const FString& Str)
{
using JetBrains::EditorPlugin::StringRange;
FRegexMatcher Matcher(Pattern, Str);
TArray<rd::Wrapper<StringRange>> Ranges;
while (Matcher.FindNext())
{
const int Start = Matcher.GetMatchBeginning();
const int End = Matcher.GetMatchEnding();
FString PathName = Str.Mid(Start, End - Start);
if (BluePrintProvider::IsBlueprint(PathName))
Ranges.Emplace(StringRange(Start, End));
}
return Ranges;
}
static TArray<rd::Wrapper<JetBrains::EditorPlugin::StringRange>> GetMethodRanges(
const FRegexPattern& Pattern,
const FString& Str)
{
using JetBrains::EditorPlugin::StringRange;
FRegexMatcher Matcher(Pattern, Str);
TArray<rd::Wrapper<StringRange>> Ranges;
while (Matcher.FindNext())
{
Ranges.Emplace(StringRange(Matcher.GetMatchBeginning(), Matcher.GetMatchEnding()));
}
return Ranges;
}
static bool SendMessageToRider(const JetBrains::EditorPlugin::LogMessageInfo& MessageInfo, const FString& Message)
{
static const FRegexPattern PathPattern = FRegexPattern(TEXT("(/[\\w\\.]+)+"));
static const FRegexPattern MethodPattern = FRegexPattern(TEXT("[0-9a-z_A-Z]+::~?[0-9a-z_A-Z]+"));
return IRiderLinkModule::Get().FireAsyncAction(
[&MessageInfo, &Message] (JetBrains::EditorPlugin::RdEditorModel const& RdEditorModel)
{
rd::ISignal<JetBrains::EditorPlugin::UnrealLogEvent> const& UnrealLog = RdEditorModel.get_unrealLog();
UnrealLog.fire({
MessageInfo,
Message,
GetPathRanges(PathPattern, Message),
GetMethodRanges(MethodPattern, Message)
});
});
}
void SendMessageInChunks(FString* Msg, const JetBrains::EditorPlugin::LogMessageInfo& MessageInfo)
{
static int NUMBER_OF_CHUNKS = 1024;
while (!Msg->IsEmpty())
{
SendMessageToRider(MessageInfo, Msg->Left(NUMBER_OF_CHUNKS));
*Msg = Msg->RightChop(NUMBER_OF_CHUNKS);
}
}
void ScheduledSendMessage(FString* Msg, const JetBrains::EditorPlugin::LogMessageInfo& MessageInfo)
{
FString ToSend;
while (Msg->Split("\n", &ToSend, Msg))
{
SendMessageInChunks(&ToSend, MessageInfo);
}
SendMessageInChunks(Msg, MessageInfo);
}
}
void FRiderLoggingModule::StartupModule()
{
UE_LOG(FLogRiderLoggingModule, Verbose, TEXT("STARTUP START"));
static const auto START_TIME = FDateTime::UtcNow().ToUnixTimestamp();
static const auto GetTimeNow = [](double Time) -> rd::DateTime
{
return rd::DateTime(START_TIME + static_cast<int64>(Time));
};
ModuleLifetimeDef = IRiderLinkModule::Get().CreateNestedLifetimeDefinition();
LoggingScheduler = MakeUnique<rd::SingleThreadScheduler>(ModuleLifetimeDef.lifetime, "LoggingScheduler");
ModuleLifetimeDef.lifetime->bracket(
[this]()
{
OutputDevice.Setup([this](const TCHAR* msg, ELogVerbosity::Type Type, const FName& Name, TOptional<double> Time)
{
if (Type > ELogVerbosity::All) return;
rd::optional<rd::DateTime> DateTime;
if (Time)
{
DateTime = GetTimeNow(Time.GetValue());
}
const FString PlainName = Name.GetPlainNameString();
const JetBrains::EditorPlugin::LogMessageInfo MessageInfo{Type, PlainName, DateTime};
LoggingScheduler->queue([Msg = FString(msg), MessageInfo]() mutable
{
LoggingExtensionImpl::ScheduledSendMessage(&Msg, MessageInfo);
});
});
},
[this]()
{
OutputDevice.TearDown();
});
UE_LOG(FLogRiderLoggingModule, Verbose, TEXT("STARTUP FINISH"));
}
void FRiderLoggingModule::ShutdownModule()
{
UE_LOG(FLogRiderLoggingModule, Verbose, TEXT("SHUTDOWN START"));
ModuleLifetimeDef.terminate();
UE_LOG(FLogRiderLoggingModule, Verbose, TEXT("SHUTDOWN FINISH"));
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,31 @@
#pragma once
#include "RiderOutputDevice.hpp"
#include "Templates/UniquePtr.h"
#include "lifetime/LifetimeDefinition.h"
#include "Logging/LogMacros.h"
#include "Logging/LogVerbosity.h"
#include "Modules/ModuleInterface.h"
#include "scheduler/SingleThreadScheduler.h"
DECLARE_LOG_CATEGORY_EXTERN(FLogRiderLoggingModule, Log, All);
class FRiderLoggingModule : public IModuleInterface
{
public:
FRiderLoggingModule() = default;
virtual ~FRiderLoggingModule() override = default;
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual bool SupportsDynamicReloading() override { return true; }
private:
TUniquePtr<rd::SingleThreadScheduler> LoggingScheduler;
FRiderOutputDevice OutputDevice;
rd::LifetimeDefinition ModuleLifetimeDef;
};

View File

@@ -0,0 +1,51 @@
#include "RiderOutputDevice.hpp"
#include "CoreGlobals.h"
#include "Misc/ScopeLock.h"
#include "Misc/OutputDeviceRedirector.h"
void FRiderOutputDevice::Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category)
{
Serialize(V, Verbosity, Category, {});
}
void FRiderOutputDevice::Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category,
const double Time)
{
FScopeLock Lock{&CriticalSection};
onSerializeMessage.ExecuteIfBound(V, Verbosity, Category, {Time});
}
FRiderOutputDevice::~FRiderOutputDevice()
{
// At shutdown, GLog may already be null
// This should be out of scoped lock, because it'll implicitly try take a lock in OutputDeviceRedirector
// And Serialize is already holding that lock, so we'll have a deadlock here
if (GLog != nullptr)
{
GLog->RemoveOutputDevice(this);
}
}
void FRiderOutputDevice::Setup(TFunction<FOnSerializeMessage::TFuncType> Callback)
{
FScopeLock Lock{&CriticalSection};
if(onSerializeMessage.IsBound()) return;
onSerializeMessage.BindLambda(Callback);
GLog->AddOutputDevice(this);
#if ENGINE_MAJOR_VERSION < 5 || (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 7)
GLog->SerializeBacklog(this);
#endif
}
void FRiderOutputDevice::TearDown()
{
FScopeLock Lock{&CriticalSection};
if(onSerializeMessage.IsBound() == false) return;
onSerializeMessage.Unbind();
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "Misc/OutputDevice.h"
#include "Delegates/Delegate.h"
#include "Logging/LogVerbosity.h"
#include "Runtime/Launch/Resources/Version.h"
using FOnSerializeMessage =
#if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION < 26
TBaseDelegate<void, const TCHAR*, ELogVerbosity::Type, const FName&, TOptional<double>>;
#elif ENGINE_MAJOR_VERSION < 5 || (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION < 3)
TDelegate<void(const TCHAR*, ELogVerbosity::Type, const FName&, TOptional<double>)>;
#else
TDelegate<void(const TCHAR*, ELogVerbosity::Type, const FName&, TOptional<double>), FDefaultTSDelegateUserPolicy>;
#endif
class FRiderOutputDevice : public FOutputDevice {
public:
~FRiderOutputDevice();
void Setup(TFunction<FOnSerializeMessage::TFuncType>);
virtual void TearDown() override;
protected:
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override;
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category, double Time) override;
private:
FOnSerializeMessage onSerializeMessage;
FCriticalSection CriticalSection;
};

View File

@@ -0,0 +1,36 @@
using UnrealBuildTool;
public class RiderLogging : ModuleRules
{
public RiderLogging(ReadOnlyTargetRules Target) : base(Target)
{
#if UE_4_22_OR_LATER
PCHUsage = PCHUsageMode.NoPCHs;
#else
PCHUsage = PCHUsageMode.NoSharedPCHs;
#endif
#if UE_5_2_OR_LATER
if(Target.Platform == UnrealTargetPlatform.Linux || Target.Platform == UnrealTargetPlatform.Mac)
{
bUseRTTI = false;
}
else
#endif
{
bUseRTTI = true;
}
#if UE_5_2_OR_LATER
bDisableStaticAnalysis = true;
#endif
PrivateDependencyModuleNames.AddRange(new []
{
"Core",
"RD",
"RiderLink",
"RiderBlueprint"
});
}
}