├── .gitattributes ├── .gitignore ├── Config ├── DefaultEditor.ini ├── DefaultEditorPerProjectUserSettings.ini ├── DefaultEngine.ini ├── DefaultGame.ini └── DefaultInput.ini ├── Plugins └── MultiplayerSessions │ ├── MultiplayerSessions.uplugin │ ├── Resources │ └── Icon128.png │ └── Source │ └── MultiplayerSessions │ ├── MultiplayerSessions.Build.cs │ ├── Private │ ├── Menu.cpp │ ├── MultiplayerSessions.cpp │ └── MultiplayerSessionsSubsystem.cpp │ └── Public │ ├── Menu.h │ ├── MultiplayerSessions.h │ └── MultiplayerSessionsSubsystem.h ├── Source ├── MenuSystem.Target.cs ├── MenuSystem │ ├── LobbyGameMode.cpp │ ├── LobbyGameMode.h │ ├── MenuSystem.Build.cs │ ├── MenuSystem.cpp │ ├── MenuSystem.h │ ├── MenuSystemCharacter.cpp │ ├── MenuSystemCharacter.h │ ├── MenuSystemGameMode.cpp │ └── MenuSystemGameMode.h └── MenuSystemEditor.Target.cs └── Steps to use Menu System Plugin.pdf /.gitattributes: -------------------------------------------------------------------------------- 1 | Content/** filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries 2 | Build 3 | Content 4 | DerivedDataCache 5 | Intermediate 6 | Saved 7 | .vs 8 | .vscode 9 | *.VC.db 10 | *.opensdf 11 | *.opendb 12 | *.sdf 13 | *.sln 14 | *.suo 15 | *.xcodeproj 16 | *.xcworkspace 17 | *.uproject -------------------------------------------------------------------------------- /Config/DefaultEditor.ini: -------------------------------------------------------------------------------- 1 | [UnrealEd.SimpleMap] 2 | SimpleMapName=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 3 | 4 | [EditoronlyBP] 5 | bAllowClassAndBlueprintPinMatching=true 6 | bReplaceBlueprintWithClass= true 7 | bDontLoadBlueprintOutsideEditor= true 8 | bBlueprintIsNotBlueprintType= true 9 | 10 | -------------------------------------------------------------------------------- /Config/DefaultEditorPerProjectUserSettings.ini: -------------------------------------------------------------------------------- 1 | [ContentBrowser] 2 | ContentBrowserTab1.SelectedPaths=/Game/ThirdPersonCPP -------------------------------------------------------------------------------- /Config/DefaultEngine.ini: -------------------------------------------------------------------------------- 1 | [/Script/EngineSettings.GameMapsSettings] 2 | GameDefaultMap=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 3 | EditorStartupMap=/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap 4 | GlobalDefaultGameMode="/Script/MenuSystem.MenuSystemGameMode" 5 | 6 | [/Script/IOSRuntimeSettings.IOSRuntimeSettings] 7 | MinimumiOSVersion=IOS_13 8 | 9 | [/Script/HardwareTargeting.HardwareTargetingSettings] 10 | TargetedHardwareClass=Desktop 11 | AppliedTargetedHardwareClass=Desktop 12 | DefaultGraphicsPerformance=Maximum 13 | AppliedDefaultGraphicsPerformance=Maximum 14 | 15 | [/Script/Engine.RendererSettings] 16 | r.GenerateMeshDistanceFields=True 17 | r.DynamicGlobalIlluminationMethod=1 18 | r.ReflectionMethod=1 19 | r.Shadow.Virtual.Enable=1 20 | 21 | [/Script/Engine.Engine] 22 | +ActiveGameNameRedirects=(OldGameName="TP_ThirdPerson",NewGameName="/Script/MenuSystem") 23 | +ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/MenuSystem") 24 | +ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="MenuSystemGameMode") 25 | +ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="MenuSystemCharacter") 26 | 27 | [/Script/Engine.GameEngine] 28 | +NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver") 29 | 30 | [OnlineSubsystem] 31 | DefaultPlatformService=Steam 32 | 33 | [OnlineSubsystemSteam] 34 | bEnabled=true 35 | SteamDevAppId=480 36 | 37 | [/Script/OnlineSubsystemSteam.SteamNetDriver] 38 | NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection" -------------------------------------------------------------------------------- /Config/DefaultGame.ini: -------------------------------------------------------------------------------- 1 | [/Script/EngineSettings.GeneralProjectSettings] 2 | ProjectID=D13AA2B24E0E2411359C0290EC0B0A6B 3 | ProjectName=Third Person Game Template 4 | 5 | [StartupActions] 6 | bAddPacks=True 7 | InsertPack=(PackSource="StarterContent.upack",PackName="StarterContent") 8 | 9 | [/Script/Engine.GameSession] 10 | MaxPlayers=100 -------------------------------------------------------------------------------- /Config/DefaultInput.ini: -------------------------------------------------------------------------------- 1 | 2 | [/Script/Engine.InputSettings] 3 | +AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 4 | +AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 5 | +AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 6 | +AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 7 | +AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 8 | +AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 9 | +AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 10 | +AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 11 | +AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 12 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 13 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 14 | +AxisConfig=(AxisKeyName="MotionController_Left_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 15 | +AxisConfig=(AxisKeyName="MotionController_Left_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 16 | +AxisConfig=(AxisKeyName="MotionController_Left_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 17 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 18 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 19 | +AxisConfig=(AxisKeyName="MotionController_Right_TriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 20 | +AxisConfig=(AxisKeyName="MotionController_Right_Grip1Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 21 | +AxisConfig=(AxisKeyName="MotionController_Right_Grip2Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 22 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 23 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 24 | +AxisConfig=(AxisKeyName="MotionController_Left_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 25 | +AxisConfig=(AxisKeyName="MotionController_Right_Thumbstick_Z",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 26 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 27 | +AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 28 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 29 | +AxisConfig=(AxisKeyName="OculusTouch_Left_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 30 | +AxisConfig=(AxisKeyName="OculusTouch_Left_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 31 | +AxisConfig=(AxisKeyName="OculusTouch_Left_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 32 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 33 | +AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton1",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 34 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 35 | +AxisConfig=(AxisKeyName="OculusTouch_Right_FaceButton2",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 36 | +AxisConfig=(AxisKeyName="OculusTouch_Right_IndexPointing",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 37 | +AxisConfig=(AxisKeyName="OculusTouch_Right_ThumbUp",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 38 | +AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 39 | +AxisConfig=(AxisKeyName="OculusTouchpad_Touchpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 40 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 41 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 42 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 43 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 44 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Left_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 45 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_HandGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 46 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_IndexGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 47 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_MiddleGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 48 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_RingGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 49 | +AxisConfig=(AxisKeyName="SteamVR_Knuckles_Right_PinkyGrip",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 50 | +AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 51 | +AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 52 | +AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 53 | +AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 54 | +AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 55 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 56 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 57 | +AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 58 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 59 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 60 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 61 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 62 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 63 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 64 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 65 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 66 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 67 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 68 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 69 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 70 | +AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 71 | +AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 72 | +AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 73 | +AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 74 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 75 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 76 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 77 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 78 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 79 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 80 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 81 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 82 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 83 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 84 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 85 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 86 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 87 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 88 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 89 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 90 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Touch",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 91 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 92 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 93 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 94 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 95 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 96 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 97 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 98 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 99 | bAltEnterTogglesFullscreen=True 100 | bF11TogglesFullscreen=True 101 | bUseMouseForTouch=False 102 | bEnableMouseSmoothing=True 103 | bEnableFOVScaling=True 104 | bCaptureMouseOnLaunch=True 105 | bAlwaysShowTouchInterface=False 106 | bShowConsoleOnFourFingerTap=True 107 | bEnableGestureRecognizer=False 108 | bUseAutocorrect=False 109 | DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown 110 | DefaultViewportMouseLockMode=LockOnCapture 111 | FOVScale=0.011110 112 | DoubleClickTime=0.200000 113 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) 114 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Bottom) 115 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Daydream_Left_Select_Click) 116 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) 117 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Daydream_Left_Trackpad_Click) 118 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Left_Trigger_Click) 119 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Right_Trigger_Click) 120 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Trigger_Click) 121 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Right_Trigger_Click) 122 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusGo_Left_Trigger_Click) 123 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Trigger_Click) 124 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_Trigger_Click) 125 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Left_Trigger_Click) 126 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Right_Trigger_Click) 127 | +ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MagicLeap_Left_Trigger) 128 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Vive_Left_Grip_Click) 129 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Thumbstick_Click) 130 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusGo_Left_Trackpad_Click) 131 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Thumbstick_Click) 132 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=ValveIndex_Left_Thumbstick_Click) 133 | +ActionMappings=(ActionName="ResetVR",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MagicLeap_Left_Bumper) 134 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=W) 135 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=S) 136 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Up) 137 | +AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=Down) 138 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Gamepad_LeftY) 139 | +AxisMappings=(AxisName="MoveRight",Scale=-1.000000,Key=A) 140 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D) 141 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Gamepad_LeftX) 142 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Gamepad_RightX) 143 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Left) 144 | +AxisMappings=(AxisName="TurnRate",Scale=1.000000,Key=Right) 145 | +AxisMappings=(AxisName="Turn",Scale=1.000000,Key=MouseX) 146 | +AxisMappings=(AxisName="LookUpRate",Scale=1.000000,Key=Gamepad_RightY) 147 | +AxisMappings=(AxisName="LookUp",Scale=-1.000000,Key=MouseY) 148 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=Vive_Right_Trackpad_X) 149 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Daydream_Left_Trackpad_Y) 150 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=Vive_Left_Trackpad_Y) 151 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Daydream_Left_Trackpad_X) 152 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=Vive_Left_Trackpad_X) 153 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=MixedReality_Left_Thumbstick_X) 154 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=OculusGo_Left_Trackpad_X) 155 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=MixedReality_Left_Thumbstick_Y) 156 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=OculusGo_Left_Trackpad_Y) 157 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=MixedReality_Right_Thumbstick_X) 158 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=OculusTouch_Right_Thumbstick_X) 159 | +AxisMappings=(AxisName="TurnRate",Scale=-1.000000,Key=ValveIndex_Right_Thumbstick_X) 160 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=OculusTouch_Left_Thumbstick_Y) 161 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=ValveIndex_Left_Thumbstick_Y) 162 | +AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=MagicLeap_Left_Trackpad_Y) 163 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=OculusTouch_Left_Thumbstick_X) 164 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=ValveIndex_Left_Thumbstick_X) 165 | +AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=MagicLeap_Left_Trackpad_X) 166 | DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks 167 | +ConsoleKeys=Tilde 168 | 169 | 170 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/MultiplayerSessions.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "MultiplayerSessions", 6 | "Description": "A plugin for handling online multiplayer sessions", 7 | "Category": "Other", 8 | "CreatedBy": "Stephen Ulibarri", 9 | "CreatedByURL": "", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "MultiplayerSessions", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default" 22 | } 23 | ], 24 | "Plugins": [ 25 | { 26 | "Name": "OnlineSubsystem", 27 | "Enabled": true 28 | }, 29 | { 30 | "Name": "OnlineSubsystemSteam", 31 | "Enabled": true 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DruidMech/MultiplayerCourseMenuSystem/5611708e31ab857f0cb56bb1c5b3d879a5e98089/Plugins/MultiplayerSessions/Resources/Icon128.png -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/MultiplayerSessions.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class MultiplayerSessions : ModuleRules 6 | { 7 | public MultiplayerSessions(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | "OnlineSubsystem", 30 | "OnlineSubsystemSteam", 31 | "UMG", 32 | "Slate", 33 | "SlateCore" 34 | // ... add other public dependencies that you statically link with here ... 35 | } 36 | ); 37 | 38 | 39 | PrivateDependencyModuleNames.AddRange( 40 | new string[] 41 | { 42 | "CoreUObject", 43 | "Engine", 44 | "Slate", 45 | "SlateCore", 46 | // ... add private dependencies that you statically link with here ... 47 | } 48 | ); 49 | 50 | 51 | DynamicallyLoadedModuleNames.AddRange( 52 | new string[] 53 | { 54 | // ... add any modules that your module loads dynamically here ... 55 | } 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/Menu.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "Menu.h" 5 | #include "Components/Button.h" 6 | #include "MultiplayerSessionsSubsystem.h" 7 | #include "OnlineSessionSettings.h" 8 | #include "OnlineSubsystem.h" 9 | 10 | void UMenu::MenuSetup(int32 NumberOfPublicConnections, FString TypeOfMatch, FString LobbyPath) 11 | { 12 | PathToLobby = FString::Printf(TEXT("%s?listen"), *LobbyPath); 13 | NumPublicConnections = NumberOfPublicConnections; 14 | MatchType = TypeOfMatch; 15 | AddToViewport(); 16 | SetVisibility(ESlateVisibility::Visible); 17 | bIsFocusable = true; 18 | 19 | UWorld* World = GetWorld(); 20 | if (World) 21 | { 22 | APlayerController* PlayerController = World->GetFirstPlayerController(); 23 | if (PlayerController) 24 | { 25 | FInputModeUIOnly InputModeData; 26 | InputModeData.SetWidgetToFocus(TakeWidget()); 27 | InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); 28 | PlayerController->SetInputMode(InputModeData); 29 | PlayerController->SetShowMouseCursor(true); 30 | } 31 | } 32 | 33 | UGameInstance* GameInstance = GetGameInstance(); 34 | if (GameInstance) 35 | { 36 | MultiplayerSessionsSubsystem = GameInstance->GetSubsystem(); 37 | } 38 | 39 | if (MultiplayerSessionsSubsystem) 40 | { 41 | MultiplayerSessionsSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this, &ThisClass::OnCreateSession); 42 | MultiplayerSessionsSubsystem->MultiplayerOnFindSessionsComplete.AddUObject(this, &ThisClass::OnFindSessions); 43 | MultiplayerSessionsSubsystem->MultiplayerOnJoinSessionComplete.AddUObject(this, &ThisClass::OnJoinSession); 44 | MultiplayerSessionsSubsystem->MultiplayerOnDestroySessionComplete.AddDynamic(this, &ThisClass::OnDestroySession); 45 | MultiplayerSessionsSubsystem->MultiplayerOnStartSessionComplete.AddDynamic(this, &ThisClass::OnStartSession); 46 | } 47 | } 48 | 49 | bool UMenu::Initialize() 50 | { 51 | if (!Super::Initialize()) 52 | { 53 | return false; 54 | } 55 | 56 | if (HostButton) 57 | { 58 | HostButton->OnClicked.AddDynamic(this, &ThisClass::HostButtonClicked); 59 | } 60 | if (JoinButton) 61 | { 62 | JoinButton->OnClicked.AddDynamic(this, &ThisClass::JoinButtonClicked); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | void UMenu::NativeDestruct() 69 | { 70 | MenuTearDown(); 71 | Super::NativeDestruct(); 72 | } 73 | 74 | void UMenu::OnCreateSession(bool bWasSuccessful) 75 | { 76 | if (bWasSuccessful) 77 | { 78 | UWorld* World = GetWorld(); 79 | if (World) 80 | { 81 | World->ServerTravel(PathToLobby); 82 | } 83 | } 84 | else 85 | { 86 | if (GEngine) 87 | { 88 | GEngine->AddOnScreenDebugMessage( 89 | -1, 90 | 15.f, 91 | FColor::Red, 92 | FString(TEXT("Failed to create session!")) 93 | ); 94 | } 95 | HostButton->SetIsEnabled(true); 96 | } 97 | } 98 | 99 | void UMenu::OnFindSessions(const TArray& SessionResults, bool bWasSuccessful) 100 | { 101 | if (MultiplayerSessionsSubsystem == nullptr) 102 | { 103 | return; 104 | } 105 | 106 | for (auto Result : SessionResults) 107 | { 108 | FString SettingsValue; 109 | Result.Session.SessionSettings.Get(FName("MatchType"), SettingsValue); 110 | if (SettingsValue == MatchType) 111 | { 112 | MultiplayerSessionsSubsystem->JoinSession(Result); 113 | return; 114 | } 115 | } 116 | if (!bWasSuccessful || SessionResults.Num() == 0) 117 | { 118 | JoinButton->SetIsEnabled(true); 119 | } 120 | } 121 | 122 | void UMenu::OnJoinSession(EOnJoinSessionCompleteResult::Type Result) 123 | { 124 | IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(); 125 | if (Subsystem) 126 | { 127 | IOnlineSessionPtr SessionInterface = Subsystem->GetSessionInterface(); 128 | if (SessionInterface.IsValid()) 129 | { 130 | FString Address; 131 | SessionInterface->GetResolvedConnectString(NAME_GameSession, Address); 132 | 133 | APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController(); 134 | if (PlayerController) 135 | { 136 | PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute); 137 | } 138 | } 139 | } 140 | } 141 | 142 | void UMenu::OnDestroySession(bool bWasSuccessful) 143 | { 144 | } 145 | 146 | void UMenu::OnStartSession(bool bWasSuccessful) 147 | { 148 | } 149 | 150 | void UMenu::HostButtonClicked() 151 | { 152 | HostButton->SetIsEnabled(false); 153 | if (MultiplayerSessionsSubsystem) 154 | { 155 | MultiplayerSessionsSubsystem->CreateSession(NumPublicConnections, MatchType); 156 | } 157 | } 158 | 159 | void UMenu::JoinButtonClicked() 160 | { 161 | JoinButton->SetIsEnabled(false); 162 | if (MultiplayerSessionsSubsystem) 163 | { 164 | MultiplayerSessionsSubsystem->FindSessions(10000); 165 | } 166 | } 167 | 168 | void UMenu::MenuTearDown() 169 | { 170 | RemoveFromParent(); 171 | UWorld* World = GetWorld(); 172 | if (World) 173 | { 174 | APlayerController* PlayerController = World->GetFirstPlayerController(); 175 | if (PlayerController) 176 | { 177 | FInputModeGameOnly InputModeData; 178 | PlayerController->SetInputMode(InputModeData); 179 | PlayerController->SetShowMouseCursor(false); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessions.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "MultiplayerSessions.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FMultiplayerSessionsModule" 6 | 7 | void FMultiplayerSessionsModule::StartupModule() 8 | { 9 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 10 | } 11 | 12 | void FMultiplayerSessionsModule::ShutdownModule() 13 | { 14 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 15 | // we call this function before unloading the module. 16 | } 17 | 18 | #undef LOCTEXT_NAMESPACE 19 | 20 | IMPLEMENT_MODULE(FMultiplayerSessionsModule, MultiplayerSessions) -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Private/MultiplayerSessionsSubsystem.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "MultiplayerSessionsSubsystem.h" 5 | #include "OnlineSubsystem.h" 6 | #include "OnlineSessionSettings.h" 7 | #include "Online/OnlineSessionNames.h" 8 | 9 | UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem(): 10 | CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete)), 11 | FindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnFindSessionsComplete)), 12 | JoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnJoinSessionComplete)), 13 | DestroySessionCompleteDelegate(FOnDestroySessionCompleteDelegate::CreateUObject(this, &ThisClass::OnDestroySessionComplete)), 14 | StartSessionCompleteDelegate(FOnStartSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnStartSessionComplete)) 15 | { 16 | 17 | } 18 | 19 | void UMultiplayerSessionsSubsystem::CreateSession(int32 NumPublicConnections, FString MatchType) 20 | { 21 | if (!IsValidSessionInterface()) 22 | { 23 | return; 24 | } 25 | 26 | auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession); 27 | if (ExistingSession != nullptr) 28 | { 29 | bCreateSessionOnDestroy = true; 30 | LastNumPublicConnections = NumPublicConnections; 31 | LastMatchType = MatchType; 32 | 33 | DestroySession(); 34 | } 35 | 36 | // Store the delegate in a FDelegateHandle so we can later remove it from the delegate list 37 | CreateSessionCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate); 38 | 39 | LastSessionSettings = MakeShareable(new FOnlineSessionSettings()); 40 | LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; 41 | LastSessionSettings->NumPublicConnections = NumPublicConnections; 42 | LastSessionSettings->bAllowJoinInProgress = true; 43 | LastSessionSettings->bAllowJoinViaPresence = true; 44 | LastSessionSettings->bShouldAdvertise = true; 45 | LastSessionSettings->bUsesPresence = true; 46 | LastSessionSettings->Set(FName("MatchType"), MatchType, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing); 47 | LastSessionSettings->BuildUniqueId = 1; 48 | 49 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 50 | if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings)) 51 | { 52 | SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle); 53 | 54 | // Broadcast our own custom delegate 55 | MultiplayerOnCreateSessionComplete.Broadcast(false); 56 | } 57 | } 58 | 59 | void UMultiplayerSessionsSubsystem::FindSessions(int32 MaxSearchResults) 60 | { 61 | if (!IsValidSessionInterface()) 62 | { 63 | return; 64 | } 65 | 66 | FindSessionsCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate); 67 | 68 | LastSessionSearch = MakeShareable(new FOnlineSessionSearch()); 69 | LastSessionSearch->MaxSearchResults = MaxSearchResults; 70 | LastSessionSearch->bIsLanQuery = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false; 71 | LastSessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); 72 | 73 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 74 | if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef())) 75 | { 76 | SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle); 77 | 78 | MultiplayerOnFindSessionsComplete.Broadcast(TArray(), false); 79 | } 80 | } 81 | 82 | void UMultiplayerSessionsSubsystem::JoinSession(const FOnlineSessionSearchResult& SessionResult) 83 | { 84 | if (!SessionInterface.IsValid()) 85 | { 86 | MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError); 87 | return; 88 | } 89 | 90 | JoinSessionCompleteDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate); 91 | 92 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 93 | if (!SessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, SessionResult)) 94 | { 95 | SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle); 96 | 97 | MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError); 98 | } 99 | } 100 | 101 | void UMultiplayerSessionsSubsystem::DestroySession() 102 | { 103 | if (!SessionInterface.IsValid()) 104 | { 105 | MultiplayerOnDestroySessionComplete.Broadcast(false); 106 | return; 107 | } 108 | 109 | DestroySessionCompleteDelegateHandle = SessionInterface->AddOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegate); 110 | 111 | if (!SessionInterface->DestroySession(NAME_GameSession)) 112 | { 113 | SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle); 114 | MultiplayerOnDestroySessionComplete.Broadcast(false); 115 | } 116 | } 117 | 118 | void UMultiplayerSessionsSubsystem::StartSession() 119 | { 120 | } 121 | 122 | bool UMultiplayerSessionsSubsystem::IsValidSessionInterface() 123 | { 124 | if (!SessionInterface) 125 | { 126 | IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get(); 127 | if (Subsystem) 128 | { 129 | SessionInterface = Subsystem->GetSessionInterface(); 130 | } 131 | } 132 | return SessionInterface.IsValid(); 133 | } 134 | 135 | void UMultiplayerSessionsSubsystem::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) 136 | { 137 | if (SessionInterface) 138 | { 139 | SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegateHandle); 140 | } 141 | 142 | MultiplayerOnCreateSessionComplete.Broadcast(bWasSuccessful); 143 | } 144 | 145 | void UMultiplayerSessionsSubsystem::OnFindSessionsComplete(bool bWasSuccessful) 146 | { 147 | if (SessionInterface) 148 | { 149 | SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle); 150 | } 151 | 152 | if (LastSessionSearch->SearchResults.Num() <= 0) 153 | { 154 | MultiplayerOnFindSessionsComplete.Broadcast(TArray(), false); 155 | return; 156 | } 157 | 158 | MultiplayerOnFindSessionsComplete.Broadcast(LastSessionSearch->SearchResults, bWasSuccessful); 159 | } 160 | 161 | void UMultiplayerSessionsSubsystem::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) 162 | { 163 | if (SessionInterface) 164 | { 165 | SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegateHandle); 166 | } 167 | 168 | MultiplayerOnJoinSessionComplete.Broadcast(Result); 169 | } 170 | 171 | void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful) 172 | { 173 | if (SessionInterface) 174 | { 175 | SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle); 176 | } 177 | if (bWasSuccessful && bCreateSessionOnDestroy) 178 | { 179 | bCreateSessionOnDestroy = false; 180 | CreateSession(LastNumPublicConnections, LastMatchType); 181 | } 182 | MultiplayerOnDestroySessionComplete.Broadcast(bWasSuccessful); 183 | } 184 | 185 | void UMultiplayerSessionsSubsystem::OnStartSessionComplete(FName SessionName, bool bWasSuccessful) 186 | { 187 | } 188 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/Menu.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Blueprint/UserWidget.h" 7 | #include "Interfaces/OnlineSessionInterface.h" 8 | #include "Menu.generated.h" 9 | 10 | /** 11 | * 12 | */ 13 | UCLASS() 14 | class MULTIPLAYERSESSIONS_API UMenu : public UUserWidget 15 | { 16 | GENERATED_BODY() 17 | public: 18 | UFUNCTION(BlueprintCallable) 19 | void MenuSetup(int32 NumberOfPublicConnections = 4, FString TypeOfMatch = FString(TEXT("FreeForAll")), FString LobbyPath = FString(TEXT("/Game/ThirdPersonCPP/Maps/Lobby"))); 20 | 21 | protected: 22 | 23 | virtual bool Initialize() override; 24 | virtual void NativeDestruct() override; 25 | 26 | // 27 | // Callbacks for the custom delegates on the MultiplayerSessionsSubsystem 28 | // 29 | UFUNCTION() 30 | void OnCreateSession(bool bWasSuccessful); 31 | void OnFindSessions(const TArray& SessionResults, bool bWasSuccessful); 32 | void OnJoinSession(EOnJoinSessionCompleteResult::Type Result); 33 | UFUNCTION() 34 | void OnDestroySession(bool bWasSuccessful); 35 | UFUNCTION() 36 | void OnStartSession(bool bWasSuccessful); 37 | 38 | private: 39 | 40 | UPROPERTY(meta = (BindWidget)) 41 | class UButton* HostButton; 42 | 43 | UPROPERTY(meta = (BindWidget)) 44 | UButton* JoinButton; 45 | 46 | UFUNCTION() 47 | void HostButtonClicked(); 48 | 49 | UFUNCTION() 50 | void JoinButtonClicked(); 51 | 52 | void MenuTearDown(); 53 | 54 | // The subsystem designed to handle all online session functionality 55 | class UMultiplayerSessionsSubsystem* MultiplayerSessionsSubsystem; 56 | 57 | int32 NumPublicConnections{4}; 58 | FString MatchType{TEXT("FreeForAll")}; 59 | FString PathToLobby{TEXT("")}; 60 | }; 61 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessions.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | class FMultiplayerSessionsModule : public IModuleInterface 9 | { 10 | public: 11 | 12 | /** IModuleInterface implementation */ 13 | virtual void StartupModule() override; 14 | virtual void ShutdownModule() override; 15 | }; 16 | -------------------------------------------------------------------------------- /Plugins/MultiplayerSessions/Source/MultiplayerSessions/Public/MultiplayerSessionsSubsystem.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Subsystems/GameInstanceSubsystem.h" 7 | #include "Interfaces/OnlineSessionInterface.h" 8 | 9 | #include "MultiplayerSessionsSubsystem.generated.h" 10 | 11 | // 12 | // Delcaring our own custom delegates for the Menu class to bind callbacks to 13 | // 14 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnCreateSessionComplete, bool, bWasSuccessful); 15 | DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiplayerOnFindSessionsComplete, const TArray& SessionResults, bool bWasSuccessful); 16 | DECLARE_MULTICAST_DELEGATE_OneParam(FMultiplayerOnJoinSessionComplete, EOnJoinSessionCompleteResult::Type Result); 17 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnDestroySessionComplete, bool, bWasSuccessful); 18 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiplayerOnStartSessionComplete, bool, bWasSuccessful); 19 | 20 | /** 21 | * 22 | */ 23 | UCLASS() 24 | class MULTIPLAYERSESSIONS_API UMultiplayerSessionsSubsystem : public UGameInstanceSubsystem 25 | { 26 | GENERATED_BODY() 27 | public: 28 | UMultiplayerSessionsSubsystem(); 29 | 30 | // 31 | // To handle session functionality. The Menu class will call these 32 | // 33 | void CreateSession(int32 NumPublicConnections, FString MatchType); 34 | void FindSessions(int32 MaxSearchResults); 35 | void JoinSession(const FOnlineSessionSearchResult& SessionResult); 36 | void DestroySession(); 37 | void StartSession(); 38 | 39 | bool IsValidSessionInterface(); 40 | 41 | // 42 | // Our own custom delegates for the Menu class to bind callbacks to 43 | // 44 | FMultiplayerOnCreateSessionComplete MultiplayerOnCreateSessionComplete; 45 | FMultiplayerOnFindSessionsComplete MultiplayerOnFindSessionsComplete; 46 | FMultiplayerOnJoinSessionComplete MultiplayerOnJoinSessionComplete; 47 | FMultiplayerOnDestroySessionComplete MultiplayerOnDestroySessionComplete; 48 | FMultiplayerOnStartSessionComplete MultiplayerOnStartSessionComplete; 49 | 50 | protected: 51 | 52 | // 53 | // Internal callbacks for the delegates we'll add to the Online Session Interface delegate list. 54 | // Thise don't need to be called outside this class. 55 | // 56 | void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful); 57 | void OnFindSessionsComplete(bool bWasSuccessful); 58 | void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); 59 | void OnDestroySessionComplete(FName SessionName, bool bWasSuccessful); 60 | void OnStartSessionComplete(FName SessionName, bool bWasSuccessful); 61 | 62 | private: 63 | IOnlineSessionPtr SessionInterface; 64 | TSharedPtr LastSessionSettings; 65 | TSharedPtr LastSessionSearch; 66 | 67 | // 68 | // To add to the Online Session Interface delegate list. 69 | // We'll bind our MultiplayerSessionsSubsystem internal callbacks to these. 70 | // 71 | FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate; 72 | FDelegateHandle CreateSessionCompleteDelegateHandle; 73 | FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate; 74 | FDelegateHandle FindSessionsCompleteDelegateHandle; 75 | FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate; 76 | FDelegateHandle JoinSessionCompleteDelegateHandle; 77 | FOnDestroySessionCompleteDelegate DestroySessionCompleteDelegate; 78 | FDelegateHandle DestroySessionCompleteDelegateHandle; 79 | FOnStartSessionCompleteDelegate StartSessionCompleteDelegate; 80 | FDelegateHandle StartSessionCompleteDelegateHandle; 81 | 82 | bool bCreateSessionOnDestroy{ false }; 83 | int32 LastNumPublicConnections; 84 | FString LastMatchType; 85 | }; 86 | -------------------------------------------------------------------------------- /Source/MenuSystem.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class MenuSystemTarget : TargetRules 7 | { 8 | public MenuSystemTarget(TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Game; 11 | DefaultBuildSettings = BuildSettingsVersion.V2; 12 | ExtraModuleNames.Add("MenuSystem"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/MenuSystem/LobbyGameMode.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | 4 | #include "LobbyGameMode.h" 5 | #include "GameFramework/GameStateBase.h" 6 | #include "GameFramework/PlayerState.h" 7 | 8 | void ALobbyGameMode::PostLogin(APlayerController* NewPlayer) 9 | { 10 | Super::PostLogin(NewPlayer); 11 | 12 | if (GameState) 13 | { 14 | int32 NumberOfPlayers = GameState.Get()->PlayerArray.Num(); 15 | 16 | if (GEngine) 17 | { 18 | GEngine->AddOnScreenDebugMessage( 19 | 1, 20 | 600.f, 21 | FColor::Yellow, 22 | FString::Printf(TEXT("Players in game: %d"), NumberOfPlayers) 23 | ); 24 | 25 | APlayerState* PlayerState = NewPlayer->GetPlayerState(); 26 | if (PlayerState) 27 | { 28 | FString PlayerName = PlayerState->GetPlayerName(); 29 | GEngine->AddOnScreenDebugMessage( 30 | 2, 31 | 60.f, 32 | FColor::Cyan, 33 | FString::Printf(TEXT("%s has joined the game!"), *PlayerName) 34 | ); 35 | } 36 | } 37 | } 38 | } 39 | 40 | void ALobbyGameMode::Logout(AController* Exiting) 41 | { 42 | Super::Logout(Exiting); 43 | 44 | APlayerState* PlayerState = Exiting->GetPlayerState(); 45 | if (PlayerState) 46 | { 47 | int32 NumberOfPlayers = GameState.Get()->PlayerArray.Num(); 48 | GEngine->AddOnScreenDebugMessage( 49 | 1, 50 | 600.f, 51 | FColor::Yellow, 52 | FString::Printf(TEXT("Players in game: %d"), NumberOfPlayers - 1) 53 | ); 54 | 55 | FString PlayerName = PlayerState->GetPlayerName(); 56 | GEngine->AddOnScreenDebugMessage( 57 | 2, 58 | 60.f, 59 | FColor::Cyan, 60 | FString::Printf(TEXT("%s has exited the game!"), *PlayerName) 61 | ); 62 | } 63 | } -------------------------------------------------------------------------------- /Source/MenuSystem/LobbyGameMode.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/GameModeBase.h" 7 | #include "LobbyGameMode.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class MENUSYSTEM_API ALobbyGameMode : public AGameModeBase 14 | { 15 | GENERATED_BODY() 16 | 17 | public: 18 | virtual void PostLogin(APlayerController* NewPlayer) override; 19 | virtual void Logout(AController* Exiting) override; 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystem.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class MenuSystem : ModuleRules 6 | { 7 | public MenuSystem(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "OnlineSubsystemSteam", "OnlineSubsystem"}); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystem.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "MenuSystem.h" 4 | #include "Modules/ModuleManager.h" 5 | 6 | IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, MenuSystem, "MenuSystem" ); 7 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystem.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystemCharacter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "MenuSystemCharacter.h" 4 | #include "HeadMountedDisplayFunctionLibrary.h" 5 | #include "Camera/CameraComponent.h" 6 | #include "Components/CapsuleComponent.h" 7 | #include "Components/InputComponent.h" 8 | #include "GameFramework/CharacterMovementComponent.h" 9 | #include "GameFramework/Controller.h" 10 | #include "GameFramework/SpringArmComponent.h" 11 | #include "OnlineSubsystem.h" 12 | #include "OnlineSessionSettings.h" 13 | 14 | 15 | ////////////////////////////////////////////////////////////////////////// 16 | // AMenuSystemCharacter 17 | 18 | AMenuSystemCharacter::AMenuSystemCharacter(): 19 | CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete)), 20 | FindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnFindSessionsComplete)), 21 | JoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnJoinSessionComplete)) 22 | { 23 | // Set size for collision capsule 24 | GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); 25 | 26 | // set our turn rates for input 27 | BaseTurnRate = 45.f; 28 | BaseLookUpRate = 45.f; 29 | 30 | // Don't rotate when the controller rotates. Let that just affect the camera. 31 | bUseControllerRotationPitch = false; 32 | bUseControllerRotationYaw = false; 33 | bUseControllerRotationRoll = false; 34 | 35 | // Configure character movement 36 | GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input... 37 | GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate 38 | GetCharacterMovement()->JumpZVelocity = 600.f; 39 | GetCharacterMovement()->AirControl = 0.2f; 40 | 41 | // Create a camera boom (pulls in towards the player if there is a collision) 42 | CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); 43 | CameraBoom->SetupAttachment(RootComponent); 44 | CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character 45 | CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller 46 | 47 | // Create a follow camera 48 | FollowCamera = CreateDefaultSubobject(TEXT("FollowCamera")); 49 | FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation 50 | FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm 51 | 52 | // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 53 | // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++) 54 | 55 | IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get(); 56 | if (OnlineSubsystem) 57 | { 58 | OnlineSessionInterface = OnlineSubsystem->GetSessionInterface(); 59 | } 60 | } 61 | 62 | ////////////////////////////////////////////////////////////////////////// 63 | // Input 64 | 65 | void AMenuSystemCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) 66 | { 67 | // Set up gameplay key bindings 68 | check(PlayerInputComponent); 69 | PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); 70 | PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); 71 | 72 | PlayerInputComponent->BindAxis("MoveForward", this, &AMenuSystemCharacter::MoveForward); 73 | PlayerInputComponent->BindAxis("MoveRight", this, &AMenuSystemCharacter::MoveRight); 74 | 75 | // We have 2 versions of the rotation bindings to handle different kinds of devices differently 76 | // "turn" handles devices that provide an absolute delta, such as a mouse. 77 | // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick 78 | PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput); 79 | PlayerInputComponent->BindAxis("TurnRate", this, &AMenuSystemCharacter::TurnAtRate); 80 | PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput); 81 | PlayerInputComponent->BindAxis("LookUpRate", this, &AMenuSystemCharacter::LookUpAtRate); 82 | 83 | // handle touch devices 84 | PlayerInputComponent->BindTouch(IE_Pressed, this, &AMenuSystemCharacter::TouchStarted); 85 | PlayerInputComponent->BindTouch(IE_Released, this, &AMenuSystemCharacter::TouchStopped); 86 | 87 | // VR headset functionality 88 | PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &AMenuSystemCharacter::OnResetVR); 89 | } 90 | 91 | void AMenuSystemCharacter::CreateGameSession() 92 | { 93 | // Called when pressing the 1 key 94 | if (!OnlineSessionInterface.IsValid()) 95 | { 96 | return; 97 | } 98 | 99 | auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession); 100 | if (ExistingSession != nullptr) 101 | { 102 | OnlineSessionInterface->DestroySession(NAME_GameSession); 103 | } 104 | 105 | OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate); 106 | 107 | TSharedPtr SessionSettings = MakeShareable(new FOnlineSessionSettings()); 108 | SessionSettings->bIsLANMatch = false; 109 | SessionSettings->NumPublicConnections = 4; 110 | SessionSettings->bAllowJoinInProgress = true; 111 | SessionSettings->bAllowJoinViaPresence = true; 112 | SessionSettings->bShouldAdvertise = true; 113 | SessionSettings->bUsesPresence = true; 114 | SessionSettings->Set(FName("MatchType"), FString("FreeForAll"), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing); 115 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 116 | OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings); 117 | } 118 | 119 | void AMenuSystemCharacter::JoinGameSession() 120 | { 121 | // Find game sessions 122 | if (!OnlineSessionInterface.IsValid()) 123 | { 124 | return; 125 | } 126 | 127 | OnlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate); 128 | 129 | SessionSearch = MakeShareable(new FOnlineSessionSearch()); 130 | SessionSearch->MaxSearchResults = 10000; 131 | SessionSearch->bIsLanQuery = false; 132 | SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals); 133 | 134 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 135 | OnlineSessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), SessionSearch.ToSharedRef()); 136 | } 137 | 138 | void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) 139 | { 140 | if (bWasSuccessful) 141 | { 142 | if (GEngine) 143 | { 144 | GEngine->AddOnScreenDebugMessage( 145 | -1, 146 | 15.f, 147 | FColor::Blue, 148 | FString::Printf(TEXT("Created session: %s"), *SessionName.ToString()) 149 | ); 150 | } 151 | 152 | UWorld* World = GetWorld(); 153 | if (World) 154 | { 155 | World->ServerTravel(FString("/Game/ThirdPersonCPP/Maps/Lobby?listen")); 156 | } 157 | } 158 | else 159 | { 160 | if (GEngine) 161 | { 162 | GEngine->AddOnScreenDebugMessage( 163 | -1, 164 | 15.f, 165 | FColor::Red, 166 | FString(TEXT("Failed to create session!")) 167 | ); 168 | } 169 | } 170 | } 171 | 172 | void AMenuSystemCharacter::OnFindSessionsComplete(bool bWasSuccessful) 173 | { 174 | if (!OnlineSessionInterface.IsValid()) 175 | { 176 | return; 177 | } 178 | 179 | for (auto Result : SessionSearch->SearchResults) 180 | { 181 | FString Id = Result.GetSessionIdStr(); 182 | FString User = Result.Session.OwningUserName; 183 | FString MatchType; 184 | Result.Session.SessionSettings.Get(FName("MatchType"), MatchType); 185 | if (GEngine) 186 | { 187 | GEngine->AddOnScreenDebugMessage( 188 | -1, 189 | 15.f, 190 | FColor::Cyan, 191 | FString::Printf(TEXT("Id: %s, User: %s"), *Id, *User) 192 | ); 193 | } 194 | if (MatchType == FString("FreeForAll")) 195 | { 196 | if (GEngine) 197 | { 198 | GEngine->AddOnScreenDebugMessage( 199 | -1, 200 | 15.f, 201 | FColor::Cyan, 202 | FString::Printf(TEXT("Joining Match Type: %s"), *MatchType) 203 | ); 204 | } 205 | 206 | OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate); 207 | 208 | const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); 209 | OnlineSessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, Result); 210 | } 211 | } 212 | } 213 | 214 | void AMenuSystemCharacter::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) 215 | { 216 | if (!OnlineSessionInterface.IsValid()) 217 | { 218 | return; 219 | } 220 | FString Address; 221 | if (OnlineSessionInterface->GetResolvedConnectString(NAME_GameSession, Address)) 222 | { 223 | if (GEngine) 224 | { 225 | GEngine->AddOnScreenDebugMessage( 226 | -1, 227 | 15.f, 228 | FColor::Yellow, 229 | FString::Printf(TEXT("Connect string: %s"), *Address) 230 | ); 231 | } 232 | 233 | APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController(); 234 | if (PlayerController) 235 | { 236 | PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute); 237 | } 238 | } 239 | } 240 | 241 | 242 | void AMenuSystemCharacter::OnResetVR() 243 | { 244 | // If MenuSystem is added to a project via 'Add Feature' in the Unreal Editor the dependency on HeadMountedDisplay in MenuSystem.Build.cs is not automatically propagated 245 | // and a linker error will result. 246 | // You will need to either: 247 | // Add "HeadMountedDisplay" to [YourProject].Build.cs PublicDependencyModuleNames in order to build successfully (appropriate if supporting VR). 248 | // or: 249 | // Comment or delete the call to ResetOrientationAndPosition below (appropriate if not supporting VR) 250 | UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition(); 251 | } 252 | 253 | void AMenuSystemCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location) 254 | { 255 | Jump(); 256 | } 257 | 258 | void AMenuSystemCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location) 259 | { 260 | StopJumping(); 261 | } 262 | 263 | void AMenuSystemCharacter::TurnAtRate(float Rate) 264 | { 265 | // calculate delta for this frame from the rate information 266 | AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds()); 267 | } 268 | 269 | void AMenuSystemCharacter::LookUpAtRate(float Rate) 270 | { 271 | // calculate delta for this frame from the rate information 272 | AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds()); 273 | } 274 | 275 | void AMenuSystemCharacter::MoveForward(float Value) 276 | { 277 | if ((Controller != nullptr) && (Value != 0.0f)) 278 | { 279 | // find out which way is forward 280 | const FRotator Rotation = Controller->GetControlRotation(); 281 | const FRotator YawRotation(0, Rotation.Yaw, 0); 282 | 283 | // get forward vector 284 | const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); 285 | AddMovementInput(Direction, Value); 286 | } 287 | } 288 | 289 | void AMenuSystemCharacter::MoveRight(float Value) 290 | { 291 | if ( (Controller != nullptr) && (Value != 0.0f) ) 292 | { 293 | // find out which way is right 294 | const FRotator Rotation = Controller->GetControlRotation(); 295 | const FRotator YawRotation(0, Rotation.Yaw, 0); 296 | 297 | // get right vector 298 | const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); 299 | // add movement in that direction 300 | AddMovementInput(Direction, Value); 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystemCharacter.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/Character.h" 7 | #include "Interfaces/OnlineSessionInterface.h" 8 | 9 | #include "MenuSystemCharacter.generated.h" 10 | 11 | UCLASS(config=Game) 12 | class AMenuSystemCharacter : public ACharacter 13 | { 14 | GENERATED_BODY() 15 | 16 | /** Camera boom positioning the camera behind the character */ 17 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) 18 | class USpringArmComponent* CameraBoom; 19 | 20 | /** Follow camera */ 21 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) 22 | class UCameraComponent* FollowCamera; 23 | public: 24 | AMenuSystemCharacter(); 25 | 26 | /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */ 27 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) 28 | float BaseTurnRate; 29 | 30 | /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */ 31 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera) 32 | float BaseLookUpRate; 33 | 34 | protected: 35 | 36 | /** Resets HMD orientation in VR. */ 37 | void OnResetVR(); 38 | 39 | /** Called for forwards/backward input */ 40 | void MoveForward(float Value); 41 | 42 | /** Called for side to side input */ 43 | void MoveRight(float Value); 44 | 45 | /** 46 | * Called via input to turn at a given rate. 47 | * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate 48 | */ 49 | void TurnAtRate(float Rate); 50 | 51 | /** 52 | * Called via input to turn look up/down at a given rate. 53 | * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate 54 | */ 55 | void LookUpAtRate(float Rate); 56 | 57 | /** Handler for when a touch input begins. */ 58 | void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location); 59 | 60 | /** Handler for when a touch input stops. */ 61 | void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location); 62 | 63 | protected: 64 | // APawn interface 65 | virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; 66 | // End of APawn interface 67 | 68 | public: 69 | /** Returns CameraBoom subobject **/ 70 | FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; } 71 | /** Returns FollowCamera subobject **/ 72 | FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; } 73 | 74 | public: 75 | 76 | // Pointer to the online session interface 77 | IOnlineSessionPtr OnlineSessionInterface; 78 | 79 | protected: 80 | UFUNCTION(BlueprintCallable) 81 | void CreateGameSession(); 82 | 83 | UFUNCTION(BlueprintCallable) 84 | void JoinGameSession(); 85 | 86 | void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful); 87 | void OnFindSessionsComplete(bool bWasSuccessful); 88 | void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); 89 | 90 | private: 91 | 92 | FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate; 93 | FOnFindSessionsCompleteDelegate FindSessionsCompleteDelegate; 94 | TSharedPtr SessionSearch; 95 | FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate; 96 | }; 97 | 98 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystemGameMode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "MenuSystemGameMode.h" 4 | #include "MenuSystemCharacter.h" 5 | #include "UObject/ConstructorHelpers.h" 6 | 7 | AMenuSystemGameMode::AMenuSystemGameMode() 8 | { 9 | // set default pawn class to our Blueprinted character 10 | static ConstructorHelpers::FClassFinder PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter")); 11 | if (PlayerPawnBPClass.Class != NULL) 12 | { 13 | DefaultPawnClass = PlayerPawnBPClass.Class; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/MenuSystem/MenuSystemGameMode.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/GameModeBase.h" 7 | #include "MenuSystemGameMode.generated.h" 8 | 9 | UCLASS(minimalapi) 10 | class AMenuSystemGameMode : public AGameModeBase 11 | { 12 | GENERATED_BODY() 13 | 14 | public: 15 | AMenuSystemGameMode(); 16 | }; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Source/MenuSystemEditor.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class MenuSystemEditorTarget : TargetRules 7 | { 8 | public MenuSystemEditorTarget(TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Editor; 11 | DefaultBuildSettings = BuildSettingsVersion.V2; 12 | ExtraModuleNames.Add("MenuSystem"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Steps to use Menu System Plugin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DruidMech/MultiplayerCourseMenuSystem/5611708e31ab857f0cb56bb1c5b3d879a5e98089/Steps to use Menu System Plugin.pdf --------------------------------------------------------------------------------