diff --git a/AirSim/AirLib/include/common/AirSimSettings.hpp b/AirSim/AirLib/include/common/AirSimSettings.hpp index a073bc9f..0535398f 100644 --- a/AirSim/AirLib/include/common/AirSimSettings.hpp +++ b/AirSim/AirLib/include/common/AirSimSettings.hpp @@ -312,6 +312,10 @@ struct AirSimSettings { std::string api_server_address = ""; int api_port = RpcLibPort; + // If the current game is running as a listen server, and a spectator connects, + // it must proide this password to be allowed to enter. + std::string spectator_server_password = "password"; + std::string clock_type = ""; float clock_speed = 1.0f; bool log_messages_visible = true; @@ -890,6 +894,7 @@ struct AirSimSettings { speed_unit_factor = settings_json.getFloat("SpeedUnitFactor", 1.0f); speed_unit_label = settings_json.getString("SpeedUnitLabel", "m\\s"); log_messages_visible = settings_json.getBool("LogMessagesVisible", true); + spectator_server_password = settings_json.getString("SpectatorServerPassword", "password"); { //load origin geopoint Settings origin_geopoint_json; diff --git a/UE4Project/Config/DefaultEngine.ini b/UE4Project/Config/DefaultEngine.ini index ad502658..befc7a05 100644 --- a/UE4Project/Config/DefaultEngine.ini +++ b/UE4Project/Config/DefaultEngine.ini @@ -5,10 +5,10 @@ TransitionMap= bUseSplitscreen=True TwoPlayerSplitscreenLayout=Horizontal ThreePlayerSplitscreenLayout=FavorTop -GameInstanceClass=/AirSim/DisconnectGameInstance.DisconnectGameInstance_C +GameInstanceClass=/AirSim/Blueprints/AirsimGameInstance.AirsimGameInstance_C GameDefaultMap=/AirSim/MainMenuLevel.MainMenuLevel ServerDefaultMap=/Engine/Maps/Entry -GlobalDefaultGameMode=/Script/AirSim.AirSimGameMode +GlobalDefaultGameMode=/Script/Engine.GameMode GlobalDefaultServerGameMode=None diff --git a/UE4Project/Plugins/AirSim/Content/Blueprints/AirsimGameInstance.uasset b/UE4Project/Plugins/AirSim/Content/Blueprints/AirsimGameInstance.uasset index ee450a17..a47a6911 100644 --- a/UE4Project/Plugins/AirSim/Content/Blueprints/AirsimGameInstance.uasset +++ b/UE4Project/Plugins/AirSim/Content/Blueprints/AirsimGameInstance.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0826818588a47990b665e799521de19c018115102deb8297c12e99645e6dd47 -size 47030 +oid sha256:c31b478880f4ff7ea8c615044cf7c6bf573b0d60f6ae3f74824f00fc36e5e45c +size 30362 diff --git a/UE4Project/Plugins/AirSim/Content/MainMenuLevel.umap b/UE4Project/Plugins/AirSim/Content/MainMenuLevel.umap index ad4ef3fd..c846ad94 100644 Binary files a/UE4Project/Plugins/AirSim/Content/MainMenuLevel.umap and b/UE4Project/Plugins/AirSim/Content/MainMenuLevel.umap differ diff --git a/UE4Project/Plugins/AirSim/Content/MainMenuUi.uasset b/UE4Project/Plugins/AirSim/Content/MainMenuUi.uasset index 30baf98c..a51e6250 100644 --- a/UE4Project/Plugins/AirSim/Content/MainMenuUi.uasset +++ b/UE4Project/Plugins/AirSim/Content/MainMenuUi.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:477bdb6f5cbf5a455c4af679c842b7e54f0259b776e7158883f842166dae0b79 -size 117840 +oid sha256:d5f8844ce66a309214de7ffa46a44270f6ea37b8df5086aca542712cca785efd +size 118348 diff --git a/UE4Project/Plugins/AirSim/Source/AirBlueprintLib.h b/UE4Project/Plugins/AirSim/Source/AirBlueprintLib.h index 17f01b92..3b5786c1 100644 --- a/UE4Project/Plugins/AirSim/Source/AirBlueprintLib.h +++ b/UE4Project/Plugins/AirSim/Source/AirBlueprintLib.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "GameFramework/Actor.h" +#include "Misc/MessageDialog.h" #include "Components/InputComponent.h" #include "GameFramework/PlayerInput.h" #include "IImageWrapperModule.h" @@ -47,6 +48,12 @@ class UAirBlueprintLib : public UBlueprintFunctionLibrary static void LogMessage(const FString &prefix, const FString &suffix, LogDebugLevel level, float persist_sec = 60); static float GetWorldToMetersScale(const AActor* context); + UFUNCTION(BlueprintCallable, Category = "Utils") + static void showMessageAlertDialog(const FText& message, const FText& title) + { + FMessageDialog::Open(EAppMsgType::Ok, message, & title); + } + template static T* GetActorComponent(AActor* actor, FString name); diff --git a/UE4Project/Plugins/AirSim/Source/AirSimGameMode.cpp b/UE4Project/Plugins/AirSim/Source/AirSimGameMode.cpp index 5fad6faa..50ee9a7f 100644 --- a/UE4Project/Plugins/AirSim/Source/AirSimGameMode.cpp +++ b/UE4Project/Plugins/AirSim/Source/AirSimGameMode.cpp @@ -54,12 +54,17 @@ AAirSimGameMode::AAirSimGameMode(const FObjectInitializer& ObjectInitializer) static IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked(TEXT("ImageWrapper")); } +void AAirSimGameMode::InitGame(const FString & MapName, const FString & Options, FString & ErrorMessage) +{ + AGameModeBase::InitGame(MapName, Options, ErrorMessage); + initializeSettings(); +} + void AAirSimGameMode::BeginPlay() { try { UAirBlueprintLib::OnBeginPlay(); - initializeSettings(); setUnrealEngineSettings(); } catch (std::exception &ex) @@ -78,6 +83,16 @@ void AAirSimGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void AAirSimGameMode::PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) +{ + FString clientPassword = UGameplayStatics::ParseOption(Options, TEXT("password")); + std::string serverPassword = msr::airlib::AirSimSettings::singleton().spectator_server_password; + if(clientPassword != FString(serverPassword.c_str())) { + // login attamed is blocked if ErrorMessage is set to non-null string + ErrorMessage = FString(TEXT("Incorrect password")); + } +} + void AAirSimGameMode::PostLogin(APlayerController * newPlayer) { newPlayer->StartSpectatingOnly(); } diff --git a/UE4Project/Plugins/AirSim/Source/AirSimGameMode.h b/UE4Project/Plugins/AirSim/Source/AirSimGameMode.h index e6509da6..0ecab482 100644 --- a/UE4Project/Plugins/AirSim/Source/AirSimGameMode.h +++ b/UE4Project/Plugins/AirSim/Source/AirSimGameMode.h @@ -17,8 +17,10 @@ class AIRSIM_API AAirSimGameMode : public AGameModeBase public: GENERATED_BODY() + virtual void InitGame(const FString & MapName, const FString & Options, FString & ErrorMessage) override; virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) override; virtual void PostLogin(APlayerController * NewPlayer) override; diff --git a/docs/spectator.md b/docs/spectator.md index f5cd0e32..4857a2dc 100644 --- a/docs/spectator.md +++ b/docs/spectator.md @@ -2,36 +2,48 @@ The spectator provides an eye into the virtual world from an external computer. Through a network connection the virtual world state is replicated and shown on the screen. The user can operate the camera with its mouse and keyboard. +Spectators are not able to interact with the world -## Launching the spectator +## Launching the server A simulator launched as 'server' will accept external viewers (spectators) to join the game. -The spectators are not able to interact with the world. -Spectators can enter the ip of the server in the main menu to connect to a running simulator. -Multiple simultaneous spectators in a single world should work as well. +You can launch the simulation as a server in the main menu by pressing the 'TODO' button. -> If a spectator loses connection to the server it will go back to the main menu. - -If you want to give access to clients from external computers you must ensure the specified port is accessible. -In most cases you will have to add a firewall rule to allow the traffic. +The server will run on port 7777 port, make sure spectators can connect to it. +In most cases you will need to add a firewall rule to allow TCP and UDP traffic. When behind a router you might need to do some port forwarding. -Both TCP and UDP traffic must be able to travel from client to server on port 7777. -To skip the menu and launch the game as server or spectator directly, you can use the following commandline options: +To skip the menu and launch the game as server directly, you can use the following command: + +``` +FSDS.exe /Game/TrainingMap?listen +``` +This opens the TrainingMap and allows external clients (spectators) to connect. + +Within the `settings.json` you can configure the server password. +Using the password is usefull to prevent trolls and curious people from connecting to the simulator and breaking the simulator. -**Run the game as a server** ``` -FSDS.exe /Game/TrainingMap?listen -log +{ + "SpectatorPassword": "password", + ... ``` -This runs the simulator like normal but now external clients (spectators) are welcome to connect. +If the password is not configured in the settings.json, the password is set to `password`. +At this moment it is not possible to start a server without password. + +## Launching the spectator +Spectators can enter the ip of the server in the main menu to connect to a running simulator. +Multiple simultaneous spectators in a single world should work as well. +If a spectator loses connection to the server it will go back to the main menu. +To skip the menu and launch the spectator directly, you can use the following command: -**Running the spectator** ``` -FSDS.exe 0.0.0.0 -log +FSDS.exe 0.0.0.0?password=123456 ``` -Where `0.0.0.0` is replaced by the external ip of the server. +Where `0.0.0.0` is replaced by the external ip of the server and `123456` is replaced by the server password. +**If you enter a wrong password you are taken back to the main menu. No error will be shown.** ## Using the spectator diff --git a/settings.json b/settings.json index db40a580..c4c47ba8 100644 --- a/settings.json +++ b/settings.json @@ -3,6 +3,7 @@ "SettingsVersion": 1.2, "ViewMode": "SpringArmChase", "ClockSpeed": 1.0, + "SpectatorServerPassword": "password", "PawnPaths": { "DefaultCar": { "PawnBP": "Class'/AirSim/VehicleAdv/Cars/TechnionCar/TechnionCarPawn.TechnionCarPawn_C'" } },