├── .gitignore ├── LICENSE ├── README.md ├── Resources └── Icon128.png ├── SingleTon.uplugin └── Source └── SingleTon ├── Private ├── SingleActor.cpp └── SingleTon.cpp ├── Public ├── SingleActor.h └── SingleTon.h └── SingleTon.Build.cs /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | Intermediate/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 inveta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SingleTon 2 | 基于文件锁实现了UE5程序的单例启动模式,并通过插件的方式,实现了应用层零调用。 3 | 4 | 另外还兼容了,可以开多个程序的需求,通过启动参数传入不同的id实现。 5 | 6 | 示例如下 7 | ``` 8 | -ProjectID=singleton 9 | ``` 10 | 11 | 12 | 详细介绍参考公众号文章: 13 | https://mp.weixin.qq.com/s/_FSu8q2xqlmpSfEKz91bNA 14 | 15 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inveta/SingleTon/00762dd5b796cebc04425a7db452ff3d4be1910c/Resources/Icon128.png -------------------------------------------------------------------------------- /SingleTon.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0.0", 5 | "FriendlyName": "SingleTon", 6 | "Description": "This plugin makes it possible only one instance of your game can be run at the same time", 7 | "Category": "Other", 8 | "CreatedBy": "g0415shenw", 9 | "CanContainContent": false, 10 | "IsBetaVersion": false, 11 | "IsExperimentalVersion": false, 12 | "Installed": false, 13 | "Modules": [ 14 | { 15 | "Name": "SingleTon", 16 | "Type": "Runtime", 17 | "LoadingPhase": "EarliestPossible", 18 | "WhitelistPlatforms": [ 19 | "Win64" 20 | ] 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /Source/SingleTon/Private/SingleActor.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "SingleActor.h" 5 | #include "Misc/CommandLine.h" 6 | #include "Misc/Parse.h" 7 | #include "Kismet/KismetSystemLibrary.h" 8 | #include "HAL/FileManager.h" 9 | #include "Runtime/ApplicationCore/Public/Windows/WindowsPlatformApplicationMisc.h" 10 | 11 | // Sets default values 12 | ASingleActor::ASingleActor() 13 | { 14 | // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 15 | //PrimaryActorTick.bCanEverTick = true; 16 | m_fLock = nullptr; 17 | } 18 | 19 | // Called when the game starts or when spawned 20 | void ASingleActor::BeginPlay() 21 | { 22 | Super::BeginPlay(); 23 | 24 | #if !UE_EDITOR 25 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 26 | UE_LOG(LogTemp, Log, TEXT("CheckAnotherAppInstance enter")); 27 | 28 | auto CmdLine = UKismetSystemLibrary::GetCommandLine(); 29 | UE_LOG(LogTemp, Log, TEXT("%s"), *CmdLine); 30 | 31 | FString ProjectIDParam = "UE5"; 32 | if (true == FParse::Value(FCommandLine::Get(), TEXT("ProjectID="), ProjectIDParam)) 33 | { 34 | UE_LOG(LogTemp, Log, TEXT("ProjectID= %s"), *ProjectIDParam); 35 | } 36 | 37 | // Only one instance of the game can be initialized! 38 | const FString LockFilePath = FPlatformProcess::UserTempDir() + ProjectIDParam; 39 | 40 | UE_LOG(LogTemp, Log, TEXT("LockFilePath= %s"), *LockFilePath); 41 | 42 | m_fLock = IFileManager::Get().CreateFileWriter(*LockFilePath, 0); 43 | if (!m_fLock) 44 | { 45 | UE_LOG(LogTemp, Log, TEXT("CheckAnotherAppInstance RequestExit")); 46 | FPlatformApplicationMisc::RequestMinimize(); 47 | FPlatformMisc::RequestExit(0); 48 | } 49 | #endif 50 | } 51 | 52 | void ASingleActor::EndPlay(const EEndPlayReason::Type EndPlayReason) 53 | { 54 | #if !UE_EDITOR 55 | if (nullptr != m_fLock) 56 | { 57 | m_fLock->Close(); 58 | } 59 | #endif 60 | Super::EndPlay(EndPlayReason); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /Source/SingleTon/Private/SingleTon.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Andrew Bindraw. All Rights Reserved. 2 | 3 | #include "SingleTon.h" 4 | 5 | 6 | #define LOCTEXT_NAMESPACE "FSingleTonModule" 7 | 8 | void FSingleTonModule::StartupModule() 9 | { 10 | 11 | } 12 | 13 | void FSingleTonModule::ShutdownModule() 14 | { 15 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 16 | // we call this function before unloading the module. 17 | } 18 | 19 | #undef LOCTEXT_NAMESPACE 20 | 21 | IMPLEMENT_MODULE(FSingleTonModule, SingleTon) -------------------------------------------------------------------------------- /Source/SingleTon/Public/SingleActor.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/Actor.h" 7 | #include "SingleActor.generated.h" 8 | 9 | UCLASS() 10 | class SINGLETON_API ASingleActor : public AActor 11 | { 12 | GENERATED_BODY() 13 | 14 | public: 15 | // Sets default values for this actor's properties 16 | ASingleActor(); 17 | 18 | protected: 19 | // Called when the game starts or when spawned 20 | virtual void BeginPlay() override; 21 | virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; 22 | 23 | FArchive* m_fLock; 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /Source/SingleTon/Public/SingleTon.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Andrew Bindraw. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "Modules/ModuleManager.h" 6 | 7 | class FSingleTonModule : public IModuleInterface 8 | { 9 | public: 10 | /** IModuleInterface implementation */ 11 | virtual void StartupModule() override; 12 | virtual void ShutdownModule() override; 13 | }; 14 | -------------------------------------------------------------------------------- /Source/SingleTon/SingleTon.Build.cs: -------------------------------------------------------------------------------- 1 | // Some copyright should be here... 2 | 3 | using UnrealBuildTool; 4 | 5 | public class SingleTon : ModuleRules 6 | { 7 | public SingleTon(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | // ... add other public dependencies that you statically link with here ... 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "Slate", 40 | "SlateCore", 41 | "EngineSettings", 42 | "ApplicationCore", 43 | // ... add private dependencies that you statically link with here ... 44 | } 45 | ); 46 | 47 | 48 | DynamicallyLoadedModuleNames.AddRange( 49 | new string[] 50 | { 51 | // ... add any modules that your module loads dynamically here ... 52 | } 53 | ); 54 | } 55 | } 56 | --------------------------------------------------------------------------------