diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3ee46f6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,30 @@ +[attr]lock filter=lfs diff=lfs merge=binary -text lockable +[attr]lockonly lockable +[attr]lfs filter=lfs diff=lfs merge=binary -text +[attr]lfstext filter=lfs diff=lfstext merge=lfstext -text +# Unreal Engine file types. +*.uasset lock +*.umap lock +*.locres lfs +*.locmeta lfs +# Steam Audio files +*.phononscene lfs +*.probebox lfs +*.probebatch lfs +*.bakedsources lfs +# Binaries +*.exe lfs +*.dll lfs +*.rcc lfs +# FMOD +*.bank lfs +*.wav lfs +*.mp3 lfs +*.ogg lfs +*.flac lfs +# Icons +*.png lfs +*.ico lfs +*.icns lfs +# Movies +*.bk2 lfs diff --git a/Pawn_Unreal/.gitignore b/Pawn_Unreal/.gitignore new file mode 100644 index 0000000..513c6da --- /dev/null +++ b/Pawn_Unreal/.gitignore @@ -0,0 +1,96 @@ +# Created by https://www.toptal.com/developers/gitignore/api/unrealengine +# Edit at https://www.toptal.com/developers/gitignore?templates=unrealengine + +### UnrealEngine ### +# Visual Studio 2015 user specific files +.vs/ + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*.ipa + +# These project files can be generated by the engine +*.xcodeproj +*.xcworkspace +*.sln +*.suo +*.opensdf +*.sdf +*.VC.db +*.VC.opendb + +# Precompiled Assets +SourceArt/**/*.png +SourceArt/**/*.tga + +# Binary Files +Binaries/* +Plugins/*/Binaries/* + +# Builds +Build/* + +# Whitelist PakBlacklist-.txt files +!Build/*/ +Build/*/** +!Build/*/PakBlacklist*.txt + +# Don't ignore icon files in Build +!Build/**/*.ico + +# Built data for maps +*_BuiltData.uasset + +# Configuration files generated by the Editor +Saved/* + +# Compiled source files for the engine to use +Intermediate/* +Plugins/*/Intermediate/* + +# Cache files for the editor to use +DerivedDataCache/* + +### UnrealEngine Patch ### +# Don't ignore icon and splash images for mobile app +!Build/IOS/Resources/ +Build/IOS/Resources/* +!Build/IOS/Resources/Graphics/ +Build/IOS/Resources/Graphics/* +!Build/IOS/Resources/Graphics/*.png +!Build/Android/res/ +Build/Android/res/* +!Build/Android/res/*/ +Build/Android/res/*/* +!Build/Android/res/*/*.png +# Ignore plugins binaries on deep subfolders +Plugins/**/Binaries/* +Plugins/**/Intermediate/* + +# End of https://www.toptal.com/developers/gitignore/api/unrealengine \ No newline at end of file diff --git a/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/.gitignore b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/.gitignore new file mode 100644 index 0000000..5937d94 --- /dev/null +++ b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.Pawn_Unreal.iml +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/encodings.xml b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/indexLayout.xml b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/vcs.xml b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/Pawn_Unreal/.idea/.idea.Pawn_Unreal/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Pawn_Unreal/Config/DefaultEditor.ini b/Pawn_Unreal/Config/DefaultEditor.ini new file mode 100644 index 0000000..4ecb6eb --- /dev/null +++ b/Pawn_Unreal/Config/DefaultEditor.ini @@ -0,0 +1,8 @@ +[UnrealEd.SimpleMap] +SimpleMapName=/Game/TP_ThirdPerson/Maps/ThirdPersonExampleMap + +[EditoronlyBP] +bAllowClassAndBlueprintPinMatching=true +bReplaceBlueprintWithClass= true +bDontLoadBlueprintOutsideEditor= true +bBlueprintIsNotBlueprintType= true \ No newline at end of file diff --git a/Pawn_Unreal/Config/DefaultEditorPerProjectUserSettings.ini b/Pawn_Unreal/Config/DefaultEditorPerProjectUserSettings.ini new file mode 100644 index 0000000..d3d6cc0 --- /dev/null +++ b/Pawn_Unreal/Config/DefaultEditorPerProjectUserSettings.ini @@ -0,0 +1,2 @@ +[ContentBrowser] +ContentBrowserTab1.SelectedPaths=/Game/ThirdPersonBP \ No newline at end of file diff --git a/Pawn_Unreal/Config/DefaultEngine.ini b/Pawn_Unreal/Config/DefaultEngine.ini new file mode 100644 index 0000000..2a0a7be --- /dev/null +++ b/Pawn_Unreal/Config/DefaultEngine.ini @@ -0,0 +1,26 @@ +[URL] +GameName=Pawn_Unreal + +[/Script/EngineSettings.GameMapsSettings] +EditorStartupMap=/Game/ThirdPersonBP/Maps/ThirdPersonExampleMap +GameDefaultMap=/Game/ThirdPersonBP/Maps/ThirdPersonExampleMap +TransitionMap= +bUseSplitscreen=True +TwoPlayerSplitscreenLayout=Horizontal +ThreePlayerSplitscreenLayout=FavorTop +GlobalDefaultGameMode=/Game/ThirdPersonBP/Blueprints/ThirdPersonGameMode.ThirdPersonGameMode_C +GlobalDefaultServerGameMode=None + +[/Script/IOSRuntimeSettings.IOSRuntimeSettings] +MinimumiOSVersion=IOS_12 + +[/Script/HardwareTargeting.HardwareTargetingSettings] +TargetedHardwareClass=Desktop +AppliedTargetedHardwareClass=Desktop +DefaultGraphicsPerformance=Maximum +AppliedDefaultGraphicsPerformance=Maximum + +[/Script/Engine.Engine] ++ActiveGameNameRedirects=(OldGameName="TP_ThirdPersonBP",NewGameName="/Script/Pawn_Unreal") ++ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPersonBP",NewGameName="/Script/Pawn_Unreal") + diff --git a/Pawn_Unreal/Config/DefaultGame.ini b/Pawn_Unreal/Config/DefaultGame.ini new file mode 100644 index 0000000..6eeb526 --- /dev/null +++ b/Pawn_Unreal/Config/DefaultGame.ini @@ -0,0 +1,7 @@ +[/Script/EngineSettings.GeneralProjectSettings] +ProjectID=B0B7992A413759BDE97DC3BB5AD26D25 +ProjectName=Third Person BP Game Template + +[StartupActions] +bAddPacks=True +InsertPack=(PackSource="StarterContent.upack",PackName="StarterContent") diff --git a/Pawn_Unreal/Config/DefaultInput.ini b/Pawn_Unreal/Config/DefaultInput.ini new file mode 100644 index 0000000..202fad6 --- /dev/null +++ b/Pawn_Unreal/Config/DefaultInput.ini @@ -0,0 +1,169 @@ + +[/Script/Engine.InputSettings] ++AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Touch",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) ++AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) +bAltEnterTogglesFullscreen=True +bF11TogglesFullscreen=True +bUseMouseForTouch=False +bEnableMouseSmoothing=True +bEnableFOVScaling=True +bCaptureMouseOnLaunch=True +bAlwaysShowTouchInterface=False +bShowConsoleOnFourFingerTap=True +bEnableGestureRecognizer=False +bUseAutocorrect=False +DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown +DefaultViewportMouseLockMode=LockOnCapture +FOVScale=0.011110 +DoubleClickTime=0.200000 ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Bottom) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Daydream_Left_Select_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Daydream_Left_Trackpad_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Left_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Right_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Right_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusGo_Left_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Left_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Right_Trigger_Click) ++ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MagicLeap_Left_Trigger) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Left_Grip_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Thumbstick_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusGo_Left_Trackpad_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Thumbstick_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Left_Thumbstick_Click) ++ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MagicLeap_Left_Bumper) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=W) ++AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=S) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Up) ++AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=Down) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Gamepad_LeftY) ++AxisMappings=(AxisName="MoveRight",Scale=-1.000000,Key=A) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Gamepad_LeftX) ++AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Gamepad_RightX) ++AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Left) ++AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Right) ++AxisMappings=(AxisName="Turn",Scale=1.000000,Key=MouseX) ++AxisMappings=(AxisName="LookUpRate",Scale=1.000000,Key=Gamepad_RightY) ++AxisMappings=(AxisName="LookUp",Scale=-1.000000,Key=MouseY) ++AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Vive_Right_Trackpad_X) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Daydream_Left_Trackpad_Y) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Vive_Left_Trackpad_Y) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Daydream_Left_Trackpad_X) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Vive_Left_Trackpad_X) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=MixedReality_Left_Thumbstick_X) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=OculusGo_Left_Trackpad_X) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=MixedReality_Left_Thumbstick_Y) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=OculusGo_Left_Trackpad_Y) ++AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=MixedReality_Right_Thumbstick_X) ++AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=OculusTouch_Right_Thumbstick_X) ++AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=ValveIndex_Right_Thumbstick_X) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=OculusTouch_Left_Thumbstick_Y) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=ValveIndex_Left_Thumbstick_Y) ++AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=MagicLeap_Left_Trackpad_Y) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=OculusTouch_Left_Thumbstick_X) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=ValveIndex_Left_Thumbstick_X) ++AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=MagicLeap_Left_Trackpad_X) +DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks ++ConsoleKeys=Tilde + + diff --git a/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube.uasset b/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube.uasset new file mode 100644 index 0000000..5919b81 --- /dev/null +++ b/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:349245bef4ee3ebbf1922aabdaf5a098a7f26f0625d48f3dfcaeb3bb2e650415 +size 74831 diff --git a/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube_Chamfer.uasset b/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube_Chamfer.uasset new file mode 100644 index 0000000..6d0f85f --- /dev/null +++ b/Pawn_Unreal/Content/Geometry/Meshes/1M_Cube_Chamfer.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e1b503aeb4bfb06c23f1291e529b4a3732d3893981bb6882bb60e48dc39ddd9 +size 107373 diff --git a/Pawn_Unreal/Content/Geometry/Meshes/CubeMaterial.uasset b/Pawn_Unreal/Content/Geometry/Meshes/CubeMaterial.uasset new file mode 100644 index 0000000..2e7a612 --- /dev/null +++ b/Pawn_Unreal/Content/Geometry/Meshes/CubeMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee28745e598a38998c78a3b8a1206fcc25967fc786f35b273682bcd26a087be6 +size 92524 diff --git a/Pawn_Unreal/Content/Geometry/Meshes/TemplateFloor.uasset b/Pawn_Unreal/Content/Geometry/Meshes/TemplateFloor.uasset new file mode 100644 index 0000000..38de739 --- /dev/null +++ b/Pawn_Unreal/Content/Geometry/Meshes/TemplateFloor.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:51aa7e4e6709c59e5bf9e0128df1c285f982c691b00b0f9b20385fc47ba35132 +size 96163 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonIdle.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonIdle.uasset new file mode 100644 index 0000000..3beafd2 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonIdle.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6118dd94e0bfa1c590f6b4fe8a5c3419a040d0097cb4ddbc6a0b8e482d811cb +size 168253 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_End.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_End.uasset new file mode 100644 index 0000000..c1e766d --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_End.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce0680beedf719cd4e10bb2cb6d6ad5bdbfb5d19dce4884573687fe6720b36e9 +size 114597 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Loop.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Loop.uasset new file mode 100644 index 0000000..b20fd97 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Loop.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d1c856577cc7bbb07922289e50410071989479234b98ec0530a57078d95b71a +size 125105 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Start.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Start.uasset new file mode 100644 index 0000000..652d294 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonJump_Start.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b80a7be930243413616e39f2515290be4623b092c7d5f3e67217671d2e46ab5 +size 119538 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonRun.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonRun.uasset new file mode 100644 index 0000000..27b9a35 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonRun.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca0b5e1ae4917450af52a6a518122bb5dc4aa778647c536d5c9ae238f9d5e37d +size 123042 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonWalk.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonWalk.uasset new file mode 100644 index 0000000..d495e7d --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPersonWalk.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e2a7a476cddda072ad184332cede5298777616a91d2f234e0b89b2da3a465b4 +size 136368 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_AnimBP.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_AnimBP.uasset new file mode 100644 index 0000000..1dc4037 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_AnimBP.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c814834b6f1e879705df8faf705a550206a473cb4229dbacd10673853a971ff +size 385816 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_IdleRun_2D.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_IdleRun_2D.uasset new file mode 100644 index 0000000..3fa4222 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_IdleRun_2D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:654d7c5f1565f34e9cc34d4c253ac75fe65d255764be9e148e7d1ec00d706547 +size 88481 diff --git a/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_Jump.uasset b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_Jump.uasset new file mode 100644 index 0000000..13b2db2 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Animations/ThirdPerson_Jump.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b77b886f8b6fd558038410306f7c2e44266a92ee6121edadfe02b371759f9ac6 +size 114710 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MI_Female_Body.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MI_Female_Body.uasset new file mode 100644 index 0000000..11d919c --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MI_Female_Body.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13207149c13d6dd7b26cfd3b598e70aa7bd4d55e589c027f462d26e756915cf1 +size 111411 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/M_Male_Body.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/M_Male_Body.uasset new file mode 100644 index 0000000..1661231 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/M_Male_Body.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a94773796b91ef59427d40239016d4f41e9c56ce5d775c0c0633fe08a28ff8a +size 136371 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset new file mode 100644 index 0000000..f788943 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/M_UE4Man_ChestLogo.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4dca3ab96339bd2289f2fac12c53caa35506b308274c84bfdc7f2c7ff733324d +size 86137 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset new file mode 100644 index 0000000..f60e7e1 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_GlossyBlack_Latex_UE4.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8b2e6239a56f62edba83a122cfac313e1c108c6945c1eae8e13895541e629b6 +size 88520 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset new file mode 100644 index 0000000..25e0ba9 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:beb8f7d7b9170fc778263ead685cd5eb2c0585873930f8cf825232db465d753c +size 100833 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset new file mode 100644 index 0000000..40d33cf --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_Plastic_Shiny_Beige_LOGO.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1731520aa83e01757d33d9a26e1c0098ca0f9a59abac64256805a5c3c485747b +size 88820 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset new file mode 100644 index 0000000..16ce5fe --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/ML_SoftMetal_UE4.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42b18c5b4817111ea7445b031314ee21b47d9159e94f31356f96b894c47d82c9 +size 89102 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset new file mode 100644 index 0000000..7a90db2 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:20636a582c2eef0621ebfae0389c1ea2a05f2a135eb9ddccd052c5ee9cb8a73f +size 456908 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset new file mode 100644 index 0000000..a403edf --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7f76c15dd847b8ab35a3d4044faea7e3b83f49a47a1ee6337b15687a8caebdc +size 472485 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset new file mode 100644 index 0000000..298ab79 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be54e07b8338e29241e7b2be2192541cf11bab5bcdb51a19e6ff45b51556604 +size 501625 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset new file mode 100644 index 0000000..3964d38 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9789904cb8ff7c5400a6d85f5c178bfc24a6424bb8e17ca3606df55239c73a89 +size 428303 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin.uasset b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin.uasset new file mode 100644 index 0000000..cf5502e --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1cf46f513d1a3f4a82ecd23aa846e34b9becb35923b3b5d6c655a3c0b1215a4 +size 5666619 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female.uasset b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female.uasset new file mode 100644 index 0000000..18254be --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a5bc1027e05ae89910d9dda961582e885fbd03bbb1b99ed3221c577db83151f +size 6833677 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female_PhysicsAsset.uasset b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female_PhysicsAsset.uasset new file mode 100644 index 0000000..d2e908b --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_Female_PhysicsAsset.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:502ebecb2d63961ff005a001485a3d946d06f9f4849a51b14ff010c0a0c50d37 +size 114445 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_PhysicsAsset.uasset b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_PhysicsAsset.uasset new file mode 100644 index 0000000..7bdc1d1 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Mesh/SK_Mannequin_PhysicsAsset.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fba8d20d98c42c2faead5842d5fe0d7a5d1c9e8a27012e1994a65837d430e673 +size 26016 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset b/Pawn_Unreal/Content/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset new file mode 100644 index 0000000..222e003 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Mesh/UE4_Mannequin_Skeleton.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4011542c4c068b62f1367ca55066cf63d226bac7754da032dc5c47aaa1f0259 +size 21568 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_Mask.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_Mask.uasset new file mode 100644 index 0000000..0532d0f --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_Mask.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7dcc057762665b4270373963afebb70076b34e67607acc696209bde7a3eaffea +size 260846 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_N.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_N.uasset new file mode 100644 index 0000000..5b6cdc5 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Female_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d96c198ce224253d5347a99bac4850b80a661e567c469b721f6248758509140 +size 18480682 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_Mask.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_Mask.uasset new file mode 100644 index 0000000..cba4767 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_Mask.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1dafab33ae84d6a64bb24a8d40502625dfa738c9f5bec8e370aea0659a77321a +size 270617 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_N.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_N.uasset new file mode 100644 index 0000000..c652a08 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_Male_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4cf1aa1e1585df26c19a6674655b1ccb4b22757bb3ca7e4aaa2789e97ce1e8c +size 5481844 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_Mask.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_Mask.uasset new file mode 100644 index 0000000..470d7a5 --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_Mask.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:694abd54c26eb78ae228c35a39f3dee497eb9935d55b7d5ba8450a6eac56392f +size 96026 diff --git a/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_N.uasset b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_N.uasset new file mode 100644 index 0000000..714245d --- /dev/null +++ b/Pawn_Unreal/Content/Mannequin/Character/Textures/T_UE4Logo_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:59489d0e8fd2b5163776e5d4eff067d5eb718fd6f46d25831f449a13dd74c874 +size 144758 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Floor_400x400.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Floor_400x400.uasset new file mode 100644 index 0000000..702407a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Floor_400x400.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1ba77d634f594dc1bcfa2ff571ab0040d18074efb56698a90c70d09fb7c1a59 +size 87803 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Pillar_50x500.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Pillar_50x500.uasset new file mode 100644 index 0000000..5b2ce28 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Pillar_50x500.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c4d85be6cad305d2cdc7dcb7af8cb5098df903da6fa50da443084c9a5ecb648 +size 65452 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/SM_AssetPlatform.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/SM_AssetPlatform.uasset new file mode 100644 index 0000000..7d1b0db --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/SM_AssetPlatform.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ab571e8bab1be7c4ae4ec038151f5ad6330f93446e25ce40615d5a586686412 +size 452977 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x200.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x200.uasset new file mode 100644 index 0000000..7c96b16 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x200.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:629b8725214e505785b18e5645308f49f3f0fac9d5bf0d2fd0230966a1726f8a +size 42169 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x300.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x300.uasset new file mode 100644 index 0000000..482aad2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x300.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:355ab5f0e043a5ead3afbf1e225b3caa24087a5ecfe903fac2a89eccb9e00ce1 +size 41804 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x400.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x400.uasset new file mode 100644 index 0000000..3ec2814 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_400x400.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01321d9304a60b831b470196f200846eb9430f410960fff89586b3ea24c6734d +size 43426 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_500x500.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_500x500.uasset new file mode 100644 index 0000000..ae44d09 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_500x500.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3352393fee50e0b9700c5387c52f65ea265f6abd2f9700fd678deb1514912bae +size 57909 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x300.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x300.uasset new file mode 100644 index 0000000..1bbe1e6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x300.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26f30eb5adeddd7afb0917c48229bd1ef728a0d6cc1d0f60ed883eb6320ab987 +size 52430 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x400.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x400.uasset new file mode 100644 index 0000000..c2459c9 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Door_400x400.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4136d98e3ecd935eb5f2ab6091b6a37906c9fb18642f15b3504c3af9354fe66c +size 53246 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x300.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x300.uasset new file mode 100644 index 0000000..10e92cd --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x300.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9dcac8d733c2a85995617772faf92e5a670cac878e7c3364be08bfb2a456731 +size 53709 diff --git a/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x400.uasset b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x400.uasset new file mode 100644 index 0000000..759ed3a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Architecture/Wall_Window_400x400.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec78a6dfeb0aed640660c22734930c78e37d3c805c558d143863a75a6841ba0c +size 54778 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Collapse01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Collapse01.uasset new file mode 100644 index 0000000..5e3ff30 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Collapse01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85c827023ee4b466228ec65e92b4b4a0415a106de041ac1c2cab481a2a5dfa8d +size 348532 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Collapse02.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Collapse02.uasset new file mode 100644 index 0000000..f45a091 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Collapse02.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5690c3cdc857ea7d3ae21ed1c6a22e82bb15e8bb24b995228af244c2bb4f0d3 +size 346701 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Collapse_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Collapse_Cue.uasset new file mode 100644 index 0000000..81e69e1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Collapse_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bbd215bbb20c2a86f7b9ba4d90aa1870edd1999e00b5ff64a52a657a50a690b +size 6517 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Explosion01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Explosion01.uasset new file mode 100644 index 0000000..5a0119b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Explosion01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16c3e6decfc990f2bc468b309a9652d7eb98d4481fbd26563ff88139052ace5c +size 282440 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Explosion02.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Explosion02.uasset new file mode 100644 index 0000000..dfdedf4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Explosion02.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d44ed6a6a3a6dec3a4ec729cc4b5ecd3ac4477ca4c9f32107b357ea02dafcddc +size 289195 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Explosion_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Explosion_Cue.uasset new file mode 100644 index 0000000..a67301e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Explosion_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91b66cedcfeedcaa25d7b2afe79c3dfb636e625f626fb56ce9b410fc6495ef3b +size 8088 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Fire01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Fire01.uasset new file mode 100644 index 0000000..67eb428 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Fire01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2a6926e93f33107f58a79edd09d5a4ed06196b797f5fc284efc35fbe2df073d +size 549696 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Fire01_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Fire01_Cue.uasset new file mode 100644 index 0000000..b723ef5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Fire01_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3c93dca255ffe4fcd045103b0cf1341adda3640b47a5656c82ef6236639a51c +size 4280 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01.uasset new file mode 100644 index 0000000..8159b34 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad12649c70f5ef2acd9c19835c59855aaecd4c946260bf6aee182d3fe317d0f2 +size 796274 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01_Cue.uasset new file mode 100644 index 0000000..693d437 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Fire_Sparks01_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c13448535c552552c0216aa5a9d5af5957d4606153a004cdcec934ea5e9a22b +size 4299 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Light01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Light01.uasset new file mode 100644 index 0000000..dcb7c70 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Light01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:267cbc3d508a60edd5aaa8efe0d62e0097c9741782a57fab3d63ffda96314586 +size 364532 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Light01_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Light01_Cue.uasset new file mode 100644 index 0000000..24a1775 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Light01_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc123926fc005aceaa148edfc4cf3778e694a8c17e1e359448377462d4a63d95 +size 4237 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Light02.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Light02.uasset new file mode 100644 index 0000000..55b3882 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Light02.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4ac34417b5db1bf38044e258066d93415e7439dbfec09465c70eb3b96e9a201 +size 308156 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Light02_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Light02_Cue.uasset new file mode 100644 index 0000000..da4e413 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Light02_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c65561c4b6d3767df9e90d24684abfb9fd7b8f980c1a812e329d319b15ab1c87 +size 4237 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Smoke01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Smoke01.uasset new file mode 100644 index 0000000..97d92a1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Smoke01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9d9cdaab035abab672f71362fe0710533dac23e0c4b4f7fc0f48fa1dd613758 +size 476002 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Smoke01_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Smoke01_Cue.uasset new file mode 100644 index 0000000..d0d0bbf --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Smoke01_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97a08e7214107b0f39835ba844b7dcbc69b6613b3573de87e3e9c0e9cfe1a057 +size 4257 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Background_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Background_Cue.uasset new file mode 100644 index 0000000..8eed863 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Background_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36bc3a7bbeaad1ecf33a97465da041171bdd205f780a171d8ec712b16174e8b8 +size 10330 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Birds01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Birds01.uasset new file mode 100644 index 0000000..48fe853 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Birds01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e17fb5652999970bbd06344540cdfd616331a382da43a82de082374883bdc84e +size 2689459 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music01.uasset new file mode 100644 index 0000000..9034d40 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7eb074ff2fea1ac87017ca6638cb140b26ec60733878503ea2c618d726a780c +size 8445372 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music_Cue.uasset new file mode 100644 index 0000000..9b4e0b5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Music_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6fdbda2320b26aa806d967ca88390fbd6dd6078432952800fd029cf313bb2ce +size 3753 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind05.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind05.uasset new file mode 100644 index 0000000..5b51a8b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind05.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57ff816d0d35668e42096d85b2beabd89d6a87751f4f2c4ab030f4ee32b64ce7 +size 2312702 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind06.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind06.uasset new file mode 100644 index 0000000..13d7d30 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Starter_Wind06.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:517dad0128fbc9bf1acc611065a47892ff48f23e68fdde1d37d84cecb8dc0c7f +size 2195539 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Steam01.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Steam01.uasset new file mode 100644 index 0000000..96b5845 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Steam01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eaf02809b4d2541d2f851691f852afe55587710645207cea7bf01e0b8418473f +size 819028 diff --git a/Pawn_Unreal/Content/StarterContent/Audio/Steam01_Cue.uasset b/Pawn_Unreal/Content/StarterContent/Audio/Steam01_Cue.uasset new file mode 100644 index 0000000..2050940 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Audio/Steam01_Cue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c43fb733ebfc395af98ce820de46fed7d2b3f2a42ad03f55c8cf8e12d1bd417f +size 4285 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/FogBrightnessLUT.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/FogBrightnessLUT.uasset new file mode 100644 index 0000000..d92619f --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/FogBrightnessLUT.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38e07717499d03b1c67ec665e97f506873abc1467fb684b0a91ada159022dbf5 +size 1011 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Arrows.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Arrows.uasset new file mode 100644 index 0000000..88d202c --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Arrows.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4bb406076803f0a334b39cc075f1faf7de41b8443efce2c847243d0183607b6 +size 44857 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Black.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Black.uasset new file mode 100644 index 0000000..70bc908 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Black.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0931f2206f0d518529180371faca5154a92496de79f66fa9bdf6f1413ec5c239 +size 67062 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_HDRI.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_HDRI.uasset new file mode 100644 index 0000000..6de051c --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_HDRI.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b0bdbd07f341c968a33788bdc7405fda6b35c14be63a85e5b5a4edf44b1785a +size 100458 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Master.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Master.uasset new file mode 100644 index 0000000..731cddd --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/M_LightStage_Skybox_Master.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19c01ca4029a945710da9cda402637fb78c5cdbd44ee79c6a6eb77abdef2b86e +size 75669 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SM_Arrows.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SM_Arrows.uasset new file mode 100644 index 0000000..5b806ef --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SM_Arrows.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0339e4064beb122a74dbcfa9fb2021b2f837b6f696c44982f4bff844713bd43 +size 520136 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/Skybox.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/Skybox.uasset new file mode 100644 index 0000000..5234d14 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/Skybox.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:050f542626a97e0dd66040313037ceb138a1579ffbaf0ff6b22e50ccb92dbb8f +size 792947 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SunlightColorLUT.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SunlightColorLUT.uasset new file mode 100644 index 0000000..efe2224 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Assets/SunlightColorLUT.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24df919d06f5aff48925880834d3963da990e8786dabdcbd8062d6a33ca9d0c9 +size 4255 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/BP_LightStudio.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/BP_LightStudio.uasset new file mode 100644 index 0000000..b83f914 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/BP_LightStudio.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2747cabd39b194e82b6a66afe74312ae94e358131444e4b39ccc2beb56086313 +size 547392 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_CeilingLight.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_CeilingLight.uasset new file mode 100644 index 0000000..c5c3b84 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_CeilingLight.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a60a29ad596546d481e43dfb8698842a78cc07f4a4b1000fa397cfba4e72331 +size 158206 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Explosion.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Explosion.uasset new file mode 100644 index 0000000..4269e35 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Explosion.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcd9abdc6a00b26e0721b48a0bb06e3100c4c1ac407fcc3e4141225572d56cc2 +size 16095 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Fire.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Fire.uasset new file mode 100644 index 0000000..97e76f4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Fire.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dad0a791b92c961cde738111acefeab728b3b4e61589d133144b5a1c84b3a6fc +size 16096 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Smoke.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Smoke.uasset new file mode 100644 index 0000000..ca8a053 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Smoke.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad60f189780f8ae94abd489b48cbd5de03a539e118a842c78585a174a09280eb +size 16117 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Sparks.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Sparks.uasset new file mode 100644 index 0000000..d1cd7fc --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Sparks.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b80b6d88fabd6b817e73b3b1da4b33def861812ea41b1971154f34c8f8420658 +size 14539 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Steam.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Steam.uasset new file mode 100644 index 0000000..a2ee9aa --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_Effect_Steam.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ae4ddbe5ac59963ae5a3177f417bb812d01be33076308bb1bd352a934149c38 +size 16133 diff --git a/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_WallSconce.uasset b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_WallSconce.uasset new file mode 100644 index 0000000..d4c7b4e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Blueprints/Blueprint_WallSconce.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c6ae820b88cfa7250fa16726c0dedcb150760c0e0b7c824993b01e152751607 +size 158241 diff --git a/Pawn_Unreal/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset b/Pawn_Unreal/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset new file mode 100644 index 0000000..0f99058 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc35eb2d43a47427d30aba0196f9eac90d089dd3abca319528c5d25c83510d0d +size 72364642 diff --git a/Pawn_Unreal/Content/StarterContent/Maps/Advanced_Lighting.umap b/Pawn_Unreal/Content/StarterContent/Maps/Advanced_Lighting.umap new file mode 100644 index 0000000..ec8eff1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Maps/Advanced_Lighting.umap @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:285c67c63d3781fa401267302d4f816a94002efae742b159faad04fe80348c9b +size 44639 diff --git a/Pawn_Unreal/Content/StarterContent/Maps/Minimal_Default.umap b/Pawn_Unreal/Content/StarterContent/Maps/Minimal_Default.umap new file mode 100644 index 0000000..10c999c --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Maps/Minimal_Default.umap @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9fec4ad1898d20b630d79bac6222482df89f9e68a0e0963e3bdbc3dfe22b93e +size 653218 diff --git a/Pawn_Unreal/Content/StarterContent/Maps/StarterMap.umap b/Pawn_Unreal/Content/StarterContent/Maps/StarterMap.umap new file mode 100644 index 0000000..59362e3 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Maps/StarterMap.umap @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cd205fe0b91226c5aade79f2f8b88596cceddb541d53cf6c88039854fc6e7a9 +size 970103 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_AssetPlatform.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_AssetPlatform.uasset new file mode 100644 index 0000000..7270b60 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_AssetPlatform.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a106364bc2de5fa639d7a2c42962b650b2ada6481580747722036e216afe08b +size 91023 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Floor.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Floor.uasset new file mode 100644 index 0000000..da72132 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Floor.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50c04525eb66dce42783727ea5124369a8687cbbc9874aaba1817cc4599b05b3 +size 95397 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Wall.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Wall.uasset new file mode 100644 index 0000000..aa2ed6a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Basic_Wall.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d02fce275e89f40c715445239a723968e0d0473dd3e506fe5f3158d165e72ab +size 83202 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Beveled.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Beveled.uasset new file mode 100644 index 0000000..bd70364 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Beveled.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6300c7d46de8dbab2b02eb86cb8aa84d0cd24f61b23bd31265d68a62c59f21c8 +size 150135 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_New.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_New.uasset new file mode 100644 index 0000000..a7fdec5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_New.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:503c42095e01b248fc1ca5e06968d54d0d60522f52c55f48cee2b3a489558e12 +size 162039 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Old.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Old.uasset new file mode 100644 index 0000000..f49004e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Clay_Old.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30d379b1f4a1d602fe96d3572ef933c331a3e8483517805954134e71b6c86fa6 +size 183105 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Cut_Stone.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Cut_Stone.uasset new file mode 100644 index 0000000..2259bf4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Cut_Stone.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d112cb77a41308076c23f1580d9ec2288ef50cbf26a78a9a08c18582ebc49e72 +size 178482 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Hewn_Stone.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Hewn_Stone.uasset new file mode 100644 index 0000000..a118902 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Brick_Hewn_Stone.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77471e6a63d10e3154280dbc8bab37e18305b2c98a5624859d914760ca184c9d +size 157160 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Ceramic_Tile_Checker.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Ceramic_Tile_Checker.uasset new file mode 100644 index 0000000..f1301a2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Ceramic_Tile_Checker.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa35cadc5c920bbc192837aab5295d40c2415894797c4481f240359f41754d2a +size 145799 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Pebble.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Pebble.uasset new file mode 100644 index 0000000..f332249 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Pebble.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09af1142c898cca36e71fca9206d19ce6479e4257d8601cafacf5335e4d67b15 +size 173593 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Rough.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Rough.uasset new file mode 100644 index 0000000..a6db8a3 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Rough.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:76f065c90fcc6622af3597f2a7a092c0cad3487b860001d15d136c4b240bf654 +size 299191 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Smooth.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Smooth.uasset new file mode 100644 index 0000000..9737f51 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_CobbleStone_Smooth.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:182aebc7bf0fddae62d174690fd714e8099b3cdf8ddf8d79ea24e4aba61697d9 +size 305997 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_ColorGrid_LowSpec.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_ColorGrid_LowSpec.uasset new file mode 100644 index 0000000..8801545 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_ColorGrid_LowSpec.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a0840024071b11234baeb63a1ee76ec9dc7aec6f8c40766434f2feb49a0eb78 +size 107968 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Grime.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Grime.uasset new file mode 100644 index 0000000..b16a8b0 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Grime.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6547640d461d13356917169c8249ec0b7e9ac7b879f8295e60a8e6de864014d +size 174645 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Panels.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Panels.uasset new file mode 100644 index 0000000..3780964 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Panels.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50656badd74bf66a0681d8557dfbace7c4085f4c5fda8afc564b050254ec9e66 +size 147753 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Poured.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Poured.uasset new file mode 100644 index 0000000..ac89e86 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Poured.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6dcf2c2660ea78392f7a57c86c459a0225e403f76971bf0bee40e3a8fd8e675 +size 147147 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Tiles.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Tiles.uasset new file mode 100644 index 0000000..70c84e6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Concrete_Tiles.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75840c73541b727fb00814f8899d684c138d2b84a69a58626da62a0bd597c272 +size 158828 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Glass.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Glass.uasset new file mode 100644 index 0000000..b97d5aa --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Glass.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8e3817356869ad63c0cd791d6980fc343454539eae99d3b52bc7aeb13c86967 +size 91114 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Grass.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Grass.uasset new file mode 100644 index 0000000..4207312 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Grass.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93f8378f49433e80abf49838fc6223a02616336b49d6a4f55f4e43af0ca56d41 +size 205248 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Gravel.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Gravel.uasset new file mode 100644 index 0000000..1182895 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Gravel.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:662e037da3d7ad9c4e5063598534ed844c5e138a238d7e3cb5b6539121775b6f +size 167066 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Moss.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Moss.uasset new file mode 100644 index 0000000..0196965 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Ground_Moss.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:644f84ca723f525221f66b1879d21b178f8791598b066258adff04f6faf0bcab +size 192691 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Brushed_Nickel.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Brushed_Nickel.uasset new file mode 100644 index 0000000..4600cb2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Brushed_Nickel.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a16874973331d3f69aa4a66f9b656f59706e2de12608ffd3e33495b8faab1d66 +size 109064 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Burnished_Steel.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Burnished_Steel.uasset new file mode 100644 index 0000000..bd632c8 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Burnished_Steel.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0756a5bd644070cef0e5549b5ed9f054f3aee6fa6f6452b85a1da9014f0c25e6 +size 139424 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Chrome.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Chrome.uasset new file mode 100644 index 0000000..5765c2e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Chrome.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfc4d805a754a1110ba52b37e768c600acf5becca0eef22dc38589ccf80cf364 +size 110060 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Copper.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Copper.uasset new file mode 100644 index 0000000..ace1f20 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Copper.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55cbe529f878d029fddd47edff2d312410803fbe298148a13ba87416b8f5ed22 +size 137941 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Gold.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Gold.uasset new file mode 100644 index 0000000..990af76 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Gold.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e01673207c470bde0f31a77b053bce74f238501c229be6f1520145a16f504e8 +size 144292 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Rust.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Rust.uasset new file mode 100644 index 0000000..7151a9d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Rust.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a70db7bc33fc9c4972fa6230716ce2535cee694478c87fb178f18c08bd9dc0e1 +size 174005 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Steel.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Steel.uasset new file mode 100644 index 0000000..f8eb23e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Metal_Steel.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7a787d732e52118314ae81245bbbd2b862504804a429ddc86ff0159c9876035 +size 154534 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Basalt.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Basalt.uasset new file mode 100644 index 0000000..5ddd028 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Basalt.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e165649d33d33ee387b843d94ab61d6fabe0ce81229387fc4486a9d239c6dd09 +size 193836 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Marble_Polished.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Marble_Polished.uasset new file mode 100644 index 0000000..bcf78c8 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Marble_Polished.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa3f2a3219dd1296e15703d1e8aa9588e5dd823221da7806ef4110de4222a465 +size 163904 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Sandstone.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Sandstone.uasset new file mode 100644 index 0000000..8bb5124 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Sandstone.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b321b204b23879d455dce2e8361e06d5ad17956838171f2788d5cd1a8e944450 +size 169139 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Slate.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Slate.uasset new file mode 100644 index 0000000..3fef0c6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Rock_Slate.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bafd269b154d00a79e0015370cd799161be633d1db3bd035201096897f0f4d2a +size 171523 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Checker_Dot.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Checker_Dot.uasset new file mode 100644 index 0000000..d0bed65 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Checker_Dot.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c1f27852c04b5eb80062e8f2c63a5dd998dd93e9522d98192b2218d038a9f6e +size 140137 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile.uasset new file mode 100644 index 0000000..c479f69 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08fa5906593f76f3887561de005151e1f185f8b042b3627d3d0e8abd003728bf +size 171077 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile_Pulse.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile_Pulse.uasset new file mode 100644 index 0000000..5e0c350 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Hex_Tile_Pulse.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b11b14b6f876fb85cee60f42bc1ca9d565d6e8f3058f35146fa195c076d14ac1 +size 148791 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Panel.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Panel.uasset new file mode 100644 index 0000000..ca4c730 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Tech_Panel.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b533daeee4d1f6bc00ae80590ef00810b8b5a945f08afdbda87c99683576a9ca +size 131699 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Lake.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Lake.uasset new file mode 100644 index 0000000..544e8d0 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Lake.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f26e9ddce96ea5369cde02eb006201f3a87ba3f6ab27bafb5cef523935ba6d7 +size 141029 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Ocean.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Ocean.uasset new file mode 100644 index 0000000..620abe9 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Water_Ocean.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d070ede9b44ad4e268b37689f3320906b992d11949fa1f84db55a0f0cc5ce8cc +size 145065 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Polished.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Polished.uasset new file mode 100644 index 0000000..fb5225e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Polished.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:653b14312993e683c7fd4b98ca13a2c4498843f16546c9a8e9708e2e4ac63a3e +size 153293 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Worn.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Worn.uasset new file mode 100644 index 0000000..146638b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Floor_Walnut_Worn.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec27d23d375d4a05e107801b0d908b4fbe1ea03c8fbfe1d302220fc606676240 +size 154174 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Oak.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Oak.uasset new file mode 100644 index 0000000..f9ef627 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Oak.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3e8a7d2160df0383e54bd6eac405e436ce704f1ebcf48bcbe8149451d620dd2 +size 159368 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Pine.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Pine.uasset new file mode 100644 index 0000000..add9ba7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Pine.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d58dc5fef8535e21966b1785dfdca0c71be750a865a174560e80b616ca0f5179 +size 153062 diff --git a/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Walnut.uasset b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Walnut.uasset new file mode 100644 index 0000000..e41b863 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Materials/M_Wood_Walnut.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75bdcbbd640251fa991ee4b4119aaea3c92f5f77f934bc508f0cde136ce21b47 +size 146548 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Burst.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Burst.uasset new file mode 100644 index 0000000..51a8937 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Burst.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ccc5d11e0363bd4b17f681e5a3461c254a7835e4411e7baab1f988e155b7839 +size 43524 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Dust_Particle.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Dust_Particle.uasset new file mode 100644 index 0000000..61fa896 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Dust_Particle.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f77cef838e35a557185f8764c432a72ef3c528d13d7464229bee9dba808e18cc +size 82354 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Fire_SubUV.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Fire_SubUV.uasset new file mode 100644 index 0000000..db5f4f2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Fire_SubUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9ac89313a68dcf203c3e05c1b5c05cde0e500739dca06fd582b509d7de910fd +size 105604 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Heat_Distortion.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Heat_Distortion.uasset new file mode 100644 index 0000000..b9167c1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Heat_Distortion.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f330475bda72d73914d630403eff81c894ed097e9241fa8a000a26e55af4cd3 +size 86737 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Radial_Gradient.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Radial_Gradient.uasset new file mode 100644 index 0000000..6a620f8 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Radial_Gradient.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d60f3db8d9d32c6141f4f4340e22e046b59b0a6163594af1abb7fd135b21408 +size 41181 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Spark.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Spark.uasset new file mode 100644 index 0000000..d0af715 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_Spark.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ae67322c7782f784a4327ea898a83ede1b2f152469fe765cb6652d64fb1c238 +size 94041 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_explosion_subUV.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_explosion_subUV.uasset new file mode 100644 index 0000000..eb9b227 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_explosion_subUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66ea83f9670fcac1ee59b1c877e5e6bc6d2868eca6e6e1158dd7d09e113bd5bb +size 62151 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_radial_ramp.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_radial_ramp.uasset new file mode 100644 index 0000000..ae69b17 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_radial_ramp.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9485250b8a86884ee17b32a305b826af9f5f025011fe350cb9b7f199f8d53e62 +size 41193 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_smoke_subUV.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_smoke_subUV.uasset new file mode 100644 index 0000000..17f8714 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/M_smoke_subUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b02bcf4d6ab878b8425e196caa2b6aedd49274b074f7e605ef7ed3450be92193 +size 108259 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/Materials/m_flare_01.uasset b/Pawn_Unreal/Content/StarterContent/Particles/Materials/m_flare_01.uasset new file mode 100644 index 0000000..a023b46 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/Materials/m_flare_01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c493febe6e9b8ebdc08b3f168a74003537916e5cf81660e9ff38713cca0901f5 +size 48172 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Ambient_Dust.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Ambient_Dust.uasset new file mode 100644 index 0000000..bf2e439 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Ambient_Dust.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01ef616c7a8bd90cd1b7a13efb18a56f33346efbae51efa31f09804478b7621d +size 43456 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Explosion.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Explosion.uasset new file mode 100644 index 0000000..d3796ba --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Explosion.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f21bbb2c9d69226415dd25268ce3c3f74af71981018c537d0080ec7df5d32309 +size 280221 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Fire.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Fire.uasset new file mode 100644 index 0000000..38533cc --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Fire.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e2d1cb2ba9933d298c62788996e50a3015632eff8908f08ec28d85fe116cc073 +size 259431 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Smoke.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Smoke.uasset new file mode 100644 index 0000000..b1b00f9 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Smoke.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e66c5b6ed61896f44a837c0c88ac7cdd6ed16e7bdc9e0ded78e0742e83c4d60e +size 65670 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Sparks.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Sparks.uasset new file mode 100644 index 0000000..061ebce --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Sparks.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ae32a7cc9882bcb982df7db98dac68bbe0db2bf08c40f49fcd85c8e1407d415 +size 171805 diff --git a/Pawn_Unreal/Content/StarterContent/Particles/P_Steam_Lit.uasset b/Pawn_Unreal/Content/StarterContent/Particles/P_Steam_Lit.uasset new file mode 100644 index 0000000..7f3b1e0 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Particles/P_Steam_Lit.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:018c1d52865cea019dd1607b284acc89e0363c2e832d16e0d3f9e1164d337494 +size 117332 diff --git a/Pawn_Unreal/Content/StarterContent/Props/MaterialSphere.uasset b/Pawn_Unreal/Content/StarterContent/Props/MaterialSphere.uasset new file mode 100644 index 0000000..1285489 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/MaterialSphere.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3610c1f4c2ae939371a133f6203b9237e2e88982af7dacf3fcf8b2970b9cd5e2 +size 174533 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Bush.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Bush.uasset new file mode 100644 index 0000000..5dc76c5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Bush.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e843d70bb914f8a4a8c57797db04b751e070ae4b52772363d0854632704992e0 +size 99988 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Chair.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Chair.uasset new file mode 100644 index 0000000..9901c1d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Chair.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:736bcc8202f9bf46da6025412048ffa27c7648f27ebafe9e404375d6bf72134d +size 90187 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Door.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Door.uasset new file mode 100644 index 0000000..0ced8d7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Door.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:786ab66b2e8788919498b1e33ee5856eecf70b6b040b153be047800cdb9bc9e4 +size 87249 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Frame.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Frame.uasset new file mode 100644 index 0000000..43b39aa --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Frame.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d4327843712f60a88df948ffacbee0ac3e31c316e376f2232fd11a6d4e47b00 +size 114579 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Lamp.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Lamp.uasset new file mode 100644 index 0000000..0091673 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Lamp.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65dbd6d574c00a9c9ced47636fcf31f5329460847c05840fe57522fd50c0069a +size 128995 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere.uasset new file mode 100644 index 0000000..bee4f79 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:729f38ae69eee8363c08aee179d77216629e30586b03ec70b4c9d7f792e94d39 +size 66766 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere_Plain.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere_Plain.uasset new file mode 100644 index 0000000..d23d0be --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_MaterialSphere_Plain.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c1881118dc6656938d5f2a03543210eaa3947813460c8a2cc0d32b796150877 +size 58832 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Rock.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Rock.uasset new file mode 100644 index 0000000..a0172fb --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Rock.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc757e65f035e0c60aff320d7d432344c8d0dedb218dec5d8d7531e2afbd1730 +size 114715 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Shelf.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Shelf.uasset new file mode 100644 index 0000000..05d5337 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Shelf.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e28d90ffca791a13bb9e08d72fc113f568f0691231ed71500a65b60aabec5fe +size 78255 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Statue.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Statue.uasset new file mode 100644 index 0000000..9834377 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_Statue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a93849ce8d05966a53c7226dbb6d106738a66064183f9515c320c9b725a4ef9c +size 103184 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_StatueGlass.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_StatueGlass.uasset new file mode 100644 index 0000000..20428d5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_StatueGlass.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d4e3053d1ca199f8c417c21caecf71794cd5eaf2b8215a3d7523bcc487b1ffa +size 101919 diff --git a/Pawn_Unreal/Content/StarterContent/Props/Materials/M_TableRound.uasset b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_TableRound.uasset new file mode 100644 index 0000000..9c53684 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/Materials/M_TableRound.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:423008872d91d8ebb08cc77e1dd5bddab3ee14ff614cc265f53d7991732e9a0f +size 125965 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Bush.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Bush.uasset new file mode 100644 index 0000000..3f61514 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Bush.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:737851f7bf15cb3b27717edaf7ce27662e2ed2e45f07832f9c2344761609a4c1 +size 152902 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Chair.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Chair.uasset new file mode 100644 index 0000000..1a981e3 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Chair.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fe2c9d9b8cfb5a80d8ad04998ccdfae564409b571e5ebc4ce91b1bbe6cfd257 +size 213058 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_CornerFrame.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_CornerFrame.uasset new file mode 100644 index 0000000..97abfdf --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_CornerFrame.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffde89faaa320ba94bbba36e9496cb61c7e576de19a1220a9a2be356b729b27a +size 104587 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Couch.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Couch.uasset new file mode 100644 index 0000000..261ff54 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Couch.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b264dbe0486d028dab6ad962a189e757fced4db58993a6e65ea80b3f1264fb3c +size 254658 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Door.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Door.uasset new file mode 100644 index 0000000..cba1c57 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Door.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b20778a4a06e27614a28e87d1822142b59ee18ef45aec71905778cf158e1d0a +size 214917 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_DoorFrame.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_DoorFrame.uasset new file mode 100644 index 0000000..e96bcb1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_DoorFrame.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b451ad899ba38b35eed36982d738c4678ce272d19c59ec8d77f9726c8410323 +size 65546 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_GlassWindow.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_GlassWindow.uasset new file mode 100644 index 0000000..0b677ab --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_GlassWindow.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84ab4006cb783cf2d72a567750a7856d76ac5f6d0166e0a6085258fc0a70a37e +size 97538 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Ceiling.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Ceiling.uasset new file mode 100644 index 0000000..d1ba3d5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Ceiling.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa48f6998c78fb88c360129f2ab0b8d52d69aaf76e6ae82659b0d2e3beee929b +size 318571 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Wall.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Wall.uasset new file mode 100644 index 0000000..70ba50d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Lamp_Wall.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d479325367b590f25eae2686e3ac03c2fd8d7bb6437a72170b0ece9ec65415c2 +size 140246 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_MatPreviewMesh_02.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_MatPreviewMesh_02.uasset new file mode 100644 index 0000000..fa41b11 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_MatPreviewMesh_02.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6eb9e6c7e680e9b3b8a8fe3fd3e2b14aa2cfa80c5d23b99ed90d5d39b18c9fe +size 2396647 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame.uasset new file mode 100644 index 0000000..42c56e0 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:423bde487af524f2ab0569e36f19d58383836c4db5f6f80602adc7d7b092e809 +size 127007 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame300.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame300.uasset new file mode 100644 index 0000000..24ffa81 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_PillarFrame300.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8237734ef9a5f0db12f3a098285f0985f6f89e73bccee203379d7a544ed65cd +size 124350 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Rock.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Rock.uasset new file mode 100644 index 0000000..b729ae6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Rock.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ae10c19314550dce38fd573d60284b4de00f2656466ec533f637a0ed7ace97c +size 175516 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Shelf.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Shelf.uasset new file mode 100644 index 0000000..ad80390 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Shelf.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca90492e235d71f932d10dbf3ed2fe659f53b6a6663acef1f9f883ec5fb25746 +size 108862 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Stairs.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Stairs.uasset new file mode 100644 index 0000000..9f3fd64 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Stairs.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88695e9a950946ebe61dc84124009ca46780312bc83310dfb750516a1e8b45bd +size 66807 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_Statue.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_Statue.uasset new file mode 100644 index 0000000..43515f4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_Statue.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b47b5029ab2ec9b658b85450dd1dc3afa505392768a6bd8ff9519d443105760 +size 537153 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_TableRound.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_TableRound.uasset new file mode 100644 index 0000000..26b490e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_TableRound.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ec022af96389414545991f84453594998f7cce83c2e3679d0c4bae655c683a4 +size 528732 diff --git a/Pawn_Unreal/Content/StarterContent/Props/SM_WindowFrame.uasset b/Pawn_Unreal/Content/StarterContent/Props/SM_WindowFrame.uasset new file mode 100644 index 0000000..9e53598 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Props/SM_WindowFrame.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a0dab4215722ee64c78bd95ae42151d3d32f570dd3c5d17aaeabea94d827271 +size 68758 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cone.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cone.uasset new file mode 100644 index 0000000..7ef443e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cone.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e66945bb2a5bde032363221846eac83d673461261a876ced086da0c3f1cdd01 +size 94233 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cube.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cube.uasset new file mode 100644 index 0000000..2e36231 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cube.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28041535ff2c33720f2e67002529bbf592f2063b2acead30e5b5e85e0464bd4c +size 45498 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cylinder.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cylinder.uasset new file mode 100644 index 0000000..02c7cf5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Cylinder.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d097bc691d550e417ef9033bca8cf8fd3272bc0b03d26bd10b82491acdf26f77 +size 109276 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_NarrowCapsule.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_NarrowCapsule.uasset new file mode 100644 index 0000000..592f235 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_NarrowCapsule.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e9e39b0cd0819023f41c12be2c2281ea95fa66988e58a2ab67fccf06e9b1114 +size 211325 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe.uasset new file mode 100644 index 0000000..f42dbba --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4558f8ca4fba367623fca84b98adeafcaaa85d84e43bae085e918625b5bdb1e3 +size 78407 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_180.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_180.uasset new file mode 100644 index 0000000..cc8cd0e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_180.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f300a68e1340ec3912c6fd1caf7a2f8e123df3580dc78d5a1104c9321c550bc2 +size 193692 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_90.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_90.uasset new file mode 100644 index 0000000..077c1d9 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Pipe_90.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd06fe450ec0bc349b8b09c3c45e962b3c530bdcde0b68f587f5fbca17fc576c +size 120200 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Plane.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Plane.uasset new file mode 100644 index 0000000..a82558e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Plane.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32e6fd25247a16daaae4e70ab9b48f75a0a88dbcf3e055abe18c75d091d2a3f0 +size 43121 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_QuadPyramid.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_QuadPyramid.uasset new file mode 100644 index 0000000..9e2c98b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_QuadPyramid.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c11e4f057ae35953635134cb126d80f4180049c82f9f2f15b00f948a3ddb7cc3 +size 43744 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Sphere.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Sphere.uasset new file mode 100644 index 0000000..9affe73 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Sphere.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32ad0261fd9278177071b49e2539e9eea1a4f981e1d636eb2f40e68e470d7e0d +size 264634 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Torus.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Torus.uasset new file mode 100644 index 0000000..38a91d6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Torus.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12798a18f296855dfe99fecb8271047514b254aa94a9c5978cb0420d4e475f06 +size 558042 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_TriPyramid.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_TriPyramid.uasset new file mode 100644 index 0000000..dc1f9f8 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_TriPyramid.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c764985dac1e5ef6ccd70089a959c57b4279c2f9fb342fbcc272be503c4abcd7 +size 41629 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim.uasset new file mode 100644 index 0000000..769ee6a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9ee55a3396e3cda288dd62d762aeb6eacd9bd2727c2d0cc3c135ff6ce493c04 +size 51867 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_In.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_In.uasset new file mode 100644 index 0000000..79909f5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_In.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1222af18dda4f4cb0a98f180783162f1c0d3d8d237c61c9ed611b411a1bad31 +size 74804 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_Out.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_Out.uasset new file mode 100644 index 0000000..64a021d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Trim_90_Out.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2af5c493393ea486d5c2d5570ca6d43c6a3aaef22031aa3022123f121e35e585 +size 75706 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Tube.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Tube.uasset new file mode 100644 index 0000000..fb39aaf --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Tube.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:585a46fef1bdf06af7fcb1caa7d8ac0f08884d30995dd46da717f3b4d78a408b +size 190123 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_A.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_A.uasset new file mode 100644 index 0000000..1d1aca4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_A.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07d0d06229359785d9aa511350cf6f050b5b1f3aec394849a7d3f73bc01cfd87 +size 45020 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_B.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_B.uasset new file mode 100644 index 0000000..ef8091d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_Wedge_B.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d99c65bd6f4e251044aab1d561571f40e0efddf87dba99879d6d7e185e34e30e +size 40642 diff --git a/Pawn_Unreal/Content/StarterContent/Shapes/Shape_WideCapsule.uasset b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_WideCapsule.uasset new file mode 100644 index 0000000..f41fbd4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Shapes/Shape_WideCapsule.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:891e25491dfd9985bfc876a896db2bb8c26701a01bf4af35f0e39329aa36f203 +size 150007 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_D.uasset new file mode 100644 index 0000000..9ffa6fa --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae1213ed482afcc070afa935777c007a016c7de619fe1f0ac060a08eaec039ab +size 7649619 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_M.uasset new file mode 100644 index 0000000..ed6cad6 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a93958e70a93dcfd3d9c3951bd54efac9ba0aa02e21820ca156aab49d520d6b +size 8326301 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_N.uasset new file mode 100644 index 0000000..207dd45 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Beveled_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d55e40a3d4b263feadf837fba93530bbce2df1b75340b9e1b503611c1bca1313 +size 7553391 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_D.uasset new file mode 100644 index 0000000..9d56c40 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bfaa2e5812f517db4d8815139ad32ec002e47bdfe4c621de783b27929e48c5e +size 6035708 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_M.uasset new file mode 100644 index 0000000..29f1106 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ae6db92679b2c34669a93c611c60bae6df6ca06a1dbaa51175d9b3e2cffc153 +size 9201530 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_N.uasset new file mode 100644 index 0000000..138acee --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_New_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a26a31f56112fc132f2f1a6d1cda40afb916dec5573fc6802616b8b267d91bb0 +size 7865847 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_D.uasset new file mode 100644 index 0000000..c0b4357 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f49e924c5d070b837d8735071ad3f211c535367f6f0b2d29fcf190f29927727d +size 11424774 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_N.uasset new file mode 100644 index 0000000..70022a9 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Clay_Old_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a867e56b65892db775788655490a52f206fa8863ec7c77304cafc74e4d650be5 +size 7794699 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_D.uasset new file mode 100644 index 0000000..96ec7ed --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe0582dfc178ee935e7d46d680c01b9af01d39a84bd6b2ce902592251b88631c +size 13386492 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_N.uasset new file mode 100644 index 0000000..26730f4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Cut_Stone_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:634c067049b6ab3652862c7ae71d9c887cb1a3c03683eae415507cefd79e79c5 +size 6679434 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_D.uasset new file mode 100644 index 0000000..8b13c96 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:788abca114951b9dfe36728ba7edc61fa99d63013d0fca1cc8c0b2ed73dd8af1 +size 7446677 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_M.uasset new file mode 100644 index 0000000..20e3a30 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d244a51d9a2c0c4b3b84ba630d6286be0275d5918a8d5aa5c5759f2468dc7758 +size 6802269 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_N.uasset new file mode 100644 index 0000000..75c8ecf --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Brick_Hewn_Stone_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71891e186659e1344e8c036bdda0909f62caac306c6f5ba4f62852dbe3f8ed52 +size 8992435 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Burst_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Burst_M.uasset new file mode 100644 index 0000000..f13ba11 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Burst_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07f91d423c228fe5c7f880271a581b3d09106d2d8abf56bb07951bf121f2a5b7 +size 150025 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_D.uasset new file mode 100644 index 0000000..7fa73f1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f878d3ce291b9e0ec0aeec7bec5dacea3b171b25ad41d1ce6a8946b1b94eac0c +size 552540 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_N.uasset new file mode 100644 index 0000000..0ae108a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Bush_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea964f1604f3c15e347f9dacd08df9bc0f325b3f37bc72c717e4f9623e7d04c3 +size 396574 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_M.uasset new file mode 100644 index 0000000..1081979 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edd01c79ee94b93a1fd5943e05f06953f4871e72f9692051bde3bd5b39520f90 +size 277243 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_N.uasset new file mode 100644 index 0000000..8b0be0a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ceramic_Tile_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dda183a05e51052804108b7aec46bbb3e8ddf56ad9fb212478222965b340698e +size 228293 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_M.uasset new file mode 100644 index 0000000..313a262 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08d98c98f59de587246fc6e5fb55168719efc4bf1cbffe9c7dcf3fd6469e26c9 +size 576769 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_N.uasset new file mode 100644 index 0000000..808a8a2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Chair_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:231bae025cc94d632e5a9f63dd54f6d9346cdab7622bcd5c3051f3b852a992d5 +size 1937145 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Checker_Noise_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Checker_Noise_M.uasset new file mode 100644 index 0000000..0451fdb --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Checker_Noise_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c443d3a3d38c6d4a5c6592ae6c987a1117881ea96300e61878e2baf94aeb90b +size 158406 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_D.uasset new file mode 100644 index 0000000..01f7038 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62cf11c47d265b2f0ffbba90b16697352afdece30c4c27753668fa137f8257a4 +size 11812314 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_M.uasset new file mode 100644 index 0000000..f472d20 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4af930353444a446f3706ec94ccb004ecbdb84456b210eb2ff42b447a8b7cfdc +size 1313598 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_N.uasset new file mode 100644 index 0000000..492fad1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Pebble_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:021c8e61bb4ade6da0654e2f0680e7471acc1a051c6f0775a7922710942f31d7 +size 11858728 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_D.uasset new file mode 100644 index 0000000..780cf19 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71be78adf2062e526135cbc269b930522ecc695af9c55b5106382adbc214f52f +size 2936250 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_N.uasset new file mode 100644 index 0000000..56197b7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Rough_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5d4b6fed8486cefa5414a9b87300ed3fc84d6e458427b60ac4fdd8ee340c3c5 +size 2768117 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_D.uasset new file mode 100644 index 0000000..52eab01 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e52253da7eae0fdf06788fabc99116cc80af16e7327fe9e83620ddb578eda2e +size 6603341 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_M.uasset new file mode 100644 index 0000000..7aecfb1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2cb96e28e3fda7e527570df959133ca99c1a704c92dcea0c71c6dbb30ff3735 +size 5739577 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_N.uasset new file mode 100644 index 0000000..9aed1cf --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_CobbleStone_Smooth_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de1606b700ce3b768e87c3ba87d9e54ecc7d350c0d574cf4e402e9ebeb703ecc +size 8846507 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Grime_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Grime_D.uasset new file mode 100644 index 0000000..d96a8db --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Grime_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:772cf0f32482bf09a8f1fb41fafb98c7e6e618ab38720c06a20f4816a94d795c +size 10691506 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_D.uasset new file mode 100644 index 0000000..d4e251e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78f1fb6d2275ab0db5ccb9d09c2740fe2844a818936a3bba56a973e3595279a1 +size 8513286 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_N.uasset new file mode 100644 index 0000000..95cc9c8 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Panels_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4d26912394d2e4fbbe45f877122dd991aa386a3588d298b5ff0d647231e2973 +size 6558914 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_D.uasset new file mode 100644 index 0000000..67fab27 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:801b1c699f3131c700d092791f317faddae04a7c162d702682673b1246e71a65 +size 11600993 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_N.uasset new file mode 100644 index 0000000..9a20d36 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Poured_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:441d509c226c555df9f7485a0ce2231873a36bcb2082ac51249e28baa943f07a +size 7452814 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_D.uasset new file mode 100644 index 0000000..be8bd5b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:726c21d68b436a88231bd143e2c0eaf1c76f42f17bdcb90ad5a27c28aed43857 +size 4956380 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_M.uasset new file mode 100644 index 0000000..1036eab --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2263f308ca49ec7c177605b7534917a1a592ec658d9efdd396044d5695b6f8f8 +size 5759659 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_N.uasset new file mode 100644 index 0000000..0b3a26e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04eac07ab8ffc6b649c3a1cc9e7d952022b09461c5d38f116a6f7bdc22aa3369 +size 6611650 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_Variation_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_Variation_M.uasset new file mode 100644 index 0000000..fc01b2c --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Concrete_Tiles_Variation_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6911df55c9e2906aa33fbf93b6f79565cd4c3e341add9edf0cb55d98381331c +size 4809 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Detail_Rocky_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Detail_Rocky_N.uasset new file mode 100644 index 0000000..2ca791b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Detail_Rocky_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3f3744b814bbb7abc3d049dc32d130a208c4c3ba17997d2d52ff31dfd73f0d6 +size 2850093 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Door_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Door_M.uasset new file mode 100644 index 0000000..dcd0646 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Door_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a15c89637e98961e80905fdc88c9ecd84eb50c0bdd9b8deafc2e907196171dd +size 554190 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Door_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Door_N.uasset new file mode 100644 index 0000000..e43c4a7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Door_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ea391c588a47c11ce3a79b46ccb66a1ddeea3b65deeae9f3c50642901745833 +size 1074859 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Dust_Particle_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Dust_Particle_D.uasset new file mode 100644 index 0000000..e802906 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Dust_Particle_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce512978ebcb5dfc9a7344dbc7cdae06b00253845c245f471850f711cd85e593 +size 32071 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Explosion_SubUV.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Explosion_SubUV.uasset new file mode 100644 index 0000000..491a176 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Explosion_SubUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:123a75a60ad2f7d93948e4e6b019d4515ef1c7422c0fc3c346fbb0aa6bfc44ce +size 3004336 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_SubUV.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_SubUV.uasset new file mode 100644 index 0000000..c2be716 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_SubUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3abd0273b3e94b5c95528910b425bea79d1aa78c6103383324f312fef40ca2d8 +size 525012 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_Tiled_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_Tiled_D.uasset new file mode 100644 index 0000000..3566641 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Fire_Tiled_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e3f75a88deb055bf15fcf27a9dee9c90b784265f7742c8cf72b7b103aef90fa +size 553370 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_M.uasset new file mode 100644 index 0000000..f25d113 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d624d28cc125bdccf49cb4fd5ecd537ac332dddfa94e0bc75775f8677a8841e +size 536068 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_N.uasset new file mode 100644 index 0000000..017b926 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Frame_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e7e8d6da7a559c853c1f592a91229fd4d35f42cb06f5b7d537f020d983658cd +size 1249187 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Gradinet_01.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Gradinet_01.uasset new file mode 100644 index 0000000..ba3bf4d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Gradinet_01.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2f8e85666d34a7813dd6ee849e4bb67291bb95f51e755250850df01998e32fd +size 5447 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_D.uasset new file mode 100644 index 0000000..4742dda --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68febc3730979e5660f2c9bb142dfce4f2cec0513014c86313c59eff91f9bc36 +size 12014827 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_N.uasset new file mode 100644 index 0000000..906e99e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Grass_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:188a235f10e6ddb567db2d6e44be8bdfe422ae03d1731eb69a88123635b88b9a +size 11617917 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_D.uasset new file mode 100644 index 0000000..92d45db --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:265c31534d4d2eeff3fe28588cbaef59bca7f319d058eae37d752d47fa21794a +size 10627659 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_N.uasset new file mode 100644 index 0000000..5bd4833 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Gravel_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4445cdee2d65a26e8e6e4c7be6acfeb79812fec5cfff7a29825d7542637f923d +size 7408581 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Moss_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Moss_N.uasset new file mode 100644 index 0000000..f91f3a1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Ground_Moss_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:201d4e5c0af974e110b4967fdf0f5c85386f58d1f89b9211ffefbc11e723d54b +size 8389816 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_M.uasset new file mode 100644 index 0000000..d02c21d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86dc633c051ea6341a7ef5eb92c32ebefc340ca6429216b1136959aabad98347 +size 781809 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_N.uasset new file mode 100644 index 0000000..3971919 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Lamp_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aab4ff1e56fcbad1adedaf4373686e6441d17dc8129c55524ac26bbeb5ccc30 +size 2076923 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_MacroVariation.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_MacroVariation.uasset new file mode 100644 index 0000000..a404432 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_MacroVariation.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:459b10ccd1742f24a8f18d9f20801a1fc7ee4cf73925a5d1d4453f1c5077953d +size 10882792 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Aluminum_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Aluminum_D.uasset new file mode 100644 index 0000000..28c2677 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Aluminum_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02fabc8ca9de999fb008334ce0ce1c608274b5976993827e7d227d02ec8709d3 +size 9680629 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Copper_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Copper_D.uasset new file mode 100644 index 0000000..c951aad --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Copper_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:685da9dccd73f061650b3ee20b70ef37cba141fb162364ad5ab1dff82ce0528d +size 8854788 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_D.uasset new file mode 100644 index 0000000..6b75601 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e809789d988bc1944be3a1e1d5245cb1065dc9a025b2976ba1a92e1c2c0bf526 +size 8838906 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_N.uasset new file mode 100644 index 0000000..74596d5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Gold_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41d81367d8c1c328abe13634b6f490584c6be67897077e5c295ef4d3af2846bb +size 2813572 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_D.uasset new file mode 100644 index 0000000..adfaf14 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4579d39044d4ef16d1aafe68a4578403dd73bb424d0f622e2b27b4f2fe15dd3 +size 9329320 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_N.uasset new file mode 100644 index 0000000..6cf9a33 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Rust_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23b100433492c5cac7fa75df9c73fa3342619e625d216df04545ea290aff688a +size 7504761 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_D.uasset new file mode 100644 index 0000000..edd26cb --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1ae1d155685a8ddd906d13da8c6325079e012c963229178c95f4e65fa3972d5 +size 3581726 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_N.uasset new file mode 100644 index 0000000..fb6ec41 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Metal_Steel_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:857faba84c82fc5af40f02a7b29846dac7a243d5b810cfd804fab19d7b2759f0 +size 4922590 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Perlin_Noise_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Perlin_Noise_M.uasset new file mode 100644 index 0000000..43a3dae --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Perlin_Noise_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bece883ac102ebc3ede6c670769f94140b7ec0e2d9995f6250c55062e710b762 +size 7869402 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_M.uasset new file mode 100644 index 0000000..97f2f1b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3e3e305c84514fc777030b0a3f612cd113f332a8760bbfe0884fed3ed7c9b69 +size 2706973 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_N.uasset new file mode 100644 index 0000000..cb7df96 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_RockMesh_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4cca0960c9668f1a286e7182440b24ceafc2c212192f3643bd15c26b15eb66e +size 5375053 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_D.uasset new file mode 100644 index 0000000..2a17332 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98fc893f2f15b2f2fa80cbeb22efbc0401bba9fb8babfd279e50e8695a77b141 +size 9359943 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_N.uasset new file mode 100644 index 0000000..970223a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Basalt_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b07a42c53c3c8d975b66f7af2ca7a63f14728cd84214afddfd181be9a9a521a1 +size 7847129 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Marble_Polished_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Marble_Polished_D.uasset new file mode 100644 index 0000000..aac31ee --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Marble_Polished_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3987c099b9761a082d51dc0f2db9603427558c8f93059e5aa463b62f672318a +size 5327483 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_D.uasset new file mode 100644 index 0000000..1d172c1 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d8ce6e42a8617cc4021dd4df77eb5af8830a8c8c038acc08ca9fc50d9df6ac2 +size 9234423 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_N.uasset new file mode 100644 index 0000000..77d36af --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Sandstone_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6115f632ebe01e0fa226bc5b01f713b2d11d57e3d87e8ecbb45a92715695be64 +size 8399811 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_D.uasset new file mode 100644 index 0000000..a9361c5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e9c1e799c3e7d4e688b14812e44ebe966eaac252e562f933b870867088bd144 +size 12333988 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_N.uasset new file mode 100644 index 0000000..b82e64e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Slate_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6927a7f01ca99210ea896a5ed384ad866959c35c6dc41a77fa23e9c32bff0ab +size 9649859 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Smooth_Granite_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Smooth_Granite_D.uasset new file mode 100644 index 0000000..e1ec0a3 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Rock_Smooth_Granite_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4cd898259422aa7bdded5d08c499ef13fc7cbf6cc46768254c92fcb5ec0aa0be +size 8829490 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_M.uasset new file mode 100644 index 0000000..15a50f2 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8d55e6e9c8ab4f0066a5339be82f0d5fe0fa878a60cb458f37f9bb1f608aa31 +size 651298 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_N.uasset new file mode 100644 index 0000000..46b4896 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Shelf_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3a0c0b53abb2074fcec92c1811b2e49e559e0d379753b11fd8759f7b7b7ce2a7 +size 1639501 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Single_Tile_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Single_Tile_N.uasset new file mode 100644 index 0000000..e1b1ccb --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Single_Tile_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d55152f3d78f7ec211dd608bd17b80105b9c57616efebf452649f320e2c9da3 +size 6402 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_SubUV.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_SubUV.uasset new file mode 100644 index 0000000..fd0e130 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_SubUV.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:773762833011cb0bc91b2d87d4dbc27bd63c4122513256cb28836516a3314c25 +size 2630744 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_Tiled_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_Tiled_D.uasset new file mode 100644 index 0000000..9b3154c --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Smoke_Tiled_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b032814d67d8d203751de76a9d62cdce51e63633d84a85a09e2607475ed662c2 +size 91431 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Spark_Core.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Spark_Core.uasset new file mode 100644 index 0000000..471ab07 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Spark_Core.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b841c25bc0549147b5764dc4e49f6c84960bec0b52eb917a977592da55afe04c +size 162316 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_M.uasset new file mode 100644 index 0000000..29da55a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f99f47b9bd28704bafbb6f4feb3dba1efdba779a4a541bf4b7068485e7d6d892 +size 546786 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_N.uasset new file mode 100644 index 0000000..6021715 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Statue_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:73bca3462a64aabc528afa8b23e1a38eb4b947497482213ccd535b3ba22a9278 +size 515360 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_M.uasset new file mode 100644 index 0000000..e19e77d --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8fac89589631c9521cb0745483e301cff454cc2b3632f2aa5a96c83ec63da953 +size 870486 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_N.uasset new file mode 100644 index 0000000..9a60724 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_TableRound_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a646c9275d23357a81f3fe81bd386c4e10ef02dfab7ea006e8f1ce60ce08979 +size 1549086 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_M.uasset new file mode 100644 index 0000000..69afe46 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1074b14c911419d9207d85f0a14ac699e39ed7b6ebec9f4c7f65332f3f6f08e0 +size 107174 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_N.uasset new file mode 100644 index 0000000..f9a221a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Dot_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3cee5a07f1b75bce7864cf8cc1df23c317c819e7460a0fdef6c11bfbd240a6eb +size 202333 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_M.uasset new file mode 100644 index 0000000..84decc5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c37cd27ec9067f05b4a0ec58bcfb2df5a63cde82b8286ba7e5c08fa16800082d +size 793459 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_N.uasset new file mode 100644 index 0000000..29b66a4 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Hex_Tile_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6df7e17f7d5cedd3fc9d3d84f81e648cd560292d42a2f8e7f8be5dbd0f72d19 +size 493875 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_M.uasset new file mode 100644 index 0000000..e0c32c7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8194fbc530d92432829695060a446bcf139f579f79ede12be5f901ddece7600b +size 979689 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_N.uasset new file mode 100644 index 0000000..7f3af00 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Tech_Panel_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7057eea89c2a4a09dc666628038127b195ba4308c7beb888087ea981672df689 +size 1860674 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Water_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Water_M.uasset new file mode 100644 index 0000000..dd245ef --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Water_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd8239b2b042ac321ba66d10f583c7076a65c15ba2a8238c3a85314af5251e1 +size 1696467 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Water_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Water_N.uasset new file mode 100644 index 0000000..c05d77e --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Water_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b565b73e0111dfe7303322cf70d57c7d8e1359516de73d82116a3da910e1559d +size 2087420 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_D.uasset new file mode 100644 index 0000000..a6e3e0a --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b585ed384b889bb1a62cdf46ead4fae16da0c9e2ff8ac22cec9d8b93e16c32d +size 4584206 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_M.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_M.uasset new file mode 100644 index 0000000..77cf750 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_M.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6123d3abe7d101ef3faba94b30bb49089f42294f9f6f7a29dc040c5502b1f0e +size 3940729 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_N.uasset new file mode 100644 index 0000000..fa1abab --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Floor_Walnut_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:301e71afd86e006c47a92d697d233eacfbf83dc6ef7bc136fceb1f76c04e2503 +size 2858538 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_D.uasset new file mode 100644 index 0000000..5b97a88 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28b8dc4700a329796f77503731dde4d79ee54b841c2e4711baba8ac55d14ba4f +size 6707252 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_N.uasset new file mode 100644 index 0000000..b998db0 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Oak_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7db9717aadade395ad7f5c5fc5388c32423ab99ec802efdf9981169d5858fb60 +size 6245295 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_D.uasset new file mode 100644 index 0000000..9d50af3 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd72a7013dca7c5e09c1b0f9e4774fc21394db1577092523cce0ae10a1da4d4d +size 9941578 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_N.uasset new file mode 100644 index 0000000..ff87b40 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Pine_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7de7d8ea43183c0bfb1ae796b99096880f4a6214159b6b70ea719f0e6b3f432 +size 3467174 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_D.uasset new file mode 100644 index 0000000..6301eb5 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b450edfff2c26ef117aeffd48006a8f1941cda54a86f821076bbf0b62490925 +size 6509713 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_N.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_N.uasset new file mode 100644 index 0000000..79e55a7 --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_Wood_Walnut_N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:29e60b11f9f5d15dff4581f41c95d801cd1b52d2afdb0a96111f90545e95afbc +size 3836013 diff --git a/Pawn_Unreal/Content/StarterContent/Textures/T_ground_Moss_D.uasset b/Pawn_Unreal/Content/StarterContent/Textures/T_ground_Moss_D.uasset new file mode 100644 index 0000000..9e1087b --- /dev/null +++ b/Pawn_Unreal/Content/StarterContent/Textures/T_ground_Moss_D.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39a0868a54b73531bd214b1249cd6213cf1c9cbabdb4cdfd60e95bcb97623ccf +size 13034653 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/Bump_StaticMesh.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/Bump_StaticMesh.uasset new file mode 100644 index 0000000..6287187 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/Bump_StaticMesh.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8078fae0f0b0165e3883d8847243b0427d181ab71d49d40ea9dd4f5cf10d521 +size 86647 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/LeftArm_StaticMesh.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/LeftArm_StaticMesh.uasset new file mode 100644 index 0000000..ec5bb4b --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/LeftArm_StaticMesh.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9faa52cfecec2347b0ec552d9194eeb4b0389726c399383dfbff6777dd0839d6 +size 88128 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/Linear_Stair_StaticMesh.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/Linear_Stair_StaticMesh.uasset new file mode 100644 index 0000000..b9b230a --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/Linear_Stair_StaticMesh.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc989af027de9de5d211e6e76fa07035003190b43194cf4dfc64f82dfd1e7658 +size 95236 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/RampMaterial.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/RampMaterial.uasset new file mode 100644 index 0000000..ee8f84f --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/RampMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24603f1159e71567863e47cf7e5ad83032f02683968ea4f585be086855a241c4 +size 89048 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/Ramp_StaticMesh.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/Ramp_StaticMesh.uasset new file mode 100644 index 0000000..1856d30 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/Ramp_StaticMesh.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c98e5ad37e0209114ee9b18e519cb35341f5aa59a1a3b66615e4b097664f3578 +size 85309 diff --git a/Pawn_Unreal/Content/ThirdPerson/Meshes/RightArm_StaticMesh.uasset b/Pawn_Unreal/Content/ThirdPerson/Meshes/RightArm_StaticMesh.uasset new file mode 100644 index 0000000..29c1871 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPerson/Meshes/RightArm_StaticMesh.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04073a425eed240d33d761b6e71d9e0579dfb71caafe8c5b12d942d34ff12c72 +size 86017 diff --git a/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonCharacter.uasset b/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonCharacter.uasset new file mode 100644 index 0000000..015ef47 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonCharacter.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:adfe7601554ffa42266a40ce6445a61080bdeaa32e883bdf2a91a43a2474beac +size 208314 diff --git a/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonGameMode.uasset b/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonGameMode.uasset new file mode 100644 index 0000000..6a8b327 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPersonBP/Blueprints/ThirdPersonGameMode.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06babe82b6ea2ddaebb37de99fd13a3b460b7a3b6de3b46cbc928b547309135f +size 12783 diff --git a/Pawn_Unreal/Content/ThirdPersonBP/Maps/ThirdPersonExampleMap.umap b/Pawn_Unreal/Content/ThirdPersonBP/Maps/ThirdPersonExampleMap.umap new file mode 100644 index 0000000..ad2fda9 --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPersonBP/Maps/ThirdPersonExampleMap.umap @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1d9eee0d25e80e972a0fa06c6580f1e36396f731da6cb57922114313f7b7682 +size 8536294 diff --git a/Pawn_Unreal/Content/ThirdPersonBP/ThirdPersonOverview.uasset b/Pawn_Unreal/Content/ThirdPersonBP/ThirdPersonOverview.uasset new file mode 100644 index 0000000..cc3b02f --- /dev/null +++ b/Pawn_Unreal/Content/ThirdPersonBP/ThirdPersonOverview.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21e359072cbe5b79e9c66e1433a43ec7a6f20a367987392bb20800e77b1fad84 +size 37498 diff --git a/Pawn_Unreal/Pawn_Unreal.uproject b/Pawn_Unreal/Pawn_Unreal.uproject new file mode 100644 index 0000000..4f34f47 --- /dev/null +++ b/Pawn_Unreal/Pawn_Unreal.uproject @@ -0,0 +1,16 @@ +{ + "FileVersion": 3, + "EngineAssociation": "4.27", + "Category": "", + "Description": "", + "Modules": [ + { + "Name": "Pawn_Unreal", + "Type": "Runtime", + "LoadingPhase": "Default", + "AdditionalDependencies": [ + "Engine" + ] + } + ] +} \ No newline at end of file diff --git a/Pawn_Unreal/Plugins/GitSourceControl/.gitbugtraq b/Pawn_Unreal/Plugins/GitSourceControl/.gitbugtraq new file mode 100644 index 0000000..e47406d --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/.gitbugtraq @@ -0,0 +1,7 @@ +# .gitbugtraq for Git GUIs (SmartGit/TortoiseGit) to show links to the Github issue tracker. +# Instead of the repository root directory, it could be added as an additional section to $GIT_DIR/config. +# (note that '\' need to be escaped). +[bugtraq] + url = https://github.com/SRombauts/UE4GitPlugin/issues/%BUGID% + loglinkregex = "#\\d+" + logregex = \\d+ diff --git a/Pawn_Unreal/Plugins/GitSourceControl/.gitignore b/Pawn_Unreal/Plugins/GitSourceControl/.gitignore new file mode 100644 index 0000000..07ee9d8 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/.gitignore @@ -0,0 +1,2 @@ +/Binaries +/Intermediate diff --git a/Pawn_Unreal/Plugins/GitSourceControl/GitSourceControl.uplugin b/Pawn_Unreal/Plugins/GitSourceControl/GitSourceControl.uplugin new file mode 100644 index 0000000..e61d5be --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/GitSourceControl.uplugin @@ -0,0 +1,25 @@ +{ + "FileVersion" : 3, + "Version" : 52, + "VersionName" : "2.52", + "FriendlyName" : "Git LFS 2", + "Description" : "Git source control management (dev)", + "Category" : "Source Control", + "CreatedBy" : "SRombauts", + "CreatedByURL" : "https://srombauts.github.io", + "DocsURL" : "", + "MarketplaceURL" : "", + "SupportURL" : "", + "EnabledByDefault" : true, + "CanContainContent" : false, + "IsBetaVersion" : true, + "Installed" : false, + "Modules" : + [ + { + "Name" : "GitSourceControl", + "Type" : "Editor", + "LoadingPhase" : "Default" + } + ] +} \ No newline at end of file diff --git a/Pawn_Unreal/Plugins/GitSourceControl/LICENSE.txt b/Pawn_Unreal/Plugins/GitSourceControl/LICENSE.txt new file mode 100644 index 0000000..a91d421 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Pawn_Unreal/Plugins/GitSourceControl/README.md b/Pawn_Unreal/Plugins/GitSourceControl/README.md new file mode 100644 index 0000000..eed5e1d --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/README.md @@ -0,0 +1,205 @@ +Unreal Engine 5 Git Source Control Plugin +----------------------------------------- + +[![release](https://img.shields.io/github/release/SRombauts/UE4GitPlugin.svg)](https://github.com/SRombauts/UE4GitPlugin/releases) +[![Git Plugin issues](https://img.shields.io/github/issues/SRombauts/UE4GitPlugin.svg)](https://github.com/SRombauts/UE4GitPlugin/issues) +[![Join the chat at https://gitter.im/SRombauts/UE4GitPlugin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/SRombauts/UE4GitPlugin) +UEGitPlugin is a simple Git Source Control Plugin for **Unreal Engine 5.0, 5.1, 5.2 and 4.27**. + +Developed and contributed by Sébastien Rombauts 2014-2023 (sebastien.rombauts@gmail.com) + + 1. First version of the plugin has been **integrated by default in UE4.7 in "beta version"**. + 2. This is a developement fork named "**Git LFS 2**" adding File Locks supported by Github. + 3. ProjectBorealis has been busy fixing and improving this plugin to make it work robustly with LFS Locks. + **See [ProjectBorealis GitPlugin v3](https://github.com/ProjectBorealis/UEGitPlugin)** + +### Instructions + +You need to install it into your Project **Plugins/** folder, and it will overwrite (replace) the default "Git (beta version)" Source Control Provider with the "Git LFS 2" plugin. + +Have a look at the [Git Plugin Tutorial on the Wiki](https://wiki.unrealengine.com/Git_source_control_%28Tutorial%29). ([alternate link](https://michaeljcole.github.io/wiki.unrealengine.com/Git_source_control_%28Tutorial%29/)) + +Written and contributed by Sebastien Rombauts (sebastien.rombauts@gmail.com) + +Source Control Login window to create a new workspace/a new repository: +![Source Control Login window - create a new repository](Screenshots/SourceControlLogin_Init.png) + +Source Control status tooltip, when hovering the Source Control icon in toolbar: +![Source Control Status Tooltip](Screenshots/SourceControlStatusTooltip.png) + +Source Control top Menu, extended with a few commands specific to Git: +![Source Control Status Tooltip](Screenshots/SourceControlMenu.png) + +Submit Files to Source Control window, to commit assets: +![Submit Files to Source Control](Screenshots/SubmitFiles.png) + +File History window, to see the changelog of an asset: +![History of a file](Screenshots/FileHistory.png) + +Visual Diffing of two revisions of a Blueprint: + + +Merge conflict of a Blueprint: + + +Status Icons: + +![New/Unsaved/Untracked](Screenshots/Icons/New.png) +![Added](Screenshots/Icons/Added.png) +![Unchanged](Screenshots/Icons/Unchanged.png) +![Modified](Screenshots/Icons/Modified.png) +![Moved/Renamed](Screenshots/Icons/Renamed.png) + +### Supported features +- initialize a new Git local repository ('git init') to manage your UE4 Game Project + - can also create an appropriate .gitignore file as part of initialization + - can also create a .gitattributes file to enable Git LFS (Large File System) as part of initialization + - can also enable Git LFS 2.x File Locks as part of initialization + - can also make the initial commit, with custom multi-line message +- display status icons to show modified/added/deleted/untracked files, not at head and conflicted +- show history of a file +- visual diff of a blueprint against depot or between previous versions of a file +- revert modifications of a file (works best with "Content Hot-Reload" experimental option of UE4.15, by default since 4.16) +- add, delete, rename a file +- checkin/commit a file (cannot handle atomically more than 50 files) +- migrate an asset between two projects if both are using Git +- solve a merge conflict on a blueprint +- show current branch name in status text +- Configure remote origin URL ('git remote add origin url') +- Sync to Pull (rebase) the current branch if there is no local modified files +- Push the current branch +- Git LFS (Github, Gitlab, Bitbucket), git-annex, git-fat and git-media are working with Git 2.10+ +- Git LFS 2 File Locks +- Git console command for the Editor +- Windows, Mac and Linux + +### What *cannot* be done presently +- Branch/Merge are not in the current Editor workflow +- Amend a commit is not in the current Editor workflow +- Revert All (using either "Stash" or "reset --hard") +- Configure user name & email ('git config user.name' & git config user.email') +- Authentication is not managed if needed for Sync (Pull) + +### Known issues +- #34 "outside repository" fatal error +- #37 Rebase workflow: conflicts not detected! +- #41 UE-44637: Deleting an asset is unsuccessful if the asset is marked for add (since UE4.13) +- #46 Merge Conflicts - Accept Target - causes engine to crash bug +- #47 Git LFS conflict resolution not working +- #49 Git LFS 2: False error in logs after a successful push +- #51 Git LFS 2: cannot revert a modified/unchecked-out asset +- #53 Git LFS 2: document the configuration and workflow +- #54 Poor performances of 'lfs locks' on Windows command line +- #55 Git LFS 2: Unlocking a renamed asset + +- missing localisation for git specific messages +- displaying states of 'Engine' assets (also needs management of 'out of tree' files) +- renaming a Blueprint in Editor leaves a redirector file, AND modify too much the asset to enable git to track its history through renaming + +### Getting started + +Quick demo of the Git Plugin on Unreal Engine 4.12 (preview) +[![Git Plugin on Unreal Engine 4.12 (preview)](https://img.youtube.com/vi/rRhPl9vL58Q/0.jpg)](https://youtu.be/rRhPl9vL58Q) + +#### Install Git + +Under Windows 64bits, you should install the standard standalone Git for Windows +(now comming with Git LFS 2 with File Locking) with default parameters, +usually in "C:\Program Files\Git\bin\git.exe". + +Then you have to configure your name and e-mail that will appear in each of your commits: + +``` +git config --global user.name "Sébastien Rombauts" +git config --global user.email sebastien.rombauts@gmail.com +``` + +#### Install this Git Plugin (dev) into your Game Project + +Unreal Engine comes with a stable version of this plugin, so no need to install it. + +This alternate "Git development plugin" needs to be installed into a subfolder or your Game Project "Plugins" directory +(that is, you cannot install it into the Engine Plugins directory): + +``` +/Plugins +``` + +You will obviously only be able to use the plugin within this project. + +See also the [Plugins official Documentation](https://docs.unrealengine.com/latest/INT/Programming/Plugins/index.html) + +#### Activate Git Source Control for your Game Project + +Load your Game Project in Unreal Engine, then open: + +``` +File->Connect To Source Control... -> Git +``` + +##### Project already managed by Git + +If your project is already under Git (it contains a ".git" subfolder), just click on "Accept Settings". This connect the Editor to your local Git repository ("Depot"). + +##### Project not already under Git + +Otherwise, the Git Plugin is able to create (initialize) a new local Git Repository with your project Assets and Sources files: + + + +Click "Initialize project with Git" that will add all relevant files to source control and make the initial commit with the customizable message. +When everything is done, click on "Accept Settings". + +#### Using the Git Source Control Provider in the Unreal Engine Editor + +The plugin mostly interacts with you local Git repository ("Depot"), not much with the remote server (usually "origin"). + +It displays Git status icons on top of assets in the Asset Browser: +- No icon means that the file is under source control and unchanged since last commit, or ignored. +- A red mark is for "modified" assets, that is the one that needs to be committed (so not the same as "Check-out" in Perforce/SVN/Plastic SCM). +- A red cross is for "added" assets, that also needs to be committed +- A blue lightning means "renamed". +- A yellow exclamation point is for files in conflict after a merge, or is not at head (latest revision on the current remote branch). +- A yellow question mark is for files not in source control. + +TODO: +- specifics of rename and redirectors, and "Fix Up Redirector in Folder" command +- history / visual diff +- CheckIn = Commit +- CheckOut = Commit+Push+unlock (when using LFS 2) + +See also the [Source Control official Documentation](https://docs.unrealengine.com/latest/INT/Engine/UI/SourceControl/index.html) + +### License + +Copyright (c) 2014-2020 Sébastien Rombauts (sebastien.rombauts@gmail.com) + +Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +or copy at http://opensource.org/licenses/MIT) + +## How to contribute +### GitHub website +The most efficient way to help and contribute to this wrapper project is to +use the tools provided by GitHub: +- please fill bug reports and feature requests here: https://github.com/SRombauts/UE4GitPlugin/issues +- fork the repository, make some small changes and submit them with independent pull-requests + +### Contact +- You can use the Unreal Engine forums. +- You can also email me directly, I will answer any questions and requests. + +### Coding Style Guidelines +The source code follow the Unreal Engine official [Coding Standard](https://docs.unrealengine.com/latest/INT/Programming/Development/CodingStandard/index.html): +- CamelCase naming convention, with a prefix letter to differentiate classes ('F'), interfaces ('I'), templates ('T') +- files (.cpp/.h) are named like the class they contains +- Doxygen comments, documentation is located with declaration, on headers +- Use portable common features of C++11 like nullptr, auto, range based for, override keyword +- Braces on their own line +- Tabs to indent code, with a width of 4 characters + +## See also + +- [Git Source Control Tutorial on the Wikis](https://wiki.unrealengine.com/Git_source_control_(Tutorial)) +- [UE4 Git Plugin website](http://srombauts.github.com/UE4GitPlugin) + +- [ue4-hg-plugin for Mercurial (and bigfiles)](https://github.com/enlight/ue4-hg-plugin) diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Resources/Icon128.png b/Pawn_Unreal/Plugins/GitSourceControl/Resources/Icon128.png new file mode 100644 index 0000000..28ec04d --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Resources/Icon128.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:863a38c1ff858f21dae96ae2ea62721f91bc774e2f434c7d030eb9e51f5037d9 +size 3292 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/FileHistory.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/FileHistory.png new file mode 100644 index 0000000..194be3a --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/FileHistory.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0ddca9fac04eab92da79d854af8a0ccc06b9e20c4cfaa185981de18bf5741b7 +size 49797 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Added.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Added.png new file mode 100644 index 0000000..7fe05ae --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Added.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a814006fb214f34a5619fb6ad1dacba6d13db533ccc72d0d39433fc51b32d8b1 +size 7009 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Modified.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Modified.png new file mode 100644 index 0000000..fe69827 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Modified.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bde66ba2c086cd3a03c4ecdfefc06cf1a90d797d2a0550b6c193e27354e26557 +size 7071 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/New.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/New.png new file mode 100644 index 0000000..3fdda60 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/New.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e19cfdd105e33a0ff3db26e0a1d068e617546c0245ea40a1138e964e7a0cfb6 +size 7537 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Renamed.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Renamed.png new file mode 100644 index 0000000..182fd22 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Renamed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37e311933ded9db43d0d7f6fece598c6752c2f707b460fb08048afd9574f255d +size 7297 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Unchanged.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Unchanged.png new file mode 100644 index 0000000..4314d29 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/Icons/Unchanged.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ad3edfb3237b6373035fd814dad2ecf8ae7db9a907a6a1d707e21c0214d0c52 +size 6811 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlLogin_Init.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlLogin_Init.png new file mode 100644 index 0000000..60c350a --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlLogin_Init.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89e1afe735d448cbe5b9cb58427c1b3181ba89c113ee867b0b5fc618847b51ef +size 63505 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlMenu.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlMenu.png new file mode 100644 index 0000000..1212b5b --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlMenu.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ff69df9e370bc2f78829947f0f64ed199e4540660e32ff409748c99c5ba94d8 +size 48179 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlStatusTooltip.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlStatusTooltip.png new file mode 100644 index 0000000..d534426 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SourceControlStatusTooltip.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1e86ed890e190e0a8cb651af9a57a2bffdd1a7e402ec64a59fe75c8aa29e436 +size 28518 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SubmitFiles.png b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SubmitFiles.png new file mode 100644 index 0000000..2083777 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Screenshots/SubmitFiles.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:34754baf6f24034861caf3c1d6e4466c86f5450b2326a2f6e072bd51d44b1421 +size 42652 diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/GitSourceControl.Build.cs b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/GitSourceControl.Build.cs new file mode 100644 index 0000000..fe3315a --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/GitSourceControl.Build.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +using UnrealBuildTool; + +public class GitSourceControl : ModuleRules +{ + public GitSourceControl(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PrivatePCHHeaderFile = "Private/GitSourceControlPrivatePCH.h"; + + PrivateDependencyModuleNames.AddRange( + new[] { + "Core", + "CoreUObject", + "Slate", + "SlateCore", + "InputCore", + "DesktopWidgets", + "EditorStyle", + "UnrealEd", + "SourceControl", + "Projects", + } + ); + + if (Target.Version.MajorVersion == 5) + { + PrivateDependencyModuleNames.Add("ToolMenus"); + } + } +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.cpp new file mode 100644 index 0000000..eaac254 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlCommand.h" + +#include "Modules/ModuleManager.h" +#include "GitSourceControlModule.h" + +FGitSourceControlCommand::FGitSourceControlCommand(const TSharedRef& InOperation, const TSharedRef& InWorker, const FSourceControlOperationComplete& InOperationCompleteDelegate) + : Operation(InOperation) + , Worker(InWorker) + , OperationCompleteDelegate(InOperationCompleteDelegate) + , bExecuteProcessed(0) + , bCommandSuccessful(false) + , bConnectionDropped(false) + , bAutoDelete(true) + , Concurrency(EConcurrency::Synchronous) +{ + // grab the providers settings here, so we don't access them once the worker thread is launched + check(IsInGameThread()); + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked( "GitSourceControl" ); + PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + bUsingGitLfsLocking = GitSourceControl.AccessSettings().IsUsingGitLfsLocking(); + PathToRepositoryRoot = GitSourceControl.GetProvider().GetPathToRepositoryRoot(); +} + +bool FGitSourceControlCommand::DoWork() +{ + bCommandSuccessful = Worker->Execute(*this); + FPlatformAtomics::InterlockedExchange(&bExecuteProcessed, 1); + + return bCommandSuccessful; +} + +void FGitSourceControlCommand::Abandon() +{ + FPlatformAtomics::InterlockedExchange(&bExecuteProcessed, 1); +} + +void FGitSourceControlCommand::DoThreadedWork() +{ + Concurrency = EConcurrency::Asynchronous; + DoWork(); +} + +ECommandResult::Type FGitSourceControlCommand::ReturnResults() +{ + // Save any messages that have accumulated + for (FString& String : InfoMessages) + { + Operation->AddInfoMessge(FText::FromString(String)); + } + for (FString& String : ErrorMessages) + { + Operation->AddErrorMessge(FText::FromString(String)); + } + + // run the completion delegate if we have one bound + ECommandResult::Type Result = bCommandSuccessful ? ECommandResult::Succeeded : ECommandResult::Failed; + OperationCompleteDelegate.ExecuteIfBound(Operation, Result); + + return Result; +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.h new file mode 100644 index 0000000..31d257e --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlCommand.h @@ -0,0 +1,92 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlProvider.h" +#include "Misc/IQueuedWork.h" + +/** + * Used to execute Git commands multi-threaded. + */ +class FGitSourceControlCommand : public IQueuedWork +{ +public: + + FGitSourceControlCommand(const TSharedRef& InOperation, const TSharedRef& InWorker, const FSourceControlOperationComplete& InOperationCompleteDelegate = FSourceControlOperationComplete() ); + + /** + * This is where the real thread work is done. All work that is done for + * this queued object should be done from within the call to this function. + */ + bool DoWork(); + + /** + * Tells the queued work that it is being abandoned so that it can do + * per object clean up as needed. This will only be called if it is being + * abandoned before completion. NOTE: This requires the object to delete + * itself using whatever heap it was allocated in. + */ + virtual void Abandon() override; + + /** + * This method is also used to tell the object to cleanup but not before + * the object has finished it's work. + */ + virtual void DoThreadedWork() override; + + /** Save any results and call any registered callbacks. */ + ECommandResult::Type ReturnResults(); + +public: + /** Path to the Git binary */ + FString PathToGitBinary; + + /** Path to the root of the Git repository: can be the ProjectDir itself, or any parent directory (found by the "Connect" operation) */ + FString PathToRepositoryRoot; + + /** Tell if using the Git LFS file Locking workflow */ + bool bUsingGitLfsLocking; + + /** Operation we want to perform - contains outward-facing parameters & results */ + TSharedRef Operation; + + /** The object that will actually do the work */ + TSharedRef Worker; + + /** Delegate to notify when this operation completes */ + FSourceControlOperationComplete OperationCompleteDelegate; + + /**If true, this command has been processed by the source control thread*/ + volatile int32 bExecuteProcessed; + + /**If true, the source control command succeeded*/ + bool bCommandSuccessful; + + /** TODO LFS If true, the source control connection was dropped while this command was being executed*/ + bool bConnectionDropped; + + /** Current Commit full SHA1 */ + FString CommitId; + + /** Current Commit description's Summary */ + FString CommitSummary; + + /** If true, this command will be automatically cleaned up in Tick() */ + bool bAutoDelete; + + /** Whether we are running multi-treaded or not*/ + EConcurrency::Type Concurrency; + + /** Files to perform this operation on */ + TArray Files; + + /**Info and/or warning message storage*/ + TArray InfoMessages; + + /**Potential error message storage*/ + TArray ErrorMessages; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.cpp new file mode 100644 index 0000000..76ea617 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) + +#include "GitSourceControlConsole.h" + +#include "ISourceControlModule.h" + +#include "GitSourceControlModule.h" +#include "GitSourceControlUtils.h" + +void FGitSourceControlConsole::Register() +{ + if (!GitConsoleCommand.IsValid()) + { + GitConsoleCommand = MakeUnique( + TEXT("git"), + TEXT("Git Command Line Interface.\n") + TEXT("Run any 'git' command directly from the Unreal Editor Console.\n") + TEXT("Type 'git help' to get a list of commands."), + FConsoleCommandWithArgsDelegate::CreateRaw(this, &FGitSourceControlConsole::ExecuteGitConsoleCommand) + ); + } +} + +void FGitSourceControlConsole::Unregister() +{ + GitConsoleCommand.Reset(); +} + +void FGitSourceControlConsole::ExecuteGitConsoleCommand(const TArray& a_args) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const FString& RepositoryRoot = GitSourceControl.GetProvider().GetPathToRepositoryRoot(); + + // The first argument is the command to send to git, the following ones are forwarded as parameters for the command + TArray Parameters = a_args; + FString Command; + if (a_args.Num() > 0) + { + Command = a_args[0]; + Parameters.RemoveAt(0); + } + else + { + // If no command is provided, use "help" to emulate the behavior of the git CLI + Command = TEXT("help"); + } + + FString Results; + FString Errors; + GitSourceControlUtils::RunCommandInternalRaw(Command, PathToGitBinary, RepositoryRoot, Parameters, TArray(), Results, Errors); + + UE_LOG(LogSourceControl, Log, TEXT("Output:\n%s"), *Results); +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.h new file mode 100644 index 0000000..dc1b028 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlConsole.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) + +#pragma once + +#include "CoreMinimal.h" +#include "HAL/IConsoleManager.h" + +/** + * Editor only console commands. + * + * Such commands can be executed from the editor output log window, but also from command line arguments, + * from Editor Blueprints utilities, or from C++ Code using. eg. GEngine->Exec("git status Content/"); + */ +class FGitSourceControlConsole +{ +public: + void Register(); + void Unregister(); + +private: + // Git Command Line Interface: Run 'git' commands directly from the Unreal Editor Console. + void ExecuteGitConsoleCommand(const TArray& a_args); + + /** Console command for interacting with 'git' CLI directly */ + TUniquePtr GitConsoleCommand; +}; \ No newline at end of file diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.cpp new file mode 100644 index 0000000..be9797d --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.cpp @@ -0,0 +1,647 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlMenu.h" + +#include "GitSourceControlModule.h" +#include "GitSourceControlProvider.h" +#include "GitSourceControlOperations.h" +#include "GitSourceControlUtils.h" + +#include "ISourceControlModule.h" +#include "ISourceControlOperation.h" +#include "SourceControlOperations.h" + +#include "LevelEditor.h" +#include "Widgets/Notifications/SNotificationList.h" +#include "Framework/Notifications/NotificationManager.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "Misc/MessageDialog.h" +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 +#include "Styling/AppStyle.h" +#else +#include "EditorStyleSet.h" +#endif + +#include "PackageTools.h" +#include "FileHelpers.h" + +#include "Logging/MessageLog.h" +#include "UObject/Linker.h" + +#if ENGINE_MAJOR_VERSION == 5 +#include "ToolMenus.h" +#include "ToolMenuContext.h" +#include "ToolMenuMisc.h" +#endif + +#define LOCTEXT_NAMESPACE "GitSourceControl" + +void FGitSourceControlMenu::Register() +{ + // Register the extension with the level editor + +#if ENGINE_MAJOR_VERSION == 5 + FToolMenuOwnerScoped SourceControlMenuOwner("GitSourceControlMenu"); + if (UToolMenus* ToolMenus = UToolMenus::Get()) + { + UToolMenu* SourceControlMenu = ToolMenus->ExtendMenu("StatusBar.ToolBar.SourceControl"); + FToolMenuSection& Section = SourceControlMenu->AddSection("GitSourceControlActions", LOCTEXT("GitSourceControlMenuHeadingActions", "Git"), FToolMenuInsert(NAME_None, EToolMenuInsertType::First)); + + AddMenuExtension(Section); + } +#else + FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr("LevelEditor"); + if (LevelEditorModule) + { + FLevelEditorModule::FLevelEditorMenuExtender ViewMenuExtender = FLevelEditorModule::FLevelEditorMenuExtender::CreateRaw(this, &FGitSourceControlMenu::OnExtendLevelEditorViewMenu); + auto& MenuExtenders = LevelEditorModule->GetAllLevelEditorToolbarSourceControlMenuExtenders(); + MenuExtenders.Add(ViewMenuExtender); + ViewMenuExtenderHandle = MenuExtenders.Last().GetHandle(); + } +#endif +} + +void FGitSourceControlMenu::Unregister() +{ + // Unregister the level editor extensions +#if ENGINE_MAJOR_VERSION == 5 + if (UToolMenus* ToolMenus = UToolMenus::Get()) + { + UToolMenus::Get()->UnregisterOwnerByName("GitSourceControlMenu"); + } +#else + FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr("LevelEditor"); + if (LevelEditorModule) + { + LevelEditorModule->GetAllLevelEditorToolbarSourceControlMenuExtenders().RemoveAll([=](const FLevelEditorModule::FLevelEditorMenuExtender& Extender) { return Extender.GetHandle() == ViewMenuExtenderHandle; }); + } +#endif +} + +bool FGitSourceControlMenu::HaveRemoteUrl() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + const FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + return !Provider.GetRemoteUrl().IsEmpty(); +} + +/// Prompt to save or discard all packages +bool FGitSourceControlMenu::SaveDirtyPackages() +{ + const bool bPromptUserToSave = true; + const bool bSaveMapPackages = true; + const bool bSaveContentPackages = true; + const bool bFastSave = false; + const bool bNotifyNoPackagesSaved = false; + const bool bCanBeDeclined = true; // If the user clicks "don't save" this will continue and lose their changes + bool bHadPackagesToSave = false; + + bool bSaved = FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &bHadPackagesToSave); + + // bSaved can be true if the user selects to not save an asset by unchecking it and clicking "save" + if (bSaved) + { + TArray DirtyPackages; + FEditorFileUtils::GetDirtyWorldPackages(DirtyPackages); + FEditorFileUtils::GetDirtyContentPackages(DirtyPackages); + bSaved = DirtyPackages.Num() == 0; + } + + return bSaved; +} + +/// Find all packages in Content directory +TArray FGitSourceControlMenu::ListAllPackages() +{ + TArray PackageRelativePaths; + FPackageName::FindPackagesInDirectory(PackageRelativePaths, *FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir())); + + TArray PackageNames; + PackageNames.Reserve(PackageRelativePaths.Num()); + for (const FString& Path : PackageRelativePaths) + { + FString PackageName; + FString FailureReason; + if (FPackageName::TryConvertFilenameToLongPackageName(Path, PackageName, &FailureReason)) + { + PackageNames.Add(PackageName); + } + else + { + FMessageLog("SourceControl").Error(FText::FromString(FailureReason)); + } + } + + return PackageNames; +} + +/// Unkink all loaded packages to allow to update them +TArray FGitSourceControlMenu::UnlinkPackages(const TArray& InPackageNames) +{ + TArray LoadedPackages; + + // Inspired from ContentBrowserUtils::SyncPathsFromSourceControl() + if (InPackageNames.Num() > 0) + { + // Form a list of loaded packages to reload... + LoadedPackages.Reserve(InPackageNames.Num()); + for (const FString& PackageName : InPackageNames) + { + UPackage* Package = FindPackage(nullptr, *PackageName); + if (Package) + { + LoadedPackages.Emplace(Package); + + // Detach the linkers of any loaded packages so that SCC can overwrite the files... + if (!Package->IsFullyLoaded()) + { + FlushAsyncLoading(); + Package->FullyLoad(); + } + ResetLoaders(Package); + } + } + UE_LOG(LogSourceControl, Log, TEXT("Reseted Loader for %d Packages"), LoadedPackages.Num()); + } + + return LoadedPackages; +} + +void FGitSourceControlMenu::ReloadPackages(TArray& InPackagesToReload) +{ + UE_LOG(LogSourceControl, Log, TEXT("Reloading %d Packages..."), InPackagesToReload.Num()); + + // Syncing may have deleted some packages, so we need to unload those rather than re-load them... + TArray PackagesToUnload; + InPackagesToReload.RemoveAll([&](UPackage* InPackage) -> bool + { + const FString PackageExtension = InPackage->ContainsMap() ? FPackageName::GetMapPackageExtension() : FPackageName::GetAssetPackageExtension(); + const FString PackageFilename = FPackageName::LongPackageNameToFilename(InPackage->GetName(), PackageExtension); + if (!FPaths::FileExists(PackageFilename)) + { + PackagesToUnload.Emplace(InPackage); + return true; // remove package + } + return false; // keep package + }); + + // Hot-reload the new packages... + UPackageTools::ReloadPackages(InPackagesToReload); + + // Unload any deleted packages... + UPackageTools::UnloadPackages(PackagesToUnload); +} + +// Ask the user if he wants to stash any modification and try to unstash them afterward, which could lead to conflicts +bool FGitSourceControlMenu::StashAwayAnyModifications() +{ + bool bStashOk = true; + + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + const FString& PathToRespositoryRoot = Provider.GetPathToRepositoryRoot(); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const TArray ParametersStatus{"--porcelain --untracked-files=no"}; + TArray InfoMessages; + TArray ErrorMessages; + // Check if there is any modification to the working tree + const bool bStatusOk = GitSourceControlUtils::RunCommand(TEXT("status"), PathToGitBinary, PathToRespositoryRoot, ParametersStatus, TArray(), InfoMessages, ErrorMessages); + if ((bStatusOk) && (InfoMessages.Num() > 0)) + { + // Ask the user before stashing + const FText DialogText(LOCTEXT("SourceControlMenu_Stash_Ask", "Stash (save) all modifications of the working tree? Required to Sync/Pull!")); + const EAppReturnType::Type Choice = FMessageDialog::Open(EAppMsgType::OkCancel, DialogText); + if (Choice == EAppReturnType::Ok) + { + const TArray ParametersStash{ "save \"Stashed by Unreal Engine Git Plugin\"" }; + bStashMadeBeforeSync = GitSourceControlUtils::RunCommand(TEXT("stash"), PathToGitBinary, PathToRespositoryRoot, ParametersStash, TArray(), InfoMessages, ErrorMessages); + if (!bStashMadeBeforeSync) + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_StashFailed", "Stashing away modifications failed!")); + SourceControlLog.Notify(); + } + } + else + { + bStashOk = false; + } + } + + return bStashOk; +} + +// Unstash any modifications if a stash was made at the beginning of the Sync operation +void FGitSourceControlMenu::ReApplyStashedModifications() +{ + if (bStashMadeBeforeSync) + { + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + const FString& PathToRespositoryRoot = Provider.GetPathToRepositoryRoot(); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const TArray ParametersStash{ "pop" }; + TArray InfoMessages; + TArray ErrorMessages; + const bool bUnstashOk = GitSourceControlUtils::RunCommand(TEXT("stash"), PathToGitBinary, PathToRespositoryRoot, ParametersStash, TArray(), InfoMessages, ErrorMessages); + if (!bUnstashOk) + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_UnstashFailed", "Unstashing previously saved modifications failed!")); + SourceControlLog.Notify(); + } + } +} + +void FGitSourceControlMenu::SyncClicked() +{ + if (!OperationInProgressNotification.IsValid()) + { + // Ask the user to save any dirty assets opened in Editor + const bool bSaved = SaveDirtyPackages(); + if (bSaved) + { + // Better way to do a pull/sync + // First fetch and check what files have really changed + // Then unload only the necessary packages instead of everything + // Then reload the changed package. + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + const FString& PathToRepositoryRoot = Provider.GetPathToRepositoryRoot(); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + + FString BranchName; + GitSourceControlUtils::GetBranchName(PathToGitBinary, PathToRepositoryRoot, BranchName); + + FString DiffOrigin("..origin/"); + DiffOrigin.Append(BranchName); + + TArray ChangedFiles; + { + TArray ErrorMessages; + TArray Parameters; + Parameters.Add(TEXT("--stat")); + Parameters.Add(TEXT("--name-only")); + Parameters.Add(DiffOrigin); + + // Get changed files remote and on local commits (we need to determine which ones are local commits) + GitSourceControlUtils::RunCommand(TEXT("diff"), PathToGitBinary, PathToRepositoryRoot, Parameters, TArray(), ChangedFiles, ErrorMessages); + + // Handle uncommitted changes + TArray LocalChangedFiles; + const TArray ParametersStatus{"--porcelain --untracked-files=no"}; + GitSourceControlUtils::RunCommand(TEXT("status"), PathToGitBinary, PathToRepositoryRoot, ParametersStatus, TArray(), LocalChangedFiles, ErrorMessages); + + for(FString& Filename: LocalChangedFiles) + { + if(Filename.StartsWith(" M") || Filename.StartsWith(" A")) + { + ChangedFiles.Add(Filename.RightChop(3)); + } + } + } + + // TODO: Handle local commits + TArray PackagesToUnlink; + for(FString& Filename: ChangedFiles) + { + FString AbsolutePath = FPaths::ConvertRelativePathToFull(PathToRepositoryRoot, Filename); + FString PackageName; + if(FPackageName::TryConvertFilenameToLongPackageName(AbsolutePath, PackageName)) + { + UE_LOG(LogTemp, Warning, TEXT("%s - %s"), *AbsolutePath, *PackageName); + PackagesToUnlink.Add(PackageName); + } + } + + PackagesToReload = UnlinkPackages(PackagesToUnlink); + + // // Ask the user if he wants to stash any modification and try to unstash them afterward, which could lead to conflicts + const bool bStashed = StashAwayAnyModifications(); + if (bStashed) + { + TSharedRef SyncOperation = ISourceControlOperation::Create(); +#if ENGINE_MAJOR_VERSION == 5 + const ECommandResult::Type Result = Provider.Execute(SyncOperation, FSourceControlChangelistPtr(), TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#else + const ECommandResult::Type Result = Provider.Execute(SyncOperation, TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#endif + if (Result == ECommandResult::Succeeded) + { + // Display an ongoing notification during the whole operation (packages will be reloaded at the completion of the operation) + DisplayInProgressNotification(SyncOperation->GetInProgressString()); + } + else + { + // Report failure with a notification and Reload all packages + DisplayFailureNotification(SyncOperation->GetName()); + ReloadPackages(PackagesToReload); + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_Sync_Unsaved", "Stash away all modifications before attempting to Sync!")); + SourceControlLog.Notify(); + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_Sync_Unsaved", "Save All Assets before attempting to Sync!")); + SourceControlLog.Notify(); + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_InProgress", "Source control operation already in progress")); + SourceControlLog.Notify(); + } +} + +void FGitSourceControlMenu::PushClicked() +{ + if (!OperationInProgressNotification.IsValid()) + { + // Launch a "Push" Operation + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + TSharedRef PushOperation = ISourceControlOperation::Create(); +#if ENGINE_MAJOR_VERSION == 5 + const ECommandResult::Type Result = Provider.Execute(PushOperation, FSourceControlChangelistPtr(), TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#else + const ECommandResult::Type Result = Provider.Execute(PushOperation, TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#endif + if (Result == ECommandResult::Succeeded) + { + // Display an ongoing notification during the whole operation + DisplayInProgressNotification(PushOperation->GetInProgressString()); + } + else + { + // Report failure with a notification + DisplayFailureNotification(PushOperation->GetName()); + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_InProgress", "Source control operation already in progress")); + SourceControlLog.Notify(); + } +} + +void FGitSourceControlMenu::RevertClicked() +{ + if (!OperationInProgressNotification.IsValid()) + { + // Ask the user before reverting all! + const FText DialogText(LOCTEXT("SourceControlMenu_Revert_Ask", "Revert all modifications of the working tree?")); + const EAppReturnType::Type Choice = FMessageDialog::Open(EAppMsgType::OkCancel, DialogText); + if (Choice == EAppReturnType::Ok) + { + // NOTE No need to force the user to SaveDirtyPackages(); since he will be presented with a choice by the Editor + + // Find and Unlink all packages in Content directory to allow to update them + PackagesToReload = UnlinkPackages(ListAllPackages()); + + // Launch a "Revert" Operation + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + TSharedRef RevertOperation = ISourceControlOperation::Create(); +#if ENGINE_MAJOR_VERSION == 5 + const ECommandResult::Type Result = Provider.Execute(RevertOperation, FSourceControlChangelistPtr(), TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#else + const ECommandResult::Type Result = Provider.Execute(RevertOperation, TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#endif + if (Result == ECommandResult::Succeeded) + { + // Display an ongoing notification during the whole operation + DisplayInProgressNotification(RevertOperation->GetInProgressString()); + } + else + { + // Report failure with a notification and Reload all packages + DisplayFailureNotification(RevertOperation->GetName()); + ReloadPackages(PackagesToReload); + } + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_InProgress", "Source control operation already in progress")); + SourceControlLog.Notify(); + } +} + +void FGitSourceControlMenu::RefreshClicked() +{ + if (!OperationInProgressNotification.IsValid()) + { + // Launch an "UpdateStatus" Operation + FGitSourceControlModule& GitSourceControl = FModuleManager::LoadModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + TSharedRef RefreshOperation = ISourceControlOperation::Create(); + RefreshOperation->SetCheckingAllFiles(true); +#if ENGINE_MAJOR_VERSION == 5 + const ECommandResult::Type Result = Provider.Execute(RefreshOperation, FSourceControlChangelistPtr(), TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#else + const ECommandResult::Type Result = Provider.Execute(RefreshOperation, TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw(this, &FGitSourceControlMenu::OnSourceControlOperationComplete)); +#endif + if (Result == ECommandResult::Succeeded) + { + // Display an ongoing notification during the whole operation + DisplayInProgressNotification(RefreshOperation->GetInProgressString()); + } + else + { + // Report failure with a notification + DisplayFailureNotification(RefreshOperation->GetName()); + } + } + else + { + FMessageLog SourceControlLog("SourceControl"); + SourceControlLog.Warning(LOCTEXT("SourceControlMenu_InProgress", "Source control operation already in progress")); + SourceControlLog.Notify(); + } +} + +// Display an ongoing notification during the whole operation +void FGitSourceControlMenu::DisplayInProgressNotification(const FText& InOperationInProgressString) +{ + if (!OperationInProgressNotification.IsValid()) + { + FNotificationInfo Info(InOperationInProgressString); + Info.bFireAndForget = false; + Info.ExpireDuration = 0.0f; + Info.FadeOutDuration = 1.0f; + OperationInProgressNotification = FSlateNotificationManager::Get().AddNotification(Info); + if (OperationInProgressNotification.IsValid()) + { + OperationInProgressNotification.Pin()->SetCompletionState(SNotificationItem::CS_Pending); + } + } +} + +// Remove the ongoing notification at the end of the operation +void FGitSourceControlMenu::RemoveInProgressNotification() +{ + if (OperationInProgressNotification.IsValid()) + { + OperationInProgressNotification.Pin()->ExpireAndFadeout(); + OperationInProgressNotification.Reset(); + } +} + +// Display a temporary success notification at the end of the operation +void FGitSourceControlMenu::DisplaySucessNotification(const FName& InOperationName) +{ + const FText NotificationText = FText::Format( + LOCTEXT("SourceControlMenu_Success", "{0} operation was successful!"), + FText::FromName(InOperationName) + ); + FNotificationInfo Info(NotificationText); + Info.bUseSuccessFailIcons = true; +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + Info.Image = FAppStyle::GetBrush(TEXT("NotificationList.SuccessImage")); +#else + Info.Image = FEditorStyle::GetBrush(TEXT("NotificationList.SuccessImage")); +#endif + FSlateNotificationManager::Get().AddNotification(Info); + UE_LOG(LogSourceControl, Log, TEXT("%s"), *NotificationText.ToString()); +} + +// Display a temporary failure notification at the end of the operation +void FGitSourceControlMenu::DisplayFailureNotification(const FName& InOperationName) +{ + const FText NotificationText = FText::Format( + LOCTEXT("SourceControlMenu_Failure", "Error: {0} operation failed!"), + FText::FromName(InOperationName) + ); + FNotificationInfo Info(NotificationText); + Info.ExpireDuration = 8.0f; + FSlateNotificationManager::Get().AddNotification(Info); + UE_LOG(LogSourceControl, Error, TEXT("%s"), *NotificationText.ToString()); +} + +void FGitSourceControlMenu::OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult) +{ + RemoveInProgressNotification(); + + if ((InOperation->GetName() == "Sync") || (InOperation->GetName() == "Revert")) + { + // Unstash any modifications if a stash was made at the beginning of the Sync operation + ReApplyStashedModifications(); + // Reload packages that where unlinked at the beginning of the Sync/Revert operation + ReloadPackages(PackagesToReload); + } + + // Report result with a notification + if (InResult == ECommandResult::Succeeded) + { + DisplaySucessNotification(InOperation->GetName()); + } + else + { + DisplayFailureNotification(InOperation->GetName()); + } +} + +#if ENGINE_MAJOR_VERSION == 5 +void FGitSourceControlMenu::AddMenuExtension(FToolMenuSection& Builder) +#else +void FGitSourceControlMenu::AddMenuExtension(FMenuBuilder& Builder) +#endif +{ + Builder.AddMenuEntry( +#if ENGINE_MAJOR_VERSION == 5 + "GitPush", +#endif + + LOCTEXT("GitPush", "Push"), + LOCTEXT("GitPushTooltip", "Push all local commits to the remote server."), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + FSlateIcon(FAppStyle::GetAppStyleSetName(), "SourceControl.Actions.Submit"), +#else + FSlateIcon(FEditorStyle::GetStyleSetName(), "SourceControl.Actions.Submit"), +#endif + FUIAction( + FExecuteAction::CreateRaw(this, &FGitSourceControlMenu::PushClicked), + FCanExecuteAction::CreateRaw(this, &FGitSourceControlMenu::HaveRemoteUrl) + ) + ); + + Builder.AddMenuEntry( +#if ENGINE_MAJOR_VERSION == 5 + "GitSync", +#endif + LOCTEXT("GitSync", "Sync/Pull"), + LOCTEXT("GitSyncTooltip", "Update all files in the local repository to the latest version of the remote server."), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + FSlateIcon(FAppStyle::GetAppStyleSetName(), "SourceControl.Actions.Sync"), +#else + FSlateIcon(FEditorStyle::GetStyleSetName(), "SourceControl.Actions.Sync"), +#endif + FUIAction( + FExecuteAction::CreateRaw(this, &FGitSourceControlMenu::SyncClicked), + FCanExecuteAction::CreateRaw(this, &FGitSourceControlMenu::HaveRemoteUrl) + ) + ); + + Builder.AddMenuEntry( +#if ENGINE_MAJOR_VERSION == 5 + "GitRevert", +#endif + LOCTEXT("GitRevert", "Revert"), + LOCTEXT("GitRevertTooltip", "Revert all files in the repository to their unchanged state."), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + FSlateIcon(FAppStyle::GetAppStyleSetName(), "SourceControl.Actions.Revert"), +#else + FSlateIcon(FEditorStyle::GetStyleSetName(), "SourceControl.Actions.Revert"), +#endif + FUIAction( + FExecuteAction::CreateRaw(this, &FGitSourceControlMenu::RevertClicked), + FCanExecuteAction() + ) + ); + + Builder.AddMenuEntry( +#if ENGINE_MAJOR_VERSION == 5 + "GitRefresh", +#endif + LOCTEXT("GitRefresh", "Refresh"), + LOCTEXT("GitRefreshTooltip", "Update the source control status of all files in the local repository."), +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + FSlateIcon(FAppStyle::GetAppStyleSetName(), "SourceControl.Actions.Refresh"), +#else + FSlateIcon(FEditorStyle::GetStyleSetName(), "SourceControl.Actions.Refresh"), +#endif + FUIAction( + FExecuteAction::CreateRaw(this, &FGitSourceControlMenu::RefreshClicked), + FCanExecuteAction() + ) + ); +} + +#if ENGINE_MAJOR_VERSION == 4 +TSharedRef FGitSourceControlMenu::OnExtendLevelEditorViewMenu(const TSharedRef CommandList) +{ + TSharedRef Extender(new FExtender()); + + Extender->AddMenuExtension( + "SourceControlActions", + EExtensionHook::After, + nullptr, + FMenuExtensionDelegate::CreateRaw(this, &FGitSourceControlMenu::AddMenuExtension)); + + return Extender; +} +#endif + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.h new file mode 100644 index 0000000..d8a4ece --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlMenu.h @@ -0,0 +1,65 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlProvider.h" + +#include "Runtime/Launch/Resources/Version.h" + +/** Git extension of the Source Control toolbar menu */ +class FGitSourceControlMenu +{ +public: + void Register(); + void Unregister(); + + /** This functions will be bound to appropriate Command. */ + void PushClicked(); + void SyncClicked(); + void RevertClicked(); + void RefreshClicked(); + +private: + bool HaveRemoteUrl() const; + + bool SaveDirtyPackages(); + TArray ListAllPackages(); + TArray UnlinkPackages(const TArray& InPackageNames); + void ReloadPackages(TArray& InPackagesToReload); + + bool StashAwayAnyModifications(); + void ReApplyStashedModifications(); + +#if ENGINE_MAJOR_VERSION == 5 + void AddMenuExtension(struct FToolMenuSection& Builder); +#else + void AddMenuExtension(class FMenuBuilder& Builder); + TSharedRef OnExtendLevelEditorViewMenu(const TSharedRef CommandList); +#endif + + void DisplayInProgressNotification(const FText& InOperationInProgressString); + void RemoveInProgressNotification(); + void DisplaySucessNotification(const FName& InOperationName); + void DisplayFailureNotification(const FName& InOperationName); + +private: +#if ENGINE_MAJOR_VERSION == 4 + FDelegateHandle ViewMenuExtenderHandle; +#endif + + /** Was there a need to stash away modifications before Sync? */ + bool bStashMadeBeforeSync; + + /** Loaded packages to reload after a Sync or Revert operation */ + TArray PackagesToReload; + + /** Current source control operation from extended menu if any */ + TWeakPtr OperationInProgressNotification; + + /** Delegate called when a source control operation has completed */ + void OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult); +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.cpp new file mode 100644 index 0000000..395fc29 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlModule.h" + +#include "Misc/App.h" +#include "Modules/ModuleManager.h" +#include "GitSourceControlOperations.h" +#include "Features/IModularFeatures.h" + +#define LOCTEXT_NAMESPACE "GitSourceControl" + +template +static TSharedRef CreateWorker() +{ + return MakeShareable( new Type() ); +} + +void FGitSourceControlModule::StartupModule() +{ + // Register our operations (implemented in GitSourceControlOperations.cpp by subclassing from Engine\Source\Developer\SourceControl\Public\SourceControlOperations.h) + GitSourceControlProvider.RegisterWorker( "Connect", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + // Note: this provider uses the "CheckOut" command only with Git LFS 2 "lock" command, since Git itself has no lock command (all tracked files in the working copy are always already checked-out). + GitSourceControlProvider.RegisterWorker( "CheckOut", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "UpdateStatus", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "MarkForAdd", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Delete", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Revert", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Sync", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Push", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "CheckIn", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Copy", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + GitSourceControlProvider.RegisterWorker( "Resolve", FGetGitSourceControlWorker::CreateStatic( &CreateWorker ) ); + + // load our settings + GitSourceControlSettings.LoadSettings(); + + // Bind our source control provider to the editor + IModularFeatures::Get().RegisterModularFeature( "SourceControl", &GitSourceControlProvider ); +} + +void FGitSourceControlModule::ShutdownModule() +{ + // shut down the provider, as this module is going away + GitSourceControlProvider.Close(); + + // unbind provider from editor + IModularFeatures::Get().UnregisterModularFeature("SourceControl", &GitSourceControlProvider); +} + +void FGitSourceControlModule::SaveSettings() +{ + if (FApp::IsUnattended() || IsRunningCommandlet()) + { + return; + } + + GitSourceControlSettings.SaveSettings(); +} + +IMPLEMENT_MODULE(FGitSourceControlModule, GitSourceControl); + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.h new file mode 100644 index 0000000..d8d8a5c --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlModule.h @@ -0,0 +1,116 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleInterface.h" +#include "GitSourceControlSettings.h" +#include "GitSourceControlProvider.h" + +/** + +UE4GitPlugin is a simple Git Source Control Plugin for Unreal Engine + +Written and contributed by Sebastien Rombauts (sebastien.rombauts@gmail.com) + +### Supported features +- initialize a new Git local repository ('git init') to manage your Unreal Engine 4 and 5 Game Project + - can also create an appropriate .gitignore file as part of initialization + - can also create a .gitattributes file to enable Git LFS (Large File System) as part of initialization + - can also make the initial commit, with custom multi-line message + - can also configure the default remote origin URL +- display status icons to show modified/added/deleted/untracked files +- show history of a file +- visual diff of a blueprint against depot or between previous versions of a file +- revert modifications of a file +- add, delete, rename a file +- checkin/commit a file (cannot handle atomically more than 50 files) +- migrate an asset between two projects if both are using Git +- solve a merge conflict on a blueprint +- show current branch name in status text +- Sync to Pull (rebase) the current branch +- Git LFS (Github, Gitlab, Bitbucket) is working with Git 2.10+ under Windows +- Git LFS 2 File Locking is working with Git 2.10+ and Git LFS 2.0.0 +- Windows, Mac and Linux + +### TODO +1. configure the name of the remote instead of default "origin" + +### TODO LFS 2.x File Locking + +Known issues: +0. False error logs after a successful push: +To https://github.com/SRombauts/UE4GitLfs2FileLocks.git + ee44ff5..59da15e HEAD -> master + +Use "TODO LFS" in the code to track things left to do/improve/refactor: +1. IsUsingGitLfsLocking() should be cached in the Provider to avoid calling AccessSettings() too frequently + it can not change without re-initializing (at least re-connect) the Provider! +2. Implement FGitSourceControlProvider::bWorkingOffline like the SubversionSourceControl plugin +3. Trying to deactivate Git LFS 2 file locking afterward on the "Login to Source Control" (Connect/Configure) screen + is not working after Git LFS 2 has switched "read-only" flag on files (which needs the Checkout operation to be editable)! + - temporarily deactivating locks may be required if we want to be able to work while not connected (do we really need this ???) + - does Git LFS have a command to do this deactivation ? + - perhaps should we rely on detection of such flags to detect LFS 2 usage (ie. the need to do a checkout) + - see SubversionSourceControl plugin that deals with such flags + - this would need a rework of the way the "bIsUsingFileLocking" is propagated, since this would no more be a configuration (or not only) but a file state + - else we should at least revert those read-only flags when going out of "Lock mode" +4. Optimize usage of "git lfs locks", ie reduce the use of UdpateStatus() in Operations + +### What *cannot* be done presently +- Branch/Merge are not in the current Editor workflow +- Fetch is not in the current Editor workflow +- Amend a commit is not in the current Editor workflow +- Configure user name & email ('git config user.name' & git config user.email') + +### Known issues +- the Editor does not show deleted files (only when deleted externally?) +- the Editor does not show missing files +- missing localization for git specific messages +- displaying states of 'Engine' assets (also needs management of 'out of tree' files) +- renaming a Blueprint in Editor leaves a redirector file, AND modify too much the asset to enable git to track its history through renaming +- standard Editor commit dialog asks if user wants to "Keep Files Checked Out" => no use for Git or Mercurial CanCheckOut()==false + + */ +class FGitSourceControlModule : public IModuleInterface +{ +public: + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + /** Access the Git source control settings */ + FGitSourceControlSettings& AccessSettings() + { + return GitSourceControlSettings; + } + + const FGitSourceControlSettings& AccessSettings() const + { + return GitSourceControlSettings; + } + + /** Save the Git source control settings */ + void SaveSettings(); + + /** Access the Git source control provider */ + FGitSourceControlProvider& GetProvider() + { + return GitSourceControlProvider; + } + + const FGitSourceControlProvider& GetProvider() const + { + return GitSourceControlProvider; + } + +private: + /** The Git source control provider */ + FGitSourceControlProvider GitSourceControlProvider; + + /** The settings for Git source control */ + FGitSourceControlSettings GitSourceControlSettings; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp new file mode 100644 index 0000000..5990804 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.cpp @@ -0,0 +1,654 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlOperations.h" + +#include "Misc/Paths.h" +#include "Modules/ModuleManager.h" +#include "SourceControlOperations.h" +#include "ISourceControlModule.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlCommand.h" +#include "GitSourceControlUtils.h" +#include "Logging/MessageLog.h" +#include "Misc/MessageDialog.h" + +#define LOCTEXT_NAMESPACE "GitSourceControl" + +FName FGitPush::GetName() const +{ + return "Push"; +} + +FText FGitPush::GetInProgressString() const +{ + // TODO Configure origin + return LOCTEXT("SourceControl_Push", "Pushing local commits to remote origin..."); +} + + +FName FGitConnectWorker::GetName() const +{ + return "Connect"; +} + +bool FGitConnectWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + TSharedRef Operation = StaticCastSharedRef(InCommand.Operation); + + // Check Git Availability + if((InCommand.PathToGitBinary.Len() > 0) && GitSourceControlUtils::CheckGitAvailability(InCommand.PathToGitBinary)) + { + // Now update the status of assets in Content/ directory and also Config files + TArray ProjectDirs; + ProjectDirs.Add(FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir())); + ProjectDirs.Add(FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir())); + InCommand.bCommandSuccessful = GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, ProjectDirs, InCommand.ErrorMessages, States); + if(!InCommand.bCommandSuccessful || InCommand.ErrorMessages.Num() > 0) + { + Operation->SetErrorText(LOCTEXT("NotAGitRepository", "Failed to enable Git source control. You need to initialize the project as a Git repository first.")); + InCommand.bCommandSuccessful = false; + } + else + { + GitSourceControlUtils::GetCommitInfo(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.CommitId, InCommand.CommitSummary); + + if(InCommand.bUsingGitLfsLocking) + { + // Check server connection by checking lock status (when using Git LFS file Locking worflow) + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("lfs locks"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), TArray(), InCommand.InfoMessages, InCommand.ErrorMessages); + } + } + } + else + { + Operation->SetErrorText(LOCTEXT("GitNotFound", "Failed to enable Git source control. You need to install Git and specify a valid path to git executable.")); + InCommand.bCommandSuccessful = false; + } + + return InCommand.bCommandSuccessful; +} + +bool FGitConnectWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitCheckOutWorker::GetName() const +{ + return "CheckOut"; +} + +bool FGitCheckOutWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + if(InCommand.bUsingGitLfsLocking) + { + // lock files: execute the LFS command on relative filenames + InCommand.bCommandSuccessful = true; + const TArray RelativeFiles = GitSourceControlUtils::RelativeFilenames(InCommand.Files, InCommand.PathToRepositoryRoot); + for(const auto& RelativeFile : RelativeFiles) + { + TArray OneFile; + OneFile.Add(RelativeFile); + InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand(TEXT("lfs lock"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), OneFile, InCommand.InfoMessages, InCommand.ErrorMessages); + } + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + } + else + { + InCommand.bCommandSuccessful = false; + } + + return InCommand.bCommandSuccessful; +} + +bool FGitCheckOutWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +static FText ParseCommitResults(const TArray& InResults) +{ + if(InResults.Num() >= 1) + { + const FString& FirstLine = InResults[0]; + return FText::Format(LOCTEXT("CommitMessage", "Commited {0}."), FText::FromString(FirstLine)); + } + return LOCTEXT("CommitMessageUnknown", "Submitted revision."); +} + +// Get Locked Files (that is, CheckedOut files, not Added ones) +const TArray GetLockedFiles(const TArray& InFiles) +{ + TArray LockedFiles; + + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + + TArray> LocalStates; + Provider.GetState(InFiles, LocalStates, EStateCacheUsage::Use); + for(const auto& State : LocalStates) + { + if(State->IsCheckedOut()) + { + LockedFiles.Add(State->GetFilename()); + } + } + + return LockedFiles; +} + +FName FGitCheckInWorker::GetName() const +{ + return "CheckIn"; +} + +bool FGitCheckInWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + TSharedRef Operation = StaticCastSharedRef(InCommand.Operation); + + // make a temp file to place our commit message in + FGitScopedTempFile CommitMsgFile(Operation->GetDescription()); + if(CommitMsgFile.GetFilename().Len() > 0) + { + TArray Parameters; + FString ParamCommitMsgFilename = TEXT("--file=\""); + ParamCommitMsgFilename += FPaths::ConvertRelativePathToFull(CommitMsgFile.GetFilename()); + ParamCommitMsgFilename += TEXT("\""); + Parameters.Add(ParamCommitMsgFilename); + + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommit(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, Parameters, InCommand.Files, InCommand.InfoMessages, InCommand.ErrorMessages); + if(InCommand.bCommandSuccessful) + { + // Remove any deleted files from status cache + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + + TArray> LocalStates; + Provider.GetState(InCommand.Files, LocalStates, EStateCacheUsage::Use); + for(const auto& State : LocalStates) + { + if(State->IsDeleted()) + { + Provider.RemoveFileFromCache(State->GetFilename()); + } + } + + Operation->SetSuccessMessage(ParseCommitResults(InCommand.InfoMessages)); + const FString Message = (InCommand.InfoMessages.Num() > 0) ? InCommand.InfoMessages[0] : TEXT(""); + UE_LOG(LogSourceControl, Log, TEXT("commit successful: %s"), *Message); + + // git-lfs: push and unlock files + if(InCommand.bUsingGitLfsLocking && + InCommand.bCommandSuccessful && + GitSourceControl.AccessSettings().IsPushAfterCommitEnabled()) + { + TArray Parameters2; + // TODO Configure origin + Parameters2.Add(TEXT("origin")); + Parameters2.Add(TEXT("HEAD")); + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("push"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, Parameters2, TArray(), InCommand.InfoMessages, InCommand.ErrorMessages); + if(!InCommand.bCommandSuccessful) + { + // if out of date, pull first, then try again + bool bWasOutOfDate = false; + for (const auto& PushError : InCommand.ErrorMessages) + { + if (PushError.Contains(TEXT("[rejected]")) && PushError.Contains(TEXT("non-fast-forward"))) + { + // Don't do it during iteration, want to append pull results to InCommand.ErrorMessages + bWasOutOfDate = true; + break; + } + } + if (bWasOutOfDate) + { + // Trying to resolve this automatically can cause too many problems because UE being open prevents + // LFS files from being replaced, meaning the rebase fails which is a nasty place to be for + // unfamiliar Git users. Better to ask them to close UE and pull externally to be safe + FText PushFailMessage(LOCTEXT("GitPush_OutOfDate_Msg", "Git Push failed because there are changes you need to pull. \n" + "However, pulling while the Unreal Editor is open can cause conflicts since files cannot always be replaced. We recommend" + "you exit the editor, and run the following command:\n\n" + " git pull --rebase --autostash\n\n" + "Or run the equivalent in a Git GUI client of your choice")); + FText PushFailTitle(LOCTEXT("GitPush_OutOfDate_Title", "Git Pull Required")); + FMessageDialog::Open(EAppMsgType::Ok, PushFailMessage, &PushFailTitle); + UE_LOG(LogSourceControl, Log, TEXT("Push failed because we're out of date, prompting user to resolve manually")); + } + } + if(InCommand.bCommandSuccessful) + { + // unlock files: execute the LFS command on relative filenames + // (unlock only locked files, that is, not Added files) + const TArray LockedFiles = GetLockedFiles(InCommand.Files); + if(LockedFiles.Num() > 0) + { + const TArray RelativeFiles = GitSourceControlUtils::RelativeFilenames(LockedFiles, InCommand.PathToRepositoryRoot); + for(const auto& RelativeFile : RelativeFiles) + { + TArray OneFile; + OneFile.Add(RelativeFile); + GitSourceControlUtils::RunCommand(TEXT("lfs unlock"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), OneFile, InCommand.InfoMessages, InCommand.ErrorMessages); + } + } + } + } + } + } + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + GitSourceControlUtils::GetCommitInfo(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.CommitId, InCommand.CommitSummary); + + return InCommand.bCommandSuccessful; +} + +bool FGitCheckInWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitMarkForAddWorker::GetName() const +{ + return "MarkForAdd"; +} + +bool FGitMarkForAddWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("add"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), InCommand.Files, InCommand.InfoMessages, InCommand.ErrorMessages); + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + + return InCommand.bCommandSuccessful; +} + +bool FGitMarkForAddWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitDeleteWorker::GetName() const +{ + return "Delete"; +} + +bool FGitDeleteWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("rm"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), InCommand.Files, InCommand.InfoMessages, InCommand.ErrorMessages); + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + + return InCommand.bCommandSuccessful; +} + +bool FGitDeleteWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + + +// Get lists of Missing files (ie "deleted"), Modified files, and "other than Added" Existing files +void GetMissingVsExistingFiles(const TArray& InFiles, TArray& OutMissingFiles, TArray& OutAllExistingFiles, TArray& OutOtherThanAddedExistingFiles) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + + const TArray Files = (InFiles.Num() > 0) ? (InFiles) : (Provider.GetFilesInCache()); + + TArray> LocalStates; + Provider.GetState(Files, LocalStates, EStateCacheUsage::Use); + for(const auto& State : LocalStates) + { + if(FPaths::FileExists(State->GetFilename())) + { + if(State->IsAdded()) + { + OutAllExistingFiles.Add(State->GetFilename()); + } + else if(State->IsModified()) + { + OutOtherThanAddedExistingFiles.Add(State->GetFilename()); + OutAllExistingFiles.Add(State->GetFilename()); + } + else if(State->CanRevert()) // for locked but unmodified files + { + OutOtherThanAddedExistingFiles.Add(State->GetFilename()); + } + } + else + { + if (State->IsSourceControlled()) + { + OutMissingFiles.Add(State->GetFilename()); + } + } + } +} + +FName FGitRevertWorker::GetName() const +{ + return "Revert"; +} + +bool FGitRevertWorker::Execute(FGitSourceControlCommand& InCommand) +{ + // Filter files by status to use the right "revert" commands on them + TArray MissingFiles; + TArray AllExistingFiles; + TArray OtherThanAddedExistingFiles; + GetMissingVsExistingFiles(InCommand.Files, MissingFiles, AllExistingFiles, OtherThanAddedExistingFiles); + + InCommand.bCommandSuccessful = true; + if(MissingFiles.Num() > 0) + { + // "Added" files that have been deleted needs to be removed from source control + InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand(TEXT("rm"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), MissingFiles, InCommand.InfoMessages, InCommand.ErrorMessages); + } + if(AllExistingFiles.Num() > 0) + { + // reset any changes already added to the index + InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand(TEXT("reset"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), AllExistingFiles, InCommand.InfoMessages, InCommand.ErrorMessages); + } + if(OtherThanAddedExistingFiles.Num() > 0) + { + // revert any changes in working copy (this would fails if the asset was in "Added" state, since after "reset" it is now "untracked") + InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand(TEXT("checkout"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), OtherThanAddedExistingFiles, InCommand.InfoMessages, InCommand.ErrorMessages); + } + + if(InCommand.bUsingGitLfsLocking) + { + // unlock files: execute the LFS command on relative filenames + // (unlock only locked files, that is, not Added files) + const TArray LockedFiles = GetLockedFiles(OtherThanAddedExistingFiles); + if(LockedFiles.Num() > 0) + { + const TArray RelativeFiles = GitSourceControlUtils::RelativeFilenames(LockedFiles, InCommand.PathToRepositoryRoot); + for(const auto& RelativeFile : RelativeFiles) + { + TArray OneFile; + OneFile.Add(RelativeFile); + GitSourceControlUtils::RunCommand(TEXT("lfs unlock"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), OneFile, InCommand.InfoMessages, InCommand.ErrorMessages); + } + } + } + + // If no files were specified (full revert), refresh all relevant files instead of the specified files (which is an empty list in full revert) + // This is required so that files that were "Marked for add" have their status updated after a full revert. + TArray FilesToUpdate = InCommand.Files; + if (InCommand.Files.Num() <= 0) + { + for (const auto& File : MissingFiles) FilesToUpdate.Add(File); + for (const auto& File : AllExistingFiles) FilesToUpdate.Add(File); + for (const auto& File : OtherThanAddedExistingFiles) FilesToUpdate.Add(File); + } + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, FilesToUpdate, InCommand.ErrorMessages, States); + + return InCommand.bCommandSuccessful; +} + +bool FGitRevertWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitSyncWorker::GetName() const +{ + return "Sync"; +} + +bool FGitSyncWorker::Execute(FGitSourceControlCommand& InCommand) +{ + // pull the branch to get remote changes by rebasing any local commits (not merging them to avoid complex graphs) + TArray Parameters; + Parameters.Add(TEXT("--rebase")); + Parameters.Add(TEXT("--autostash")); + // TODO Configure origin + Parameters.Add(TEXT("origin")); + Parameters.Add(TEXT("HEAD")); + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("pull"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, Parameters, TArray(), InCommand.InfoMessages, InCommand.ErrorMessages); + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + GitSourceControlUtils::GetCommitInfo(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.CommitId, InCommand.CommitSummary); + + return InCommand.bCommandSuccessful; +} + +bool FGitSyncWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + + +FName FGitPushWorker::GetName() const +{ + return "Push"; +} + +bool FGitPushWorker::Execute(FGitSourceControlCommand& InCommand) +{ + + // If we have any locked files, check if we should unlock them + TArray FilesToUnlock; + if (InCommand.bUsingGitLfsLocking) + { + TMap Locks; + // Get locks as relative paths + GitSourceControlUtils::GetAllLocks(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, false, InCommand.ErrorMessages, Locks); + if(Locks.Num() > 0) + { + // test to see what lfs files we would push, and compare to locked files, unlock after if push OK + FString BranchName; + GitSourceControlUtils::GetBranchName(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, BranchName); + + TArray LfsPushParameters; + LfsPushParameters.Add(TEXT("push")); + LfsPushParameters.Add(TEXT("--dry-run")); + LfsPushParameters.Add(TEXT("origin")); + LfsPushParameters.Add(BranchName); + TArray LfsPushInfoMessages; + TArray LfsPushErrMessages; + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("lfs"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, LfsPushParameters, TArray(), LfsPushInfoMessages, LfsPushErrMessages); + + if(InCommand.bCommandSuccessful) + { + // Result format is of the form + // push f4ee401c063058a78842bb3ed98088e983c32aa447f346db54fa76f844a7e85e => Path/To/Asset.uasset + // With some potential informationals we can ignore + for (auto& Line : LfsPushInfoMessages) + { + if (Line.StartsWith(TEXT("push"))) + { + FString Prefix, Filename; + if (Line.Split(TEXT("=>"), &Prefix, &Filename)) + { + Filename = Filename.TrimStartAndEnd(); + if (Locks.Contains(Filename)) + { + // We do not need to check user or if the file has local modifications before attempting unlocking, git-lfs will reject the unlock if so + // No point duplicating effort here + FilesToUnlock.Add(Filename); + UE_LOG(LogSourceControl, Log, TEXT("Post-push will try to unlock: %s"), *Filename); + } + } + } + } + } + } + + } + // push the branch to its default remote + // (works only if the default remote "origin" is set and does not require authentication) + TArray Parameters; + Parameters.Add(TEXT("--set-upstream")); + // TODO Configure origin + Parameters.Add(TEXT("origin")); + Parameters.Add(TEXT("HEAD")); + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("push"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, Parameters, TArray(), InCommand.InfoMessages, InCommand.ErrorMessages); + + if(InCommand.bCommandSuccessful && InCommand.bUsingGitLfsLocking && FilesToUnlock.Num() > 0) + { + // unlock files: execute the LFS command on relative filenames + for(const auto& FileToUnlock : FilesToUnlock) + { + TArray OneFile; + OneFile.Add(FileToUnlock); + bool bUnlocked = GitSourceControlUtils::RunCommand(TEXT("lfs unlock"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), OneFile, InCommand.InfoMessages, InCommand.ErrorMessages); + if (!bUnlocked) + { + // Report but don't fail, it's not essential + UE_LOG(LogSourceControl, Log, TEXT("Unlock failed for %s"), *FileToUnlock); + } + } + + // We need to update status if we unlock + // This command needs absolute filenames + TArray AbsFilesToUnlock = GitSourceControlUtils::AbsoluteFilenames(FilesToUnlock, InCommand.PathToRepositoryRoot); + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, AbsFilesToUnlock, InCommand.ErrorMessages, States); + + } + + return InCommand.bCommandSuccessful; +} + +bool FGitPushWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitUpdateStatusWorker::GetName() const +{ + return "UpdateStatus"; +} + +bool FGitUpdateStatusWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + TSharedRef Operation = StaticCastSharedRef(InCommand.Operation); + + if(InCommand.Files.Num() > 0) + { + InCommand.bCommandSuccessful = GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + GitSourceControlUtils::RemoveRedundantErrors(InCommand, TEXT("' is outside repository")); + + if(Operation->ShouldUpdateHistory()) + { + for(int32 Index = 0; Index < States.Num(); Index++) + { + FString& File = InCommand.Files[Index]; + TGitSourceControlHistory History; + + if(States[Index].IsConflicted()) + { + // In case of a merge conflict, we first need to get the tip of the "remote branch" (MERGE_HEAD) + GitSourceControlUtils::RunGetHistory(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, File, true, InCommand.ErrorMessages, History); + } + // Get the history of the file in the current branch + InCommand.bCommandSuccessful &= GitSourceControlUtils::RunGetHistory(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, File, false, InCommand.ErrorMessages, History); + Histories.Add(*File, History); + } + } + } + else + { + // no path provided: only update the status of assets in Content/ directory and also Config files + TArray ProjectDirs; + ProjectDirs.Add(FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir())); + ProjectDirs.Add(FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir())); + InCommand.bCommandSuccessful = GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, ProjectDirs, InCommand.ErrorMessages, States); + } + + GitSourceControlUtils::GetCommitInfo(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.CommitId, InCommand.CommitSummary); + + // don't use the ShouldUpdateModifiedState() hint here as it is specific to Perforce: the above normal Git status has already told us this information (like Git and Mercurial) + + return InCommand.bCommandSuccessful; +} + +bool FGitUpdateStatusWorker::UpdateStates() const +{ + bool bUpdated = GitSourceControlUtils::UpdateCachedStates(States); + + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked( "GitSourceControl" ); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + + const FDateTime Now = FDateTime::Now(); + + // add history, if any + for(const auto& History : Histories) + { + TSharedRef State = Provider.GetStateInternal(History.Key); + State->History = History.Value; + State->TimeStamp = Now; + bUpdated = true; + } + + return bUpdated; +} + +FName FGitCopyWorker::GetName() const +{ + return "Copy"; +} + +bool FGitCopyWorker::Execute(FGitSourceControlCommand& InCommand) +{ + check(InCommand.Operation->GetName() == GetName()); + + // Copy or Move operation on a single file : Git does not need an explicit copy nor move, + // but after a Move the Editor create a redirector file with the old asset name that points to the new asset. + // The redirector needs to be commited with the new asset to perform a real rename. + // => the following is to "MarkForAdd" the redirector, but it still need to be committed by selecting the whole directory and "check-in" + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("add"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), InCommand.Files, InCommand.InfoMessages, InCommand.ErrorMessages); + + return InCommand.bCommandSuccessful; +} + +bool FGitCopyWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +FName FGitResolveWorker::GetName() const +{ + return "Resolve"; +} + +bool FGitResolveWorker::Execute( class FGitSourceControlCommand& InCommand ) +{ + check(InCommand.Operation->GetName() == GetName()); + + // mark the conflicting files as resolved: + TArray Results; + InCommand.bCommandSuccessful = GitSourceControlUtils::RunCommand(TEXT("add"), InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, TArray(), InCommand.Files, Results, InCommand.ErrorMessages); + + // now update the status of our files + GitSourceControlUtils::RunUpdateStatus(InCommand.PathToGitBinary, InCommand.PathToRepositoryRoot, InCommand.bUsingGitLfsLocking, InCommand.Files, InCommand.ErrorMessages, States); + + return InCommand.bCommandSuccessful; +} + +bool FGitResolveWorker::UpdateStates() const +{ + return GitSourceControlUtils::UpdateCachedStates(States); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.h new file mode 100644 index 0000000..96f91e7 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlOperations.h @@ -0,0 +1,192 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "IGitSourceControlWorker.h" +#include "GitSourceControlState.h" + +#include "ISourceControlOperation.h" + +/** + * Internal operation used to push local commits to configured remote origin +*/ +class FGitPush : public ISourceControlOperation +{ +public: + // ISourceControlOperation interface + virtual FName GetName() const override; + + virtual FText GetInProgressString() const override; +}; + +/** Called when first activated on a project, and then at project load time. + * Look for the root directory of the git repository (where the ".git/" subdirectory is located). */ +class FGitConnectWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitConnectWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Lock (check-out) a set of files using Git LFS 2. */ +class FGitCheckOutWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitCheckOutWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Commit (check-in) a set of files to the local depot. */ +class FGitCheckInWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitCheckInWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Add an untraked file to source control (so only a subset of the git add command). */ +class FGitMarkForAddWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitMarkForAddWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Delete a file and remove it from source control. */ +class FGitDeleteWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitDeleteWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Revert any change to a file to its state on the local depot. */ +class FGitRevertWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitRevertWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Git pull --rebase to update branch from its configured remote */ +class FGitSyncWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitSyncWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Git push to publish branch for its configured remote */ +class FGitPushWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitPushWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** Get source control status of files on local working copy. */ +class FGitUpdateStatusWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitUpdateStatusWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; + + /** Map of filenames to history */ + TMap Histories; +}; + +/** Copy or Move operation on a single file */ +class FGitCopyWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitCopyWorker() {} + // IGitSourceControlWorker interface + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +public: + /** Temporary states for results */ + TArray States; +}; + +/** git add to mark a conflict as resolved */ +class FGitResolveWorker : public IGitSourceControlWorker +{ +public: + virtual ~FGitResolveWorker() {} + virtual FName GetName() const override; + virtual bool Execute(class FGitSourceControlCommand& InCommand) override; + virtual bool UpdateStates() const override; + +private: + /** Temporary states for results */ + TArray States; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlPrivatePCH.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlPrivatePCH.h new file mode 100644 index 0000000..fbf6dee --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlPrivatePCH.h @@ -0,0 +1,15 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlModule.h" +#include "ISourceControlOperation.h" +#include "ISourceControlProvider.h" +#include "ISourceControlRevision.h" +#include "ISourceControlState.h" +#include "Misc/Paths.h" +#include "Modules/ModuleManager.h" diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp new file mode 100644 index 0000000..4f72170 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.cpp @@ -0,0 +1,531 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlProvider.h" + +#include "HAL/PlatformProcess.h" +#include "Misc/Paths.h" +#include "Misc/QueuedThreadPool.h" +#include "Modules/ModuleManager.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "GitSourceControlCommand.h" +#include "ISourceControlModule.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlUtils.h" +#include "SGitSourceControlSettings.h" +#include "Logging/MessageLog.h" +#include "ScopedSourceControlProgress.h" +#include "SourceControlHelpers.h" +#include "SourceControlOperations.h" +#include "Interfaces/IPluginManager.h" + +#define LOCTEXT_NAMESPACE "GitSourceControl" + +static FName ProviderName("Git LFS 2"); + +void FGitSourceControlProvider::Init(bool bForceConnection) +{ + // Init() is called multiple times at startup: do not check git each time + if (!bGitAvailable) + { + const TSharedPtr Plugin = IPluginManager::Get().FindPlugin(TEXT("GitSourceControl")); + if (Plugin.IsValid()) + { + UE_LOG(LogSourceControl, Log, TEXT("Git plugin '%s'"), *(Plugin->GetDescriptor().VersionName)); + } + + CheckGitAvailability(); + + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + bUsingGitLfsLocking = GitSourceControl.AccessSettings().IsUsingGitLfsLocking(); + } + + // bForceConnection: not used anymore +} + +void FGitSourceControlProvider::CheckGitAvailability() +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + FString PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + if (PathToGitBinary.IsEmpty()) + { + // Try to find Git binary, and update settings accordingly + PathToGitBinary = GitSourceControlUtils::FindGitBinaryPath(); + if (!PathToGitBinary.IsEmpty()) + { + GitSourceControl.AccessSettings().SetBinaryPath(PathToGitBinary); + } + } + + if (!PathToGitBinary.IsEmpty()) + { + UE_LOG(LogSourceControl, Log, TEXT("Using '%s'"), *PathToGitBinary); + bGitAvailable = GitSourceControlUtils::CheckGitAvailability(PathToGitBinary, &GitVersion); + if (bGitAvailable) + { + CheckRepositoryStatus(PathToGitBinary); + + // Register Console Commands (even without a workspace) + GitSourceControlConsole.Register(); + } + } + else + { + bGitAvailable = false; + } +} + +void FGitSourceControlProvider::CheckRepositoryStatus(const FString& InPathToGitBinary) +{ + // Find the path to the root Git directory (if any, else uses the ProjectDir) + const FString PathToProjectDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()); + bGitRepositoryFound = GitSourceControlUtils::FindRootDirectory(PathToProjectDir, PathToRepositoryRoot); + if (bGitRepositoryFound) + { + GitSourceControlMenu.Register(); + + // Get branch name + bGitRepositoryFound = GitSourceControlUtils::GetBranchName(InPathToGitBinary, PathToRepositoryRoot, BranchName); + if (bGitRepositoryFound) + { + GitSourceControlUtils::GetRemoteUrl(InPathToGitBinary, PathToRepositoryRoot, RemoteUrl); + } + else + { + UE_LOG(LogSourceControl, Error, TEXT("'%s' is not a valid Git repository"), *PathToRepositoryRoot); + } + } + else + { + UE_LOG(LogSourceControl, Warning, TEXT("'%s' is not part of a Git repository"), *FPaths::ProjectDir()); + } + + // Get user name & email (of the repository, else from the global Git config) + GitSourceControlUtils::GetUserConfig(InPathToGitBinary, PathToRepositoryRoot, UserName, UserEmail); +} + +void FGitSourceControlProvider::Close() +{ + // clear the cache + StateCache.Empty(); + // Remove all extensions to the "Source Control" menu in the Editor Toolbar + GitSourceControlMenu.Unregister(); + // Unregister Console Commands + GitSourceControlConsole.Unregister(); + + bGitAvailable = false; + bGitRepositoryFound = false; + UserName.Empty(); + UserEmail.Empty(); +} + +TSharedRef FGitSourceControlProvider::GetStateInternal(const FString& Filename) +{ + TSharedRef* State = StateCache.Find(Filename); + if (State != NULL) + { + // found cached item + return (*State); + } + else + { + // cache an unknown state for this item + TSharedRef NewState = MakeShareable(new FGitSourceControlState(Filename, bUsingGitLfsLocking)); + StateCache.Add(Filename, NewState); + return NewState; + } +} + +FText FGitSourceControlProvider::GetStatusText() const +{ + FFormatNamedArguments Args; + Args.Add(TEXT("RepositoryName"), FText::FromString(PathToRepositoryRoot)); + Args.Add(TEXT("RemoteUrl"), FText::FromString(RemoteUrl)); + Args.Add(TEXT("UserName"), FText::FromString(UserName)); + Args.Add(TEXT("UserEmail"), FText::FromString(UserEmail)); + Args.Add(TEXT("BranchName"), FText::FromString(BranchName)); + Args.Add(TEXT("CommitId"), FText::FromString(CommitId.Left(8))); + Args.Add(TEXT("CommitSummary"), FText::FromString(CommitSummary)); + + return FText::Format(NSLOCTEXT("Status", "Provider: Git\nEnabledLabel", "Local repository: {RepositoryName}\nRemote origin: {RemoteUrl}\nUser: {UserName}\nE-mail: {UserEmail}\n[{BranchName} {CommitId}] {CommitSummary}"), Args); +} + +/** Quick check if source control is enabled */ +bool FGitSourceControlProvider::IsEnabled() const +{ + return bGitRepositoryFound; +} + +/** Quick check if source control is available for use (useful for server-based providers) */ +bool FGitSourceControlProvider::IsAvailable() const +{ + return bGitRepositoryFound; +} + +const FName& FGitSourceControlProvider::GetName(void) const +{ + return ProviderName; +} + +ECommandResult::Type FGitSourceControlProvider::GetState(const TArray& InFiles, TArray>& OutState, EStateCacheUsage::Type InStateCacheUsage) +{ + if (!IsEnabled()) + { + return ECommandResult::Failed; + } + + TArray AbsoluteFiles = SourceControlHelpers::AbsoluteFilenames(InFiles); + + if (InStateCacheUsage == EStateCacheUsage::ForceUpdate) + { + Execute(ISourceControlOperation::Create(), AbsoluteFiles); + } + + for (const auto& AbsoluteFile : AbsoluteFiles) + { + OutState.Add(GetStateInternal(*AbsoluteFile)); + } + + return ECommandResult::Succeeded; +} + +#if ENGINE_MAJOR_VERSION == 5 +ECommandResult::Type FGitSourceControlProvider::GetState(const TArray& InChangelists, TArray& OutState, EStateCacheUsage::Type InStateCacheUsage) +{ + return ECommandResult::Failed; +} +#endif + +TArray FGitSourceControlProvider::GetCachedStateByPredicate(TFunctionRef Predicate) const +{ + TArray Result; + for (const auto& CacheItem : StateCache) + { + FSourceControlStateRef State = CacheItem.Value; + if (Predicate(State)) + { + Result.Add(State); + } + } + return Result; +} + +bool FGitSourceControlProvider::RemoveFileFromCache(const FString& Filename) +{ + return StateCache.Remove(Filename) > 0; +} + +/** Get files in cache */ +TArray FGitSourceControlProvider::GetFilesInCache() +{ + TArray Files; + for (const auto& State : StateCache) + { + Files.Add(State.Key); + } + return Files; +} + +FDelegateHandle FGitSourceControlProvider::RegisterSourceControlStateChanged_Handle(const FSourceControlStateChanged::FDelegate& SourceControlStateChanged) +{ + return OnSourceControlStateChanged.Add(SourceControlStateChanged); +} + +void FGitSourceControlProvider::UnregisterSourceControlStateChanged_Handle(FDelegateHandle Handle) +{ + OnSourceControlStateChanged.Remove(Handle); +} + +#if ENGINE_MAJOR_VERSION == 5 +ECommandResult::Type FGitSourceControlProvider::Execute(const FSourceControlOperationRef& InOperation, FSourceControlChangelistPtr InChangelist, const TArray& InFiles, EConcurrency::Type InConcurrency /* = EConcurrency::Synchronous */, const FSourceControlOperationComplete& InOperationCompleteDelegate) +#else +ECommandResult::Type FGitSourceControlProvider::Execute(const TSharedRef& InOperation, const TArray& InFiles, EConcurrency::Type InConcurrency /* = EConcurrency::Synchronous */, const FSourceControlOperationComplete& InOperationCompleteDelegate) +#endif +{ + if (!IsEnabled() && !(InOperation->GetName() == "Connect")) // Only Connect operation allowed while not Enabled (Repository found) + { + InOperationCompleteDelegate.ExecuteIfBound(InOperation, ECommandResult::Failed); + return ECommandResult::Failed; + } + + TArray AbsoluteFiles = SourceControlHelpers::AbsoluteFilenames(InFiles); + + // Query to see if we allow this operation + TSharedPtr Worker = CreateWorker(InOperation->GetName()); + if (!Worker.IsValid()) + { + // this operation is unsupported by this source control provider + FFormatNamedArguments Arguments; + Arguments.Add(TEXT("OperationName"), FText::FromName(InOperation->GetName())); + Arguments.Add(TEXT("ProviderName"), FText::FromName(GetName())); + FText Message(FText::Format(LOCTEXT("UnsupportedOperation", "Operation '{OperationName}' not supported by source control provider '{ProviderName}'"), Arguments)); + FMessageLog("SourceControl").Error(Message); + InOperation->AddErrorMessge(Message); + + InOperationCompleteDelegate.ExecuteIfBound(InOperation, ECommandResult::Failed); + return ECommandResult::Failed; + } + + FGitSourceControlCommand* Command = new FGitSourceControlCommand(InOperation, Worker.ToSharedRef()); + Command->Files = AbsoluteFiles; + Command->OperationCompleteDelegate = InOperationCompleteDelegate; + + // fire off operation + if (InConcurrency == EConcurrency::Synchronous) + { + Command->bAutoDelete = false; + + UE_LOG(LogSourceControl, Log, TEXT("ExecuteSynchronousCommand(%s)"), *InOperation->GetName().ToString()); + return ExecuteSynchronousCommand(*Command, InOperation->GetInProgressString()); + } + else + { + Command->bAutoDelete = true; + + UE_LOG(LogSourceControl, Log, TEXT("IssueAsynchronousCommand(%s)"), *InOperation->GetName().ToString()); + return IssueCommand(*Command); + } +} + +bool FGitSourceControlProvider::CanCancelOperation(const FSourceControlOperationRef& InOperation) const +{ + return false; +} + +void FGitSourceControlProvider::CancelOperation(const FSourceControlOperationRef& InOperation) +{ +} + +bool FGitSourceControlProvider::UsesLocalReadOnlyState() const +{ + return bUsingGitLfsLocking; // Git LFS Lock uses read-only state +} + +bool FGitSourceControlProvider::UsesChangelists() const +{ + return false; +} + +bool FGitSourceControlProvider::UsesCheckout() const +{ + return bUsingGitLfsLocking; // Git LFS Lock uses read-only state +} + +/** Whether the provider uses individual file revisions. Used to enable partial 'Sync' operations on Content Browser Folders. */ +bool FGitSourceControlProvider::UsesFileRevisions() const +{ + return false; // Partial 'Sync' doesn't make sense for Git, only for Perforce +} + +/** + * Whether the current source control client is at the latest version. Used to enable a global 'Sync' button on the Toolbar. + * @note Experimental, hidden behind an setting in XxxEditor.ini [SourceControlSettings] DisplaySourceControlSyncStatus=true + * @note This concept is currently only implemented for the Skein source control provider. + */ +TOptional FGitSourceControlProvider::IsAtLatestRevision() const +{ + return TOptional(); +} + +/** + * Returns the number of changes in the local workspace. Used to enable a global 'CheckIn' button on the Toolbar. + * @note Experimental, hidden behind an setting in XxxEditor.ini [SourceControlSettings] DisplaySourceControlCheckInStatus=true + * @note This concept is currently only implemented for the Skein source control provider. + */ +TOptional FGitSourceControlProvider::GetNumLocalChanges() const +{ + return TOptional(); +} + +bool FGitSourceControlProvider::UsesUncontrolledChangelists() const +{ + return true; +} + +bool FGitSourceControlProvider::UsesSnapshots() const +{ + return false; +} + +bool FGitSourceControlProvider::AllowsDiffAgainstDepot() const +{ + return true; +} + +TSharedPtr FGitSourceControlProvider::CreateWorker(const FName& InOperationName) const +{ + const FGetGitSourceControlWorker* Operation = WorkersMap.Find(InOperationName); + if (Operation != nullptr) + { + return Operation->Execute(); + } + + return nullptr; +} + +void FGitSourceControlProvider::RegisterWorker(const FName& InName, const FGetGitSourceControlWorker& InDelegate) +{ + WorkersMap.Add(InName, InDelegate); +} + +void FGitSourceControlProvider::OutputCommandMessages(const FGitSourceControlCommand& InCommand) const +{ + FMessageLog SourceControlLog("SourceControl"); + + for (int32 ErrorIndex = 0; ErrorIndex < InCommand.ErrorMessages.Num(); ++ErrorIndex) + { + SourceControlLog.Error(FText::FromString(InCommand.ErrorMessages[ErrorIndex])); + } + + for (int32 InfoIndex = 0; InfoIndex < InCommand.InfoMessages.Num(); ++InfoIndex) + { + SourceControlLog.Info(FText::FromString(InCommand.InfoMessages[InfoIndex])); + } +} + +void FGitSourceControlProvider::UpdateRepositoryStatus(const class FGitSourceControlCommand& InCommand) +{ + // For all operations running UpdateStatus, get Commit informations: + if (!InCommand.CommitId.IsEmpty()) + { + CommitId = InCommand.CommitId; + CommitSummary = InCommand.CommitSummary; + } +} + +void FGitSourceControlProvider::Tick() +{ + bool bStatesUpdated = false; + + for (int32 CommandIndex = 0; CommandIndex < CommandQueue.Num(); ++CommandIndex) + { + FGitSourceControlCommand& Command = *CommandQueue[CommandIndex]; + if (Command.bExecuteProcessed) + { + // Remove command from the queue + CommandQueue.RemoveAt(CommandIndex); + + // Update respository status on UpdateStatus operations + UpdateRepositoryStatus(Command); + + // let command update the states of any files + bStatesUpdated |= Command.Worker->UpdateStates(); + + // dump any messages to output log + OutputCommandMessages(Command); + + // run the completion delegate callback if we have one bound + Command.ReturnResults(); + + // commands that are left in the array during a tick need to be deleted + if (Command.bAutoDelete) + { + // Only delete commands that are not running 'synchronously' + delete &Command; + } + + // only do one command per tick loop, as we dont want concurrent modification + // of the command queue (which can happen in the completion delegate) + break; + } + } + + if (bStatesUpdated) + { + OnSourceControlStateChanged.Broadcast(); + } +} + +TArray> FGitSourceControlProvider::GetLabels(const FString& InMatchingSpec) const +{ + TArray> Tags; + + // NOTE list labels. Called by CrashDebugHelper() (to remote debug Engine crash) + // and by SourceControlHelpers::AnnotateFile() (to add source file to report) + // Reserved for internal use by Epic Games with Perforce only + return Tags; +} + +#if ENGINE_MAJOR_VERSION == 5 +TArray FGitSourceControlProvider::GetChangelists(EStateCacheUsage::Type InStateCacheUsage) +{ + return TArray(); +} +#endif + +#if SOURCE_CONTROL_WITH_SLATE +TSharedRef FGitSourceControlProvider::MakeSettingsWidget() const +{ + return SNew(SGitSourceControlSettings); +} +#endif + +ECommandResult::Type FGitSourceControlProvider::ExecuteSynchronousCommand(FGitSourceControlCommand& InCommand, const FText& Task) +{ + ECommandResult::Type Result = ECommandResult::Failed; + + // Display the progress dialog if a string was provided + { + FScopedSourceControlProgress Progress(Task); + + // Issue the command asynchronously... + IssueCommand(InCommand); + + // ... then wait for its completion (thus making it synchronous) + while (!InCommand.bExecuteProcessed) + { + // Tick the command queue and update progress. + Tick(); + + Progress.Tick(); + + // Sleep for a bit so we don't busy-wait so much. + FPlatformProcess::Sleep(0.01f); + } + + // always do one more Tick() to make sure the command queue is cleaned up. + Tick(); + + if (InCommand.bCommandSuccessful) + { + Result = ECommandResult::Succeeded; + } + } + + // Delete the command now (asynchronous commands are deleted in the Tick() method) + check(!InCommand.bAutoDelete); + + // ensure commands that are not auto deleted do not end up in the command queue + if (CommandQueue.Contains(&InCommand)) + { + CommandQueue.Remove(&InCommand); + } + delete &InCommand; + + return Result; +} + +ECommandResult::Type FGitSourceControlProvider::IssueCommand(FGitSourceControlCommand& InCommand) +{ + if (GThreadPool != nullptr) + { + // Queue this to our worker thread(s) for resolving + GThreadPool->AddQueuedWork(&InCommand); + CommandQueue.Add(&InCommand); + return ECommandResult::Succeeded; + } + else + { + FText Message(LOCTEXT("NoSCCThreads", "There are no threads available to process the source control command.")); + + FMessageLog("SourceControl").Error(Message); + InCommand.bCommandSuccessful = false; + InCommand.Operation->AddErrorMessge(Message); + + return InCommand.ReturnResults(); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h new file mode 100644 index 0000000..63954ea --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h @@ -0,0 +1,232 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlOperation.h" +#include "ISourceControlState.h" +#include "ISourceControlProvider.h" +#include "IGitSourceControlWorker.h" +#include "GitSourceControlState.h" +#include "GitSourceControlMenu.h" +#include "GitSourceControlConsole.h" + +#include "Runtime/Launch/Resources/Version.h" + +class FGitSourceControlCommand; + +DECLARE_DELEGATE_RetVal(FGitSourceControlWorkerRef, FGetGitSourceControlWorker) + +/// Git version and capabilites extracted from the string "git version 2.11.0.windows.3" +struct FGitVersion +{ + // Git version extracted from the string "git version 2.11.0.windows.3" (Windows) or "git version 2.11.0" (Linux/Mac/Cygwin/WSL) + int Major; // 2 Major version number + int Minor; // 11 Minor version number + int Patch; // 0 Patch/bugfix number + int Windows; // 3 Windows specific revision number (under Windows only) + + uint32 bHasCatFileWithFilters : 1; + uint32 bHasGitLfs : 1; + uint32 bHasGitLfsLocking : 1; + + FGitVersion() + : Major(0) + , Minor(0) + , Patch(0) + , Windows(0) + , bHasCatFileWithFilters(false) + , bHasGitLfs(false) + , bHasGitLfsLocking(false) + { + } + + inline bool IsGreaterOrEqualThan(int InMajor, int InMinor) const + { + return (Major > InMajor) || (Major == InMajor && (Minor >= InMinor)); + } +}; + +class FGitSourceControlProvider : public ISourceControlProvider +{ +public: + /** Constructor */ + FGitSourceControlProvider() + { + } + + /* ISourceControlProvider implementation */ + virtual void Init(bool bForceConnection = true) override; + virtual void Close() override; + virtual FText GetStatusText() const override; + virtual bool IsEnabled() const override; + virtual bool IsAvailable() const override; + virtual const FName& GetName(void) const override; + virtual bool QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest) override { return false; } + virtual void RegisterStateBranches(const TArray& BranchNames, const FString& ContentRoot) override {} + virtual int32 GetStateBranchIndex(const FString& InBranchName) const override { return INDEX_NONE; } + virtual ECommandResult::Type GetState(const TArray& InFiles, TArray& OutState, EStateCacheUsage::Type InStateCacheUsage) override; +#if ENGINE_MAJOR_VERSION == 5 + virtual ECommandResult::Type GetState(const TArray& InChangelists, TArray& OutState, EStateCacheUsage::Type InStateCacheUsage) override; +#endif + virtual TArray GetCachedStateByPredicate(TFunctionRef Predicate) const override; + virtual FDelegateHandle RegisterSourceControlStateChanged_Handle(const FSourceControlStateChanged::FDelegate& SourceControlStateChanged) override; + virtual void UnregisterSourceControlStateChanged_Handle(FDelegateHandle Handle) override; +#if ENGINE_MAJOR_VERSION == 5 + virtual ECommandResult::Type Execute(const FSourceControlOperationRef& InOperation, FSourceControlChangelistPtr InChangelist, const TArray& InFiles, EConcurrency::Type InConcurrency = EConcurrency::Synchronous, const FSourceControlOperationComplete& InOperationCompleteDelegate = FSourceControlOperationComplete() ) override; +#else + virtual ECommandResult::Type Execute(const FSourceControlOperationRef& InOperation, const TArray& InFiles, EConcurrency::Type InConcurrency = EConcurrency::Synchronous, const FSourceControlOperationComplete& InOperationCompleteDelegate = FSourceControlOperationComplete() ) override; +#endif + virtual bool CanCancelOperation(const FSourceControlOperationRef& InOperation) const override; + virtual void CancelOperation(const FSourceControlOperationRef& InOperation) override; + virtual bool UsesLocalReadOnlyState() const override; + virtual bool UsesChangelists() const override; + virtual bool UsesCheckout() const override; + virtual bool UsesFileRevisions() const; /* override NOTE: added in UE5.1 */ + virtual TOptional IsAtLatestRevision() const; /* override NOTE: added in UE5.1 */ + virtual TOptional GetNumLocalChanges() const; /* override NOTE: added in UE5.1 */ + virtual bool UsesUncontrolledChangelists() const; /* override NOTE: added in UE5.2 */ + virtual bool UsesSnapshots() const; /* override NOTE: added in UE5.2 */ + virtual bool AllowsDiffAgainstDepot() const; /* override NOTE: added in UE5.2 */ + virtual void Tick() override; + virtual TArray< TSharedRef > GetLabels(const FString& InMatchingSpec) const override; +#if ENGINE_MAJOR_VERSION == 5 + virtual TArray GetChangelists(EStateCacheUsage::Type InStateCacheUsage) override; +#endif +#if SOURCE_CONTROL_WITH_SLATE + virtual TSharedRef MakeSettingsWidget() const override; +#endif + + using ISourceControlProvider::Execute; + + /** + * Check configuration, else standard paths, and run a Git "version" command to check the availability of the binary. + */ + void CheckGitAvailability(); + + /** + * Find the .git/ repository and check it's status. + */ + void CheckRepositoryStatus(const FString& InPathToGitBinary); + + /** Is git binary found and working. */ + inline bool IsGitAvailable() const + { + return bGitAvailable; + } + + /** Git version for feature checking */ + inline const FGitVersion& GetGitVersion() const + { + return GitVersion; + } + + /** Get the path to the root of the Git repository: can be the ProjectDir itself, or any parent directory */ + inline const FString& GetPathToRepositoryRoot() const + { + return PathToRepositoryRoot; + } + + /** Git config user.name */ + inline const FString& GetUserName() const + { + return UserName; + } + + /** Git config user.email */ + inline const FString& GetUserEmail() const + { + return UserEmail; + } + + /** Git remote origin url */ + inline const FString& GetRemoteUrl() const + { + return RemoteUrl; + } + + /** Helper function used to update state cache */ + TSharedRef GetStateInternal(const FString& Filename); + + /** + * Register a worker with the provider. + * This is used internally so the provider can maintain a map of all available operations. + */ + void RegisterWorker( const FName& InName, const FGetGitSourceControlWorker& InDelegate ); + + /** Remove a named file from the state cache */ + bool RemoveFileFromCache(const FString& Filename); + + /** Get files in cache */ + TArray GetFilesInCache(); + +private: + + /** Is git binary found and working. */ + bool bGitAvailable = false; + + /** Is git repository found. */ + bool bGitRepositoryFound = false; + + /** Is LFS File Locking enabled? */ + bool bUsingGitLfsLocking = false; + + /** Helper function for Execute() */ + TSharedPtr CreateWorker(const FName& InOperationName) const; + + /** Helper function for running command synchronously. */ + ECommandResult::Type ExecuteSynchronousCommand(class FGitSourceControlCommand& InCommand, const FText& Task); + /** Issue a command asynchronously if possible. */ + ECommandResult::Type IssueCommand(class FGitSourceControlCommand& InCommand); + + /** Output any messages this command holds */ + void OutputCommandMessages(const class FGitSourceControlCommand& InCommand) const; + + /** Update repository status on Connect and UpdateStatus operations */ + void UpdateRepositoryStatus(const class FGitSourceControlCommand& InCommand); + + /** Path to the root of the Git repository: can be the ProjectDir itself, or any parent directory (found by the "Connect" operation) */ + FString PathToRepositoryRoot; + + /** Git config user.name (from local repository, else globally) */ + FString UserName; + + /** Git config user.email (from local repository, else globally) */ + FString UserEmail; + + /** Name of the current branch */ + FString BranchName; + + /** URL of the "origin" defaut remote server */ + FString RemoteUrl; + + /** Current Commit full SHA1 */ + FString CommitId; + + /** Current Commit description's Summary */ + FString CommitSummary; + + /** State cache */ + TMap > StateCache; + + /** The currently registered source control operations */ + TMap WorkersMap; + + /** Queue for commands given by the main thread */ + TArray < FGitSourceControlCommand* > CommandQueue; + + /** For notifying when the source control states in the cache have changed */ + FSourceControlStateChanged OnSourceControlStateChanged; + + /** Git version for feature checking */ + FGitVersion GitVersion; + + /** Source Control Menu Extension */ + FGitSourceControlMenu GitSourceControlMenu; + + /** Source Control Console commands */ + FGitSourceControlConsole GitSourceControlConsole; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.cpp new file mode 100644 index 0000000..3812ba6 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.cpp @@ -0,0 +1,126 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlRevision.h" + +#include "HAL/FileManager.h" +#include "Misc/Paths.h" +#include "Modules/ModuleManager.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlProvider.h" +#include "GitSourceControlUtils.h" + +#define LOCTEXT_NAMESPACE "GitSourceControl" + +#if ENGINE_MAJOR_VERSION == 5 +bool FGitSourceControlRevision::Get(FString& InOutFilename, EConcurrency::Type InConcurrency /* = EConcurrency::Synchronous */) const +#else +bool FGitSourceControlRevision::Get(FString& InOutFilename) const +#endif +{ +#if ENGINE_MAJOR_VERSION == 5 + if (InConcurrency != EConcurrency::Synchronous) + { + UE_LOG(LogSourceControl, Warning, TEXT("Only EConcurrency::Synchronous is tested/supported for this operation.")); + } +#endif + + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const FString PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const FString PathToRepositoryRoot = GitSourceControl.GetProvider().GetPathToRepositoryRoot(); + + // if a filename for the temp file wasn't supplied generate a unique-ish one + if(InOutFilename.Len() == 0) + { + // create the diff dir if we don't already have it (Git wont) + IFileManager::Get().MakeDirectory(*FPaths::DiffDir(), true); + // create a unique temp file name based on the unique commit Id + const FString TempFileName = FString::Printf(TEXT("%stemp-%s-%s"), *FPaths::DiffDir(), *CommitId, *FPaths::GetCleanFilename(Filename)); + InOutFilename = FPaths::ConvertRelativePathToFull(TempFileName); + } + + // Diff against the revision + const FString Parameter = FString::Printf(TEXT("%s:%s"), *CommitId, *Filename); + + bool bCommandSuccessful; + if(FPaths::FileExists(InOutFilename)) + { + bCommandSuccessful = true; // if the temp file already exists, reuse it directly + } + else + { + bCommandSuccessful = GitSourceControlUtils::RunDumpToFile(PathToGitBinary, PathToRepositoryRoot, Parameter, InOutFilename); + } + return bCommandSuccessful; +} + +bool FGitSourceControlRevision::GetAnnotated( TArray& OutLines ) const +{ + return false; +} + +bool FGitSourceControlRevision::GetAnnotated( FString& InOutFilename ) const +{ + return false; +} + +const FString& FGitSourceControlRevision::GetFilename() const +{ + return Filename; +} + +int32 FGitSourceControlRevision::GetRevisionNumber() const +{ + return RevisionNumber; +} + +const FString& FGitSourceControlRevision::GetRevision() const +{ + return ShortCommitId; +} + +const FString& FGitSourceControlRevision::GetDescription() const +{ + return Description; +} + +const FString& FGitSourceControlRevision::GetUserName() const +{ + return UserName; +} + +const FString& FGitSourceControlRevision::GetClientSpec() const +{ + static FString EmptyString(TEXT("")); + return EmptyString; +} + +const FString& FGitSourceControlRevision::GetAction() const +{ + return Action; +} + +TSharedPtr FGitSourceControlRevision::GetBranchSource() const +{ + // if this revision was copied/moved from some other revision + return BranchSource; +} + +const FDateTime& FGitSourceControlRevision::GetDate() const +{ + return Date; +} + +int32 FGitSourceControlRevision::GetCheckInIdentifier() const +{ + return CommitIdNumber; +} + +int32 FGitSourceControlRevision::GetFileSize() const +{ + return FileSize; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.h new file mode 100644 index 0000000..f411971 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlRevision.h @@ -0,0 +1,78 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlRevision.h" + +#include "Runtime/Launch/Resources/Version.h" + +/** Revision of a file, linked to a specific commit */ +class FGitSourceControlRevision : public ISourceControlRevision +{ +public: + + /** ISourceControlRevision interface */ +#if ENGINE_MAJOR_VERSION == 5 + virtual bool Get(FString& InOutFilename, EConcurrency::Type InConcurrency = EConcurrency::Synchronous) const override; +#else + virtual bool Get(FString& InOutFilename) const override; +#endif + virtual bool GetAnnotated(TArray& OutLines) const override; + virtual bool GetAnnotated(FString& InOutFilename) const override; + virtual const FString& GetFilename() const override; + virtual int32 GetRevisionNumber() const override; + virtual const FString& GetRevision() const override; + virtual const FString& GetDescription() const override; + virtual const FString& GetUserName() const override; + virtual const FString& GetClientSpec() const override; + virtual const FString& GetAction() const override; + virtual TSharedPtr GetBranchSource() const override; + virtual const FDateTime& GetDate() const override; + virtual int32 GetCheckInIdentifier() const override; + virtual int32 GetFileSize() const override; + +public: + + /** The filename this revision refers to */ + FString Filename; + + /** The full hexadecimal SHA1 id of the commit this revision refers to */ + FString CommitId; + + /** The short hexadecimal SHA1 id (8 first hex char out of 40) of the commit: the string to display */ + FString ShortCommitId; + + /** The numeric value of the short SHA1 (8 first hex char out of 40) */ + int32 CommitIdNumber = 0; + + /** The index of the revision in the history (SBlueprintRevisionMenu assumes order for the "Depot" label) */ + int32 RevisionNumber = 0; + + /** The SHA1 identifier of the file at this revision */ + FString FileHash; + + /** The description of this revision */ + FString Description; + + /** The user that made the change */ + FString UserName; + + /** The action (add, edit, branch etc.) performed at this revision */ + FString Action; + + /** Source of move ("branch" in Perforce term) if any */ + TSharedPtr BranchSource; + + /** The date this revision was made */ + FDateTime Date; + + /** The size of the file at this revision */ + int32 FileSize; +}; + +/** History composed of the last 100 revisions of the file */ +typedef TArray< TSharedRef > TGitSourceControlHistory; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp new file mode 100644 index 0000000..7c2a98c --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlSettings.h" + +#include "Misc/ScopeLock.h" +#include "Misc/ConfigCacheIni.h" +#include "Modules/ModuleManager.h" +#include "SourceControlHelpers.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlUtils.h" + +namespace GitSettingsConstants +{ + +/** The section of the ini file we load our settings from */ +static const FString SettingsSection = TEXT("GitSourceControl.GitSourceControlSettings"); + +} + +const FString FGitSourceControlSettings::GetBinaryPath() const +{ + FScopeLock ScopeLock(&CriticalSection); + return BinaryPath; // Return a copy to be thread-safe +} + +bool FGitSourceControlSettings::SetBinaryPath(const FString& InString) +{ + FScopeLock ScopeLock(&CriticalSection); + const bool bChanged = (BinaryPath != InString); + if(bChanged) + { + BinaryPath = InString; + } + return bChanged; +} + +/** Tell if using the Git LFS file Locking workflow */ +bool FGitSourceControlSettings::IsUsingGitLfsLocking() const +{ + FScopeLock ScopeLock(&CriticalSection); + return bUsingGitLfsLocking; +} + +/** Configure the usage of Git LFS file Locking workflow */ +bool FGitSourceControlSettings::SetUsingGitLfsLocking(const bool InUsingGitLfsLocking) +{ + FScopeLock ScopeLock(&CriticalSection); + const bool bChanged = (bUsingGitLfsLocking != InUsingGitLfsLocking); + bUsingGitLfsLocking = InUsingGitLfsLocking; + return bChanged; +} + +const FString FGitSourceControlSettings::GetLfsUserName() const +{ + FScopeLock ScopeLock(&CriticalSection); + return LfsUserName; // Return a copy to be thread-safe +} + +bool FGitSourceControlSettings::SetLfsUserName(const FString& InString) +{ + FScopeLock ScopeLock(&CriticalSection); + const bool bChanged = (LfsUserName != InString); + if (bChanged) + { + LfsUserName = InString; + } + return bChanged; +} + +bool FGitSourceControlSettings::SetIsPushAfterCommitEnabled(bool bInEnabled) +{ + FScopeLock ScopeLock(&CriticalSection); + const bool bChanged = (bIsPushAfterCommitEnabled != bInEnabled); + if (bChanged) + { + bIsPushAfterCommitEnabled = bInEnabled; + } + return bChanged; +} + +bool FGitSourceControlSettings::IsPushAfterCommitEnabled() const +{ + FScopeLock ScopeLock(&CriticalSection); + return bIsPushAfterCommitEnabled; +} + +// This is called at startup nearly before anything else in our module: BinaryPath will then be used by the provider +void FGitSourceControlSettings::LoadSettings() +{ + FScopeLock ScopeLock(&CriticalSection); + const FString& IniFile = SourceControlHelpers::GetSettingsIni(); + GConfig->GetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), BinaryPath, IniFile); + GConfig->GetBool(*GitSettingsConstants::SettingsSection, TEXT("UsingGitLfsLocking"), bUsingGitLfsLocking, IniFile); + GConfig->GetString(*GitSettingsConstants::SettingsSection, TEXT("LfsUserName"), LfsUserName, IniFile); + GConfig->GetBool(*GitSettingsConstants::SettingsSection, TEXT("IsPushAfterCommitEnabled"), bIsPushAfterCommitEnabled, IniFile); +} + +void FGitSourceControlSettings::SaveSettings() const +{ + FScopeLock ScopeLock(&CriticalSection); + const FString& IniFile = SourceControlHelpers::GetSettingsIni(); + GConfig->SetString(*GitSettingsConstants::SettingsSection, TEXT("BinaryPath"), *BinaryPath, IniFile); + GConfig->SetBool(*GitSettingsConstants::SettingsSection, TEXT("UsingGitLfsLocking"), bUsingGitLfsLocking, IniFile); + GConfig->SetString(*GitSettingsConstants::SettingsSection, TEXT("LfsUserName"), *LfsUserName, IniFile); + GConfig->SetBool(*GitSettingsConstants::SettingsSection, TEXT("IsPushAfterCommitEnabled"), bIsPushAfterCommitEnabled, IniFile); +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h new file mode 100644 index 0000000..b028351 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlSettings.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" + +class FGitSourceControlSettings +{ +public: + /** Get the Git Binary Path */ + const FString GetBinaryPath() const; + + /** Set the Git Binary Path */ + bool SetBinaryPath(const FString& InString); + + /** Tell if using the Git LFS file Locking workflow */ + bool IsUsingGitLfsLocking() const; + + /** Configure the usage of Git LFS file Locking workflow */ + bool SetUsingGitLfsLocking(const bool InUsingGitLfsLocking); + + /** Get the username used by the Git LFS 2 File Locks server */ + const FString GetLfsUserName() const; + + /** Set the username used by the Git LFS 2 File Locks server */ + bool SetLfsUserName(const FString& InString); + + /** Set whether Submit means Commit AND push (default true) */ + bool SetIsPushAfterCommitEnabled(bool bCond); + + /** Get whether Submit means Commit AND push (default true) */ + bool IsPushAfterCommitEnabled() const; + + /** Load settings from ini file */ + void LoadSettings(); + + /** Save settings to ini file */ + void SaveSettings() const; + +private: + /** A critical section for settings access */ + mutable FCriticalSection CriticalSection; + + /** Git binary path */ + FString BinaryPath; + + /** Tells if using the Git LFS file Locking workflow */ + bool bUsingGitLfsLocking; + + /** Username used by the Git LFS 2 File Locks server */ + FString LfsUserName; + + /** Does Submit mean Commit AND push */ + bool bIsPushAfterCommitEnabled = true; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.cpp new file mode 100644 index 0000000..55fe510 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.cpp @@ -0,0 +1,428 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlState.h" +#if ENGINE_MAJOR_VERSION == 5 +#include "Styling/AppStyle.h" +#endif + +#define LOCTEXT_NAMESPACE "GitSourceControl.State" + +int32 FGitSourceControlState::GetHistorySize() const +{ + return History.Num(); +} + +TSharedPtr FGitSourceControlState::GetHistoryItem(int32 HistoryIndex) const +{ + check(History.IsValidIndex(HistoryIndex)); + return History[HistoryIndex]; +} + +TSharedPtr FGitSourceControlState::FindHistoryRevision(int32 RevisionNumber) const +{ + for (const auto& Revision : History) + { + if (Revision->GetRevisionNumber() == RevisionNumber) + { + return Revision; + } + } + + return nullptr; +} + +TSharedPtr FGitSourceControlState::FindHistoryRevision(const FString& InRevision) const +{ + for (const auto& Revision : History) + { + if (Revision->GetRevision() == InRevision) + { + return Revision; + } + } + + return nullptr; +} + +TSharedPtr FGitSourceControlState::GetBaseRevForMerge() const +{ + for (const auto& Revision : History) + { + // look for the the SHA1 id of the file, not the commit id (revision) + if (Revision->FileHash == PendingMergeBaseFileHash) + { + return Revision; + } + } + + return nullptr; +} + +#if ENGINE_MAJOR_VERSION == 5 + +FSlateIcon FGitSourceControlState::GetIcon() const +{ + switch (WorkingCopyState) + { + case EWorkingCopyState::Modified: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.CheckedOut"); + case EWorkingCopyState::Added: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.OpenForAdd"); + case EWorkingCopyState::Renamed: + case EWorkingCopyState::Copied: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.Branched"); + case EWorkingCopyState::Deleted: // Deleted & Missing files does not show in Content Browser + case EWorkingCopyState::Missing: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.MarkedForDelete"); + case EWorkingCopyState::Conflicted: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.NotAtHeadRevision"); + case EWorkingCopyState::NotControlled: + return FSlateIcon(FAppStyle::GetAppStyleSetName(), "Subversion.NotInDepot"); + case EWorkingCopyState::Unknown: + case EWorkingCopyState::Unchanged: // Unchanged is the same as "Pristine" (not checked out) for Perforce, ie no icon + case EWorkingCopyState::Ignored: + default: + return FSlateIcon(); + } + + return FSlateIcon(); +} + +#else + +// @todo add Slate icons for git specific states (NotAtHead vs Conflicted...) +FName FGitSourceControlState::GetIconName() const +{ + if(LockState == ELockState::Locked) + { + return FName("Subversion.CheckedOut"); + } + else if(LockState == ELockState::LockedOther) + { + return FName("Subversion.CheckedOutByOtherUser"); + } + else if (!IsCurrent()) + { + return FName("Subversion.NotAtHeadRevision"); + } + + switch(WorkingCopyState) + { + case EWorkingCopyState::Modified: + if(bUsingGitLfsLocking) + { + return FName("Subversion.NotInDepot"); + } + else + { + return FName("Subversion.CheckedOut"); + } + case EWorkingCopyState::Added: + return FName("Subversion.OpenForAdd"); + case EWorkingCopyState::Renamed: + case EWorkingCopyState::Copied: + return FName("Subversion.Branched"); + case EWorkingCopyState::Deleted: // Deleted & Missing files does not show in Content Browser + case EWorkingCopyState::Missing: + return FName("Subversion.MarkedForDelete"); + case EWorkingCopyState::Conflicted: + return FName("Subversion.ModifiedOtherBranch"); + case EWorkingCopyState::NotControlled: + return FName("Subversion.NotInDepot"); + case EWorkingCopyState::Unknown: + case EWorkingCopyState::Unchanged: // Unchanged is the same as "Pristine" (not checked out) for Perforce, ie no icon + case EWorkingCopyState::Ignored: + default: + return NAME_None; + } + + return NAME_None; +} + +FName FGitSourceControlState::GetSmallIconName() const +{ + if(LockState == ELockState::Locked) + { + return FName("Subversion.CheckedOut_Small"); + } + else if(LockState == ELockState::LockedOther) + { + return FName("Subversion.CheckedOutByOtherUser_Small"); + } + else if (!IsCurrent()) + { + return FName("Subversion.NotAtHeadRevision_Small"); + } + + switch(WorkingCopyState) + { + case EWorkingCopyState::Modified: + if(bUsingGitLfsLocking) + { + return FName("Subversion.NotInDepot_Small"); + } + else + { + return FName("Subversion.CheckedOut_Small"); + } + case EWorkingCopyState::Added: + return FName("Subversion.OpenForAdd_Small"); + case EWorkingCopyState::Renamed: + case EWorkingCopyState::Copied: + return FName("Subversion.Branched_Small"); + case EWorkingCopyState::Deleted: // Deleted & Missing files can appear in the Submit to Source Control window + case EWorkingCopyState::Missing: + return FName("Subversion.MarkedForDelete_Small"); + case EWorkingCopyState::Conflicted: + return FName("Subversion.ModifiedOtherBranch_Small"); + case EWorkingCopyState::NotControlled: + return FName("Subversion.NotInDepot_Small"); + case EWorkingCopyState::Unknown: + case EWorkingCopyState::Unchanged: // Unchanged is the same as "Pristine" (not checked out) for Perforce, ie no icon + case EWorkingCopyState::Ignored: + default: + return NAME_None; + } + + return NAME_None; +} + +#endif + +FText FGitSourceControlState::GetDisplayName() const +{ + if (LockState == ELockState::Locked) + { + return LOCTEXT("Locked", "Locked For Editing"); + } + else if (LockState == ELockState::LockedOther) + { + return FText::Format(LOCTEXT("LockedOther", "Locked by "), FText::FromString(LockUser)); + } + else if (!IsCurrent()) + { + return LOCTEXT("NotCurrent", "Not current"); + } + + switch (WorkingCopyState) + { + case EWorkingCopyState::Unknown: + return LOCTEXT("Unknown", "Unknown"); + case EWorkingCopyState::Unchanged: + return LOCTEXT("Unchanged", "Unchanged"); + case EWorkingCopyState::Added: + return LOCTEXT("Added", "Added"); + case EWorkingCopyState::Deleted: + return LOCTEXT("Deleted", "Deleted"); + case EWorkingCopyState::Modified: + return LOCTEXT("Modified", "Modified"); + case EWorkingCopyState::Renamed: + return LOCTEXT("Renamed", "Renamed"); + case EWorkingCopyState::Copied: + return LOCTEXT("Copied", "Copied"); + case EWorkingCopyState::Conflicted: + return LOCTEXT("ContentsConflict", "Contents Conflict"); + case EWorkingCopyState::Ignored: + return LOCTEXT("Ignored", "Ignored"); + case EWorkingCopyState::NotControlled: + return LOCTEXT("NotControlled", "Not Under Source Control"); + case EWorkingCopyState::Missing: + return LOCTEXT("Missing", "Missing"); + } + + return FText(); +} + +FText FGitSourceControlState::GetDisplayTooltip() const +{ + if (LockState == ELockState::Locked) + { + return LOCTEXT("Locked_Tooltip", "Locked for editing by current user"); + } + else if (LockState == ELockState::LockedOther) + { + return FText::Format(LOCTEXT("LockedOther_Tooltip", "Locked for editing by: {0}"), FText::FromString(LockUser)); + } + else if (!IsCurrent()) + { + return LOCTEXT("NotCurrent_Tooltip", "The file(s) are not at the head revision"); + } + + switch (WorkingCopyState) + { + case EWorkingCopyState::Unknown: + return LOCTEXT("Unknown_Tooltip", "Unknown source control state"); + case EWorkingCopyState::Unchanged: + return LOCTEXT("Pristine_Tooltip", "There are no modifications"); + case EWorkingCopyState::Added: + return LOCTEXT("Added_Tooltip", "Item is scheduled for addition"); + case EWorkingCopyState::Deleted: + return LOCTEXT("Deleted_Tooltip", "Item is scheduled for deletion"); + case EWorkingCopyState::Modified: + return LOCTEXT("Modified_Tooltip", "Item has been modified"); + case EWorkingCopyState::Renamed: + return LOCTEXT("Renamed_Tooltip", "Item has been renamed"); + case EWorkingCopyState::Copied: + return LOCTEXT("Copied_Tooltip", "Item has been copied"); + case EWorkingCopyState::Conflicted: + return LOCTEXT("ContentsConflict_Tooltip", "The contents of the item conflict with updates received from the repository."); + case EWorkingCopyState::Ignored: + return LOCTEXT("Ignored_Tooltip", "Item is being ignored."); + case EWorkingCopyState::NotControlled: + return LOCTEXT("NotControlled_Tooltip", "Item is not under version control."); + case EWorkingCopyState::Missing: + return LOCTEXT("Missing_Tooltip", "Item is missing (e.g., you moved or deleted it without using Git). This also indicates that a directory is incomplete (a checkout or update was interrupted)."); + } + + return FText(); +} + +const FString& FGitSourceControlState::GetFilename() const +{ + return LocalFilename; +} + +const FDateTime& FGitSourceControlState::GetTimeStamp() const +{ + return TimeStamp; +} + +// Deleted and Missing assets cannot appear in the Content Browser, but the do in the Submit files to Source Control window! +bool FGitSourceControlState::CanCheckIn() const +{ + if (bUsingGitLfsLocking) + { + return (((LockState == ELockState::Locked) && !IsConflicted()) || (WorkingCopyState == EWorkingCopyState::Added)) && IsCurrent(); + } + else + { + return (WorkingCopyState == EWorkingCopyState::Added + || WorkingCopyState == EWorkingCopyState::Deleted + || WorkingCopyState == EWorkingCopyState::Missing + || WorkingCopyState == EWorkingCopyState::Modified + || WorkingCopyState == EWorkingCopyState::Renamed) && IsCurrent(); + } +} + +bool FGitSourceControlState::CanCheckout() const +{ + if (bUsingGitLfsLocking) + { + // We don't want to allow checkout if the file is out-of-date, as modifying an out-of-date binary file will most likely result in a merge conflict + return (WorkingCopyState == EWorkingCopyState::Unchanged || WorkingCopyState == EWorkingCopyState::Modified) && LockState == ELockState::NotLocked && IsCurrent(); + } + else + { + return false; // With Git all tracked files in the working copy are always already checked-out (as opposed to Perforce) + } +} + +bool FGitSourceControlState::IsCheckedOut() const +{ + if (bUsingGitLfsLocking) + { + return LockState == ELockState::Locked; + } + else + { + return IsSourceControlled(); // With Git all tracked files in the working copy are always checked-out (as opposed to Perforce) + } +} + +bool FGitSourceControlState::IsCheckedOutOther(FString* Who) const +{ + if (Who != NULL) + { + *Who = LockUser; + } + return LockState == ELockState::LockedOther; +} + +bool FGitSourceControlState::IsCurrent() const +{ + return !bNewerVersionOnServer; +} + +bool FGitSourceControlState::IsSourceControlled() const +{ + return WorkingCopyState != EWorkingCopyState::NotControlled && WorkingCopyState != EWorkingCopyState::Ignored && WorkingCopyState != EWorkingCopyState::Unknown; +} + +bool FGitSourceControlState::IsAdded() const +{ + return WorkingCopyState == EWorkingCopyState::Added; +} + +bool FGitSourceControlState::IsDeleted() const +{ + return WorkingCopyState == EWorkingCopyState::Deleted || WorkingCopyState == EWorkingCopyState::Missing; +} + +bool FGitSourceControlState::IsIgnored() const +{ + return WorkingCopyState == EWorkingCopyState::Ignored; +} + +bool FGitSourceControlState::CanEdit() const +{ + return IsCurrent(); // With Git all files in the working copy are always editable (as opposed to Perforce) +} + +bool FGitSourceControlState::CanDelete() const +{ + return !IsCheckedOutOther() && IsSourceControlled() && IsCurrent(); +} + +bool FGitSourceControlState::IsUnknown() const +{ + return WorkingCopyState == EWorkingCopyState::Unknown; +} + +bool FGitSourceControlState::IsModified() const +{ + // Warning: for Perforce, a checked-out file is locked for modification (whereas with Git all tracked files are checked-out), + // so for a clean "check-in" (commit) checked-out files unmodified should be removed from the changeset (the index) + // http://stackoverflow.com/questions/12357971/what-does-revert-unchanged-files-mean-in-perforce + // + // Thus, before check-in UE Editor call RevertUnchangedFiles() in PromptForCheckin() and CheckinFiles(). + // + // So here we must take care to enumerate all states that need to be commited, + // all other will be discarded : + // - Unknown + // - Unchanged + // - NotControlled + // - Ignored + return WorkingCopyState == EWorkingCopyState::Added + || WorkingCopyState == EWorkingCopyState::Deleted + || WorkingCopyState == EWorkingCopyState::Modified + || WorkingCopyState == EWorkingCopyState::Renamed + || WorkingCopyState == EWorkingCopyState::Copied + || WorkingCopyState == EWorkingCopyState::Missing + || WorkingCopyState == EWorkingCopyState::Conflicted; +} + + +bool FGitSourceControlState::CanAdd() const +{ + return WorkingCopyState == EWorkingCopyState::NotControlled; +} + +bool FGitSourceControlState::IsConflicted() const +{ + return WorkingCopyState == EWorkingCopyState::Conflicted; +} + +bool FGitSourceControlState::CanRevert() const +{ + return CanCheckIn(); +} + +TSharedPtr FGitSourceControlState::GetCurrentRevision() const +{ + return nullptr; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.h new file mode 100644 index 0000000..1115b93 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlState.h @@ -0,0 +1,125 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "ISourceControlState.h" +#include "ISourceControlRevision.h" +#include "GitSourceControlRevision.h" + +#include "Runtime/Launch/Resources/Version.h" + +namespace EWorkingCopyState +{ + enum Type + { + Unknown, + Unchanged, + // called "clean" in SVN, "Pristine" in Perforce + Added, + Deleted, + Modified, + Renamed, + Copied, + Missing, + Conflicted, + NotControlled, + Ignored, + }; +} + +namespace ELockState +{ + enum Type + { + Unknown, + NotLocked, + Locked, + LockedOther, + }; +} + +class FGitSourceControlState : public ISourceControlState +{ +public: + FGitSourceControlState(const FString& InLocalFilename, const bool InUsingLfsLocking) + : LocalFilename(InLocalFilename) + , WorkingCopyState(EWorkingCopyState::Unknown) + , LockState(ELockState::Unknown) + , bUsingGitLfsLocking(InUsingLfsLocking) + , bNewerVersionOnServer(false) + , TimeStamp(0) + { + } + + /** ISourceControlState interface */ + virtual int32 GetHistorySize() const override; + virtual TSharedPtr GetHistoryItem(int32 HistoryIndex) const override; + virtual TSharedPtr FindHistoryRevision(int32 RevisionNumber) const override; + virtual TSharedPtr FindHistoryRevision(const FString& InRevision) const override; + virtual TSharedPtr GetBaseRevForMerge() const override; + virtual TSharedPtr GetCurrentRevision() const; /* override NOTE: added in UE5.2 */ +#if ENGINE_MAJOR_VERSION == 5 + virtual FSlateIcon GetIcon() const override; +#else + virtual FName GetIconName() const override; + virtual FName GetSmallIconName() const override; +#endif + virtual FText GetDisplayName() const override; + virtual FText GetDisplayTooltip() const override; + virtual const FString& GetFilename() const override; + virtual const FDateTime& GetTimeStamp() const override; + virtual bool CanCheckIn() const override; + virtual bool CanCheckout() const override; + virtual bool IsCheckedOut() const override; + virtual bool IsCheckedOutOther(FString* Who = nullptr) const override; + virtual bool IsCheckedOutInOtherBranch(const FString& CurrentBranch = FString()) const override { return false; } + virtual bool IsModifiedInOtherBranch(const FString& CurrentBranch = FString()) const override { return false; } + virtual bool IsCheckedOutOrModifiedInOtherBranch(const FString& CurrentBranch = FString()) const override { return IsCheckedOutInOtherBranch(CurrentBranch) || IsModifiedInOtherBranch(CurrentBranch); } + virtual TArray GetCheckedOutBranches() const override { return TArray(); } + virtual FString GetOtherUserBranchCheckedOuts() const override { return FString(); } + virtual bool GetOtherBranchHeadModification(FString& HeadBranchOut, FString& ActionOut, int32& HeadChangeListOut) const override { return false; } + virtual bool IsCurrent() const override; + virtual bool IsSourceControlled() const override; + virtual bool IsAdded() const override; + virtual bool IsDeleted() const override; + virtual bool IsIgnored() const override; + virtual bool CanEdit() const override; + virtual bool IsUnknown() const override; + virtual bool IsModified() const override; + virtual bool CanAdd() const override; + virtual bool CanDelete() const override; + virtual bool IsConflicted() const override; + virtual bool CanRevert() const override; + +public: + /** History of the item, if any */ + TGitSourceControlHistory History; + + /** Filename on disk */ + FString LocalFilename; + + /** File Id with which our local revision diverged from the remote revision */ + FString PendingMergeBaseFileHash; + + /** State of the working copy */ + EWorkingCopyState::Type WorkingCopyState; + + /** Lock state */ + ELockState::Type LockState; + + /** Name of user who has locked the file */ + FString LockUser; + + /** Tells if using the Git LFS file Locking workflow */ + bool bUsingGitLfsLocking; + + /** Whether a newer version exists on the server */ + bool bNewerVersionOnServer; + + /** The timestamp of the last update */ + FDateTime TimeStamp; +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp new file mode 100644 index 0000000..6bd7fe8 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.cpp @@ -0,0 +1,1560 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "GitSourceControlUtils.h" + +#include "GitSourceControlCommand.h" +#include "HAL/PlatformProcess.h" +#if ENGINE_MAJOR_VERSION >= 5 +#include "HAL/PlatformFileManager.h" +#else +#include "HAL/PlatformFilemanager.h" +#endif +#include "HAL/FileManager.h" +#include "Misc/FileHelper.h" +#include "Misc/Paths.h" +#include "Modules/ModuleManager.h" +#include "ISourceControlModule.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlProvider.h" + +#if PLATFORM_LINUX +#include +#endif + + +namespace GitSourceControlConstants +{ + /** The maximum number of files we submit in a single Git command */ + const int32 MaxFilesPerBatch = 50; +} + +FGitScopedTempFile::FGitScopedTempFile(const FText& InText) +{ + Filename = FPaths::CreateTempFilename(*FPaths::ProjectLogDir(), TEXT("Git-Temp"), TEXT(".txt")); + if(!FFileHelper::SaveStringToFile(InText.ToString(), *Filename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) + { + UE_LOG(LogSourceControl, Error, TEXT("Failed to write to temp file: %s"), *Filename); + } +} + +FGitScopedTempFile::~FGitScopedTempFile() +{ + if(FPaths::FileExists(Filename)) + { + if(!FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*Filename)) + { + UE_LOG(LogSourceControl, Error, TEXT("Failed to delete temp file: %s"), *Filename); + } + } +} + +const FString& FGitScopedTempFile::GetFilename() const +{ + return Filename; +} + + +namespace GitSourceControlUtils +{ + +// Launch the Git command line process and extract its results & errors +bool RunCommandInternalRaw(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, FString& OutResults, FString& OutErrors, const int32 ExpectedReturnCode /* = 0 */) +{ + int32 ReturnCode = 0; + FString FullCommand; + FString LogableCommand; // short version of the command for logging purpose + + if(!InRepositoryRoot.IsEmpty()) + { + FString RepositoryRoot = InRepositoryRoot; + + // Detect a "migrate asset" scenario (a "git add" command is applied to files outside the current project) + if ( (InFiles.Num() > 0) && !FPaths::IsRelative(InFiles[0]) && !InFiles[0].StartsWith(InRepositoryRoot) ) + { + // in this case, find the git repository (if any) of the destination Project + FString DestinationRepositoryRoot; + if(FindRootDirectory(FPaths::GetPath(InFiles[0]), DestinationRepositoryRoot)) + { + RepositoryRoot = DestinationRepositoryRoot; // if found use it for the "add" command (else not, to avoid producing one more error in logs) + } + } + + // Specify the working copy (the root) of the git repository (before the command itself) + FullCommand = TEXT("-C \""); + FullCommand += RepositoryRoot; + FullCommand += TEXT("\" "); + } + // then the git command itself ("status", "log", "commit"...) + LogableCommand += InCommand; + + // Append to the command all parameters, and then finally the files + for(const auto& Parameter : InParameters) + { + LogableCommand += TEXT(" "); + LogableCommand += Parameter; + } + for(const auto& File : InFiles) + { + LogableCommand += TEXT(" \""); + LogableCommand += File; + LogableCommand += TEXT("\""); + } + // Also, Git does not have a "--non-interactive" option, as it auto-detects when there are no connected standard input/output streams + + FullCommand += LogableCommand; + + UE_LOG(LogSourceControl, Log, TEXT("RunCommand: 'git %s'"), *LogableCommand); + + FString PathToGitOrEnvBinary = InPathToGitBinary; +#if PLATFORM_MAC + // The Cocoa application does not inherit shell environment variables, so add the path expected to have git-lfs to PATH + FString PathEnv = FPlatformMisc::GetEnvironmentVariable(TEXT("PATH")); + FString GitInstallPath = FPaths::GetPath(InPathToGitBinary); + + TArray PathArray; + PathEnv.ParseIntoArray(PathArray, FPlatformMisc::GetPathVarDelimiter()); + bool bHasGitInstallPath = false; + for (auto Path : PathArray) + { + if (GitInstallPath.Equals(Path, ESearchCase::CaseSensitive)) + { + bHasGitInstallPath = true; + break; + } + } + + if (!bHasGitInstallPath) + { + PathToGitOrEnvBinary = FString("/usr/bin/env"); + FullCommand = FString::Printf(TEXT("PATH=\"%s%s%s\" \"%s\" %s"), *GitInstallPath, FPlatformMisc::GetPathVarDelimiter(), *PathEnv, *InPathToGitBinary, *FullCommand); + } +#endif + FPlatformProcess::ExecProcess(*PathToGitOrEnvBinary, *FullCommand, &ReturnCode, &OutResults, &OutErrors); + + // TODO: add a setting to easily enable Verbose logging + UE_LOG(LogSourceControl, Verbose, TEXT("RunCommand(%s):\n%s"), *InCommand, *OutResults); + if(ReturnCode != ExpectedReturnCode || OutErrors.Len() > 0) + { + UE_LOG(LogSourceControl, Warning, TEXT("RunCommand(%s) ReturnCode=%d:\n%s"), *InCommand, ReturnCode, *OutErrors); + } + + // Move push/pull progress information from the error stream to the info stream + if(ReturnCode == ExpectedReturnCode && OutErrors.Len() > 0) + { + OutResults.Append(OutErrors); + OutErrors.Empty(); + } + + return ReturnCode == ExpectedReturnCode; +} + +// Basic parsing or results & errors from the Git command line process +static bool RunCommandInternal(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages) +{ + bool bResult; + FString Results; + FString Errors; + + bResult = RunCommandInternalRaw(InCommand, InPathToGitBinary, InRepositoryRoot, InParameters, InFiles, Results, Errors); + Results.ParseIntoArray(OutResults, TEXT("\n"), true); + Errors.ParseIntoArray(OutErrorMessages, TEXT("\n"), true); + + return bResult; +} + +FString FindGitBinaryPath() +{ +#if PLATFORM_WINDOWS + // 1) First of all, look into standard install directories + // NOTE using only "git" (or "git.exe") relying on the "PATH" envvar does not always work as expected, depending on the installation: + // If the PATH is set with "git/cmd" instead of "git/bin", + // "git.exe" launch "git/cmd/git.exe" that redirect to "git/bin/git.exe" and ExecProcess() is unable to catch its outputs streams. + // First check the 64-bit program files directory: + FString GitBinaryPath(TEXT("C:/Program Files/Git/bin/git.exe")); + bool bFound = CheckGitAvailability(GitBinaryPath); + if(!bFound) + { + // otherwise check the 32-bit program files directory. + GitBinaryPath = TEXT("C:/Program Files (x86)/Git/bin/git.exe"); + bFound = CheckGitAvailability(GitBinaryPath); + } + if(!bFound) + { + // else the install dir for the current user: C:\Users\UserName\AppData\Local\Programs\Git\cmd + const FString AppDataLocalPath = FPlatformMisc::GetEnvironmentVariable(TEXT("LOCALAPPDATA")); + GitBinaryPath = FString::Printf(TEXT("%s/Programs/Git/cmd/git.exe"), *AppDataLocalPath); + bFound = CheckGitAvailability(GitBinaryPath); + } + + // 2) Else, look for the version of Git bundled with SmartGit "Installer with JRE" + if(!bFound) + { + GitBinaryPath = TEXT("C:/Program Files (x86)/SmartGit/git/bin/git.exe"); + bFound = CheckGitAvailability(GitBinaryPath); + if (!bFound) + { + // If git is not found in "git/bin/" subdirectory, try the "bin/" path that was in use before + GitBinaryPath = TEXT("C:/Program Files (x86)/SmartGit/bin/git.exe"); + bFound = CheckGitAvailability(GitBinaryPath); + } + } + + // 3) Else, look for the local_git provided by SourceTree + if(!bFound) + { + // C:\Users\UserName\AppData\Local\Atlassian\SourceTree\git_local\bin + const FString AppDataLocalPath = FPlatformMisc::GetEnvironmentVariable(TEXT("LOCALAPPDATA")); + GitBinaryPath = FString::Printf(TEXT("%s/Atlassian/SourceTree/git_local/bin/git.exe"), *AppDataLocalPath); + bFound = CheckGitAvailability(GitBinaryPath); + } + + // 4) Else, look for the PortableGit provided by GitHub Desktop + if(!bFound) + { + // The latest GitHub Desktop adds its binaries into the local appdata directory: + // C:\Users\UserName\AppData\Local\GitHub\PortableGit_c2ba306e536fdf878271f7fe636a147ff37326ad\cmd + const FString AppDataLocalPath = FPlatformMisc::GetEnvironmentVariable(TEXT("LOCALAPPDATA")); + const FString SearchPath = FString::Printf(TEXT("%s/GitHub/PortableGit_*"), *AppDataLocalPath); + TArray PortableGitFolders; + IFileManager::Get().FindFiles(PortableGitFolders, *SearchPath, false, true); + if(PortableGitFolders.Num() > 0) + { + // FindFiles just returns directory names, so we need to prepend the root path to get the full path. + GitBinaryPath = FString::Printf(TEXT("%s/GitHub/%s/cmd/git.exe"), *AppDataLocalPath, *(PortableGitFolders.Last())); // keep only the last PortableGit found + bFound = CheckGitAvailability(GitBinaryPath); + if (!bFound) + { + // If Portable git is not found in "cmd/" subdirectory, try the "bin/" path that was in use before + GitBinaryPath = FString::Printf(TEXT("%s/GitHub/%s/bin/git.exe"), *AppDataLocalPath, *(PortableGitFolders.Last())); // keep only the last PortableGit found + bFound = CheckGitAvailability(GitBinaryPath); + } + } + } + + // 5) Else, look for the version of Git bundled with Tower + if (!bFound) + { + GitBinaryPath = TEXT("C:/Program Files (x86)/fournova/Tower/vendor/Git/bin/git.exe"); + bFound = CheckGitAvailability(GitBinaryPath); + } + +#elif PLATFORM_MAC + // 1) First of all, look for the version of git provided by official git + FString GitBinaryPath = TEXT("/usr/local/git/bin/git"); + bool bFound = CheckGitAvailability(GitBinaryPath); + + // 2) Else, look for the version of git provided by Homebrew + if (!bFound) + { + GitBinaryPath = TEXT("/usr/local/bin/git"); + bFound = CheckGitAvailability(GitBinaryPath); + } + + // 3) Else, look for the version of git provided by MacPorts + if (!bFound) + { + GitBinaryPath = TEXT("/opt/local/bin/git"); + bFound = CheckGitAvailability(GitBinaryPath); + } + + // 4) Else, look for the version of git provided by Command Line Tools + if (!bFound) + { + GitBinaryPath = TEXT("/usr/bin/git"); + bFound = CheckGitAvailability(GitBinaryPath); + } + + { + SCOPED_AUTORELEASE_POOL; + NSWorkspace* SharedWorkspace = [NSWorkspace sharedWorkspace]; + + // 5) Else, look for the version of local_git provided by SmartGit + if (!bFound) + { + NSURL* AppURL = [SharedWorkspace URLForApplicationWithBundleIdentifier:@"com.syntevo.smartgit"]; + if (AppURL != nullptr) + { + NSBundle* Bundle = [NSBundle bundleWithURL:AppURL]; + GitBinaryPath = FString::Printf(TEXT("%s/git/bin/git"), *FString([Bundle resourcePath])); + bFound = CheckGitAvailability(GitBinaryPath); + } + } + + // 6) Else, look for the version of local_git provided by SourceTree + if (!bFound) + { + NSURL* AppURL = [SharedWorkspace URLForApplicationWithBundleIdentifier:@"com.torusknot.SourceTreeNotMAS"]; + if (AppURL != nullptr) + { + NSBundle* Bundle = [NSBundle bundleWithURL:AppURL]; + GitBinaryPath = FString::Printf(TEXT("%s/git_local/bin/git"), *FString([Bundle resourcePath])); + bFound = CheckGitAvailability(GitBinaryPath); + } + } + + // 7) Else, look for the version of local_git provided by GitHub Desktop + if (!bFound) + { + NSURL* AppURL = [SharedWorkspace URLForApplicationWithBundleIdentifier:@"com.github.GitHubClient"]; + if (AppURL != nullptr) + { + NSBundle* Bundle = [NSBundle bundleWithURL:AppURL]; + GitBinaryPath = FString::Printf(TEXT("%s/app/git/bin/git"), *FString([Bundle resourcePath])); + bFound = CheckGitAvailability(GitBinaryPath); + } + } + + // 8) Else, look for the version of local_git provided by Tower2 + if (!bFound) + { + NSURL* AppURL = [SharedWorkspace URLForApplicationWithBundleIdentifier:@"com.fournova.Tower2"]; + if (AppURL != nullptr) + { + NSBundle* Bundle = [NSBundle bundleWithURL:AppURL]; + GitBinaryPath = FString::Printf(TEXT("%s/git/bin/git"), *FString([Bundle resourcePath])); + bFound = CheckGitAvailability(GitBinaryPath); + } + } + } + +#else + FString GitBinaryPath = TEXT("/usr/bin/git"); + bool bFound = CheckGitAvailability(GitBinaryPath); +#endif + + if(bFound) + { + FPaths::MakePlatformFilename(GitBinaryPath); + } + else + { + // If we did not find a path to Git, set it empty + GitBinaryPath.Empty(); + } + + return GitBinaryPath; +} + +bool CheckGitAvailability(const FString& InPathToGitBinary, FGitVersion *OutVersion) +{ + FString InfoMessages; + FString ErrorMessages; + bool bGitAvailable = RunCommandInternalRaw(TEXT("version"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages); + if(bGitAvailable) + { + if(!InfoMessages.Contains("git")) + { + bGitAvailable = false; + } + else if(OutVersion) + { + ParseGitVersion(InfoMessages, OutVersion); + FindGitCapabilities(InPathToGitBinary, OutVersion); + FindGitLfsCapabilities(InPathToGitBinary, OutVersion); + } + } + + return bGitAvailable; +} + +void ParseGitVersion(const FString& InVersionString, FGitVersion *OutVersion) +{ + // Parse "git version 2.11.0.windows.3" into the string tokens "git", "version", "2.11.0.windows.3" + TArray TokenizedString; + InVersionString.ParseIntoArrayWS(TokenizedString); + + // Select the string token containing the version "2.11.0.windows.3" + const FString* TokenVersionStringPtr = TokenizedString.FindByPredicate([](FString& s) { return TChar::IsDigit(s[0]); }); + if(TokenVersionStringPtr) + { + // Parse the version into its numerical components + TArray ParsedVersionString; + TokenVersionStringPtr->ParseIntoArray(ParsedVersionString, TEXT(".")); + if(ParsedVersionString.Num() >= 3) + { + if(ParsedVersionString[0].IsNumeric() && ParsedVersionString[1].IsNumeric() && ParsedVersionString[2].IsNumeric()) + { + OutVersion->Major = FCString::Atoi(*ParsedVersionString[0]); + OutVersion->Minor = FCString::Atoi(*ParsedVersionString[1]); + OutVersion->Patch = FCString::Atoi(*ParsedVersionString[2]); + if(ParsedVersionString.Num() >= 5) + { + if((ParsedVersionString[3] == TEXT("windows")) && ParsedVersionString[4].IsNumeric()) + { + OutVersion->Windows = FCString::Atoi(*ParsedVersionString[4]); + } + } + UE_LOG(LogSourceControl, Log, TEXT("Git version %d.%d.%d(%d)"), OutVersion->Major, OutVersion->Minor, OutVersion->Patch, OutVersion->Windows); + } + } + } +} + +void FindGitCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion) +{ + FString InfoMessages; + FString ErrorMessages; + RunCommandInternalRaw(TEXT("cat-file -h"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages, 129); + if (InfoMessages.Contains("--filters")) + { + OutVersion->bHasCatFileWithFilters = true; + } +} + +void FindGitLfsCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion) +{ + FString InfoMessages; + FString ErrorMessages; + bool bGitLfsAvailable = RunCommandInternalRaw(TEXT("lfs version"), InPathToGitBinary, FString(), TArray(), TArray(), InfoMessages, ErrorMessages); + if(bGitLfsAvailable) + { + OutVersion->bHasGitLfs = true; + + if(InfoMessages.Compare(TEXT("git-lfs/2.0.0")) >= 0) + { + OutVersion->bHasGitLfsLocking = true; // Git LFS File Locking workflow introduced in "git-lfs/2.0.0" + } + UE_LOG(LogSourceControl, Log, TEXT("%s"), *InfoMessages); + } +} + +// Find the root of the Git repository, looking from the provided path and upward in its parent directories. +bool FindRootDirectory(const FString& InPath, FString& OutRepositoryRoot) +{ + bool bFound = false; + FString PathToGitSubdirectory; + OutRepositoryRoot = InPath; + + auto TrimTrailing = [](FString& Str, const TCHAR Char) + { + int32 Len = Str.Len(); + while(Len && Str[Len - 1] == Char) + { + Str = Str.LeftChop(1); + Len = Str.Len(); + } + }; + + TrimTrailing(OutRepositoryRoot, '\\'); + TrimTrailing(OutRepositoryRoot, '/'); + + while(!bFound && !OutRepositoryRoot.IsEmpty()) + { + // Look for the ".git" subdirectory (or file) present at the root of every Git repository + PathToGitSubdirectory = OutRepositoryRoot / TEXT(".git"); + bFound = IFileManager::Get().DirectoryExists(*PathToGitSubdirectory) || IFileManager::Get().FileExists(*PathToGitSubdirectory); + if(!bFound) + { + int32 LastSlashIndex; + if(OutRepositoryRoot.FindLastChar('/', LastSlashIndex)) + { + OutRepositoryRoot = OutRepositoryRoot.Left(LastSlashIndex); + } + else + { + OutRepositoryRoot.Empty(); + } + } + } + if(!bFound) + { + OutRepositoryRoot = InPath; // If not found, return the provided dir as best possible root. + } + return bFound; +} + +void GetUserConfig(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutUserName, FString& OutUserEmail) +{ + bool bResults; + TArray InfoMessages; + TArray ErrorMessages; + TArray Parameters; + Parameters.Add(TEXT("user.name")); + bResults = RunCommandInternal(TEXT("config"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if(bResults && InfoMessages.Num() > 0) + { + OutUserName = InfoMessages[0]; + } + + Parameters.Reset(); + Parameters.Add(TEXT("user.email")); + InfoMessages.Reset(); + bResults &= RunCommandInternal(TEXT("config"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if(bResults && InfoMessages.Num() > 0) + { + OutUserEmail = InfoMessages[0]; + } +} + +bool GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName) +{ + bool bResults; + TArray InfoMessages; + TArray ErrorMessages; + TArray Parameters; + Parameters.Add(TEXT("--short")); + Parameters.Add(TEXT("--quiet")); // no error message while in detached HEAD + Parameters.Add(TEXT("HEAD")); + bResults = RunCommandInternal(TEXT("symbolic-ref"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if(bResults && InfoMessages.Num() > 0) + { + OutBranchName = InfoMessages[0]; + } + else + { + Parameters.Reset(); + Parameters.Add(TEXT("-1")); + Parameters.Add(TEXT("--format=\"%h\"")); // no error message while in detached HEAD + bResults = RunCommandInternal(TEXT("log"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if(bResults && InfoMessages.Num() > 0) + { + OutBranchName = "HEAD detached at "; + OutBranchName += InfoMessages[0]; + } + else + { + bResults = false; + } + } + + return bResults; +} + +bool GetCommitInfo(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutCommitId, FString& OutCommitSummary) +{ + bool bResults; + TArray InfoMessages; + TArray ErrorMessages; + TArray Parameters; + Parameters.Add(TEXT("-1")); + Parameters.Add(TEXT("--format=\"%H %s\"")); + bResults = RunCommandInternal(TEXT("log"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if(bResults && InfoMessages.Num() > 0) + { + OutCommitId = InfoMessages[0].Left(40); + OutCommitSummary = InfoMessages[0].RightChop(41); + } + + return bResults; +} + +bool GetRemoteUrl(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutRemoteUrl) +{ + TArray InfoMessages; + TArray ErrorMessages; + TArray Parameters; + Parameters.Add(TEXT("get-url")); + Parameters.Add(TEXT("origin")); + const bool bResults = RunCommandInternal(TEXT("remote"), InPathToGitBinary, InRepositoryRoot, Parameters, TArray(), InfoMessages, ErrorMessages); + if (bResults && InfoMessages.Num() > 0) + { + OutRemoteUrl = InfoMessages[0]; + } + + return bResults; +} + +bool RunCommand(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages) +{ + bool bResult = true; + + if(InFiles.Num() > GitSourceControlConstants::MaxFilesPerBatch) + { + // Batch files up so we dont exceed command-line limits + int32 FileCount = 0; + while(FileCount < InFiles.Num()) + { + TArray FilesInBatch; + for(int32 FileIndex = 0; FileCount < InFiles.Num() && FileIndex < GitSourceControlConstants::MaxFilesPerBatch; FileIndex++, FileCount++) + { + FilesInBatch.Add(InFiles[FileCount]); + } + + TArray BatchResults; + TArray BatchErrors; + bResult &= RunCommandInternal(InCommand, InPathToGitBinary, InRepositoryRoot, InParameters, FilesInBatch, BatchResults, BatchErrors); + OutResults += BatchResults; + OutErrorMessages += BatchErrors; + } + } + else + { + bResult &= RunCommandInternal(InCommand, InPathToGitBinary, InRepositoryRoot, InParameters, InFiles, OutResults, OutErrorMessages); + } + + return bResult; +} + +// Run a Git "commit" command by batches +bool RunCommit(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages) +{ + bool bResult = true; + + if(InFiles.Num() > GitSourceControlConstants::MaxFilesPerBatch) + { + // Batch files up so we dont exceed command-line limits + int32 FileCount = 0; + { + TArray FilesInBatch; + for(int32 FileIndex = 0; FileIndex < GitSourceControlConstants::MaxFilesPerBatch; FileIndex++, FileCount++) + { + FilesInBatch.Add(InFiles[FileCount]); + } + // First batch is a simple "git commit" command with only the first files + bResult &= RunCommandInternal(TEXT("commit"), InPathToGitBinary, InRepositoryRoot, InParameters, FilesInBatch, OutResults, OutErrorMessages); + } + + TArray Parameters; + for(const auto& Parameter : InParameters) + { + Parameters.Add(Parameter); + } + Parameters.Add(TEXT("--amend")); + + while(FileCount < InFiles.Num()) + { + TArray FilesInBatch; + for(int32 FileIndex = 0; FileCount < InFiles.Num() && FileIndex < GitSourceControlConstants::MaxFilesPerBatch; FileIndex++, FileCount++) + { + FilesInBatch.Add(InFiles[FileCount]); + } + // Next batches "amend" the commit with some more files + TArray BatchResults; + TArray BatchErrors; + bResult &= RunCommandInternal(TEXT("commit"), InPathToGitBinary, InRepositoryRoot, Parameters, FilesInBatch, BatchResults, BatchErrors); + OutResults += BatchResults; + OutErrorMessages += BatchErrors; + } + } + else + { + bResult = RunCommandInternal(TEXT("commit"), InPathToGitBinary, InRepositoryRoot, InParameters, InFiles, OutResults, OutErrorMessages); + } + + return bResult; +} + +/** + * Parse informations on a file locked with Git LFS + * + * Example output of "git lfs locks" +Content\ThirdPersonBP\Blueprints\ThirdPersonCharacter.uasset SRombauts ID:891 +Content\ThirdPersonBP\Blueprints\ThirdPersonGameMode.uasset SRombauts ID:896 + */ +class FGitLfsLocksParser +{ +public: + FGitLfsLocksParser(const FString& InRepositoryRoot, const FString& InStatus, const bool bAbsolutePaths = true) + { + TArray Informations; + InStatus.ParseIntoArray(Informations, TEXT("\t"), true); + if(Informations.Num() >= 3) + { + Informations[0].TrimEndInline(); // Trim whitespace from the end of the filename + Informations[1].TrimEndInline(); // Trim whitespace from the end of the username + if (bAbsolutePaths) + LocalFilename = FPaths::ConvertRelativePathToFull(InRepositoryRoot, Informations[0]); + else + LocalFilename = Informations[0]; + LockUser = MoveTemp(Informations[1]); + } + } + + FString LocalFilename; ///< Filename on disk + FString LockUser; ///< Name of user who has file locked +}; + +/** + * @brief Extract the relative filename from a Git status result. + * + * Examples of status results: +M Content/Textures/T_Perlin_Noise_M.uasset +R Content/Textures/T_Perlin_Noise_M.uasset -> Content/Textures/T_Perlin_Noise_M2.uasset +?? Content/Materials/M_Basic_Wall.uasset +!! BasicCode.sln + * + * @param[in] InResult One line of status + * @return Relative filename extracted from the line of status + * + * @see FGitStatusFileMatcher and StateFromGitStatus() + */ +static FString FilenameFromGitStatus(const FString& InResult) +{ + int32 RenameIndex; + if(InResult.FindLastChar('>', RenameIndex)) + { + // Extract only the second part of a rename "from -> to" + return InResult.RightChop(RenameIndex + 2); + } + else + { + // Extract the relative filename from the Git status result (after the 2 letters status and 1 space) + return InResult.RightChop(3); + } +} + +/** Match the relative filename of a Git status result with a provided absolute filename */ +class FGitStatusFileMatcher +{ +public: + FGitStatusFileMatcher(const FString& InAbsoluteFilename) + : AbsoluteFilename(InAbsoluteFilename) + { + } + + bool operator()(const FString& InResult) const + { + return AbsoluteFilename.Contains(FilenameFromGitStatus(InResult)); + } + +private: + const FString& AbsoluteFilename; +}; + +/** + * Extract and interpret the file state from the given Git status result. + * @see http://git-scm.com/docs/git-status + * ' ' = unmodified + * 'M' = modified + * 'A' = added + * 'D' = deleted + * 'R' = renamed + * 'C' = copied + * 'U' = updated but unmerged + * '?' = unknown/untracked + * '!' = ignored +*/ +class FGitStatusParser +{ +public: + FGitStatusParser(const FString& InResult) + { + TCHAR IndexState = InResult[0]; + TCHAR WCopyState = InResult[1]; + if( (IndexState == 'U' || WCopyState == 'U') + || (IndexState == 'A' && WCopyState == 'A') + || (IndexState == 'D' && WCopyState == 'D')) + { + // "Unmerged" conflict cases are generally marked with a "U", + // but there are also the special cases of both "A"dded, or both "D"eleted + State = EWorkingCopyState::Conflicted; + } + else if(IndexState == 'A') + { + State = EWorkingCopyState::Added; + } + else if(IndexState == 'D') + { + State = EWorkingCopyState::Deleted; + } + else if(WCopyState == 'D') + { + State = EWorkingCopyState::Missing; + } + else if(IndexState == 'M' || WCopyState == 'M') + { + State = EWorkingCopyState::Modified; + } + else if(IndexState == 'R') + { + State = EWorkingCopyState::Renamed; + } + else if(IndexState == 'C') + { + State = EWorkingCopyState::Copied; + } + else if(IndexState == '?' || WCopyState == '?') + { + State = EWorkingCopyState::NotControlled; + } + else if(IndexState == '!' || WCopyState == '!') + { + State = EWorkingCopyState::Ignored; + } + else + { + // Unmodified never yield a status + State = EWorkingCopyState::Unknown; + } + } + + EWorkingCopyState::Type State; +}; + +/** + * Extract the status of a unmerged (conflict) file + * + * Example output of git ls-files --unmerged Content/Blueprints/BP_Test.uasset +100644 d9b33098273547b57c0af314136f35b494e16dcb 1 Content/Blueprints/BP_Test.uasset +100644 a14347dc3b589b78fb19ba62a7e3982f343718bc 2 Content/Blueprints/BP_Test.uasset +100644 f3137a7167c840847cd7bd2bf07eefbfb2d9bcd2 3 Content/Blueprints/BP_Test.uasset + * + * 1: The "common ancestor" of the file (the version of the file that both the current and other branch originated from). + * 2: The version from the current branch (the master branch in this case). + * 3: The version from the other branch (the test branch) +*/ +class FGitConflictStatusParser +{ +public: + /** Parse the unmerge status: extract the base SHA1 identifier of the file */ + FGitConflictStatusParser(const TArray& InResults) + { + const FString& FirstResult = InResults[0]; // 1: The common ancestor of merged branches + CommonAncestorFileId = FirstResult.Mid(7, 40); + } + + FString CommonAncestorFileId; ///< SHA1 Id of the file (warning: not the commit Id) +}; + +/** Execute a command to get the details of a conflict */ +static void RunGetConflictStatus(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InFile, FGitSourceControlState& InOutFileState) +{ + TArray ErrorMessages; + TArray Results; + TArray Files; + Files.Add(InFile); + TArray Parameters; + Parameters.Add(TEXT("--unmerged")); + bool bResult = RunCommandInternal(TEXT("ls-files"), InPathToGitBinary, InRepositoryRoot, Parameters, Files, Results, ErrorMessages); + if(bResult && Results.Num() == 3) + { + // Parse the unmerge status: extract the base revision (or the other branch?) + FGitConflictStatusParser ConflictStatus(Results); + InOutFileState.PendingMergeBaseFileHash = ConflictStatus.CommonAncestorFileId; + } +} + +/// Convert filename relative to the repository root to absolute path (inplace) +void AbsoluteFilenames(const FString& InRepositoryRoot, TArray& InFileNames) +{ + for(auto& FileName : InFileNames) + { + FileName = FPaths::ConvertRelativePathToFull(InRepositoryRoot, FileName); + } +} + +/** Run a 'git ls-files' command to get all files tracked by Git recursively in a directory. + * + * Called in case of a "directory status" (no file listed in the command) when using the "Submit to Source Control" menu. +*/ +static bool ListFilesInDirectoryRecurse(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InDirectory, TArray& OutFiles) +{ + TArray ErrorMessages; + TArray Directory; + Directory.Add(InDirectory); + const bool bResult = RunCommandInternal(TEXT("ls-files"), InPathToGitBinary, InRepositoryRoot, TArray(), Directory, OutFiles, ErrorMessages); + AbsoluteFilenames(InRepositoryRoot, OutFiles); + return bResult; +} + +/** Parse the array of strings results of a 'git status' command for a provided list of files all in a common directory + * + * Called in case of a normal refresh of status on a list of assets in a the Content Browser (or user selected "Refresh" context menu). + * + * Example git status results: +M Content/Textures/T_Perlin_Noise_M.uasset +R Content/Textures/T_Perlin_Noise_M.uasset -> Content/Textures/T_Perlin_Noise_M2.uasset +?? Content/Materials/M_Basic_Wall.uasset +!! BasicCode.sln +*/ +static void ParseFileStatusResult(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool InUsingLfsLocking, const TArray& InFiles, const TMap& InLockedFiles, const TArray& InResults, TArray& OutStates) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const FString LfsUserName = GitSourceControl.AccessSettings().GetLfsUserName(); + const FDateTime Now = FDateTime::Now(); + + // Iterate on all files explicitly listed in the command + for(const auto& File : InFiles) + { + FGitSourceControlState FileState(File, InUsingLfsLocking); + // Search the file in the list of status + int32 IdxResult = InResults.IndexOfByPredicate(FGitStatusFileMatcher(File)); + if(IdxResult != INDEX_NONE) + { + // File found in status results; only the case for "changed" files + FGitStatusParser StatusParser(InResults[IdxResult]); + // TODO LFS Debug log + UE_LOG(LogSourceControl, Log, TEXT("Status(%s) = '%s' => %d"), *File, *InResults[IdxResult], static_cast(StatusParser.State)); + + FileState.WorkingCopyState = StatusParser.State; + if(FileState.IsConflicted()) + { + // In case of a conflict (unmerged file) get the base revision to merge + RunGetConflictStatus(InPathToGitBinary, InRepositoryRoot, File, FileState); + } + } + else + { + // File not found in status + if(FPaths::FileExists(File)) + { + // usually means the file is unchanged, + FileState.WorkingCopyState = EWorkingCopyState::Unchanged; + // TODO LFS Debug log + UE_LOG(LogSourceControl, Log, TEXT("Status(%s) not found but exists => unchanged"), *File); + } + else + { + // but also the case for newly created content: there is no file on disk until the content is saved for the first time + FileState.WorkingCopyState = EWorkingCopyState::NotControlled; + // TODO LFS Debug log + UE_LOG(LogSourceControl, Log, TEXT("Status(%s) not found and does not exists => new/not controled"), *File); + } + } + if(InLockedFiles.Contains(File)) + { + FileState.LockUser = InLockedFiles[File]; + if(LfsUserName == FileState.LockUser) + { + FileState.LockState = ELockState::Locked; + } + else + { + FileState.LockState = ELockState::LockedOther; + } + // TODO LFS Debug log + UE_LOG(LogSourceControl, Log, TEXT("Status(%s) Locked by '%s'"), *File, *FileState.LockUser); + } + else + { + FileState.LockState = ELockState::NotLocked; + // TODO LFS Debug log + if (InUsingLfsLocking) + { + UE_LOG(LogSourceControl, Log, TEXT("Status(%s) Not Locked"), *File); + } + } + FileState.TimeStamp = Now; + OutStates.Add(FileState); + } +} + +/** Parse the array of strings results of a 'git status' command for a directory + * + * Called in case of a "directory status" (no file listed in the command) ONLY to detect Deleted/Missing/Untracked files + * since those files are not listed by the 'git ls-files' command. + * + * @see #ParseFileStatusResult() above for an example of a 'git status' results +*/ +static void ParseDirectoryStatusResult(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool InUsingLfsLocking, const TArray& InResults, TArray& OutStates) +{ + // Iterate on each line of result of the status command + for(const FString& Result : InResults) + { + const FString RelativeFilename = FilenameFromGitStatus(Result); + const FString File = FPaths::ConvertRelativePathToFull(InRepositoryRoot, RelativeFilename); + + FGitSourceControlState FileState(File, InUsingLfsLocking); + FGitStatusParser StatusParser(Result); + if((EWorkingCopyState::Deleted == StatusParser.State) || (EWorkingCopyState::Missing == StatusParser.State) || (EWorkingCopyState::NotControlled == StatusParser.State)) + { + FileState.WorkingCopyState = StatusParser.State; + FileState.TimeStamp.Now(); + OutStates.Add(MoveTemp(FileState)); + } + } +} + +/** + * @brief Detects how to parse the result of a "status" command to get workspace file states + * + * It is either a command for a whole directory (ie. "Content/", in case of "Submit to Source Control" menu), + * or for one or more files all on a same directory (by design, since we group files by directory in RunUpdateStatus()) + * + * @param[in] InPathToGitBinary The path to the Git binary + * @param[in] InRepositoryRoot The Git repository from where to run the command - usually the Game directory (can be empty) + * @param[in] InUsingLfsLocking Tells if using the Git LFS file Locking workflow + * @param[in] InFiles List of files in a directory, or the path to the directory itself (never empty). + * @param[out] InResults Results from the "status" command + * @param[out] OutStates States of files for witch the status has been gathered (distinct than InFiles in case of a "directory status") + */ +static void ParseStatusResults(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool InUsingLfsLocking, const TArray& InFiles, const TMap& InLockedFiles, const TArray& InResults, TArray& OutStates) +{ + if((InFiles.Num() == 1) && FPaths::DirectoryExists(InFiles[0])) + { + // 1) Special case for "status" of a directory: requires to get the list of files by ourselves. + // (this is triggered by the "Submit to Source Control" menu) + // TODO LFS Debug Log + UE_LOG(LogSourceControl, Log, TEXT("ParseStatusResults: 1) Special case for status of a directory (%s)"), *InFiles[0]); + TArray Files; + const FString& Directory = InFiles[0]; + const bool bResult = ListFilesInDirectoryRecurse(InPathToGitBinary, InRepositoryRoot, Directory, Files); + if(bResult) + { + ParseFileStatusResult(InPathToGitBinary, InRepositoryRoot, InUsingLfsLocking, Files, InLockedFiles, InResults, OutStates); + } + // The above cannot detect deleted assets since there is no file left to enumerate (either by the Content Browser or by git ls-files) + // => so we also parse the status results to explicitly look for Deleted/Missing assets + ParseDirectoryStatusResult(InPathToGitBinary, InRepositoryRoot, InUsingLfsLocking, InResults, OutStates); + } + else + { + // 2) General case for one or more files in the same directory. + // TODO LFS Debug Log + UE_LOG(LogSourceControl, Log, TEXT("ParseStatusResults: 2) General case for one or more files (%s, ...)"), *InFiles[0]); + ParseFileStatusResult(InPathToGitBinary, InRepositoryRoot, InUsingLfsLocking, InFiles, InLockedFiles, InResults, OutStates); + } +} + +bool GetAllLocks(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool bAbsolutePaths, TArray& OutErrorMessages, TMap& OutLocks) +{ + TArray Results; + TArray ErrorMessages; + const bool bResult = RunCommand(TEXT("lfs locks"), InPathToGitBinary, InRepositoryRoot, TArray(), TArray(), Results, ErrorMessages); + for(const FString& Result : Results) + { + FGitLfsLocksParser LockFile(InRepositoryRoot, Result, bAbsolutePaths); + // TODO LFS Debug log + UE_LOG(LogSourceControl, Log, TEXT("LockedFile(%s, %s)"), *LockFile.LocalFilename, *LockFile.LockUser); + OutLocks.Add(MoveTemp(LockFile.LocalFilename), MoveTemp(LockFile.LockUser)); + } + + return bResult; +} + +// Run a batch of Git "status" command to update status of given files and/or directories. +bool RunUpdateStatus(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool InUsingLfsLocking, const TArray& InFiles, TArray& OutErrorMessages, TArray& OutStates) +{ + bool bResults = true; + TMap LockedFiles; + + // 0) Issue a "git lfs locks" command at the root of the repository + if(InUsingLfsLocking) + { + TArray ErrorMessages; + GetAllLocks(InPathToGitBinary, InRepositoryRoot, true, ErrorMessages, LockedFiles); + } + + // Git status does not show any "untracked files" when called with files from different subdirectories! (issue #3) + // 1) So here we group files by path (ie. by subdirectory) + TMap> GroupOfFiles; + for(const auto& File : InFiles) + { + const FString Path = FPaths::GetPath(*File); + TArray* Group = GroupOfFiles.Find(Path); + if(Group != nullptr) + { + Group->Add(File); + } + else + { + TArray NewGroup; + NewGroup.Add(File); + GroupOfFiles.Add(Path, NewGroup); + } + } + + // Get the current branch name, since we need origin of current branch + FString BranchName; + GitSourceControlUtils::GetBranchName(InPathToGitBinary, InRepositoryRoot, BranchName); + + TArray Parameters; + Parameters.Add(TEXT("--porcelain")); + Parameters.Add(TEXT("--ignored")); + + // 2) then we can batch git status operation by subdirectory + for(const auto& Files : GroupOfFiles) + { + // "git status" can only detect renamed and deleted files when it operate on a folder, so use one folder path for all files in a directory + const FString Path = FPaths::GetPath(*Files.Value[0]); + TArray OnePath; + // Only one file: optim very useful for the .uproject file at the root to avoid parsing the whole repository + // (works only if the file exists) + if((Files.Value.Num() == 1) && (FPaths::FileExists(Files.Value[0]))) + { + OnePath.Add(Files.Value[0]); + } + else + { + OnePath.Add(Path); + } + { + TArray Results; + TArray ErrorMessages; + const bool bResult = RunCommand(TEXT("status"), InPathToGitBinary, InRepositoryRoot, Parameters, OnePath, Results, ErrorMessages); + OutErrorMessages.Append(ErrorMessages); + if(bResult) + { + ParseStatusResults(InPathToGitBinary, InRepositoryRoot, InUsingLfsLocking, Files.Value, LockedFiles, Results, OutStates); + } + } + + if (!BranchName.IsEmpty()) + { + // Using git diff, we can obtain a list of files that were modified between our current origin and HEAD. Assumes that fetch has been run to get accurate info. + // TODO: should do a fetch (at least periodically). + TArray Results; + TArray ErrorMessages; + TArray ParametersLsRemote; + ParametersLsRemote.Add(TEXT("origin")); + ParametersLsRemote.Add(BranchName); + const bool bResultLsRemote = RunCommand(TEXT("ls-remote"), InPathToGitBinary, InRepositoryRoot, ParametersLsRemote, OnePath, Results, ErrorMessages); + // If the command is successful and there is only 1 line on the output the branch exists on remote + const bool bDiffAgainstRemote = bResultLsRemote && Results.Num(); + + Results.Reset(); + ErrorMessages.Reset(); + TArray ParametersLog; + ParametersLog.Add(TEXT("--pretty=")); // this omits the commit lines, just gets us files + ParametersLog.Add(TEXT("--name-only")); + ParametersLog.Add(bDiffAgainstRemote ? TEXT("HEAD..HEAD@{upstream}") : BranchName); + const bool bResultDiff = RunCommand(TEXT("log"), InPathToGitBinary, InRepositoryRoot, ParametersLog, OnePath, Results, ErrorMessages); + OutErrorMessages.Append(ErrorMessages); + if (bResultDiff) + { + for (const FString& NewerFileName : Results) + { + const FString NewerFilePath = FPaths::ConvertRelativePathToFull(InRepositoryRoot, NewerFileName); + + // Find existing corresponding file state to update it (not found would mean new file or not in the current path) + if (FGitSourceControlState* FileStatePtr = OutStates.FindByPredicate([NewerFilePath](FGitSourceControlState& FileState) { return FileState.LocalFilename == NewerFilePath; })) + { + FileStatePtr->bNewerVersionOnServer = true; + } + } + } + } + } + + return bResults; +} + +// Run a Git `cat-file --filters` command to dump the binary content of a revision into a file. +bool RunDumpToFile(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InParameter, const FString& InDumpFileName) +{ + int32 ReturnCode = -1; + FString FullCommand; + + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const FGitVersion& GitVersion = GitSourceControl.GetProvider().GetGitVersion(); + + if(!InRepositoryRoot.IsEmpty()) + { + // Specify the working copy (the root) of the git repository (before the command itself) + FullCommand = TEXT("-C \""); + FullCommand += InRepositoryRoot; + FullCommand += TEXT("\" "); + } + + // then the git command itself + if(GitVersion.bHasCatFileWithFilters) + { + // Newer versions (2.9.3.windows.2) support smudge/clean filters used by Git LFS, git-fat, git-annex, etc + FullCommand += TEXT("cat-file --filters "); + } + else + { + // Previous versions fall-back on "git show" like before + FullCommand += TEXT("show "); + } + + // Append to the command the parameter + FullCommand += InParameter; + + const bool bLaunchDetached = false; + const bool bLaunchHidden = true; + const bool bLaunchReallyHidden = bLaunchHidden; + + void* PipeRead = nullptr; + void* PipeWrite = nullptr; + + verify(FPlatformProcess::CreatePipe(PipeRead, PipeWrite)); + + UE_LOG(LogSourceControl, Log, TEXT("RunDumpToFile: 'git %s'"), *FullCommand); + + FString PathToGitOrEnvBinary = InPathToGitBinary; + #if PLATFORM_MAC + // The Cocoa application does not inherit shell environment variables, so add the path expected to have git-lfs to PATH + FString PathEnv = FPlatformMisc::GetEnvironmentVariable(TEXT("PATH")); + FString GitInstallPath = FPaths::GetPath(InPathToGitBinary); + + TArray PathArray; + PathEnv.ParseIntoArray(PathArray, FPlatformMisc::GetPathVarDelimiter()); + bool bHasGitInstallPath = false; + for (auto Path : PathArray) + { + if (GitInstallPath.Equals(Path, ESearchCase::CaseSensitive)) + { + bHasGitInstallPath = true; + break; + } + } + + if (!bHasGitInstallPath) + { + PathToGitOrEnvBinary = FString("/usr/bin/env"); + FullCommand = FString::Printf(TEXT("PATH=\"%s%s%s\" \"%s\" %s"), *GitInstallPath, FPlatformMisc::GetPathVarDelimiter(), *PathEnv, *InPathToGitBinary, *FullCommand); + } + #endif + + FProcHandle ProcessHandle = FPlatformProcess::CreateProc(*PathToGitOrEnvBinary, *FullCommand, bLaunchDetached, bLaunchHidden, bLaunchReallyHidden, nullptr, 0, *InRepositoryRoot, PipeWrite); + if(ProcessHandle.IsValid()) + { + FPlatformProcess::Sleep(0.01); + + TArray BinaryFileContent; + while(FPlatformProcess::IsProcRunning(ProcessHandle)) + { + TArray BinaryData; + FPlatformProcess::ReadPipeToArray(PipeRead, BinaryData); + if(BinaryData.Num() > 0) + { + BinaryFileContent.Append(MoveTemp(BinaryData)); + } + } + TArray BinaryData; + FPlatformProcess::ReadPipeToArray(PipeRead, BinaryData); + if(BinaryData.Num() > 0) + { + BinaryFileContent.Append(MoveTemp(BinaryData)); + } + + FPlatformProcess::GetProcReturnCode(ProcessHandle, &ReturnCode); + if(ReturnCode == 0) + { + // Save buffer into temp file + if(FFileHelper::SaveArrayToFile(BinaryFileContent, *InDumpFileName)) + { + UE_LOG(LogSourceControl, Log, TEXT("Writed '%s' (%do)"), *InDumpFileName, BinaryFileContent.Num()); + } + else + { + UE_LOG(LogSourceControl, Error, TEXT("Could not write %s"), *InDumpFileName); + ReturnCode = -1; + } + } + else + { + UE_LOG(LogSourceControl, Error, TEXT("DumpToFile: ReturnCode=%d"), ReturnCode); + } + + FPlatformProcess::CloseProc(ProcessHandle); + } + else + { + UE_LOG(LogSourceControl, Error, TEXT("Failed to launch 'git cat-file'")); + } + + FPlatformProcess::ClosePipe(PipeRead, PipeWrite); + + return (ReturnCode == 0); +} + +/** + * Translate file actions from the given Git log --name-status command to keywords used by the Editor UI. + * + * @see https://www.kernel.org/pub/software/scm/git/docs/git-log.html + * ' ' = unmodified + * 'M' = modified + * 'A' = added + * 'D' = deleted + * 'R' = renamed + * 'C' = copied + * 'T' = type changed + * 'U' = updated but unmerged + * 'X' = unknown + * 'B' = broken pairing + * + * @see SHistoryRevisionListRowContent::GenerateWidgetForColumn(): "add", "edit", "delete", "branch" and "integrate" (everything else is taken like "edit") +*/ +static FString LogStatusToString(TCHAR InStatus) +{ + switch(InStatus) + { + case TEXT(' '): + return FString("unmodified"); + case TEXT('M'): + return FString("modified"); + case TEXT('A'): // added: keyword "add" to display a specific icon instead of the default "edit" action one + return FString("add"); + case TEXT('D'): // deleted: keyword "delete" to display a specific icon instead of the default "edit" action one + return FString("delete"); + case TEXT('R'): // renamed keyword "branch" to display a specific icon instead of the default "edit" action one + return FString("branch"); + case TEXT('C'): // copied keyword "branch" to display a specific icon instead of the default "edit" action one + return FString("branch"); + case TEXT('T'): + return FString("type changed"); + case TEXT('U'): + return FString("unmerged"); + case TEXT('X'): + return FString("unknown"); + case TEXT('B'): + return FString("broked pairing"); + } + + return FString(); +} + +/** + * Parse the array of strings results of a 'git log' command + * + * Example git log results: +commit 97a4e7626681895e073aaefd68b8ac087db81b0b +Author: Sébastien Rombauts +Date: 2014-2015-05-15 21:32:27 +0200 + + Another commit used to test History + + - with many lines + - some + - and strange characteres $*+ + +M Content/Blueprints/Blueprint_CeilingLight.uasset +R100 Content/Textures/T_Concrete_Poured_D.uasset Content/Textures/T_Concrete_Poured_D2.uasset + +commit 355f0df26ebd3888adbb558fd42bb8bd3e565000 +Author: Sébastien Rombauts +Date: 2014-2015-05-12 11:28:14 +0200 + + Testing git status, edit, and revert + +A Content/Blueprints/Blueprint_CeilingLight.uasset +C099 Content/Textures/T_Concrete_Poured_N.uasset Content/Textures/T_Concrete_Poured_N2.uasset +*/ +static void ParseLogResults(const TArray& InResults, TGitSourceControlHistory& OutHistory) +{ + TSharedRef SourceControlRevision = MakeShareable(new FGitSourceControlRevision); + for(const auto& Result : InResults) + { + if(Result.StartsWith(TEXT("commit "))) // Start of a new commit + { + // End of the previous commit + if(SourceControlRevision->RevisionNumber != 0) + { + OutHistory.Add(MoveTemp(SourceControlRevision)); + + SourceControlRevision = MakeShareable(new FGitSourceControlRevision); + } + SourceControlRevision->CommitId = Result.RightChop(7); // Full commit SHA1 hexadecimal string + SourceControlRevision->ShortCommitId = SourceControlRevision->CommitId.Left(8); // Short revision ; first 8 hex characters (max that can hold a 32 bit integer) + SourceControlRevision->CommitIdNumber = FParse::HexNumber(*SourceControlRevision->ShortCommitId); + SourceControlRevision->RevisionNumber = -1; // RevisionNumber will be set at the end, based off the index in the History + } + else if(Result.StartsWith(TEXT("Author: "))) // Author name & email + { + // Remove the 'email' part of the UserName + FString UserNameEmail = Result.RightChop(8); + int32 EmailIndex = 0; + if(UserNameEmail.FindLastChar('<', EmailIndex)) + { + SourceControlRevision->UserName = UserNameEmail.Left(EmailIndex - 1); + } + } + else if(Result.StartsWith(TEXT("Date: "))) // Commit date + { + FString Date = Result.RightChop(8); + SourceControlRevision->Date = FDateTime::FromUnixTimestamp(FCString::Atoi(*Date)); + } + // else if(Result.IsEmpty()) // empty line before/after commit message has already been taken care by FString::ParseIntoArray() + else if(Result.StartsWith(TEXT(" "))) // Multi-lines commit message + { + SourceControlRevision->Description += Result.RightChop(4); + SourceControlRevision->Description += TEXT("\n"); + } + else // Name of the file, starting with an uppercase status letter ("A"/"M"...) + { + const TCHAR Status = Result[0]; + SourceControlRevision->Action = LogStatusToString(Status); // Readable action string ("Added", Modified"...) instead of "A"/"M"... + // Take care of special case for Renamed/Copied file: extract the second filename after second tabulation + int32 IdxTab; + if(Result.FindLastChar('\t', IdxTab)) + { + SourceControlRevision->Filename = Result.RightChop(IdxTab + 1); // relative filename + } + } + } + // End of the last commit + if(SourceControlRevision->RevisionNumber != 0) + { + OutHistory.Add(MoveTemp(SourceControlRevision)); + } + + // Then set the revision number of each Revision based on its index (reverse order since the log starts with the most recent change) + for(int32 RevisionIndex = 0; RevisionIndex < OutHistory.Num(); RevisionIndex++) + { + const auto& SourceControlRevisionItem = OutHistory[RevisionIndex]; + SourceControlRevisionItem->RevisionNumber = OutHistory.Num() - RevisionIndex; + + // Special case of a move ("branch" in Perforce term): point to the previous change (so the next one in the order of the log) + if((SourceControlRevisionItem->Action == "branch") && (RevisionIndex < OutHistory.Num() - 1)) + { + SourceControlRevisionItem->BranchSource = OutHistory[RevisionIndex + 1]; + } + } +} + +/** + * Extract the SHA1 identifier and size of a blob (file) from a Git "ls-tree" command. + * + * Example output for the command git ls-tree --long 7fdaeb2 Content/Blueprints/BP_Test.uasset +100644 blob a14347dc3b589b78fb19ba62a7e3982f343718bc 70731 Content/Blueprints/BP_Test.uasset +*/ +class FGitLsTreeParser +{ +public: + /** Parse the unmerge status: extract the base SHA1 identifier of the file */ + FGitLsTreeParser(const TArray& InResults) + { + const FString& FirstResult = InResults[0]; + FileHash = FirstResult.Mid(12, 40); + int32 IdxTab; + if(FirstResult.FindChar('\t', IdxTab)) + { + const FString SizeString = FirstResult.Mid(53, IdxTab - 53); + FileSize = FCString::Atoi(*SizeString); + } + } + + FString FileHash; ///< SHA1 Id of the file (warning: not the commit Id) + int32 FileSize; ///< Size of the file (in bytes) +}; + +// Run a Git "log" command and parse it. +bool RunGetHistory(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InFile, bool bMergeConflict, TArray& OutErrorMessages, TGitSourceControlHistory& OutHistory) +{ + bool bResults; + { + TArray Results; + TArray Parameters; + Parameters.Add(TEXT("--follow")); // follow file renames + Parameters.Add(TEXT("--date=raw")); + Parameters.Add(TEXT("--name-status")); // relative filename at this revision, preceded by a status character + Parameters.Add(TEXT("--pretty=medium")); // make sure format matches expected in ParseLogResults + if(bMergeConflict) + { + // In case of a merge conflict, we also need to get the tip of the "remote branch" (MERGE_HEAD) before the log of the "current branch" (HEAD) + // @todo does not work for a cherry-pick! Test for a rebase. + Parameters.Add(TEXT("MERGE_HEAD")); + Parameters.Add(TEXT("--max-count 1")); + } + TArray Files; + Files.Add(*InFile); + bResults = RunCommand(TEXT("log"), InPathToGitBinary, InRepositoryRoot, Parameters, Files, Results, OutErrorMessages); + if(bResults) + { + ParseLogResults(Results, OutHistory); + } + } + for(auto& Revision : OutHistory) + { + // Get file (blob) sha1 id and size + TArray Results; + TArray Parameters; + Parameters.Add(TEXT("--long")); // Show object size of blob (file) entries. + Parameters.Add(Revision->GetRevision()); + TArray Files; + Files.Add(*Revision->GetFilename()); + bResults &= RunCommand(TEXT("ls-tree"), InPathToGitBinary, InRepositoryRoot, Parameters, Files, Results, OutErrorMessages); + if(bResults && Results.Num()) + { + FGitLsTreeParser LsTree(Results); + Revision->FileHash = LsTree.FileHash; + Revision->FileSize = LsTree.FileSize; + } + } + + return bResults; +} + +TArray RelativeFilenames(const TArray& InFileNames, const FString& InRelativeTo) +{ + TArray RelativeFiles; + FString RelativeTo = InRelativeTo; + + // Ensure that the path ends w/ '/' + if((RelativeTo.Len() > 0) && (RelativeTo.EndsWith(TEXT("/"), ESearchCase::CaseSensitive) == false) && (RelativeTo.EndsWith(TEXT("\\"), ESearchCase::CaseSensitive) == false)) + { + RelativeTo += TEXT("/"); + } + for(FString FileName : InFileNames) // string copy to be able to convert it inplace + { + if(FPaths::MakePathRelativeTo(FileName, *RelativeTo)) + { + RelativeFiles.Add(FileName); + } + } + + return RelativeFiles; +} + +TArray AbsoluteFilenames(const TArray& InFileNames, const FString& InRelativeTo) +{ + TArray AbsFiles; + + for(FString FileName : InFileNames) // string copy to be able to convert it inplace + { + AbsFiles.Add(FPaths::Combine(InRelativeTo, FileName)); + } + + return AbsFiles; +} + +bool UpdateCachedStates(const TArray& InStates) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked( "GitSourceControl" ); + FGitSourceControlProvider& Provider = GitSourceControl.GetProvider(); + const bool bUsingGitLfsLocking = GitSourceControl.AccessSettings().IsUsingGitLfsLocking(); + + // TODO without LFS : Workaround a bug with the Source Control Module not updating file state after a simple "Save" with no "Checkout" (when not using File Lock) + const FDateTime Now = bUsingGitLfsLocking ? FDateTime::Now() : FDateTime(); + + for(const auto& InState : InStates) + { + TSharedRef State = Provider.GetStateInternal(InState.LocalFilename); + *State = InState; + State->TimeStamp = Now; + } + + return (InStates.Num() > 0); +} + +/** + * Helper struct for RemoveRedundantErrors() + */ +struct FRemoveRedundantErrors +{ + FRemoveRedundantErrors(const FString& InFilter) + : Filter(InFilter) + { + } + + bool operator()(const FString& String) const + { + if(String.Contains(Filter)) + { + return true; + } + + return false; + } + + /** The filter string we try to identify in the reported error */ + FString Filter; +}; + +void RemoveRedundantErrors(FGitSourceControlCommand& InCommand, const FString& InFilter) +{ + bool bFoundRedundantError = false; + for(auto Iter(InCommand.ErrorMessages.CreateConstIterator()); Iter; Iter++) + { + if(Iter->Contains(InFilter)) + { + InCommand.InfoMessages.Add(*Iter); + bFoundRedundantError = true; + } + } + + InCommand.ErrorMessages.RemoveAll( FRemoveRedundantErrors(InFilter) ); + + // if we have no error messages now, assume success! + if(bFoundRedundantError && InCommand.ErrorMessages.Num() == 0 && !InCommand.bCommandSuccessful) + { + InCommand.bCommandSuccessful = true; + } +} + +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h new file mode 100644 index 0000000..aca0166 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlUtils.h @@ -0,0 +1,221 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "GitSourceControlState.h" + +class FGitSourceControlCommand; + +/** + * Helper struct for maintaining temporary files for passing to commands + */ +class FGitScopedTempFile +{ +public: + + /** Constructor - open & write string to temp file */ + FGitScopedTempFile(const FText& InText); + + /** Destructor - delete temp file */ + ~FGitScopedTempFile(); + + /** Get the filename of this temp file - empty if it failed to be created */ + const FString& GetFilename() const; + +private: + /** The filename we are writing to */ + FString Filename; +}; + +struct FGitVersion; + +namespace GitSourceControlUtils +{ + +/** + * Find the path to the Git binary, looking into a few places (standalone Git install, and other common tools embedding Git) + * @returns the path to the Git binary if found, or an empty string. + */ +FString FindGitBinaryPath(); + +/** + * Run a Git "version" command to check the availability of the binary. + * @param InPathToGitBinary The path to the Git binary + * @param OutGitVersion If provided, populate with the git version parsed from "version" command + * @returns true if the command succeeded and returned no errors + */ +bool CheckGitAvailability(const FString& InPathToGitBinary, FGitVersion* OutVersion = nullptr); + +/** + * Parse the output from the "version" command into GitMajorVersion and GitMinorVersion. + * @param InVersionString The version string returned by `git --version` + * @param OutVersion The FGitVersion to populate + */ + void ParseGitVersion(const FString& InVersionString, FGitVersion* OutVersion); + +/** + * Check git for various optional capabilities by various means. + * @param InPathToGitBinary The path to the Git binary + * @param OutGitVersion If provided, populate with the git version parsed from "version" command + */ +void FindGitCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion); + +/** + * Run a Git "lfs" command to check the availability of the "Large File System" extension. + * @param InPathToGitBinary The path to the Git binary + * @param OutGitVersion If provided, populate with the git version parsed from "version" command + */ + void FindGitLfsCapabilities(const FString& InPathToGitBinary, FGitVersion *OutVersion); + +/** + * Find the root of the Git repository, looking from the provided path and upward in its parent directories + * @param InPath The path to the Game Directory (or any path or file in any git repository) + * @param OutRepositoryRoot The path to the root directory of the Git repository if found, else the path to the ProjectDir + * @returns true if the command succeeded and returned no errors + */ +bool FindRootDirectory(const FString& InPath, FString& OutRepositoryRoot); + +/** + * Get Git config user.name & user.email + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory (can be empty) + * @param OutUserName Name of the Git user configured for this repository (or globaly) + * @param OutEmailName E-mail of the Git user configured for this repository (or globaly) + */ +void GetUserConfig(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutUserName, FString& OutUserEmail); + +/** + * Get Git current checked-out branch + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param OutBranchName Name of the current checked-out branch (if any, ie. not in detached HEAD) + * @returns true if the command succeeded and returned no errors + */ +bool GetBranchName(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutBranchName); + +/** + * Get Git current commit details + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param OutCommitId Current Commit full SHA1 + * @param OutCommitSummary Current Commit description's Summary + * @returns true if the command succeeded and returned no errors + */ +bool GetCommitInfo(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutCommitId, FString& OutCommitSummary); + +/** + * Get the URL of the "origin" defaut remote server + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param OutRemoteUrl URL of "origin" defaut remote server + * @returns true if the command succeeded and returned no errors + */ +bool GetRemoteUrl(const FString& InPathToGitBinary, const FString& InRepositoryRoot, FString& OutRemoteUrl); + +/** + * Run a Git command - output is a string TArray. + * + * @param InCommand The Git command - e.g. commit + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory (can be empty) + * @param InParameters The parameters to the Git command + * @param InFiles The files to be operated on + * @param OutResults The results (from StdOut) as an array per-line + * @param OutErrorMessages Any errors (from StdErr) as an array per-line + * @returns true if the command succeeded and returned no errors + */ +bool RunCommand(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages); +bool RunCommandInternalRaw(const FString& InCommand, const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, FString& OutResults, FString& OutErrors, const int32 ExpectedReturnCode = 0); + +/** + * Run a Git "commit" command by batches. + * + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param InParameter The parameters to the Git commit command + * @param InFiles The files to be operated on + * @param OutErrorMessages Any errors (from StdErr) as an array per-line + * @returns true if the command succeeded and returned no errors + */ +bool RunCommit(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const TArray& InParameters, const TArray& InFiles, TArray& OutResults, TArray& OutErrorMessages); + +/** + * Run a Git "status" command and parse it. + * + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory (can be empty) + * @param InUsingLfsLocking Tells if using the Git LFS file Locking workflow + * @param InFiles The files to be operated on + * @param OutErrorMessages Any errors (from StdErr) as an array per-line + * @returns true if the command succeeded and returned no errors + */ +bool RunUpdateStatus(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool InUsingLfsLocking, const TArray& InFiles, TArray& OutErrorMessages, TArray& OutStates); + +/** + * Run a Git "cat-file" command to dump the binary content of a revision into a file. + * + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param InParameter The parameters to the Git show command (rev:path) + * @param InDumpFileName The temporary file to dump the revision + * @returns true if the command succeeded and returned no errors +*/ +bool RunDumpToFile(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InParameter, const FString& InDumpFileName); + +/** + * Run a Git "log" command and parse it. + * + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param InFile The file to be operated on + * @param bMergeConflict In case of a merge conflict, we also need to get the tip of the "remote branch" (MERGE_HEAD) before the log of the "current branch" (HEAD) + * @param OutErrorMessages Any errors (from StdErr) as an array per-line + * @param OutHistory The history of the file + */ +bool RunGetHistory(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const FString& InFile, bool bMergeConflict, TArray& OutErrorMessages, TGitSourceControlHistory& OutHistory); + +/** + * Helper function to convert a filename array to relative paths. + * @param InFileNames The filename array + * @param InRelativeTo Path to the WorkspaceRoot + * @return an array of filenames, transformed into relative paths + */ +TArray RelativeFilenames(const TArray& InFileNames, const FString& InRelativeTo); + +/** + * Helper function to convert a filename array to absolute paths. + * @param InFileNames The filename array (relative paths) + * @param InRelativeTo Path to the WorkspaceRoot + * @return an array of filenames, transformed into absolute paths + */ +TArray AbsoluteFilenames(const TArray& InFileNames, const FString& InRelativeTo); + +/** + * Helper function for various commands to update cached states. + * @returns true if any states were updated + */ +bool UpdateCachedStates(const TArray& InStates); + +/** + * Remove redundant errors (that contain a particular string) and also + * update the commands success status if all errors were removed. + */ +void RemoveRedundantErrors(FGitSourceControlCommand& InCommand, const FString& InFilter); + +/** + * Run 'git lfs locks" to extract all lock information for all files in the repository + * + * @param InPathToGitBinary The path to the Git binary + * @param InRepositoryRoot The Git repository from where to run the command - usually the Game directory + * @param bAbsolutePaths Whether to report absolute filenames, false for repo-relative + * @param OutErrorMessages Any errors (from StdErr) as an array per-line + * @param OutLocks The lock results (file, username) + * @returns true if the command succeeded and returned no errors + */ +bool GetAllLocks(const FString& InPathToGitBinary, const FString& InRepositoryRoot, const bool bAbsolutePaths, TArray& OutErrorMessages, TMap& OutLocks); + +} diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/IGitSourceControlWorker.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/IGitSourceControlWorker.h new file mode 100644 index 0000000..017386d --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/IGitSourceControlWorker.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" + +class IGitSourceControlWorker +{ +public: + /** + * Name describing the work that this worker does. Used for factory method hookup. + */ + virtual FName GetName() const = 0; + + /** + * Function that actually does the work. Can be executed on another thread. + */ + virtual bool Execute( class FGitSourceControlCommand& InCommand ) = 0; + + /** + * Updates the state of any items after completion (if necessary). This is always executed on the main thread. + * @returns true if states were updated + */ + virtual bool UpdateStates() const = 0; +}; + +typedef TSharedRef FGitSourceControlWorkerRef; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp new file mode 100644 index 0000000..11550c3 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.cpp @@ -0,0 +1,820 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#include "SGitSourceControlSettings.h" + +#include "Fonts/SlateFontInfo.h" +#include "Misc/App.h" +#include "Misc/FileHelper.h" +#include "Misc/Paths.h" +#include "Modules/ModuleManager.h" +#include "Styling/SlateTypes.h" +#include "Widgets/SBoxPanel.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Input/SCheckBox.h" +#include "Widgets/Input/SEditableTextBox.h" +#include "Widgets/Input/SFilePathPicker.h" +#include "Widgets/Input/SMultiLineEditableTextBox.h" +#include "Widgets/Layout/SBorder.h" +#include "Widgets/Layout/SSeparator.h" +#include "Widgets/Notifications/SNotificationList.h" +#include "Framework/Notifications/NotificationManager.h" +#include "EditorDirectories.h" +#include "Runtime/Launch/Resources/Version.h" +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 +#include "Styling/AppStyle.h" +#else +#include "EditorStyleSet.h" +#endif +#include "SourceControlOperations.h" +#include "GitSourceControlModule.h" +#include "GitSourceControlUtils.h" + +#define LOCTEXT_NAMESPACE "SGitSourceControlSettings" + +void SGitSourceControlSettings::Construct(const FArguments& InArgs) +{ +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + const FSlateFontInfo Font = FAppStyle::GetFontStyle(TEXT("SourceControl.LoginWindow.Font")); +#else + const FSlateFontInfo Font = FEditorStyle::GetFontStyle(TEXT("SourceControl.LoginWindow.Font")); +#endif + + bAutoCreateGitIgnore = true; + bAutoCreateReadme = true; + bAutoCreateGitAttributes = false; + bAutoInitialCommit = true; + + InitialCommitMessage = LOCTEXT("InitialCommitMessage", "Initial commit"); + + const FText FileFilterType = NSLOCTEXT("GitSourceControl", "Executables", "Executables"); +#if PLATFORM_WINDOWS + const FString FileFilterText = FString::Printf(TEXT("%s (*.exe)|*.exe"), *FileFilterType.ToString()); +#else + const FString FileFilterText = FString::Printf(TEXT("%s"), *FileFilterType.ToString()); +#endif + + ReadmeContent = FText::FromString(FString(TEXT("# ")) + FApp::GetProjectName() + "\n\nDeveloped with Unreal Engine 4\n"); + + ChildSlot + [ +#if ENGINE_MAJOR_VERSION == 4 + SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("DetailsView.CategoryBottom")) + .Padding(FMargin(0.0f, 3.0f, 0.0f, 0.0f)) + [ +#endif + SNew(SVerticalBox) + // Path to the Git command line executable + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("BinaryPathLabel_Tooltip", "Path to Git binary")) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("BinaryPathLabel", "Git Path")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + [ + SNew(SFilePathPicker) +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + .BrowseButtonImage(FAppStyle::Get().GetBrush("PropertyWindow.Button_Ellipsis")) + .BrowseButtonStyle(FAppStyle::Get(), "HoverHintOnly") +#else + .BrowseButtonImage(FEditorStyle::GetBrush("PropertyWindow.Button_Ellipsis")) + .BrowseButtonStyle(FEditorStyle::Get(), "HoverHintOnly") +#endif + .BrowseDirectory(FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_OPEN)) + .BrowseTitle(LOCTEXT("BinaryPathBrowseTitle", "File picker...")) + .FilePath(this, &SGitSourceControlSettings::GetBinaryPathString) + .FileTypeFilter(FileFilterText) + .OnPathPicked(this, &SGitSourceControlSettings::OnBinaryPathPicked) + ] + ] + // Root of the local repository + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("RepositoryRootLabel_Tooltip", "Path to the root of the Git repository")) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("RepositoryRootLabel", "Root of the repository")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + [ + SNew(STextBlock) + .Text(this, &SGitSourceControlSettings::GetPathToRepositoryRoot) + .Font(Font) + ] + ] + // User Name + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("GitUserName_Tooltip", "User name configured for the Git repository")) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("GitUserName", "User Name")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + [ + SNew(STextBlock) + .Text(this, &SGitSourceControlSettings::GetUserName) + .Font(Font) + ] + ] + // User e-mail + + SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("GitUserEmail_Tooltip", "User e-mail configured for the Git repository")) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("GitUserEmail", "E-Mail")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + [ + SNew(STextBlock) + .Text(this, &SGitSourceControlSettings::GetUserEmail) + .Font(Font) + ] + ] + // Separator + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SSeparator) + ] + // Explanation text + + SVerticalBox::Slot() + .FillHeight(1.0f) + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .HAlign(HAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("RepositoryNotFound", "Current Project is not contained in a Git Repository. Fill the form below to initialize a new Repository.")) + .ToolTipText(LOCTEXT("RepositoryNotFound_Tooltip", "No Repository found at the level or above the current Project")) + .Font(Font) + ] + ] + // Option to configure the URL of the default remote 'origin' + // TODO: option to configure the name of the remote instead of the default origin + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + .ToolTipText(LOCTEXT("ConfigureOrigin_Tooltip", "Configure the URL of the default remote 'origin'")) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("ConfigureOrigin", "URL of the remote server 'origin'")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SEditableTextBox) + .Text(this, &SGitSourceControlSettings::GetRemoteUrl) + .OnTextCommitted(this, &SGitSourceControlSettings::OnRemoteUrlCommited) + .Font(Font) + ] + ] + // Option to add a proper .gitignore file (true by default) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + .ToolTipText(LOCTEXT("CreateGitIgnore_Tooltip", "Create and add a standard '.gitignore' file")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(ECheckBoxState::Checked) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateGitIgnore) + ] + + SHorizontalBox::Slot() + .FillWidth(2.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CreateGitIgnore", "Add a .gitignore file")) + .Font(Font) + ] + ] + // Option to add a README.md file with custom content + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + .ToolTipText(LOCTEXT("CreateReadme_Tooltip", "Add a README.md file")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(ECheckBoxState::Checked) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateReadme) + ] + + SHorizontalBox::Slot() + .FillWidth(0.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CreateReadme", "Add a basic README.md file")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + .Padding(2.0f) + [ + SNew(SMultiLineEditableTextBox) + .Text(this, &SGitSourceControlSettings::GetReadmeContent) + .OnTextCommitted(this, &SGitSourceControlSettings::OnReadmeContentCommited) + .IsEnabled(this, &SGitSourceControlSettings::GetAutoCreateReadme) + .SelectAllTextWhenFocused(true) + .Font(Font) + ] + ] + // Option to add a proper .gitattributes file for Git LFS (false by default) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + .ToolTipText(LOCTEXT("CreateGitAttributes_Tooltip", "Create and add a '.gitattributes' file to enable Git LFS for the whole 'Content/' directory (needs Git LFS extensions to be installed).")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(ECheckBoxState::Unchecked) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedCreateGitAttributes) + .IsEnabled(this, &SGitSourceControlSettings::CanInitializeGitLfs) + ] + + SHorizontalBox::Slot() + .FillWidth(2.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("CreateGitAttributes", "Add a .gitattributes file to enable Git LFS")) + .Font(Font) + ] + ] + // Option to use the Git LFS File Locking workflow (false by default) + // Enabled even after init to switch it off in case of no network + // TODO LFS turning it off afterwards does not work because all files are readonly ! + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("UseGitLfsLocking_Tooltip", "Uses Git LFS 2 File Locking workflow (CheckOut and Commit/Push).")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(SGitSourceControlSettings::IsUsingGitLfsLocking()) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedUseGitLfsLocking) + .IsEnabled(this, &SGitSourceControlSettings::CanUseGitLfsLocking) + ] + + SHorizontalBox::Slot() + .FillWidth(0.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("UseGitLfsLocking", "Uses Git LFS 2 File Locking workflow")) + .Font(Font) + ] + // Username credential used to access the Git LFS 2 File Locks server + + SHorizontalBox::Slot() + .FillWidth(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SEditableTextBox) + .Text(this, &SGitSourceControlSettings::GetLfsUserName) + .OnTextCommitted(this, &SGitSourceControlSettings::OnLfsUserNameCommited) + .IsEnabled(this, &SGitSourceControlSettings::GetIsUsingGitLfsLocking) + .HintText(LOCTEXT("LfsUserName_Hint", "Username to lock files on the LFS server")) + .Font(Font) + ] + ] + // Option that can be disabled to make Submit ONLY commit and not push + // This is useful in these cases: + // - To do a bunch of local commits more quickly and push in one go + // - Working disconnected + // - To combine asset changes with C++ changes in one commit; you can amend the UE commit to add the C++ changes before push + // Push can be used separately and will unlock files if using LFS locking. + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .ToolTipText(LOCTEXT("GitPushAfterCommit_Tooltip", "Always try to Push (and unlock) after Commit on Submit when using LFS. Turning this off means you have to Push separately; Push will unlock LFS files.")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(SGitSourceControlSettings::IsPushAfterCommitEnabled()) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnIsPushAfterCommitEnabled) + .IsEnabled(this, &SGitSourceControlSettings::GetIsUsingGitLfsLocking) + ] + + SHorizontalBox::Slot() + .FillWidth(3.f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("GitPushAfterCommit", "Submit means Commit AND Push")) + .Font(Font) + ] + ] + // Option to Make the initial Git commit with custom message + + SVerticalBox::Slot() + .AutoHeight() + .Padding(2.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + .ToolTipText(LOCTEXT("InitialGitCommit_Tooltip", "Make the initial Git commit")) + + SHorizontalBox::Slot() + .FillWidth(0.1f) + [ + SNew(SCheckBox) + .IsChecked(ECheckBoxState::Checked) + .OnCheckStateChanged(this, &SGitSourceControlSettings::OnCheckedInitialCommit) + ] + + SHorizontalBox::Slot() + .FillWidth(0.9f) + .VAlign(VAlign_Center) + [ + SNew(STextBlock) + .Text(LOCTEXT("InitialGitCommit", "Make the initial Git commit")) + .Font(Font) + ] + + SHorizontalBox::Slot() + .FillWidth(2.0f) + .Padding(2.0f) + [ + SNew(SMultiLineEditableTextBox) + .Text(this, &SGitSourceControlSettings::GetInitialCommitMessage) + .OnTextCommitted(this, &SGitSourceControlSettings::OnInitialCommitMessageCommited) + .IsEnabled(this, &SGitSourceControlSettings::GetAutoInitialCommit) + .SelectAllTextWhenFocused(true) + .Font(Font) + ] + ] + // Button to initialize the project with Git, create .gitignore/.gitattributes files, and make the first commit) + + SVerticalBox::Slot() + .FillHeight(2.5f) + .Padding(4.0f) + .VAlign(VAlign_Center) + [ + SNew(SHorizontalBox) + .Visibility(this, &SGitSourceControlSettings::MustInitializeGitRepository) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + [ + SNew(SButton) + .Text(LOCTEXT("GitInitRepository", "Initialize project with Git")) + .ToolTipText(LOCTEXT("GitInitRepository_Tooltip", "Initialize current project as a new Git repository")) + .OnClicked(this, &SGitSourceControlSettings::OnClickedInitializeGitRepository) + .IsEnabled(this, &SGitSourceControlSettings::CanInitializeGitRepository) + .HAlign(HAlign_Center) + .ContentPadding(6) + ] + ] +#if ENGINE_MAJOR_VERSION == 4 + ] +#endif + ]; +} + +SGitSourceControlSettings::~SGitSourceControlSettings() +{ + RemoveInProgressNotification(); +} + +FString SGitSourceControlSettings::GetBinaryPathString() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return GitSourceControl.AccessSettings().GetBinaryPath(); +} + +void SGitSourceControlSettings::OnBinaryPathPicked(const FString& PickedPath) const +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + FString PickedFullPath = FPaths::ConvertRelativePathToFull(PickedPath); + const bool bChanged = GitSourceControl.AccessSettings().SetBinaryPath(PickedFullPath); + if (bChanged) + { + // Re-Check provided git binary path for each change + GitSourceControl.GetProvider().CheckGitAvailability(); + if (GitSourceControl.GetProvider().IsGitAvailable()) + { + GitSourceControl.SaveSettings(); + } + } +} + +FText SGitSourceControlSettings::GetPathToRepositoryRoot() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return FText::FromString(GitSourceControl.GetProvider().GetPathToRepositoryRoot()); +} + +FText SGitSourceControlSettings::GetUserName() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return FText::FromString(GitSourceControl.GetProvider().GetUserName()); +} + +FText SGitSourceControlSettings::GetUserEmail() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return FText::FromString(GitSourceControl.GetProvider().GetUserEmail()); +} + +EVisibility SGitSourceControlSettings::MustInitializeGitRepository() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const bool bGitAvailable = GitSourceControl.GetProvider().IsGitAvailable(); + const bool bGitRepositoryFound = GitSourceControl.GetProvider().IsEnabled(); + return (bGitAvailable && !bGitRepositoryFound) ? EVisibility::Visible : EVisibility::Collapsed; +} + +bool SGitSourceControlSettings::CanInitializeGitRepository() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const bool bGitAvailable = GitSourceControl.GetProvider().IsGitAvailable(); + const bool bGitRepositoryFound = GitSourceControl.GetProvider().IsEnabled(); + const FString LfsUserName = GitSourceControl.AccessSettings().GetLfsUserName(); + const bool bIsUsingGitLfsLocking = GitSourceControl.AccessSettings().IsUsingGitLfsLocking(); + const bool bGitLfsConfigOk = !bIsUsingGitLfsLocking || !LfsUserName.IsEmpty(); + const bool bInitialCommitConfigOk = !bAutoInitialCommit || !InitialCommitMessage.IsEmpty(); + return (bGitAvailable && !bGitRepositoryFound && bGitLfsConfigOk && bInitialCommitConfigOk); +} + +bool SGitSourceControlSettings::CanInitializeGitLfs() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const bool bGitLfsAvailable = GitSourceControl.GetProvider().GetGitVersion().bHasGitLfs; + return bGitLfsAvailable; +} + +bool SGitSourceControlSettings::CanUseGitLfsLocking() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const bool bGitLfsLockingAvailable = GitSourceControl.GetProvider().GetGitVersion().bHasGitLfsLocking; + // TODO LFS SRombauts : check if .gitattributes file is present and if Content/ is already tracked! + const bool bGitAttributesCreated = true; + return (bGitLfsLockingAvailable && (bAutoCreateGitAttributes || bGitAttributesCreated)); +} + +FReply SGitSourceControlSettings::OnClickedInitializeGitRepository() +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + const FString& PathToGitBinary = GitSourceControl.AccessSettings().GetBinaryPath(); + const FString PathToProjectDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()); + TArray InfoMessages; + TArray ErrorMessages; + + // 1.a. Synchronous (very quick) "git init" operation: initialize a Git local repository with a .git/ subdirectory + GitSourceControlUtils::RunCommand(TEXT("init"), PathToGitBinary, PathToProjectDir, TArray(), TArray(), InfoMessages, ErrorMessages); + // 1.b. Synchronous (very quick) "git remote add" operation: configure the URL of the default remote server 'origin' if specified + if (!RemoteUrl.IsEmpty()) + { + TArray Parameters; + Parameters.Add(TEXT("add origin")); + Parameters.Add(RemoteUrl.ToString()); + GitSourceControlUtils::RunCommand(TEXT("remote"), PathToGitBinary, PathToProjectDir, Parameters, TArray(), InfoMessages, ErrorMessages); + } + + // Check the new repository status to enable connection (branch, user e-mail) + GitSourceControl.GetProvider().CheckRepositoryStatus(PathToGitBinary); + if (GitSourceControl.GetProvider().IsAvailable()) + { + // List of files to add to Source Control (.uproject, Config/, Content/, Source/ files and .gitignore/.gitattributes if any) + TArray ProjectFiles; + ProjectFiles.Add(FPaths::GetProjectFilePath()); + ProjectFiles.Add(FPaths::ProjectConfigDir()); + ProjectFiles.Add(FPaths::ProjectContentDir()); + if (FPaths::DirectoryExists(FPaths::GameSourceDir())) + { + ProjectFiles.Add(FPaths::GameSourceDir()); + } + if (bAutoCreateGitIgnore) + { + // 2.a. Create a standard ".gitignore" file with common patterns for a typical Blueprint & C++ project + const FString GitIgnoreFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT(".gitignore")); + const FString GitIgnoreContent = TEXT("Binaries\nBuild\nDerivedDataCache\nIntermediate\nSaved\nScript\nenc_temp_folder\n.idea\n.vscode\n.vs\n.vsconfig\n.ignore\n*.VC.db\n*.opensdf\n*.opendb\n*.sdf\n*.sln\n*.suo\n*.code-workspace\n*.xcodeproj\n*.xcworkspace\n*.log"); + if (FFileHelper::SaveStringToFile(GitIgnoreContent, *GitIgnoreFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) + { + ProjectFiles.Add(GitIgnoreFilename); + } + } + if (bAutoCreateReadme) + { + // 2.b. Create a "README.md" file with a custom description + const FString ReadmeFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT("README.md")); + if (FFileHelper::SaveStringToFile(ReadmeContent.ToString(), *ReadmeFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) + { + ProjectFiles.Add(ReadmeFilename); + } + } + if (bAutoCreateGitAttributes) + { + // 2.c. Synchronous (very quick) "lfs install" operation: needs only to be run once by user + GitSourceControlUtils::RunCommand(TEXT("lfs install"), PathToGitBinary, PathToProjectDir, TArray(), TArray(), InfoMessages, ErrorMessages); + + // 2.d. Create a ".gitattributes" file to enable Git LFS (Large File System) for the whole "Content/" subdir + const FString GitAttributesFilename = FPaths::Combine(FPaths::ProjectDir(), TEXT(".gitattributes")); + FString GitAttributesContent; + if (GitSourceControl.AccessSettings().IsUsingGitLfsLocking()) + { + // Git LFS 2.x File Locking mechanism + GitAttributesContent = TEXT("Content/** filter=lfs diff=lfs merge=lfs -text lockable\n"); + } + else + { + GitAttributesContent = TEXT("Content/** filter=lfs diff=lfs merge=lfs -text\n"); + } + if (FFileHelper::SaveStringToFile(GitAttributesContent, *GitAttributesFilename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) + { + ProjectFiles.Add(GitAttributesFilename); + } + } + + // 3. Add files to Source Control: launch an asynchronous MarkForAdd operation + LaunchMarkForAddOperation(ProjectFiles); + + // 4. The CheckIn will follow, at completion of the MarkForAdd operation + } + return FReply::Handled(); +} + +// Launch an asynchronous "MarkForAdd" operation and start an ongoing notification +void SGitSourceControlSettings::LaunchMarkForAddOperation(const TArray& InFiles) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + TSharedRef MarkForAddOperation = ISourceControlOperation::Create(); + ECommandResult::Type Result = GitSourceControl.GetProvider().Execute(MarkForAddOperation, InFiles, EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SGitSourceControlSettings::OnSourceControlOperationComplete)); + if (Result == ECommandResult::Succeeded) + { + DisplayInProgressNotification(MarkForAddOperation); + } + else + { + DisplayFailureNotification(MarkForAddOperation); + } +} + +// Launch an asynchronous "CheckIn" operation and start another ongoing notification +void SGitSourceControlSettings::LaunchCheckInOperation() +{ + TSharedRef CheckInOperation = ISourceControlOperation::Create(); + CheckInOperation->SetDescription(InitialCommitMessage); + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + ECommandResult::Type Result = GitSourceControl.GetProvider().Execute(CheckInOperation, TArray(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateSP(this, &SGitSourceControlSettings::OnSourceControlOperationComplete)); + if (Result == ECommandResult::Succeeded) + { + DisplayInProgressNotification(CheckInOperation); + } + else + { + DisplayFailureNotification(CheckInOperation); + } +} + +/// Delegate called when a source control operation has completed: launch the next one and manage notifications +void SGitSourceControlSettings::OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult) +{ + RemoveInProgressNotification(); + + // Report result with a notification + if (InResult == ECommandResult::Succeeded) + { + DisplaySuccessNotification(InOperation); + } + else + { + DisplayFailureNotification(InOperation); + } + + if ((InOperation->GetName() == "MarkForAdd") && (InResult == ECommandResult::Succeeded) && bAutoInitialCommit) + { + // 4. optional initial Asynchronous commit with custom message: launch a "CheckIn" Operation + LaunchCheckInOperation(); + } +} + + +// Display an ongoing notification during the whole operation +void SGitSourceControlSettings::DisplayInProgressNotification(const FSourceControlOperationRef& InOperation) +{ + FNotificationInfo Info(InOperation->GetInProgressString()); + Info.bFireAndForget = false; + Info.ExpireDuration = 0.0f; + Info.FadeOutDuration = 1.0f; + OperationInProgressNotification = FSlateNotificationManager::Get().AddNotification(Info); + if (OperationInProgressNotification.IsValid()) + { + OperationInProgressNotification.Pin()->SetCompletionState(SNotificationItem::CS_Pending); + } +} + +// Remove the ongoing notification at the end of the operation +void SGitSourceControlSettings::RemoveInProgressNotification() +{ + if (OperationInProgressNotification.IsValid()) + { + OperationInProgressNotification.Pin()->ExpireAndFadeout(); + OperationInProgressNotification.Reset(); + } +} + +// Display a temporary success notification at the end of the operation +void SGitSourceControlSettings::DisplaySuccessNotification(const FSourceControlOperationRef& InOperation) +{ + const FText NotificationText = FText::Format(LOCTEXT("InitialCommit_Success", "{0} operation was successfull!"), FText::FromName(InOperation->GetName())); + FNotificationInfo Info(NotificationText); + Info.bUseSuccessFailIcons = true; +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + Info.Image = FAppStyle::GetBrush(TEXT("NotificationList.SuccessImage")); +#else + Info.Image = FEditorStyle::GetBrush(TEXT("NotificationList.SuccessImage")); +#endif + FSlateNotificationManager::Get().AddNotification(Info); +} + +// Display a temporary failure notification at the end of the operation +void SGitSourceControlSettings::DisplayFailureNotification(const FSourceControlOperationRef& InOperation) +{ + const FText NotificationText = FText::Format(LOCTEXT("InitialCommit_Failure", "Error: {0} operation failed!"), FText::FromName(InOperation->GetName())); + FNotificationInfo Info(NotificationText); + Info.ExpireDuration = 8.0f; + FSlateNotificationManager::Get().AddNotification(Info); +} + +void SGitSourceControlSettings::OnCheckedCreateGitIgnore(ECheckBoxState NewCheckedState) +{ + bAutoCreateGitIgnore = (NewCheckedState == ECheckBoxState::Checked); +} + +void SGitSourceControlSettings::OnCheckedCreateReadme(ECheckBoxState NewCheckedState) +{ + bAutoCreateReadme = (NewCheckedState == ECheckBoxState::Checked); +} + +bool SGitSourceControlSettings::GetAutoCreateReadme() const +{ + return bAutoCreateReadme; +} + +void SGitSourceControlSettings::OnReadmeContentCommited(const FText& InText, ETextCommit::Type InCommitType) +{ + ReadmeContent = InText; +} + +FText SGitSourceControlSettings::GetReadmeContent() const +{ + return ReadmeContent; +} + +void SGitSourceControlSettings::OnCheckedCreateGitAttributes(ECheckBoxState NewCheckedState) +{ + bAutoCreateGitAttributes = (NewCheckedState == ECheckBoxState::Checked); +} + +void SGitSourceControlSettings::OnCheckedUseGitLfsLocking(ECheckBoxState NewCheckedState) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + GitSourceControl.AccessSettings().SetUsingGitLfsLocking(NewCheckedState == ECheckBoxState::Checked); + GitSourceControl.AccessSettings().SaveSettings(); +} + +bool SGitSourceControlSettings::GetIsUsingGitLfsLocking() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return GitSourceControl.AccessSettings().IsUsingGitLfsLocking(); +} + +void SGitSourceControlSettings::OnIsPushAfterCommitEnabled(ECheckBoxState NewCheckedState) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + GitSourceControl.AccessSettings().SetIsPushAfterCommitEnabled(NewCheckedState == ECheckBoxState::Checked); + GitSourceControl.AccessSettings().SaveSettings(); +} + +bool SGitSourceControlSettings::GetIsPushAfterCommitEnabled() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return GitSourceControl.AccessSettings().IsPushAfterCommitEnabled(); +} + +ECheckBoxState SGitSourceControlSettings::IsPushAfterCommitEnabled() const +{ + return (GetIsPushAfterCommitEnabled() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked); +} + +ECheckBoxState SGitSourceControlSettings::IsUsingGitLfsLocking() const +{ + return (GetIsUsingGitLfsLocking() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked); +} + +void SGitSourceControlSettings::OnLfsUserNameCommited(const FText& InText, ETextCommit::Type InCommitType) +{ + FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + GitSourceControl.AccessSettings().SetLfsUserName(InText.ToString()); + GitSourceControl.AccessSettings().SaveSettings(); +} + +FText SGitSourceControlSettings::GetLfsUserName() const +{ + const FGitSourceControlModule& GitSourceControl = FModuleManager::GetModuleChecked("GitSourceControl"); + return FText::FromString(GitSourceControl.AccessSettings().GetLfsUserName()); +} + +void SGitSourceControlSettings::OnCheckedInitialCommit(ECheckBoxState NewCheckedState) +{ + bAutoInitialCommit = (NewCheckedState == ECheckBoxState::Checked); +} + +bool SGitSourceControlSettings::GetAutoInitialCommit() const +{ + return bAutoInitialCommit; +} + +void SGitSourceControlSettings::OnInitialCommitMessageCommited(const FText& InText, ETextCommit::Type InCommitType) +{ + InitialCommitMessage = InText; +} + +FText SGitSourceControlSettings::GetInitialCommitMessage() const +{ + return InitialCommitMessage; +} + +void SGitSourceControlSettings::OnRemoteUrlCommited(const FText& InText, ETextCommit::Type InCommitType) +{ + RemoteUrl = InText; +} + +FText SGitSourceControlSettings::GetRemoteUrl() const +{ + return RemoteUrl; +} + +#undef LOCTEXT_NAMESPACE diff --git a/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h new file mode 100644 index 0000000..ad787ea --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/Source/GitSourceControl/Private/SGitSourceControlSettings.h @@ -0,0 +1,102 @@ +// Copyright (c) 2014-2022 Sebastien Rombauts (sebastien.rombauts@gmail.com) +// +// Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt +// or copy at http://opensource.org/licenses/MIT) + +#pragma once + +#include "CoreMinimal.h" +#include "Layout/Visibility.h" +#include "Input/Reply.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" +#include "SlateFwd.h" +#include "ISourceControlOperation.h" +#include "ISourceControlProvider.h" + +enum class ECheckBoxState : uint8; + +class SGitSourceControlSettings : public SCompoundWidget +{ +public: + + SLATE_BEGIN_ARGS(SGitSourceControlSettings) {} + + SLATE_END_ARGS() + +public: + + void Construct(const FArguments& InArgs); + + ~SGitSourceControlSettings(); + +private: + + /** Delegates to get Git binary path from/to settings */ + FString GetBinaryPathString() const; + void OnBinaryPathPicked(const FString & PickedPath) const; + + /** Delegate to get repository root, user name and email from provider */ + FText GetPathToRepositoryRoot() const; + FText GetUserName() const; + FText GetUserEmail() const; + + EVisibility MustInitializeGitRepository() const; + bool CanInitializeGitRepository() const; + bool CanInitializeGitLfs() const; + bool CanUseGitLfsLocking() const; + + /** Delegate to initialize a new Git repository */ + FReply OnClickedInitializeGitRepository(); + + void OnCheckedCreateGitIgnore(ECheckBoxState NewCheckedState); + bool bAutoCreateGitIgnore; + + /** Delegates to create a README.md file */ + void OnCheckedCreateReadme(ECheckBoxState NewCheckedState); + bool GetAutoCreateReadme() const; + bool bAutoCreateReadme; + void OnReadmeContentCommited(const FText& InText, ETextCommit::Type InCommitType); + FText GetReadmeContent() const; + FText ReadmeContent; + + void OnCheckedCreateGitAttributes(ECheckBoxState NewCheckedState); + bool bAutoCreateGitAttributes; + + void OnCheckedUseGitLfsLocking(ECheckBoxState NewCheckedState); + ECheckBoxState IsUsingGitLfsLocking() const; + bool GetIsUsingGitLfsLocking() const; + + void OnIsPushAfterCommitEnabled(ECheckBoxState NewCheckedState); + bool GetIsPushAfterCommitEnabled() const; + ECheckBoxState IsPushAfterCommitEnabled() const; + + void OnLfsUserNameCommited(const FText& InText, ETextCommit::Type InCommitType); + FText GetLfsUserName() const; + + void OnCheckedInitialCommit(ECheckBoxState NewCheckedState); + bool GetAutoInitialCommit() const; + bool bAutoInitialCommit; + void OnInitialCommitMessageCommited(const FText& InText, ETextCommit::Type InCommitType); + FText GetInitialCommitMessage() const; + FText InitialCommitMessage; + + void OnRemoteUrlCommited(const FText& InText, ETextCommit::Type InCommitType); + FText GetRemoteUrl() const; + FText RemoteUrl; + + /** Launch initial asynchronous add and commit operations */ + void LaunchMarkForAddOperation(const TArray& InFiles); + void LaunchCheckInOperation(); + + /** Delegate called when a source control operation has completed */ + void OnSourceControlOperationComplete(const FSourceControlOperationRef& InOperation, ECommandResult::Type InResult); + + /** Asynchronous operation progress notifications */ + TWeakPtr OperationInProgressNotification; + + void DisplayInProgressNotification(const FSourceControlOperationRef& InOperation); + void RemoveInProgressNotification(); + void DisplaySuccessNotification(const FSourceControlOperationRef& InOperation); + void DisplayFailureNotification(const FSourceControlOperationRef& InOperation); +}; diff --git a/Pawn_Unreal/Plugins/GitSourceControl/_config.yml b/Pawn_Unreal/Plugins/GitSourceControl/_config.yml new file mode 100644 index 0000000..f170406 --- /dev/null +++ b/Pawn_Unreal/Plugins/GitSourceControl/_config.yml @@ -0,0 +1,2 @@ +show_downloads: true +theme: jekyll-theme-slate \ No newline at end of file diff --git a/Pawn_Unreal/Source/Pawn_Unreal.Target.cs b/Pawn_Unreal/Source/Pawn_Unreal.Target.cs new file mode 100644 index 0000000..61e4faa --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal.Target.cs @@ -0,0 +1,15 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +using UnrealBuildTool; +using System.Collections.Generic; + +public class Pawn_UnrealTarget : TargetRules +{ + public Pawn_UnrealTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Game; + DefaultBuildSettings = BuildSettingsVersion.V2; + + ExtraModuleNames.AddRange( new string[] { "Pawn_Unreal" } ); + } +} diff --git a/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.Build.cs b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.Build.cs new file mode 100644 index 0000000..de258d0 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.Build.cs @@ -0,0 +1,23 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +using UnrealBuildTool; + +public class Pawn_Unreal : ModuleRules +{ + public Pawn_Unreal(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); + + PrivateDependencyModuleNames.AddRange(new string[] { }); + + // Uncomment if you are using Slate UI + // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); + + // Uncomment if you are using online features + // PrivateDependencyModuleNames.Add("OnlineSubsystem"); + + // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true + } +} diff --git a/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.cpp b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.cpp new file mode 100644 index 0000000..1bc1830 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.cpp @@ -0,0 +1,6 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Pawn_Unreal.h" +#include "Modules/ModuleManager.h" + +IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, Pawn_Unreal, "Pawn_Unreal" ); diff --git a/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.h b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.h new file mode 100644 index 0000000..90aad9e --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal/Pawn_Unreal.h @@ -0,0 +1,6 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" + diff --git a/Pawn_Unreal/Source/Pawn_Unreal/Private/TestActor.cpp b/Pawn_Unreal/Source/Pawn_Unreal/Private/TestActor.cpp new file mode 100644 index 0000000..95181cf --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal/Private/TestActor.cpp @@ -0,0 +1,27 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "TestActor.h" + +// Sets default values +ATestActor::ATestActor() +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + +} + +// Called when the game starts or when spawned +void ATestActor::BeginPlay() +{ + Super::BeginPlay(); + +} + +// Called every frame +void ATestActor::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + +} + diff --git a/Pawn_Unreal/Source/Pawn_Unreal/Public/TestActor.h b/Pawn_Unreal/Source/Pawn_Unreal/Public/TestActor.h new file mode 100644 index 0000000..0e7bc13 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_Unreal/Public/TestActor.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "TestActor.generated.h" + +UCLASS() +class PAWN_UNREAL_API ATestActor : public AActor +{ + GENERATED_BODY() + +public: + // Sets default values for this actor's properties + ATestActor(); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; + +}; diff --git a/Pawn_Unreal/Source/Pawn_UnrealEditor.Target.cs b/Pawn_Unreal/Source/Pawn_UnrealEditor.Target.cs new file mode 100644 index 0000000..c06e11a --- /dev/null +++ b/Pawn_Unreal/Source/Pawn_UnrealEditor.Target.cs @@ -0,0 +1,15 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +using UnrealBuildTool; +using System.Collections.Generic; + +public class Pawn_UnrealEditorTarget : TargetRules +{ + public Pawn_UnrealEditorTarget(TargetInfo Target) : base(Target) + { + Type = TargetType.Editor; + DefaultBuildSettings = BuildSettingsVersion.V2; + + ExtraModuleNames.AddRange( new string[] { "Pawn_Unreal" } ); + } +}