Keep multiplayer options in the start menu only; free M for the world map.
The menu no longer opens in-game and will not reappear after gameplay has started. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
932157eda5
commit
7cc715cad5
@ -1,16 +1,9 @@
|
|||||||
# Multiplayer, Steam & Server Admin
|
# Multiplayer, Steam & Server Admin
|
||||||
|
|
||||||
## In-Game Menu (`M`)
|
## Start Menu
|
||||||
|
|
||||||
Opens automatically on start and again with **M**:
|
Map / Steam / LAN / IP:Port selection appears **only at game start**.
|
||||||
|
It is not bound to a key in-game (`M` is reserved for the world map).
|
||||||
- **Map** selection
|
|
||||||
- **Backend**: Auto / Steam / LAN
|
|
||||||
- **Host Port** + Max Players
|
|
||||||
- **Find Steam** / **Find LAN**
|
|
||||||
- **Join selected session**
|
|
||||||
- **Connect by IP:Port**
|
|
||||||
- **Play Solo**
|
|
||||||
|
|
||||||
## Steam
|
## Steam
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,6 @@ A life-simulation action RPG remake inspired by Fantasy Life, built in **Unreal
|
|||||||
| Interact / Craft | E | X / Square |
|
| Interact / Craft | E | X / Square |
|
||||||
| Attack | LMB | RT |
|
| Attack | LMB | RT |
|
||||||
| Toggle camera (Top-Down / FP) | C | Menu |
|
| Toggle camera (Top-Down / FP) | C | Menu |
|
||||||
| Multiplayer menu | M | — |
|
|
||||||
| Pause | Esc | Start |
|
| Pause | Esc | Start |
|
||||||
|
|
||||||
### Pause menu shortcuts
|
### Pause menu shortcuts
|
||||||
|
|||||||
@ -21,6 +21,11 @@ void UVocationGameInstance::Init()
|
|||||||
OnDataReady.Broadcast();
|
OnDataReady.Broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UVocationGameInstance::MarkGameplayStarted()
|
||||||
|
{
|
||||||
|
bHasEnteredGameplay = true;
|
||||||
|
}
|
||||||
|
|
||||||
void UVocationGameInstance::InitializeDefaultData()
|
void UVocationGameInstance::InitializeDefaultData()
|
||||||
{
|
{
|
||||||
ItemDefinitions.Empty();
|
ItemDefinitions.Empty();
|
||||||
|
|||||||
@ -76,7 +76,7 @@ void AVocationHUD::DrawMainHUD()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const FString Controls = TEXT("WASD Move | C Camera | M Multiplayer | E Interact | LMB Attack | I Save | Esc Pause");
|
const FString Controls = TEXT("WASD Move | C Camera | E Interact | LMB Attack | I Save | Esc Pause");
|
||||||
Canvas->DrawColor = FColor(200, 200, 200);
|
Canvas->DrawColor = FColor(200, 200, 200);
|
||||||
Canvas->DrawText(GEngine->GetSmallFont(), Controls, 40.f * Scale, Canvas->ClipY - 60.f * Scale, Scale, Scale);
|
Canvas->DrawText(GEngine->GetSmallFont(), Controls, 40.f * Scale, Canvas->ClipY - 60.f * Scale, Scale, Scale);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "VocationMainMenuWidget.h"
|
#include "VocationMainMenuWidget.h"
|
||||||
#include "VocationSessionSubsystem.h"
|
#include "VocationSessionSubsystem.h"
|
||||||
|
#include "VocationGameInstance.h"
|
||||||
#include "Components/Button.h"
|
#include "Components/Button.h"
|
||||||
#include "Components/ComboBoxString.h"
|
#include "Components/ComboBoxString.h"
|
||||||
#include "Components/EditableTextBox.h"
|
#include "Components/EditableTextBox.h"
|
||||||
@ -72,7 +73,7 @@ void UVocationMainMenuWidget::BuildUI()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddToColumn(MakeLabel(WidgetTree, TEXT("Title"), TEXT("VocationLife Multiplayer")));
|
AddToColumn(MakeLabel(WidgetTree, TEXT("Title"), TEXT("VocationLife — Start Menu")));
|
||||||
|
|
||||||
AddToColumn(MakeLabel(WidgetTree, TEXT("MapLabel"), TEXT("Map")));
|
AddToColumn(MakeLabel(WidgetTree, TEXT("MapLabel"), TEXT("Map")));
|
||||||
MapCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("MapCombo"));
|
MapCombo = WidgetTree->ConstructWidget<UComboBoxString>(UComboBoxString::StaticClass(), TEXT("MapCombo"));
|
||||||
@ -182,6 +183,22 @@ void UVocationMainMenuWidget::SetStatus(const FString& Message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UVocationMainMenuWidget::LeaveStartMenu()
|
||||||
|
{
|
||||||
|
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||||
|
{
|
||||||
|
GI->MarkGameplayStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (APlayerController* PC = GetOwningPlayer())
|
||||||
|
{
|
||||||
|
PC->bShowMouseCursor = false;
|
||||||
|
PC->SetInputMode(FInputModeGameOnly());
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveFromParent();
|
||||||
|
}
|
||||||
|
|
||||||
void UVocationMainMenuWidget::OnHostClicked()
|
void UVocationMainMenuWidget::OnHostClicked()
|
||||||
{
|
{
|
||||||
UVocationSessionSubsystem* Sessions = GetGameInstance() ? GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>() : nullptr;
|
UVocationSessionSubsystem* Sessions = GetGameInstance() ? GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>() : nullptr;
|
||||||
@ -202,8 +219,8 @@ void UVocationMainMenuWidget::OnHostClicked()
|
|||||||
if (BackendIndex == 2) Backend = EVocationNetBackend::LAN;
|
if (BackendIndex == 2) Backend = EVocationNetBackend::LAN;
|
||||||
|
|
||||||
SetStatus(TEXT("Hosting..."));
|
SetStatus(TEXT("Hosting..."));
|
||||||
|
LeaveStartMenu();
|
||||||
Sessions->HostSession(MaxPlayers, Name, MapPath, Port, Backend, Backend == EVocationNetBackend::LAN);
|
Sessions->HostSession(MaxPlayers, Name, MapPath, Port, Backend, Backend == EVocationNetBackend::LAN);
|
||||||
RemoveFromParent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UVocationMainMenuWidget::OnFindSteamClicked()
|
void UVocationMainMenuWidget::OnFindSteamClicked()
|
||||||
@ -235,6 +252,7 @@ void UVocationMainMenuWidget::OnJoinSelectedClicked()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SetStatus(TEXT("Joining session..."));
|
SetStatus(TEXT("Joining session..."));
|
||||||
|
LeaveStartMenu();
|
||||||
Sessions->JoinSessionByIndex(Index);
|
Sessions->JoinSessionByIndex(Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,8 +264,8 @@ void UVocationMainMenuWidget::OnConnectIpClicked()
|
|||||||
const FString IP = IpBox ? IpBox->GetText().ToString() : TEXT("127.0.0.1");
|
const FString IP = IpBox ? IpBox->GetText().ToString() : TEXT("127.0.0.1");
|
||||||
const int32 Port = JoinPortBox ? FCString::Atoi(*JoinPortBox->GetText().ToString()) : 7777;
|
const int32 Port = JoinPortBox ? FCString::Atoi(*JoinPortBox->GetText().ToString()) : 7777;
|
||||||
SetStatus(FString::Printf(TEXT("Connecting to %s:%d ..."), *IP, Port));
|
SetStatus(FString::Printf(TEXT("Connecting to %s:%d ..."), *IP, Port));
|
||||||
|
LeaveStartMenu();
|
||||||
Sessions->ConnectByIP(IP, Port);
|
Sessions->ConnectByIP(IP, Port);
|
||||||
RemoveFromParent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,8 +275,8 @@ void UVocationMainMenuWidget::OnSoloClicked()
|
|||||||
{
|
{
|
||||||
const int32 MapIndex = MapCombo ? MapCombo->GetSelectedIndex() : 0;
|
const int32 MapIndex = MapCombo ? MapCombo->GetSelectedIndex() : 0;
|
||||||
const FString MapPath = CachedMaps.IsValidIndex(MapIndex) ? CachedMaps[MapIndex].MapPath : TEXT("/Engine/Maps/Entry");
|
const FString MapPath = CachedMaps.IsValidIndex(MapIndex) ? CachedMaps[MapIndex].MapPath : TEXT("/Engine/Maps/Entry");
|
||||||
|
LeaveStartMenu();
|
||||||
Sessions->TravelToMap(MapPath, false, 7777);
|
Sessions->TravelToMap(MapPath, false, 7777);
|
||||||
RemoveFromParent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +313,6 @@ void UVocationMainMenuWidget::OnSessionJoined(bool bSuccess)
|
|||||||
SetStatus(bSuccess ? TEXT("Join/host ok") : TEXT("Join/host failed"));
|
SetStatus(bSuccess ? TEXT("Join/host ok") : TEXT("Join/host failed"));
|
||||||
if (bSuccess)
|
if (bSuccess)
|
||||||
{
|
{
|
||||||
RemoveFromParent();
|
LeaveStartMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,10 +44,10 @@ void AVocationPlayerController::BeginPlay()
|
|||||||
GI->SetGraphicsPreset(GI->GetGraphicsPreset(), GI->IsRayTracingEnabled());
|
GI->SetGraphicsPreset(GI->GetGraphicsPreset(), GI->IsRayTracingEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show multiplayer menu on first load (local player only).
|
// Start menu only once per game session — not reopenable in-game (M reserved for map).
|
||||||
if (IsLocalController() && !IsRunningDedicatedServer())
|
if (IsLocalController() && !IsRunningDedicatedServer())
|
||||||
{
|
{
|
||||||
ToggleMultiplayerMenu();
|
ShowStartMenuIfNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,6 @@ void AVocationPlayerController::SetupInputComponent()
|
|||||||
InputComponent->BindKey(EKeys::F3, IE_Pressed, this, &AVocationPlayerController::ApplyHighGraphics).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::F3, IE_Pressed, this, &AVocationPlayerController::ApplyHighGraphics).bConsumeInput = false;
|
||||||
InputComponent->BindKey(EKeys::F4, IE_Pressed, this, &AVocationPlayerController::ApplyUltraGraphics).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::F4, IE_Pressed, this, &AVocationPlayerController::ApplyUltraGraphics).bConsumeInput = false;
|
||||||
InputComponent->BindKey(EKeys::F5, IE_Pressed, this, &AVocationPlayerController::ApplyRayTracingGraphics).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::F5, IE_Pressed, this, &AVocationPlayerController::ApplyRayTracingGraphics).bConsumeInput = false;
|
||||||
InputComponent->BindKey(EKeys::M, IE_Pressed, this, &AVocationPlayerController::ToggleMultiplayerMenu).bConsumeInput = false;
|
|
||||||
InputComponent->BindKey(EKeys::H, IE_Pressed, this, &AVocationPlayerController::HostCoopGame).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::H, IE_Pressed, this, &AVocationPlayerController::HostCoopGame).bConsumeInput = false;
|
||||||
InputComponent->BindKey(EKeys::J, IE_Pressed, this, &AVocationPlayerController::JoinFirstFoundSession).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::J, IE_Pressed, this, &AVocationPlayerController::JoinFirstFoundSession).bConsumeInput = false;
|
||||||
InputComponent->BindKey(EKeys::S, IE_Pressed, this, &AVocationPlayerController::QuickSave).bConsumeInput = false;
|
InputComponent->BindKey(EKeys::S, IE_Pressed, this, &AVocationPlayerController::QuickSave).bConsumeInput = false;
|
||||||
@ -118,13 +117,16 @@ void AVocationPlayerController::ClearInteractionPrompt()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVocationPlayerController::ToggleMultiplayerMenu()
|
void AVocationPlayerController::ShowStartMenuIfNeeded()
|
||||||
{
|
{
|
||||||
|
UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>();
|
||||||
|
if (!GI || GI->HasGameplayStarted())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (MultiplayerMenu && MultiplayerMenu->IsInViewport())
|
if (MultiplayerMenu && MultiplayerMenu->IsInViewport())
|
||||||
{
|
{
|
||||||
MultiplayerMenu->RemoveFromParent();
|
|
||||||
bShowMouseCursor = false;
|
|
||||||
SetInputMode(FInputModeGameOnly());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,9 +135,8 @@ void AVocationPlayerController::ToggleMultiplayerMenu()
|
|||||||
{
|
{
|
||||||
MultiplayerMenu->AddToViewport(100);
|
MultiplayerMenu->AddToViewport(100);
|
||||||
bShowMouseCursor = true;
|
bShowMouseCursor = true;
|
||||||
FInputModeGameAndUI Mode;
|
FInputModeUIOnly Mode;
|
||||||
Mode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
Mode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
||||||
Mode.SetHideCursorDuringCapture(false);
|
|
||||||
SetInputMode(Mode);
|
SetInputMode(Mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,6 +145,10 @@ void AVocationPlayerController::HostCoopGame()
|
|||||||
{
|
{
|
||||||
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
if (UVocationSessionSubsystem* Sessions = GetGameInstance()->GetSubsystem<UVocationSessionSubsystem>())
|
||||||
{
|
{
|
||||||
|
if (UVocationGameInstance* GI = GetGameInstance<UVocationGameInstance>())
|
||||||
|
{
|
||||||
|
GI->MarkGameplayStarted();
|
||||||
|
}
|
||||||
Sessions->HostSession(4, TEXT("VocationLife"), TEXT("/Engine/Maps/Entry"), 7777, EVocationNetBackend::Auto, false);
|
Sessions->HostSession(4, TEXT("VocationLife"), TEXT("/Engine/Maps/Entry"), 7777, EVocationNetBackend::Auto, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,13 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, Category = "VocationLife|Graphics")
|
UFUNCTION(BlueprintCallable, Category = "VocationLife|Graphics")
|
||||||
bool IsRayTracingEnabled() const { return bRayTracingEnabled; }
|
bool IsRayTracingEnabled() const { return bRayTracingEnabled; }
|
||||||
|
|
||||||
|
/** Once true, the start/multiplayer menu will not open again this session. */
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "VocationLife|UI")
|
||||||
|
void MarkGameplayStarted();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "VocationLife|UI")
|
||||||
|
bool HasGameplayStarted() const { return bHasEnteredGameplay; }
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable, Category = "VocationLife")
|
UPROPERTY(BlueprintAssignable, Category = "VocationLife")
|
||||||
FOnVocationDataReady OnDataReady;
|
FOnVocationDataReady OnDataReady;
|
||||||
|
|
||||||
@ -68,4 +75,7 @@ protected:
|
|||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
bool bRayTracingEnabled = false;
|
bool bRayTracingEnabled = false;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
bool bHasEnteredGameplay = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,6 +55,8 @@ protected:
|
|||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void OnSessionJoined(bool bSuccess);
|
void OnSessionJoined(bool bSuccess);
|
||||||
|
|
||||||
|
void LeaveStartMenu();
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TObjectPtr<UComboBoxString> MapCombo;
|
TObjectPtr<UComboBoxString> MapCombo;
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public:
|
|||||||
void ClearInteractionPrompt();
|
void ClearInteractionPrompt();
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "VocationLife|UI")
|
UFUNCTION(BlueprintCallable, Category = "VocationLife|UI")
|
||||||
void ToggleMultiplayerMenu();
|
void ShowStartMenuIfNeeded();
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "VocationLife|Session")
|
UFUNCTION(BlueprintCallable, Category = "VocationLife|Session")
|
||||||
void HostCoopGame();
|
void HostCoopGame();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user