#multiplayer
1 messages ¡ Page 276 of 1
I even tried to call TearOff() on the client and update foo again but the client still receive the other foo update. I wonder if this is a PIE thingđ¤
Nvm it stopped receiving updates after I called TearOff() on the client. But as long as the client haven't called their own TearOff() it's still receiving updates
tested this again and it doesnt work lol
you could disable single process and see if it changes
also, foo is false to start, right?
Tried again with longer delay (10s) and it won't update foo!
But the question remains, do you think can I trust the game so that the client receive the last update right before calling TearOff()?
using unreals standard replication system if i have 50 pawns the client is like updating every 2 seconds, im using mover 2.0, GAS and StateTrees on the Controller. no system running other then move to tasks! and its jiggy
any suggestions?
yes foo default is false
I'm pretty sure tearoff sends one last update
new log unlocked: Closed socket YYYYYY via the API, reason 1000
like it's getting throttled or you set it to be 2 second ticks?
its throttled
didnt set it to tick that way
if it's using the cmc like movement I wouldn't be shocked by that performance
could adjust the priority
I'm facing the exact same issue with quite literally exact same amount of bytes, couldn't find a solution yet, please let me know if you will
how many characters you got?
I'm using mass entity, I got 1500 of them. But the data size inside profiler shows me 10kb in total per update. And they are being delayed as well, I set them to replicate every 0.1 seconds, the more entities I have the more time it takes to replicate it all, with 1500 I end up with 0.8s delay between the updates
does it make use of mover?
no, I have my custom movement. But the issue you face is exactly the same as mine in it's core, something delays the net updates
I tried quite literally everything to fix it, nothing helps
man i dont know im a tech animator, dont know much about network at all, maybe the package size to big?
wait where did you get this number?
oh that's per second, not per tick
this isn't bad, 60kb/s is quite literally nothing. I haven't used Stat Net but I get around 70kb/s as well on net profiler
the numbers are not bad at all, but for some reason engine reacts like this is something crazy
well seems like it is bad, shaggy is laggy đ
you actually also have outcoming traffic too, so it makes sense that your delay is around twice as much as mine. but even 120 kb/s isn't like horrendous. The delay shouldn't occur, but for some reason it does
you can try increasing bandwidth though, maybe it will work for you
(it didn't for me)
i know what i do, i design it around multiplayer but focus on single player and when the systems are in place i pay kaos a big check to fix it đ
@coarse cave Thank you for the update, moving the visibility into a function on the tile was kind of fine as in the function wasnt an issue.
I was trying to go then route of having the tile update its visibility per player (The screenshot before was from the player controller) however when trying either of your suggestions for 2 this all happens on the server and is no longer unique to each player? did I miss something or did that not come across in the previous message? Unless i should set if is dead on the player state somewhere so its replicated?
Its almost as if i want a desync on visibility or thats how i think id explain it
i dont know, but id assume the owner would be the server? or the client if ever?
I got problem with server travel, server travel not working on client whatever who triggers server travel only server change level client stucks in same level how can i fix that?
You want to do it all on the client. You need observable state to trigger the updates. E.g. your phase property should be an OnRep that fires off an event when it is replicated. The same goes for the state of the player being dead. Use what already exists for that one, or add a new way to replicate it
phase and unit are both re notify
phase is on game state
unit is on player controller
So just hook into those notifies from the tile on the client only. Add events (delegates) if necessary
oh
my mistake I didn't do the game state binding on owning client
this in the tile seems to work, thank you
dont know if event tileon phase change needs to be an rpc
but thats great
are you using NPP? i think thats the culprit honestly
I canât use find and join, but steam invites are working
That will probably work for your use case here, but generally you shouldn't pass arguments to your update function; it should query all relevant state internally. You want to do this so that when you rely on multiple pieces of state they can't stomp on each other when calling the update function.
Arguments are passed in RPC when you need to send data over the network.
what is usually the best place to store if player is ready or not in lobby?
PlayerState is my guess?
Playerstate is a great place for it
Why
just make it a replicated variable
Don't use RPC to set stateful data. Very common mistakes among youtubers.
okay, i'll try
What setup do you have to create a session and join friend invite ?
You can use https://blueprintue.com to quickly copy & paste your graphs
I'm still in class. I'll show you later
#include "SoldierPlayerState.h"
#include "LastBattalion/Widget/LobbyWidget.h"
#include "Net/UnrealNetwork.h"
void ASoldierPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASoldierPlayerState, bIsReady);
}
void ASoldierPlayerState::Server_SetReady_Implementation(bool bSetReady)
{
bIsReady = bSetReady;
if (HasAuthority())
{
GetWorld()->ServerTravel(FString("/Game/Maps/Level_1/PrototypeLevel_01?listen"));;
}
}
void ASoldierPlayerState::OnRep_IsReady()
{
// UI call
OnReadyStateChangedDelegate.Broadcast(bIsReady);
}
bool ULobbyWidget::Initialize()
{
Super::Initialize();
if (ReadyButton)
{
ReadyButton->OnClicked.AddDynamic(this, &ThisClass::OnClickReadyButton);
}
PlayerState = GetOwningPlayerState<ASoldierPlayerState>();
if (PlayerState)
{
PlayerState->OnReadyStateChangedDelegate.AddDynamic(this, &ThisClass::OnStateReady);
}
return true;
}
void ULobbyWidget::OnClickReadyButton()
{
if (PlayerState->bIsReady)
{
PlayerState->Server_SetReady(false);
}
else
{
PlayerState->Server_SetReady(true);
}
}
void ULobbyWidget::OnStateReady_Implementation(bool bIsReady)
{
ButtonText->SetText(bIsReady ? FText::FromString("Ready") : FText::FromString("Not Ready"));
}
is this correct Ready setup?
You can't call RPC as client through player state.
route it to the object owned by the client.
how many mass entities you running i did some testing and it works great 500 units 8,500.00 in rate on clients!
Then what would be the way?
You can though afaik?
i will test but iirc player state is owned by the server.
pretty sure I've done RPCs on player states
by that I mean, Client Player State calling server rpc. That shouldn't be allowed from memory.
as server, it can pretty much do RPC where ever it please.
Yeah, nothing is printed.
99.9% sure the player state's owner is the player controller, that's weird
Add a delay to that RPC
welp
not on my pc so cant check but I hope I haven't been hallucinating stuff all along
You're definitely running PIE as a client and not standalone/listen server?
LOL
@verbal ice you are right it work, I was wrong.
I'm happy I'm not going crazy
don't know where I got the info from. Even some google article share the same opinion.
As it turns out anyway, rpc work as client
yeah player controller, player state and possessed pawns are generally client owned
My bad, gave wrong info. You can do RPC in the player state.
here you are.
I want to know how to avoid operation latency caused by connection latency.
i dont think that can be easily done without using c++
This will never work, any movement should go inside the FSavedMove struct which can only be done in c++.
TLDR, Moves are performed with FSavedMove, so fighting againts it (e.g by shoving data outside the struct for the movement) will just cause correction.
i missed the listen param
thanks a ton, got it working for friend invites now
there's probably a hack with big cons. It's by playing around with the AddMovementInput. But honestly just don't go ahead with bp only imo.
Rip hours of debugging. Nice to hear you sort it out though.

i have used c++ in unreal engine
@ocean swallow https://www.youtube.com/watch?v=17D4SzewYZ0&t=349s
https://discord.gg/uQjhcJSsRG
In this video I setup a new project and create a custom character movement component. I also implement movement safe sprinting which works at any ping.
https://github.com/delgoodie/Zippy
0:00 Create New Project
1:02 Setup File System
02:50 Create Custom CMC
04:43 Saved Move Class
08:37 Compressed Flags
13:35 Client...
Cool, you can follow the tutorial above then =).
I saw this but I gave up because it was in C++
It's needed for authorative movement.
Multiplayer isn't friendly to bp only designers.
especially for real time games.
I didn't know that problem before yesterday.
Gotta bite the bullet or start with single player game imo.
If I had more time I would try to implement this. But I only have less than a month left.
Why? School project?
Y
not sure what the game is about but perhaps you can turn it into split screen game.
That way no networking is required. It;s basically single player with multiple controllers.
Other than that, just let client have authorative movement.
They can cheat but who cares, it's a school project.
but at least you know now to not start a first project or second project with multiplayer.
There is no lag on a single computer, but I am using Steam to connect.
absolutely
There's always lag when there's server and client (e.g multiple computer).
no such thing as 0 ms
those Youtube bp sprint tutorial breaks the moment the game simulate any lag.
So I feel like I was cheated dogeKek
better ask in this discord channel, youtube scams you from time to time.
I didn't understand that until a few minutes ago
Hey, finally I got proximity voice chat working and everyone has good attenuation settings for everyone. However, it took a lot of trials and errors because most of the time it wasnât working either on clients, on the server, or for someone who joined late. Previously, I also wanted to include everything in OnRepNotify, but then it crashed for everyone who joined late.
My question is, is it really necessary to create this for loop and multicast init every time someone is spawned? It doesnât feel like it, but that was the only scenario where everything was initialized for everyone.
its been a while since i played with RPCs
in my widget (client) im calling a server RPC (in my game state)
i know that the local client doesnt own the game state, but shouldnt the call get the owning connection of the player controller ?
do i have to move to server RPC on the player controller and have it get the game state ?
Can't do that, the game state not owned by the player.
Move the RPC somewhere the client own.
by the time the ServerRPC is executed it's already on the server, the server can access what ever instance it has in it's world.
Does anyone know if there's a way to have the debug lines performed by a trace show on the owning client as well?
if you want to do that you'd have to send a client RPC with the relevant data
I thought that would be the case. Just wanted to make sure there wasn't something hidden away.
the gameplay debugger does have replication support if you build your debug visualisation stuff around that
Probably overkill for what I want at the moment but i'll keep that in mind for when my needs increase. đ
void UMultiplayerSessionSubsytem::CreateSession(int32 NumPublicConnection, FString MatchType)
{
if (!SessionInterface.IsValid()) return;
auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
bCreateSessionOnDestroy = true;
LastNumPublicConnections = NumPublicConnection;
LastMatchType = MatchType;
DestroySession();
}
// Store the delegate in FDelegateHandle so later can be removed from delegate list
CreateSessionsCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegate);
LastSessionSettings = MakeShareable(new FOnlineSessionSettings);
LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
LastSessionSettings->NumPublicConnections = NumPublicConnection;
LastSessionSettings->bAllowJoinInProgress = true;
LastSessionSettings->bAllowJoinViaPresence = true;
LastSessionSettings->bAllowInvites = true;
LastSessionSettings->bShouldAdvertise = true;
LastSessionSettings->bUsesPresence = true;
LastSessionSettings->bUseLobbiesIfAvailable = true;
LastSessionSettings->Set(SEARCH_KEYWORDS, FString("MatchType"), EOnlineDataAdvertisementType::ViaOnlineService);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegateHandle);
// Broadcast our own custom delegate
MultiplayerOnCreateSessionComplete.Broadcast(false);
}
}
void UMultiplayerSessionSubsytem::OnCreateSessionsComplete(FName SessionName, bool bWasSuccessful)
{
if (SessionInterface)
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegateHandle);
}
MultiplayerOnCreateSessionComplete.Broadcast(bWasSuccessful);
}
MultiplayerSessionsSubsystem->MultiplayerOnCreateSessionComplete.AddDynamic(this, &ThisClass::OnCreateSession);
void UMenu::OnCreateSession(bool bWasSuccessful)
{
if (bWasSuccessful)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow, FString(TEXT("Session Created Successfully")));
}
MenuTearDown();
UWorld* World = GetWorld();
if (World)
{
World->ServerTravel(PathToLobby);
}
}
else {
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, FString(TEXT("Session Failed")));
}
HostButton->SetIsEnabled(true);
}
}
i am in a race condition
when i click on Host, it create session
but multiple times
@pliant cypress bCreateSessionOnDestroy = true; that sounds like you trigger create session from your DestroySession code. Shouldn't you return after DestroySession(); in that case?
Also not sure the term "race condition" applies here.
It's like a function being run again and again, my create session runned 2 times and when I searched in portal, it showed 2 lobbies when only one created with host joined and other with 0 player and 4 public connection available
That's not what a race condition is
If it calls multiple times then breakpoint it an check where the calls come from.
void UMultiplayerSessionsSubsystem::DestroySession()
{
if (!SessionInterface.IsValid())
{
MultiplayerOnDestroySessionComplete.Broadcast(false);
return;
}
DestroySessionCompleteDelegateHandle = SessionInterface->AddOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegate);
if (!SessionInterface->DestroySession(NAME_GameSession))
{
SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);
MultiplayerOnDestroySessionComplete.Broadcast(false);
}
}
void UMultiplayerSessionsSubsystem::OnDestroySessionComplete(FName SessionName, bool bWasSuccessful)
{
if (SessionInterface)
{
SessionInterface->ClearOnDestroySessionCompleteDelegate_Handle(DestroySessionCompleteDelegateHandle);
}
if (bWasSuccessful && bCreateSessionOnDestroy)
{
bCreateSessionOnDestroy = false;
CreateSession(LastNumPublicConnections, LastMatchType);
}
MultiplayerOnDestroySessionComplete.Broadcast(bWasSuccessful);
}
I did, it bypassed the breakpoint
Yeah then you are calling it twice through that I guess. Make sure you return early after DestroySession();
But after delegate right?
auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
bCreateSessionOnDestroy = true;
LastNumPublicConnections = NumPublicConnection;
LastMatchType = MatchType;
DestroySession();
}
After destory session.
cause you are continueing with CreateSession even though you will trigger CreateSession again when destroy is done
Oh okay, I'll test and report back asap.
i think the issue resolved. i just retest and it worked. perhaps, i'll check again but with UE this time, in morning.
if having a pre lobby for customization skins/loadout would it be acceptable for the loadout to be saved to the lobby player controller and then the server collect all info here for all future spawn when in the actual game or would you approach it a different way? (this was a few days ago and another guy asking but he seems to have run off on his own way)
Im hoping to not have changes in gameplay and there stuck with the loadout they chose just looking for any details on approaching this from lobby to gameplay
Is the pre lobby on the server or is it before connecting to the game server?
Like, is being in a lobby a state of the game server, or is it something that happens before connection through an OSS or something?
@dark edge lobby would be on the server and the pre map the loadout screen would be local
there is an instance for both situations
ive seen on swap controllers so was maybe thinking of that for lobby on server to gameplay on server?
Dedicated servers?
id like to move to that eventually but atm im on listen
Different engine, but I can give you a breakdown the pattern that TF/TF2/Apex used for that sort of thing. It's reasonably complex though, as it is designed to handle storage of said data in a backend and all of the issues related to transfering servers/reading/writing to a backend with latency
anything is helpful atm as ive not approached this before
I may be better off with something more like a character select atm for now so nothing as involved or with a backend but it would be interesting to know anyway
i need advice, my gamestate has a few variables such as days passed and gametime. When the players seamless travel to a new map ids like the value to persist. what the cleanest way to do it?
@tame sapphire
Connection
ClientAconnects toDedicatedServerXDedicatedServerXrequestsPersistentDataforClientAfromBackendDedicatedServerXsendsClientAa copy of theirPersistentDataduring connection
Lobby
ClientAalteration ofPersistentDatahappens only betweenClientAandDedicatedServerXDedicatedServerXperiodically writes updatedPersistentDataforClientAtoBackend
Matchmaking
DedicatedServerXsendsClientAto newDedicatedServerY(e.g. after successful matchmaking)DedicatedServerXsends a copy ofPersistentDataforClientAalong withClientAtoDedicatedServerYDedicatedServerXsends a copy ofPersistentDataforClientAtoBackend
Match
DedicatedServerYis now in charge... until the process repeats when sendingClientAback to the lobby
This approach removes latency/communication with the backend from loop and prevents race conditions. By handing off the data between server transfers you remove the possibility of reading/writing stale PersistentData from Backend.
Hey everyone đ
Iâm working on a multiplayer project and I need help setting up a scoring system.
Basically, when a player throws a ball into a goal, I want only that specific player to get a point so the system needs to identify which player threw it and update that playerâs score correctly on the server (and show it on their UI).
I already have the throwing and goal overlap events working, and Iâve got a replicated IncreaseScore function in my GameMode, but Iâm struggling with how to link the thrown ball to the correct playerâs PlayerState in multiplayer.
Does anyone know how to set this up properly in Blueprints or have a video/tutorial that covers something like this?
Any help or examples would be super appreciated đ
Add a "LastThrower" field to ball that gets set every time a player picks it up?
@coarse cave thank you, I think for now ill go with a server list the player can choose from and try and push the complete player list mapped to selected or look around how a team is passed as an option
Thanks Scriptacus I will try it and let you know
Hi, so curious about I guess "more complex" networking/ replication methods.
From the pins I see push model
I see network manager
and then the network manager talks about dormancy
From how the network manager describes it, dormancy seems bad, cuz of responsive-ness.
But, what about the other 2?
Are they 2 different methods for the same thing?
Wouldn't I use less network/ NetBroadcastTick time, by using push-model, so no pulling, or computing is required?
But, then what about a network manager, that sounds like central control logic, and doesn't require special handling per actor, for push model.
Are they both "good", or does it just depend on the type of game being made?
Or, actually from actually reading it, the network manager seems worse, or at least far more time consuming?
I was under the impression it was a thing that came with UE, and was a base engine class I use.
Not a completely custom actor C++
Since, from a general overview, it seems like the network manager would waste a decent bit of data?
Cuz, the implementation in the dev tricks, doesn't seem to account for actual ref replication, so wouldn't all clients know about all health component values?
Or, am I just missing something obvious. đ
@halcyon ore Not entirely sure what you want with the Network Manager, but Push Model is indeed meant to reduce or remove the overhead of polling.
Iris will require it iirc. Current replication system has it optional but you should usually use it anyway.
I just wasnât sure.
I saw stuff in the pins for it.
Wasnât sure what it is, or how useful it is.
Oh you mean the concept of creating an actor or similar that acts as a central hub. I was thinking you meant a base class in the engine.
void UMultiplayerSessionSubsytem::FindSession(int32 MaxSearchResults)
{
if (!SessionInterface) return;
FindSessionsCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);
LastSessionSearch = MakeShareable(new FOnlineSessionSearch());
LastSessionSearch->MaxSearchResults = MaxSearchResults;
LastSessionSearch->bIsLanQuery = (IOnlineSubsystem::Get()->GetSubsystemName() == "NULL");
LastSessionSearch->QuerySettings.Set(SEARCH_KEYWORDS, FString("MatchType"), EOnlineComparisonOp::Equals);
LastSessionSearch->QuerySettings.Set(SEARCH_LOBBIES, true, EOnlineComparisonOp::Equals);
UE_LOG(LogTemp, Warning, TEXT("Session Search start"));
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef()))
{
int32 NumResults = LastSessionSearch->SearchResults.Num();
UE_LOG(LogTemp, Warning, TEXT("Number of sessions found: %d"), NumResults);
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
MultiplayerOnFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Session Search failed"));
}
}
void UMultiplayerSessionSubsytem::JoinSession(const FOnlineSessionSearchResult& SessionResult)
{
if (!SessionInterface.IsValid())
{
MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);
return;
}
JoinSessionsCompleteDelegateHandle = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionsCompleteDelegate);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, SessionResult))
{
SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionsCompleteDelegateHandle);
MultiplayerOnJoinSessionComplete.Broadcast(EOnJoinSessionCompleteResult::UnknownError);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Session join failed"));
}
}
void UMultiplayerSessionSubsytem::OnFindSessionsComplete(bool bWasSuccessful)
{
if (SessionInterface)
{
SessionInterface->ClearOnFindFriendSessionCompleteDelegate_Handle(0, FindSessionsCompleteDelegateHandle);
}
if (LastSessionSearch->SearchResults.Num() <= 0)
{
MultiplayerOnFindSessionComplete.Broadcast(TArray<FOnlineSessionSearchResult>(), false);
return;
}
MultiplayerOnFindSessionComplete.Broadcast(LastSessionSearch->SearchResults, bWasSuccessful);
}
void UMultiplayerSessionSubsytem::OnJoinSessionsComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
if (SessionInterface)
{
SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(JoinSessionsCompleteDelegateHandle);
}
MultiplayerOnJoinSessionComplete.Broadcast(Result);
}
void UMenu::OnFindSession(const TArray<FOnlineSessionSearchResult>& SessionResults, bool bWasSuccessful)
{
for (auto Result : SessionResults)
{
FString SettingsValue;
Result.Session.SessionSettings.Get(NAME_GameSession, SettingsValue);
Result.Session.SessionSettings.bUseLobbiesIfAvailable = true;
if (SettingsValue == MatchType)
{
MultiplayerSessionsSubsystem->JoinSession(Result);
return;
}
}
if (!bWasSuccessful || SessionResults.Num() == 0)
{
JoinButton->SetIsEnabled(true);
}
}
void UMenu::OnJoinSession(EOnJoinSessionCompleteResult::Type Result)
{
IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get();
if (Subsystem)
{
IOnlineSessionPtr SessionInterface = Subsystem->GetSessionInterface();
if (SessionInterface.IsValid())
{
FString Address;
SessionInterface->GetResolvedConnectString(NAME_GameSession, Address);
//UE_LOG(LogTemp, Warning, TEXT("Address: %s"), *Address.ToString());
APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController();
if (PlayerController)
{
MenuTearDown();
PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);
}
}
}
if (Result != EOnJoinSessionCompleteResult::Success)
{
JoinButton->SetIsEnabled(true);
}
}
Now the issue is, i added some breakpoint because i wasn't able to join the session. first breakpoint hit at
if (!SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef()))
then it hit inside OnFindSession inside menu where bWasSuccessful got true and log printed Session Search Started.
then upon continuing, it should hit inside Join session instead it got back into find session and hit the else case which says Session Search failed
also, it never printed Num of sessions
i am not able to understand why this happens?
optimized code
means it won't be always linear when debugging (if that's what you mean, I don't really want to read all of this without even knowing where to start)
also, my creating session code have setting like this
void UMultiplayerSessionSubsytem::CreateSession(int32 NumPublicConnection, FString MatchType)
{
if (!SessionInterface.IsValid()) return;
auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
bCreateSessionOnDestroy = true;
LastNumPublicConnections = NumPublicConnection;
LastMatchType = MatchType;
DestroySession();
}
// Store the delegate in FDelegateHandle so later can be removed from delegate list
CreateSessionsCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegate);
LastSessionSettings = MakeShareable(new FOnlineSessionSettings);
LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
LastSessionSettings->NumPublicConnections = NumPublicConnection;
LastSessionSettings->bAllowJoinInProgress = true;
LastSessionSettings->bAllowJoinViaPresence = true;
LastSessionSettings->bAllowInvites = true;
LastSessionSettings->bShouldAdvertise = true;
LastSessionSettings->bUsesPresence = true;
LastSessionSettings->bUseLobbiesIfAvailable = true;
LastSessionSettings->Set(SEARCH_KEYWORDS, FString("MatchType"), EOnlineDataAdvertisementType::ViaOnlineService);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegateHandle);
// Broadcast our own custom delegate
MultiplayerOnCreateSessionComplete.Broadcast(false);
}
}
i can find my session on EOS dev portal though
in logs it printed this
[[2025.10.18-09.06.59:447][397]]LogTemp: Warning: Session Search failed
[[2025.10.18-09.07.00:267][428]]LogOnlineSession: EOS: [FOnlineSessionEOS::StartLobbySearch] LobbySearch_Find was successful.```
start like?
i don't understand
How to safely destroy the session to avoid server crashes? My current blueprint(BP_player) is as shown in the picture.
Is this video trustworthy? https://youtu.be/7OdruBNGOM8
đ¨âđŤ My Patreon link:
https://www.patreon.com/kekdot
Download Project Files | Premium Tutorials | Courses
đšď¸ Get our Game on Steam | The Anomaly Project:
https://store.steampowered.com/app/2960770/The_Anomaly_Project/
In this tutorial we talk about Network and Traveling errors. We install the correct nodes in the game instance ...
depends if server or not
client just has to destroy session (on client side iirc, doesnt need to run it on server)
server has to destroy the session for each client (locally iirc to) and then destroy on server for himself (tyo completly destroy the session online)
The client does the above and the server does the below?
like this?
yes
.
how
I usually just have the DestroySession call in the MainMenu GameMode.
Just on BeginPlay for example.
Makes sure the Session is cleaned up for Server and Client whenever they get thrown back into the MainMenu after the Disconnect.
I use this blueprint but the server crashes
who calls it ? the sever or client ?
When either the client or the server calls this event, the server will crash.
whats the error when the client leaves and server crash
The Server crash could be totally unrelated. Need crash message and callstack .
Crashes when trying to remove the Client. That's potentially not even related to the DestroySession call.
If I use different player controllers for my preset map and game map, will they automatically switch when I open the level?
how do you get the "player to kick"
Yeah, it takes the PlayerController of the GameMode that is assigned to the given level or defined via ?game=
The client calls the server to kick self?
You should just share more of your code.
Show how this is all called from start to end.
yeah, show us the code where you call the Quit event
i dont see anything wrong
Again, I would travel to the MainMenu or whatever that is for you and have the GameMode or PlayerController of that level call DestroySession
should be working for client
If your player loses internet, you will be stuck with a Session locally.
Your code isn't covering all cases.
i wont since for server you got to destroy the session for everyone before self ?
iirc
Why would you need to?
i remember having to do this some time ago
Let the Client call it locally once they traveled back.
QuiteGameEvent -> OpenLevel
In the GameMode or PlayerController of that level -> DestroySession on BeginPlay.
đŽ
can i use level blueprint to do that?
You can, but that's the worst you could do :P
Or just assign an unused player controller
Your levels should have GameModes assigned that match what the level is for.
just add a GM main menu
Usual simplistic setup is something like:
BP_GameMode_Base
-> BP_GameMode_MainMenu
-> BP_GameMode_Gameplay
It seems that I haven't learned the basics well.
I would agree here.
Is there anything else I need to set up besides the controller?
(Inherited from the game mode base)
I would usually inherit from the non-base version for Multiplayer. With C++ you could choose the Base one and do some of the non-base stuff yourself, but for BP that's probably more powerful.
And no, the PlayerController would be enough for the MainMenu.
Your PlayerController and the other classes should more or less mirror the same inheritance as your GameModes though
BP_PlayerControler_Base
-> BP_PlayerController_MainMenu
-> BP_PlayerController_Gameplay.
Should I change it?
GameMode
you dont have to
Does anybody know a trick to getting Steam to immediately recognize an update is available?
I'm in the middle of troubleshooting some Steam stuff, which means deploying to Steam and then updating the game on a couple machines. So far the fastest way is to relaunch Steam because I don't know how to force Steam to refresh the list. I can't be the only one going crazy with this...
void UMultiplayerSessionSubsytem::CreateSession(int32 NumPublicConnection, FString MatchType)
{
if (!SessionInterface.IsValid()) return;
auto ExistingSession = SessionInterface->GetNamedSession(NAME_GameSession);
if (ExistingSession != nullptr)
{
bCreateSessionOnDestroy = true;
LastNumPublicConnections = NumPublicConnection;
LastMatchType = MatchType;
DestroySession();
}
// Store the delegate in FDelegateHandle so later can be removed from delegate list
CreateSessionsCompleteDelegateHandle = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegate);
LastSessionSettings = MakeShareable(new FOnlineSessionSettings);
LastSessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true : false;
LastSessionSettings->NumPublicConnections = NumPublicConnection;
LastSessionSettings->bAllowJoinInProgress = true;
LastSessionSettings->bAllowJoinViaPresence = true;
LastSessionSettings->bAllowInvites = true;
LastSessionSettings->bShouldAdvertise = true;
LastSessionSettings->bUsesPresence = true;
LastSessionSettings->bUseLobbiesIfAvailable = true;
LastSessionSettings->Set(SEARCH_KEYWORDS, FString("MatchType"), EOnlineDataAdvertisementType::ViaOnlineService);
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (!SessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *LastSessionSettings))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(CreateSessionsCompleteDelegateHandle);
// Broadcast our own custom delegate
MultiplayerOnCreateSessionComplete.Broadcast(false);
}
}
void UMultiplayerSessionSubsytem::FindSession(int32 MaxSearchResults)
{
if (!SessionInterface) return;
FindSessionsCompleteDelegateHandle = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegate);
LastSessionSearch = MakeShareable(new FOnlineSessionSearch());
LastSessionSearch->MaxSearchResults = MaxSearchResults;
LastSessionSearch->bIsLanQuery = (IOnlineSubsystem::Get()->GetSubsystemName() == "NULL");
LastSessionSearch->QuerySettings.Set(SEARCH_KEYWORDS, FString("MatchType"), EOnlineComparisonOp::Equals);
LastSessionSearch->QuerySettings.Set(SEARCH_LOBBIES, true, EOnlineComparisonOp::Equals);
UE_LOG(LogTemp, Warning, TEXT("Session Search start"));
const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();
if (SessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), LastSessionSearch.ToSharedRef()))
{
int32 NumResults = LastSessionSearch->SearchResults.Num();
UE_LOG(LogTemp, Warning, TEXT("Number of sessions found: %d"), NumResults);
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(FindSessionsCompleteDelegateHandle);
MultiplayerOnFindSessionComplete.Broadcast(LastSessionSearch->SearchResults, true);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Session Search failed"));
}
}
this is my create and find session
and session is created successfully
but when on find, it returns 0 session found
where di i made mistake in configuration on FindSession code?
Restarting is usually the way to go.
Bummer, thanks for the response though!
you can also force the download by verifying files on steam
but often yes restarting is just faster, depends on your game
I think there is a trick where you press the verify button but cancel the verify and get the download instantly
You also can go offline -> online, it's way faster compared to restarting
lol that's way faster. Embarassed I never thought to try that
So did I. I don't even know how I happened to discover that, I also had to restart it for the first couple of weeks, and then, maybe accidentally, tried to go offline and online lol
Do you guys client predict the visual aspect of your inventory?
Say drag and drop / splitting items in the grid?
Would it be an okay idea to just let client predict it. So when it does an action / something like transaction in mySql.
It just update locally. When the inventory is OnRep, client check if the content matches with the repped value.
If not then sync it to server value.
Or should we just let server decide? but then the input delay may feel pretty bad.
guys, how to send all the connected players back to a lobby map?
server travel
lobby in what sense though, is it still networked? is it where people waiting for each other to be ready?
That really depends on how much pain you want to go through.
The problem is often not the single predicted action, but the chain reaction of that prediction.
Yeah, when I thought about it I don't think that's worth it.
What if your backend takes a bit longer and the player moves items, swaps them, splits them, drops them, all before the first action even got resolved?
You'd need to handle a queue of stacked actions. This would basically become a movement simulation, just not on tick.
I was using it already
nvm
I think I found the problem, it's just the controller somehow didn't open the lobby menu so it seemed like it was stuck
It might be worth it. Websites usually predict all sorts of state changes to give a better user experience. Laggy inventories aren't fun.
On what channel do they notify exactly when Epic gives away assets?
Right, I will try and see how it goes. Atm my idea is to just check the server and client value on the client on the latest OnRep (For personal inventory)
That works but only if those actions have no side-effects.
using and dropping item will still server auth, so those action can;t be predicted anyway.
Yus.
True, but as long the client doesn't modify their inventory with cheating, visually it should be fine? đ¤
In theory, you'd just need to keep track of the predicted actions locally.
Ensure they have some form of timestamp for ordering and then simply ack the changes when they are fine or correct them when not.
And after a correction you could "replay" the still newer, predicted ones.
#unreal-news usually.
Thanks
Without the replaying you'd encounter the same thing movement does, which is that actions would suddenly be undone, especially unrelated ones.
Imagine you move two items to two different slots. The first move gets denied and sends back the corrected inventory. The second move was already done and would have been fine, yet the inventory gets reset.
Aka, how much pain do you want to go through :D
if only the player has access to his/her own inventory it's ok to have client predictive methink
but for public inventory like a chest...
I'd say it depends on the game's nature
if it's rather coop than competitive, then client predictive might be ok
palworld had this bug where you can use your base's inventory to build, but if you step away from it last second you won't actually cost anything
and I think they still didn't patch it out
that may destroy my head a little :P,
what do you think of this approach.
Client do something on their inventory -> Client send Server RPC -> PredictedAction++
ClientOnRep -> PredictedAction -- -> If PredictedAction is 0 (So only attempt to update latest data) -> If current data != OnRep data, set current data to OnRepData.
and just reconstruct whole inventory :S, I kinda only have 30 slots in my backpack.
Could work. I would say try it out
will see how it goes, thx.
1500
replicating a single FVector_NetQuanitize every 0.1 seconds using my custom version of a fast array (basically the normal fast array but with indices stored as bits)
but i decided to have my entities simulated on both clients and server, syncing their locations sometimes since server-only crowd isnt possible from what ive seen so far. No matter how much i increase my bandwidth, unreal still throttles it. And my data isnt THAT big (10 kb per send, 100kb per second). I tried to have 1 replicator per 250 entities, which had only made the situation worse. Screw it, ill just forget about this idea
Do you really need to sync positions is it that crucial ?
They should.be pretty similar if running deterministic stiff
Stuf
Hey all, i am using 5.6 and i just noticed that server travel is broken..
Seamless should work but that doesn't seem to be working for me? What are the things that i could be forgetting for it? I have enabled seamless travel in the gamemodes.
I can make a lobby, get both players in the same world.
When the server host runs, server travel mapname?listen the host will go.
But the other clients wont, they will stay in the lobby and after enough time no connections have been made so they go back to default map
I'm currently working on my weapon system's ammo functionalities.
My plan is to have a magazine instead of typical ammo counts, so if a player reloads it doesn't just lose number but a whole magazine with the bullets he left in it. And the player cannot carry all weapon types magazine.
So this is my current design with respect to multiplayer
--- Weapon ---
int32 MagAmmo - current ammo in the weapon
int32 MaxMagAmmo - Maximum ammo magazine can have.
--- CombatComponent ---
TMap<EWeaponType, int32> CarriedMagMap - Number of magazines per weapon type
TArray<int32> CarriedMags - set the current magazine for the EquippedWeapon. (Takes from CarriedMagMap)
But I'm not able to connect the dot of reloading functionality and loadout system (contains 4 things, 2 weapon primary/secondary with prefix magazines and 2 grenades with prefix amount)
You don't need ?listen for ServerTravel. Also make sure to test this outside the editor as PIE doesn't support it by default (unless you activate the experimental CVar).
yo bois
I am bout to word wall you so im sorry in advance but any help is super appreciated
If you already have weapons standalone, why does the combat component hold a TMap for the Carried Mags?
I feel like that could just live in the weapon or a data asset of such
Same with the TArray. Not sure why that all lives in a separate component.
Currently I am working on a FPS with a Player Actor BP "BP_TunnelPlayer" that uses Metahumans with an animation blueprint called "ABP_PlayersAims_MHRemake". I currently use a Blueprint Interface called "BPI_CharacterData" to move data between the Character's blueprint and the Animation blueprint in use. In first three pictures below you will see how I implemented an UNFINISHED pipeline for Character Gait Data (Sprinting, Slow-Walking, Jogging, etc.). Currently there is an issue where when another player sprints, they move at the correct speed but the animation being played is still the Default aka Jog animation.
I assume that this problem is because the Function Call "Update Gait" in the Player BP is Player Input Dependent, and is not replicated along with any associated variables and that is why is does not work for viewing other players in Multiplayer.
Later I implemented a GroundMatching system which needs a dependent variable "GroundDistance" which is also passed through the same BPI. It is visible in the LAST TWO pictures below and my question now becomes (and I could test it but I just figure I'd ask since I'll be away for some time): Will there be any similar issues with replicating and using the variable "GroundDistance"?
More generally speaking, since this variable is calculated in the Event Tick node, which later then uses the BPI, will the ABP for OTHER players on your screen maintain synced and current GroundDistance data? And if so, could a similar method be used for always passing current Gait Data or should that be a replicated call?
https://imgur.com/a/MRtg4tF https://imgur.com/a/rb1OYCZ https://imgur.com/a/iJgo2Fp https://imgur.com/a/prOUAOs https://imgur.com/a/xkFx6YR
ughh why do they have to come out like that, I removed the embeds on the picture so they don't nuke the entire page, but they are still usable
I'm having a bit of a struggle wrapping my head around whether things should be on the character or the controller. I am trying to make a HUD for the player with icons from the character abilities but can't seem to get the timing correct between initialization and possession.
Maybe someone has some insight in the correct process of generating the hud based on the character defaults?
Im using unreal 4.27
i predict it locally because its pretty easy to do
server replicates proper inventory after a change so if theres a mispredict it resolves itself pretty easily
when replicating a tarray of structs why changes to a property inside one of the structs not trigger the repnotify function on the array, how to work around this in a nested scenario where outer struct array contains inner tarrays?
Use a Fast Array. Then you can mark it dirty, which will cause it to replicate.
Super thanks, and here is the code of the current issue... will try to change it to fast array now
#include "AdvancedNetworkComponent.h"
#include "Net/UnrealNetwork.h"
UAdvancedNetworkComponent::UAdvancedNetworkComponent()
{
bReplicates = true;
if (HasAuthority())
{
FOuterStruct Outer;
Outer.InnerData.InnerArray = {10, 20, 30};
Outer.OuterValue = 100;
OuterArray.Add(Outer);
}
}
void UAdvancedNetworkComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UAdvancedNetworkComponent, OuterArray);
}
void UAdvancedNetworkComponent::OnRep_OuterArray()
{
// will not trigger changes for InnerData.InnerArray
}
void UAdvancedNetworkComponent::ModifyInnerArray(int32 OuterIndex, int32 InnerIndex, int32 NewValue)
{
if (HasAuthority() && OuterArray.IsValidIndex(OuterIndex) && OuterArray[OuterIndex].InnerData.InnerArray.IsValidIndex(InnerIndex))
{
OuterArray[OuterIndex].InnerData.InnerArray[InnerIndex] = NewValue;
}
}
void UAdvancedNetworkComponent::AddToInnerArray(int32 OuterIndex, int32 NewValue)
{
if (HasAuthority() && OuterArray.IsValidIndex(OuterIndex))
{
OuterArray[OuterIndex].InnerData.InnerArray.Add(NewValue);
}
}
it works, once again super thanks
Related to FastArray.
Am, I just missing something obvious?
How do I get the like "variable owner" in the fast array struct, for the add, remove, change?
Can you explain that in a different way. Not sure what you mean exactly
The fast array has the pre remove, post add, and post change
But, how do I get those to the actor with the fast array, so I can do things when things change, without re-looping the entire array with the normal onrep
Both the FastArraySerializer and the FastArraySerializerItem have that pattern.
They do vary slightly
So depends on which one you like more.
But something I tend to do if I need what you are asking for
Is I expose delegates for those functions on the FastArray
Which the Object that is using the FastArray would sub to
/* Public interface for external systems to know when the container operations were performed. These will be called on Server and Client via their respective functions below. */
DECLARE_MULTICAST_DELEGATE_OneParam(FOnAdded, const FSeat& /*AddedElement*/);
FOnAdded OnAddedDelegate;
DECLARE_MULTICAST_DELEGATE_OneParam(FOnChanged, const FSeat& /*ChangedElement*/);
FOnChanged OnChangedDelegate;
For example
Which would be called respectively by
/* These are called by the SerializerItem on both Client and Server when the container element is operated on. */
void OnAdded(const FSeat& Seat);
void OnChanged(const FSeat& Seat);
In turn called by
void PostReplicatedAdd(const struct FSeatingArrangement& InArray);
void PostReplicatedChange(const struct FSeatingArrangement& InArray);
On the FastArraySerializerItem in this case
Ah, ok.
So, easier then I thought.
I tried GPT, cuz sometimes it has more then 2 IQ.
It suggested, my owning actor, fill each entry with a ref to the owner.
I was like...
Yeah, thats wrong.
You could have the Array receive the OwningActor
Which would tightly couple them
And call functions directly on it
But I prefer the method I posted above
The AbilitySystem does that I think
Tightly couples their FastArrays to the ASC
But in their case that makes sense
Since their containers arent generally useful outside of use with the ASC
Then, since your here, if you don't mind.
Am I also lost, on how Fast Array replication is handled on initial actor replication?
Normal case says it replicated all 10k entries all at once.
But, surely thats wrong, since it defeats a likely core purpose of the Fast Array?
If that is the case, and all 10k entries get replicated at once, then how do you handle manual batching, while also having the Fast Array handle delta changes?
That is correct.
The entire Array state is sent initially.
It cannot be any other way
Since the Deltas need to operate on a known base
All Clients need to start from the base
This is true for regular arrays as well
Fast Array seems a bit useless to me then?
Still gotta replicate 10k entries all at once.
So, if too much your just fucked?
How is that handled, since like you say, and logically they all need the same starting point/ current data, for deltas to work correctly
They are far from useless
Putting aside their efficiency, just their structure is helpful for cross network operations.
Trying to figure out what element inside a regular array was changed by replication is tedious
FastArrays solve that
In the case of use large data sets
I would consider trying to think of ways to separate them into smaller groups of arrays
Instead of storing 10k elements in 1 array. Can you separate them out into 10 arrays of 1k elements
Thats just an example by the way.
Wouldn't that still hit the limit?
You still learn of 10k entries at the end of the day.
The limits apply to the individual container and Actor. So you would want to spread the load.
Maybe look up Network Managers
I believe there might be a pin in this channel
This problem is explored in a blog post somewhere
By someone on this server.
It might give you clues on how to adjust your use case
This link here
Yeah, I had found that, all other stuff I could find for my use case/ thought was fast array.
Network managers as described in this blog also use FastArrays
Yeah, I had read over it.
But, perhaps I was miss-understanding something, cuz wouldn't it run into the same issue.
A Fast Array with a ton of entries in it.
You might be missing the point of what its trying to build as a concept
The concept of a network manager is that you can have as many of them as you need
In order to spread the load of trying to handle large sets of data
I thought I understood the network manager, as just an external source to handle the replication of like 3,000 replications, into 1 replication loop.
Rather then 3,000 replicated health components.
have 3,000 default non-replicated components.
and, 1 manager handles there 1-2 vars.
Given this commet from the discord:
Replicating several hundred moving Actors is doable, however, replicating several hundred moving Actors while you have several thousand non moving replicated Actors cluttering the NetBroadcastTick is not.
Cut down on the replicated components to give more direct replication to actual systems.
Sure, but you can split them up however you like
You dont HAVE to have 1 Network Manager that does ALL health components
Valid, and thats not something I considered/ thought of.
Given, most core UE systems are 1x stuff.
What are you trying to replicate 10k elements for BTW?
What are you trying to achieve exactly?
replicating the state of foliage on the map.
Just a basic cut down, not cut down.
Oh?
Is the foliage runtime generated or baked?
Planned to be baked from the normal editor foliage.
But, at the same time, runtime would be a nice addition, but not required. đ
Ok, the difference isnt huge.
We will do just baked
So with that, I mean, all instances of foliage have a predictable ID
Meaning its the same across all machines
So a tree on a hill, has the same ID for all clients for that same tree on that same hill.
You get that?
Yes.
I was planning something similar.
But, tracking/ replication the state of each 1 tree is the cause for a 10k array. đ
So you are only tracking trees that got cut down?
If they are cut down, or not cut down.
Since, they'll re-gen after some time.
And you are expecting players to cut down 10k trees all at the same time?
Either way. This fits in perfectly with Network Managers TBH.
So
How you could handle it
Is you could make a Network Manager actor type for your Trees. That manager is responsible for just keeping track of the Tree IDs of those that have been cut down.
I don't plan too.
But, players in games are psycho.
So. đ
Seems easier to just have each possible tree in an array, for cut or not.
Rather then handle extra shit with having 1 too many trees cut down, and crashing the client.
You can then place as many of these Network Managers around the world
Ideally you would probably have some sort of mechanism that would mean they understand which trees are within a volume around them
Or by distance or something
You need to then place enough of those managers around that all trees have a linked manager
So like, in my earlier suggestion, you could have 10 tree managers that each handle 1000 trees
This then gives you further leverage with dormancy and relevancy.
Does that help?
That does.
I'm just glad I re-thought of a new method, for my original Fast Array usage.
Cuz, idk what I'd do there. đ
Keep in mind, you would be replicating an int32 for the Trees instance ID plus a bool or a uint8 (which can then handle further masked values) for every tree.
As in?
I need to still be careful about length, or?
Cuz, yeah.
and, couldn't I also make the bool into a 0-1 bit. (to reduce replication size more)
or, does that not support replication by default?
hi, i am new here and im running into a problem and wondering if anyone might be able to help.
when i update a replicated variable on the client it does not actually update. im using a delegate to communicate from the player state to the userwidget. when i first start the game it tells me the delegate is bound and i get the variable showing correctly. however when i update the clients variable the OnRep funcitno is called however the delegate is no longer bound and i dont get an update. it works perfectly fine for the server
i tried calling the function directly (no delegate) from the playerstates onrep by GetPlayerController->GetHUD however the GetHUD for the client doesnt work. again the server works fine
i dont see how this could be an auth issue however i might just be completely wrong
i tried binding the function 10 seconds after the game starts. i am still able to get the initial variable set up for the widget but i dont get an update. the client says its not bound
replicated properties should only be changed on authority which will be on the server for replicated actors
the changing of the property is happening in the player state via RPC
don't use a rpc for that
what should i use instead
or do you mean you're telling the server to change the value with a rpc?
yea
oh that's fine
so like the server knows the variable is changed. the onrep is called
but my delegate is no longer bound?
if something is getting unbound it's possible the relevancy of something changed
but if that were the case would both server player and client joining player have the issue
i also tried just straight calling the function on the widget from the playerstate. works fine for the server but again not able to for client
so i feel like for some reason the HUD is the issue
show your codes?
@pliant gull GetPlayerController->GetHUD
Where is this called? show all the relevant code.
it's called in the player state
Because the character holds the mag, the weapon doesn't need to hold the storage of the mags. Like in real life
Fair and you have no InventoryComponent (or generally Inventory-like system) where the mags can live in?
For now, it's inside the CombatComponent but i'll make a loadout component
loadoutComponent will handle inventory stuff
Like, you said you are lost on connecting Loadout to whatever your idea here is. In can tell you, without knowing much about your code and game and without sticking to your idea, how I would lay this out.
such as Loadout struct and equipments etc
(if you want)
sure
it'd give me some insights and would help me really great
Show codes?
Design: Weapon + Mags + Inventory + Loadout
I'm not at my computer at the moment. but it should be this.
AMyPlayerController* PC = GetPlayerController();
AMyHud* MyHud = Cast<AMyHud>(PC->GetHud());
I'm realizing the issue
maybe I need to cast my player controller
?
need to know the actual GetController method
client only knows their controller, so as client, if you have someone's player state. GetController will return null.
well when I do if(PC) it returns true
only as server
there's no way your client knows other controller but their own local controller.
hmm right
So if you have something like
As Client
SomeoneElsePlayerState-> OnRep->GetController it will be null
though why do you need controller?
well my delegate is unbinding (don't know why) so I tried to instead reach the HUD by going through player controller
I'm sending an updated variable to a widget
Just make a method to get the HUD
where should that be located?
you can make a blueprint function library, a static method allow you to call it anywhere.
Send all the relevant codes when you have the chance
someone else can probably help too
I don't think you should create some static function for this. It won't change anything. The Delegate shouldn't "unbind", so you'll have to share the code of this setup. Somewhere you are either doing something wrong or you expect something that is in fact not the case.
Do the CMC sync the direction of the movement or it's relative direction based on the character orientation? Meaning that if the client rotation and the server rotation is unsync. The client press move forward, do it cause desync?
I believe the CMC movement uses raw directions
though if you've made your movement dependent on orientation, like if you move slower backwards or something, yeah it'll matter
how do y'all handle ragdoll replication?
do you typically just avoid them having gameplay effects and have the client sim it with no replication?
what if it does effect gameplay, like for accessing loot? should that just be avoided?
I replied without thinking about it much so deleted it lol. You determine what the input derives its world space direction from when calling add movement input which occurs locally so won't desync. But CMC will desync from rotation being out of sync too.
Hey, I'm trying to get the voice chat volume from a VOIP talker, but the GetVoiceLevel() function doesnât work on the local player. It only sends to other players (to avoid loopback I guess?). This function only works on the local player if voice loopback is enabled via a Cvar.
Does anybody have an idea how to capture and return the value thatâs sent (or even that is captured via voip before sending?), so I can control a local player variable? Iâve been trying to go through VoiceConfig.cpp, but I havenât found any answers yet.
For now I'm using the AudioCapture component, but I have a problem with it because it's not really giving the same value you get from VOIP. Also, commands like voice.MicInputGain and voice.SilentThreshold donât affect the AudioCapture component.
What I found is that using the voice.debug.PrintAmplitude cvar from VoiceCaptureWindows.cpp, gives exactly the value I want and works without voice loopback, but my current C++ knowledge doesnât let me implement it in my own component yet
@dark parcel WidgetTest.h
UFUNCTION()
void OnMoneyUpdated(UMoneyComponent* NewMoney);
WidgetTest.cpp
#include "Widgets/MyUserWidgetTEST.h"
#include "GameModes/PlayerControllers/MyPlayerController.h"
#include "GameModes/PlayerStates/MyPlayerState.h"
void UMyUserWidgetTEST::NativeConstruct()
{
Super::NativeConstruct();
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &UMyUserWidgetTEST::AttemptBinding, 6.0f, true);
}
void UMyUserWidgetTEST::OnMoneyUpdated(UMoneyComponent* NewMoney)
{
if (CurrentBalanceText)
{
CurrentBalanceText->SetText(FText::AsNumber(NewMoney->GetBalance()));
}
}
void UMyUserWidgetTEST::AttemptBinding()
{
if (PS == nullptr)
{
APlayerController* PlayerController = GetOwningPlayer();
if (PlayerController)
{
PS = Cast<AMyPlayerState>(PlayerController->PlayerState);
}
}
if (PS)
{
PS->OnMoneyUpdated.AddDynamic(this, &UMyUserWidgetTEST::OnMoneyUpdated);
// PS->OnMoneyUpdated.AddDynamic(this, &UMyUserWidgetTEST::OnMoneyUpdated);
if (PS->OnMoneyUpdated.IsBound())
{
OnMoneyUpdated(PS->Balance);
}
GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
}
}
From the playerstate.h ``` DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMoneyUpdated, UMoneyComponent*, NewMoney);
UPROPERTY()
FOnMoneyUpdated OnMoneyUpdated;
From the playerstate.cpp
```void AMyPlayerState::OnRep_Balance(UMoneyComponent* balance)
{
if (OnMoneyUpdated.IsBound())
{
UE_LOG(LogTemp, Warning, TEXT("= bound."));
OnMoneyUpdated.Broadcast(balance);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("OnBalanceChanged delegate is not bound."));
}
}
void AMyPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyPlayerState, Balance)
}```
idk if i needed to paste anything else but yea
i also tried having the OnRep function send the varible to my controller for the hud to access it from there but i get an exception thrown and stopped there
so basically the server client still has OnMoneyUpdated bound and can broadcast, the joining client can bind, because i can use it in the Attemptbind function in the widget but after that it unbinds
@pliant gull Have you ensure that the UMoneyComponent is set to replicate?
also another thing, how is the widget created? is there only one UMyUserWidgetTest PER machine, or is it PER PlayerState?
you should make sure that client actually bind on the attempt binding. Do a print string on the block and see where you fail.
Print string will show the machine that is executing the code.
class UMoneyComponent* Balance; ```
like this?
Not only that
is OnRep called on client?
SetIsReplicatedByDefault(true);
have this on your ctor too
in the Character class?
no in the MoneyComponent class
yeah
lets move to the most important part after. Debug if you are binding on client.
you will also need to check if OnRep is called on client.
How do you check it?
does UE LOG come with the Net machine that execute it.
uh
I usually just use print string cuz it will says whos executing the code.
Try that first then we can move on to the binding
don't want to leave stones unturned.
đ
UKismetSystemLibrary::Printstring
lol thanks
The OnRep function is being called on the server
afaik OnRep shouldn't even be called on Server
its possible ive set this up completely wrong
can you show me a print screen of the print string
That's on the OnRep?
yea
and you are playing as 2 players , set to Listen server?
Oh wait, why are you OnRepping the component 0o
MoneyComponent can just be set to replicate.
What you should OnRep is the balance.
i dont understand
OnRep on money component should be called when the ptr changed. If you want to keep track of the member variable of the component, you will do that with the OnRep on the member property (in this case the balance)
UMoneyComponent is an ActorComponent?
yes
Yeah, you are just OnRepping the pointer to the Component
this is not even necessary if it's a replicated component.
Create a delegate when balance changes inside UMoneyComponent
OnRep_Balance -> Broadcast.
OnYour Player State Begin Play -> Get Player -> Get Money Component -> Bind to the delegate.
would having the moneycomponent on the player controller or character not defeat the point of replication?
Then just print string every time the delegate is fired. See how that goes.
Character is fine, player controller IS NOT if every player needs to know about each other money.
Because all controllers exist on server.
But Client only know their own controller. So there's no way for Client 1 to know Client 2 money if the component is inside the controller.
If you don't want to attach the money component inside the player character (if you have to destroy it for what ever reason).
Then you can attach it to the player state.
since every machine have a copy of every player state
well my thought process was that if it was on the playerstate players need to go through the server to edit it. as in get permission
as is with everything
oh
Replication only work from server to client, and client can only communicate with server through Server RPC.
But you don't really need the client to have a say here.
Why do you want the client to say, Hey I just got 5000 gold?
Client can make request with server RPC.
server check and verivy. Then set the value if valid and replicate the changes.
lets focus on the current issue though.
Where is the MoneyComponent atm?
Is it attached to the player state?
yea
You want to create a delegate inside money component.
Which gets broadcasted on OnRep_Balance
call it BalanceUpdate or something along those line.
Yup, or one Param if you want to broadcast the value.
to bind the delegate from UMoneyComponent to the OnRep inside the playerstate i need access to the playerstate in the UMoneyComponent.cpp. how am i supposed to get the playercontroller to access the playerstate while in an actor component. or am i getting this all wrong
AMyPlayerController* PlayerController = Cast<AMyPlayerController>(Cast<AMyCharacter>(GetOwner())->GetController());
i did this
but i feel like this is just wrong
lol
any if it works it works
ill try
No, why does the MoneyComponent even need to know the existence of player state?
MoneyComponent just broadcast it's value.
the player state, widget or anything can listen to the broadcast.
Keep dependency one way.
this is wrong too, yeah.
For one the owner is a PlayerState, not a character. ALSO, in client this will be null (the controller for non owned player state).
i figured this. the game wont even open anyways lol
yeah you probably hit exception.
yea after loading for 5 minute
Paste your money component code after you update it with OnRep on the balance and a delegate.
i have to redo cuz i misunderstood
just to confirm i should make the OnRep in the Moneycomponent
correct?
Correct, you OnRep the balance.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MoneyComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMoneyUpdated, UMoneyComponent*, NewMoney);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class THEGAME_API UMoneyComponent : public UActorComponent
{
GENERATED_BODY()
public:
//UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
UPROPERTY(ReplicateUsing = OnRep_Balance)
int Balance = 100;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Sets default values for this component's properties
UMoneyComponent();
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION()
int GetBalance() const
{
return Balance;
}
UFUNCTION(BlueprintCallable)
void AdjustBalance(const int& change)
{
Balance += change;
}
UFUNCTION(BlueprintCallable)
bool CheckBalance(const int& change)
{
return (Balance >= change);
}
UFUNCTION(BlueprintCallable)
bool Buy(const int& change)
{
if (CheckBalance(change))
{
Balance -= change;
return true;
}
else
return false;
}
UFUNCTION()
void OnRep_Balance(UMoneyComponent* currentbalance);
UFUNCTION()
FOnMoneyUpdated OnMoneyUpdated;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Statlines/MoneyComponent.h"
#include "Kismet/KismetSystemLibrary.h"
// Sets default values for this component's properties
UMoneyComponent::UMoneyComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
SetIsReplicatedByDefault(true);
// ...
}
// Called when the game starts
void UMoneyComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UMoneyComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
void UMoneyComponent::OnRep_Balance(UMoneyComponent* currentbalance)
{
OnMoneyUpdated.Broadcast(currentbalance);
}```
can you format it with cpp?
you mean just send you the file
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MoneyComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMoneyUpdated, UMoneyComponent*, NewMoney);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class THEGAME_API UMoneyComponent : public UActorComponent
{
GENERATED_BODY()
public:
//UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
UPROPERTY(ReplicateUsing = OnRep_Balance)
int Balance = 100;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Sets default values for this component's properties
UMoneyComponent();
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION()
int GetBalance() const
{
return Balance;
}
UFUNCTION(BlueprintCallable)
void AdjustBalance(const int& change)
{
Balance += change;
}
UFUNCTION(BlueprintCallable)
bool CheckBalance(const int& change)
{
return (Balance >= change);
}
UFUNCTION(BlueprintCallable)
bool Buy(const int& change)
{
if (CheckBalance(change))
{
Balance -= change;
return true;
}
else
return false;
}
UFUNCTION()
void OnRep_Balance(UMoneyComponent* currentbalance);
UFUNCTION()
FOnMoneyUpdated OnMoneyUpdated;
};
Nah, i copied your msg and saw you have extra space after the cpp
Hmm, so you want to broadcast the component instead of just the value? I mean it should work, just not sure about this approach.
well i mean i can just add currentbalance->GetBalance();
i suppose you are right, better to just share the value
Well it would be more accurate to call it TheMoneyComponent instead of currentBalance but that aside, we can move on.
Nah it's fine, just keep the component.
you can just access the balance getter from the comp.
On your PlayerState Begin play, bind to that delegate.
so whenever your balance is updated, the player state will be informed.
what do i bind it to?
OnMoneyUpdated
sorry i mean what in the playerstate gets bound to the onmoneyupdated
to your custom Function
PlayerState BeginPlay -> Get Money Component -> Bind OnMoneyUpdate to some function.
Call that function PlayerMoneyUpdated
And in that function you can just do a print string.
print the balance of the mOneyComponent
PlayerMoneyUpdated (MoneyComp* PlayerMoneyComp)
{
print (PlayerMoneyComp->GetBalance())
}
at this stage, it should print both on server and client if the OnRep work.
Man, I would love to help, but that has been quite a lot of messages by now and I don't even know at what stage we are now.
I saw OnRep_MoneyComponent, which seems redundant.
void AMyPlayerState::BeginPlay()
{
Super::BeginPlay();
Balance->OnMoneyUpdated.AddDynamic(this, &AMyPlayerState::OnUpdatedMoney);
}
like such?
weve moved the delegate to the actual moneycomponent instead of the playerstate
please
- Who all needs to know about the Money of a given client value and that it changed?
- Local client only?
- All clients?
- Where do you create the Widget that is supposed to display the value and update from the delegate?
only the given player needs to know that the value has changed in order to update the widget created in the HUD
so i suppoes everyone needs to know their own value
Does player 1 need to know Player 2 and 3 money, ever?
no
watt
well
i mean i just dont see the need for that to happen
maybe i am just missing something
well anyway, how do you go with this?
when server change the money value, you should get a callback on every machine.
show the callstack
Run the project with debugger.
What is MoneyComponent derived from? Does Actor component even have begin play?
Then you shouldn't put any of this on the PlayerState. You are making your life so much harder here than it needs to be.
Yes
it came with it upon class creation
what would you recommend
Since only the local player needs to know about the value and that it changed, place the Component onto the PlayerController.
Why is that better?
-
Each player/client only has access to their own PlayerController. Other player's PlayerControllers aren't replicated to them. So you already, naturally, ensure others can't read the value and you aren't wasting bandwidth on replicating it to others that don't care to begin with.
-
Since you create the Widget in an AHUD child class, which itself is created in the APlayerController, you aren't running into issues with order of initialization of Actors or their replication. Right now, you struggle with timing, which is why you also have that nasty looping timer in your Widget. Since the PlayerController spawns the AHUD locally and at that point the Component is also already valid, you can simply access the Component directly, without fearing that it hasn't replicated yet.
what would i do in regards to not allowing tempering of the values or is this not an actual problem
Note about the looping timer:
I understand why that instantly becomes the fallback when people notice that something isn't valid "yet", but seems to be valid "later". However, there isn't really a need for this, especially when you are using C++.
If you ever have a Widget that does in fact need to access the PlayerState, then you should fall back to delegates in Actors that you know are valid and that can tell you about the PlayerState becoming valid.
For the local player, their PlayerState will replicate potentially a bit later than the PlayerController, which is why you have the Timer. However, the PlayerState has an OnRep_PlayerState in the PlayerController (or rather in the AController class), which is virtual and can be overridden. So you can simply override that in your own PlayerController and broadcast a custom delegate. In your Widget you can then get the PlayerState and if it's invalid bind to that delegate. No need for the timer.
The only edge case here would be a ListenServer, as OnRep functions, in native code (so not your code but UEs) are often not called for Servers. So you would need to override a second function that is called for the server, such as InitPlayerState, and broadcast there too (after Super::).
This concept also works for Pawns/Characters/ for example. If you have a HealthComponent or so on your Pawn/Character, you can't be sure that it's valid when the Widgets are created from within your PlayerController or HUD.
You could add the Widget from within the Pawn/Character, but if you don't want that you'd basically require the same delegate setup.
Good news in that case is that AController has OnPossessedPawnChanged, so you don't even need to create your own.
For PlayerStates of non-local players, you usually want to simply ensure that he Widgets are also added when the PlayerStates become valid (e.g. through BeginPlay of the PlayerState).
Did you read the Network Compendium that is pinned to this channel?
It should have made very clear that 'automatic' replication always only works from Server to Clients and the only option for Clients to tell the Server something is to use a ServerRPC.
So placing the Component on PlayerController or PlayerState doesn't make a difference.
The thing that stops people from tampering with the value is YOU not giving them a ServeRPC that asks the Server blindly to change the value.
no but i see it now and ill def read that thank you
In theory, as a really vague rule of thumb, you only ever want to use a ServerRPC to tell the Server about something it can't possibly know.
And that "something" is almost always user input. Mouse, Keyboard, Gamepad and UI interactions. EVERYTHING ELSE, should never be ServerRPC'd. Shooting a gun? Send RPC when LMB is pressed. After that, Server can do the shooting and damaging.
So if you don't have an RPC that asks the Server to change Money to a new value, then they can also not temper with it.
They can locally change it, but that won't replicate to anyone.
One last word of advice: If you aren't planning on using Dedicated Servers for your game AND hosting those yourself, away from the players' reach (which is pretty expensive), then you shouldn't worry about cheating anyway, cause you can't prevent it.
okay well thank you very much for all the info
so for the most part, i can still obtain the same goal by putting it in the player controller
and if im putting things together properly the main reason to use the playerstate is for things shared with everyone? kinda?
Yes
Dedicated Server
- Client_1_PlayerController
- Client_1_PlayerState
- Client_1_Character
- Client_2_PlayerController
- Client_2_PlayerState
- Client_2_Character
Client_1
- Client_1_PlayerController
- Client_1_PlayerState
- Client_1_Character
-
- Client_2_PlayerState
- Client_2_Character
Client_2
-
- Client_1_PlayerState
- Client_1_Character
- Client_2_PlayerController
- Client_2_PlayerState
- Client_2_Character
so playerstates are actually known by other players?
Difference between PlayerState and Character (Pawn) would be that a client doesn't need to always have a Pawn and can potentially switch between different ones, respawn, etc. PlayerState remains one and the same for the entire session (until changing level and similar things).
Yes
hmm had no idea
Listen Server
- ListenServer_PlayerController
- ListenServer_PlayerState
- ListenServer_Character
- Client_1_PlayerController
- Client_1_PlayerState
- Client_1_Character
- Client_2_PlayerController
- Client_2_PlayerState
- Client_2_Character
Client_1
-
- ListenServer_PlayerState
- ListenServer_Character
- Client_1_PlayerController
- Client_1_PlayerState
- Client_1_Character
-
- Client_2_PlayerState
- Client_2_Character
Client_2
-
- ListenServer_PlayerState
- ListenServer_Character
-
- Client_1_PlayerState
- Client_1_Character
- Client_2_PlayerController
- Client_2_PlayerState
- Client_2_Character
Same thing for ListenServer. ListenServer is always a bit of an odd ball, cause the rules still apply all, but given the ListenServer is a Server after all, it does actually have access to all of the other Client's PlayerControllers, even though it's a player.
In the more traditional usage of Unreal Engine, that being Unreal Tournament for example, the PlayerState used to hold things like Kills, Deaths, Assists, while the Character held things like Health.
But you can read most of that in the Compendium, which was written to avoid repeating the basics :D so I will stop now.
lol
i will def read it
thank you for pointing it out to me
and sorry for my ignorance but thank you very much for everything
I found the exact same problem, and also ended up using UAudioCaptureComponent for the local player. I bind an event to OnAudioEnvelopeValue to store the latest local amplitude.
From looking at the code in VoiceCaptureWindows.cpp it looks like it should account for voice.MicInputGain etc, but I am not 100% certain.
how do you deal with large log files? is there any parser that you use to provide a useful summary instead of scrolling through endless lines?
Yeah, in voicecapturewindows.cpp there is this debug cvar voice.debug.Printsamplittude and it accounts for these cvars. Problem is with audio capture component, its propably using something else, or its own parms instead of cvars. I will maybe look for help in audio thread
From what I can see, the Audio Capture component eventually uses the class in VoiceCaptureWindow to do the actual recording.
void ULoadoutComponent::OnRep_PrimaryWeapon()
{
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("WeaponHandle"));
if (HandSocket)
{
HandSocket->AttachActor(PrimaryWeapon, Character->GetMesh());
}
}
void ULoadoutComponent::OnRep_SecondaryWeapon()
{
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("WeaponHandle"));
if (HandSocket)
{
HandSocket->AttachActor(SecondaryWeapon, Character->GetMesh());
}
}
void ULoadoutComponent::SetWeapon(int32 index, AWeapon* NewWeapon)
{
if (NewWeapon == nullptr) return;
switch (index)
{
case 0:
PrimaryWeapon = NewWeapon;
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("WeaponHandle"));
if (HandSocket)
{
HandSocket->AttachActor(PrimaryWeapon, Character->GetMesh());
}
break;
case 1:
SecondaryWeapon = NewWeapon;
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("WeaponHandle"));
if (HandSocket)
{
HandSocket->AttachActor(SecondaryWeapon, Character->GetMesh());
}
break;
}
}
this is my loadout component
and i gotta bit confuse now
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
if (SoldierCharacter == nullptr || WeaponToEquip == nullptr || SoldierCharacter->GetLoadoutComponent())
{
return;
}
EquippedWeapon = WeaponToEquip;
SoldierCharacter->GetLoadoutComponent()->SetWeapon(0, EquippedWeapon);
HandleEquip();
EquippedWeapon->SetOwner(SoldierCharacter);
EquippedWeapon->SetHUDAmmo();
if (Controller)
{
Controller->SetHUDCarriedMagazine(CarriedMagazine);
}
}
this is my function on CombatComponent
called via Server
the thing i cannot comprehend is how do i store the weapon and do not crash like i don't have a weapon at begin and when i equip, it should be in my hand but if i have a weapon on hand (Equipped) then the other weapon should go to the back of my mesh (Secondary Weapon)
Hi,
I'm having a situation where an actor of a particular class is being possessed on the server, in the editor it shows as autonomous proxy, but PreNetReceive never gets called on a particular component, which it should when it receives the changed role from the server, but changing the class to a different one with the same base class, makes it work, that is PreNetReceive gets called and the component is able to react to the role change. The component is the same for both classes
I tried debugging Unreal source code but we only have a prebuilt version built in release
This also isn't my code
component is replicated right?
Yes
i would say to just debug during PreNetReceive and see why its skipped but without a source build itll be trash
is this a bp/c++/both class?
I was trying to debug the actor channel itself, but I realised I can't trust the values I see
yeah debugging any engine code without a source debug build is pointless
They have a C++ base class but BP derived
is it a component with a similar or same name as another component added in bp or c++?
you could try copying the component list and looking at it in debug
also, does PreNetReceive get called when changing role? i thought it was just for properties
Well, in the case of the working actor class that's how it reacts to role change...I'm honestly pretty new
I didn't design any of this so I can't say if it's done right
I assume it is bc it's a fork of the network prediction plugin
@haughty ingot hi, question about Use less RPCs
Does client send ServerRequestPickup() and ServerAddToInventory() from the same tick?
If not (i.e. server decides what ItemID to drop so ServerAddToInventory() will be called sequentially, after ClientConfirmPickup() response, then how does Transactional semantics in Command approach exactly works? Is it 2 FInventoryTransaction RPC calls from client to server?
why even call server add to inventory? ideally client requests the server to pickup with ServerRequestPickup and then the server validates it and picks up
then the item replicates to the client as a replicated property
only 1 rpc
I'm pretty sure that article is advising against the design it first calls out
I guess it's artificial example and there are might be real cases when you send a multiple related RPCs from the same tick. My question more about Command approach from the article and how it handles sequential scenarios
well, in the article it wraps multiple actions into a single transaction
so there is once action dependent on the previous, but they come from the same RPC
if you have dependent state it needs to be a single rpc, otherwise the order isn't guaranteed
he also shows an array that you could use for batching multiple transactions in order
so if you were to move 5 items in a row, make each move a transaction in an array. then send that array in the rpc
Hi, sorry I just saw this.
I'm pretty sure that article is advising against the design it first calls out
That's precisely it, although there is a disclaimer at the top that reiterates it's purely an opinion, and there isn't a one-size fits all solution to anything. The purpose was to invite the reader to consider if they actually needed multiple RPCs to represent a flow of data, it may not work for every scenario and you very may well want RPCs to arrive sequentially (which brings a fight of it's own). The "transactional" aspect refers to treating the entire flow as a single logical operation from the caller's perspective. The server processes this command atomically and replies with the result state, not intermediate steps.
The article argues against reflexively creating separate RPCs for every micro-action (Pickup, Add, Remove, Stack, etc.) when you could model the caller's intent as a single command. Whether that works for your specific game depends on your latency tolerance and gameplay requirements.
Added note: this is also a comment section on the blog. Feel free to encapsulate the conversation there as well
I've been having trouble having a client Player controller from one pawn to another, I read up on some solutions and I'm not sure what I'm doing wrong. This block of code starts off an Advanced Input Action and it works to possess a camera pawn and works perfectly for the server, when testing from the client it is like the "possess" node gets skipped. What's my problem?
(Edit: the real custom event is run on server)
what BP am I even looking at? client->server RPCs will only work if the actor is something the player owns
sorry this is the pawn spawned by the server possessed by the client. as far as i can tell the server rpc works fine, as print string node will say it was from the server after the rpc but not before.
???
what
your response made very little sense. also input is not networked, so you will have to send something to the server (as the owning client) to trigger any of this
a pawn the player is possessing is an example of something the player owns
ah so i need to go to the client after input, then to the server?
I'm not sure why you'd need the former, you're either a client or a listen server host if you're running input
the input just needs to trigger a server RPC and that takes care of the rest
ok i tested this and some other variations and its still not working, am i getting the PC wrong?
Well the whole left hand side isn't even connected to anything
Also you know the relevant player controller, you don't need to pass it in the RPC
yes the input now goes straight to server rpc and nothing is passed through it
the cut away code is making it very difficult or impossible to help.
first of all, if the client is executing the code (pressing the input), that bp camera will only spawn on it's machine. The server will not get a copy as replication work from server to client, not vice versa.
So I'm not sure about the idea of getting Current Camera. It will be null anyway in the case of the client pressing the input.
a replicated actor will replicate only if spawned by server.
meaning every players will get a copy.
I'm not sure what you are going to change though, what's the actual goal? why do you have to communicate the act of looking at a camera?
perhaps just spawn and execute the code locally.
this code is for placing and using a camera that you can look though anytime
please expand
Why do you have to RPC it?
why do client have to tell server, hey execute this function in your machine
i might not after replicating the spawning logic. also i have no idea bro i am winging this
ok my original code was fine the problem was that the actor wasn't replicated. THX @dark parcel
all g but must server replicate the camera? it's probably useless for other players.
you can just spawn locally and use set View Target with blend.
that will eliminate waiting for server too (delay). It sucks for player with considerable latency.
will the other players still be able to see and interact with it then?
Not if spawn locally, they will not get a copy
are you making a security camera or something
ok i will need it on server so others can shoot it and stuff.
yes.
well yeah, that have to be done on server then.
hey does anyone know why GetHUD() on the client playercontroller returns null
and if theres any way around it
I've encountered a weird UE issue that's stumping me. Tapping into the hive mind here.
When you mark an actor AND its component to replicate, changing visibility of that component on a server replicates visibility to clients. All as expected. In my room fade this means that hiding an actor on the server affects all clients for replicated components. So I created a small proxy to multicast to clients to revert the visibility change when they see it. That all works.
Here's the problem. If you change the visibility on a client, that state is sent back to the server! I know, this seems wrong, but I've spent hours confirming my code. It totally brakes server authority and I don't know how to fix it. If I don't change visibility on the client the server is fine. Change it on the client and the server changes too!
It shouldn't so you'd need to share where you are calling it.
Would need to see your code. Some properties of components are replicated if you'd mark the component as replicated but not everything of course. On top of that, visibility and hide actor are two different things.
None of it should allow the client to modify the server. And client/multicast RPCs to modify visibility, which is a state, is wrong to begin with.
I'd expect GetHUD() to return null for a remote client
the AHUD actor is spawned clientside by the player controller and is not replicated in any way
Hi all, let's say I have a ai-controlled Character that follows the player. Would it be correct to set its Owner to be the player Character (or the PlayerController) so a client can call server RPCs on it?
depending on the context that could be permissable, but it really depends what you want to do
not sure if that'll mess things up for the AI controller's possession
generally speaking it would only make sense to change the owner if the player had some unique control over them imo
what happens if another player needs to call the rpc? do they just keep swapping owners over and over?
my first guess would be to avoid that situation instead of gambling on the engine being okay with that personally
just make a new controller/playerstate component that describes to rpc with the npc as one of the params for the server rpc
yeah RTS style controls is what came to mind
yeah that would make sense
I'm honestly not even sure how live ownership changes work
I tend to just have stuff in the 3 regular owner actors
that would be the case yes, each player has its own ai-controlled character. No other player could call RPCs on it.
But maybe its safer to have a component in the controller as you say, just in case
thank you!
How do i make montages be replicated for an NPC
like the server can see when an NPC plays a montage but not the clients
Play Montage etc are local iirc
so you have to run it on all clients with a reped var or a multicast
ohh gotcha, thanks
Some context. This is in a plugin that has no access to the design of the components hidden. The plugin fades out rooms and actor contents locally depending on camera position. On listen servers, we only want components hidden locally, but if the component is replicated we need to temporarily suppress replication of bHiddenInGame. Because we don't own that component, we hesitate to disable replication because we don't know side effects. So, my idea was to RPC to clients to locally revert the hide change. That works, but when I unset HiddenInGame on the client, that strangely undoes the hide on the server (only tested in PIE). I was not expecting state to be sent back to the server! I am fully aware how replication is supposed to work, and this breaks my understanding.
And yes I am being loose with actors and components here. When I say I hide an actor, I mean all the components in the actor. Other options considered were removing component from main render pass on server, but that does not work for Niagara and mesh render holes in world. I could add a invisible mask material for mesh, but I wanted shadows to be preserved and that breaks that. Visibility is best if I can get it to work.
Why would visible not work in this case?
Because visibility is replicated, and when I revert the replication on the client, that change strangely gets replicated back to the server. I know, that is not supposed to happen, but it is.
By visibility I mean either Visible, or HiddenInGame. They both behave strangely (in PIE at least).
After looking.
I would say I got it mixed up, but sounds like your still having issues?
Cuz, I was gonna say bHiddenInGame doesn't have direct replication on the component.
But, I guess the actors replicate hidden must make that replicate to?
If both the actor and its component are set to replicate, the visibility and HiddenInGame are replicated. This is a little different than normal parameter replication in that there is a big switch for the entire component (CompOwner->SetReplicatedComponentNetCondition can update replicate conditions similar to GetLifetimeReplicatedProps, but is not helping me here so far).
The weird part is why changing visibility on the client affects the server. I've protected my code on the client with " if (HasAuthority()) return;" to triple ensure that it is the setting on the client that affects the server and verified in the debugger. Also double checked that NetMode == NM_Client. It's very strange.
btw, the bHiddenInGame stuff stops a given Actor from replicating at all, cause it won't be NetRelevant anymore. At least most of them won't.
Yeah, that's part of the reason why I was hiding the actor components individually rather than the actor itself. Good to know though, thanks!
I think the issue is that some properties like visibility and movement are client authoritative. Can be overridden on server but are passed from client to server. I donât know how to suppress this.
The item in question is a weapon attached to a character.
before even asking , i know this issue is quite vague but i really don't know where else to ask atm
i have been testing my game in standalone with EOS for a long time now, and all of the sudden this morning, the server map will send the client back to the main menu immediately, and i have no idea why. i checked all the logs and most are basically empty excpet there are a few lines that i found semi suspcious, but i dont know much more, and im hoping someone else might have an answer as to where i can look
2025-10-22 15:53:06.641 UnrealEditor[7007:67207] [UE] [2025.10.22-19.53.06:641][134]LogNet: Warning: UNetConnection::Tick: Connection TIMED OUT. Closing connection.. Elapsed: 23.20, Real: 23.19, Good: 23.19, DriverTime: 23.20, Threshold: 20.00, [UNetConnection] RemoteAddr: 127.0.0.1:17777, Name: IpConnection_0, Driver: Name:PendingNetDriver Def:GameNetDriver NetDriverEIK_0, IsServer: NO, PC: NULL, Owner: NULL, UniqueId: INVALID 2025-10-22 15:53:06.641 UnrealEditor[7007:67207] [UE] [2025.10.22-19.53.06:641][134]LogNet: Error: UEngine::BroadcastNetworkFailure: FailureType = ConnectionTimeout, ErrorString = UNetConnection::Tick: Connection TIMED OUT. Closing connection.. Elapsed: 23.20, Real: 23.19, Good: 23.19, DriverTime: 23.20, Threshold: 20.00, [UNetConnection] RemoteAddr: 127.0.0.1:17777, Name: IpConnection_0, Driver: Name:PendingNetDriver Def:GameNetDriver NetDriverEIK_0, IsServer: NO, PC: NULL, Owner: NULL, UniqueId: INVALID, Driver = Name:PendingNetDriver Def:GameNetDriver NetDriverEIK_0 2025-10-22 15:53:06.649
and
2025-10-22 15:53:06.721 UnrealEditor[7007:67207] [UE] [2025.10.22-19.53.06:721][135]LogNet: Connection failed; returning to Entry 2025-10-22 15:53:06.721 UnrealEditor[7007:67207] [UE] [2025.10.22-19.53.06:721][135]LogLoad: LoadMap: /Game/LEVELS/MAIWORLDMAINMENU?closed 2025-10-22 15:53:06.721 UnrealEditor[7007:67207] [UE] [2025.10.22-19.53.06:721][135]LogWorld: BeginTearingDown for /Temp/Untitled_0
did you manually set it to use port 17777 or is that a typo
so not sure what oculd cause a timeout / not being able to connect, but that's just weird to me, and then the second one is just also strange because of the /Temp/Untitled_0 as i don't have a map / level named this at all ?
honestly im not even sure
i know it's typically 7777
not sure wher ei would have done 17777 tho
the default is 7777 so it looks like a config typo or something
where would i set this ? that seems like it would be an easy try
Question: What/how would you recommend setting/storing a team and/or a loadout struct variables from a pre level lobbyto carry on to the gameplay lvl using the server? (Im currently using on swap player controller but feel like the player should ask the server what team and/or loadout they have not the player controller tell the server when it comes to respawning?)
I would assume GameInstance and then passing to player state for replication?
i was using this, so i guess it was giving me 17777 for some reason, but chaning to 7777 didn't fix
well actually, im noticing that it's still saying 17777 ?
maybe there's another place for that
2025-10-22 16:24:13.784 UnrealEditor[13144:117918] [UE] [2025.10.22-20.24.13:784][ 0]LogInit: Display: Starting Game. 2025-10-22 16:24:13.784 UnrealEditor[13144:117918] [UE] [2025.10.22-20.24.13:784][ 0]LogGlobalStatus: Browse Started Browse: "/Game/LEVELS/WORLD?Name=Player" 2025-10-22 16:24:13.784 UnrealEditor[13144:117918] [UE] [2025.10.22-20.24.13:784][ 0]LogNet: Browse: /Game/LEVELS/WORLD?Name=Player 2025-10-22 16:24:13.784 UnrealEditor[13144:117918] [UE] [2025.10.22-20.24.13:784][ 0]LogLoad: LoadMap: /Game/LEVELS/WORLD?Name=Player 2025-10-22 16:24:13.789 UnrealEditor[13144:117918] [UE] [2025.10.22-20.24.13:789][ 0]LogWorld: BeginTearingDown for /Temp/Untitled_0
the above is still the more concerning part tho, it just immediately destroys the world for some reason, and im not sure what it's trying to do ther, and aagin, dont have any level for /Temp/Untitled_0
it also works when i just play in viewport, but it also doesnt represent the game fully cause i can't get any info really from the server like a fake save game file so hard to actually test like that
Perhaps OwnerNoSee and OnlyOwnerSee are the only way to make visibility differ between client and server for replicated components. Not quite enough for my use case as I never want to hide the owner on his machine. OnlyOwnerSee would hide on all other clients when I only want to hide on some. Investigating. Maybe I can set separately on clients and servers?
im spamming but my client logs say im opening up the main menu, no mention of the main level at all, and the server says the thing i posted above. im baffled and may just have to revert to a version from 24hrs ago
SetOwnerOnlySee for the win! Badly named api, but I think it solves my problem. A flag I can set anywhere that is not replicated!
successfully reverted to a version from 24hrs ago, all is working fine. only lost the 12 hours of today but half of that was me trying to figure out what ahppened, and i have zero idea. not a clue
Hey guys, i wanna have a manger actor, and in this manager i want to allow every client to call this manager's server functions. How can i do that? Maybe some quick workaround?
As you have found, clients can only call Server RPC on owned actors. Practically, this is the clients' PlayerController or Pawn.
So usually you would add a function to the PC or Pawn that routes the function call to the manager.
To make this a bit more manageable, for our game we made a UServerRPC component that we added to the players pawn, that handled all these rpc routing functions.
so it isnt possible to do that without routing... sad, alright, thanks
Following on and as an example:
The lobby has a list of weapons you can select from (this could be not locked as in all players could choose the same weapon), The local player then selects the weapon they wish to use. This is then the only weapon they can spawn with when in the gameplay level.
Is it still select weapon in lobby, lobby updates game instance. Travel to new map then game instance updates player state to replicate the variable or should this be more server controlled (As I understand it the game instance is unique to each player so should only have the local players load-out/weapon/profile and isn't set up to be server authoritative? i.e. I think it should be more local player asks server what his load-out/weapon/profile is when in gameplay but in lobby he can tell the server?)
Even the client 'owned' actors like PlayerController are server authoritative.
In the pre-match screen, the client sends a server RPC on the PC to the server to request a specific loadout.
Server validates this is OK, then stores the loadout in a replicated variable (on the PC, or maybe on the PlayerState, etc). Make sure these actors make it through server travel, of course.
When the client loads into the new map, query the replicated variables for the current loadout.
I have a question about this Blueprint. It checks if the total of all players' possessions for a specific item is greater than a specified value. However, when a player calls the check event, AccEvent only counts the value sent by the client who pressed G, and it executes the same number of times as the total number of players. Values ââsent by other players are not counted.
I can't understand what I did wrong đ
Additional Notes: The inventory system is functioning correctly and players' items are not mixed up.
only a client that owns the actor can call a server RPC.. so when you call the multicast, all the clients that dont own the actor will have their server RPC not go through
are the players inventory different locally than the servers or something? you shouldnt need clients to send info back to the server like that
Like using the get all actors of class method?
My idea is to only let the server collect the client's calculation results
@tardy fossil
So is it recommended to use nested loops?
It depends
Sometimes a nested loop is fine. Other times it could be done better.
But depending on the problem, you probably want to do it in C++ because loops are one of the worst areas for BP to do
So in my player controller something like
and weapon class gets passed in from ui
?
and player state is
Why my 157,436 element BP array slow! BP sux c++ is better!
You can speed up the array by making sure they are all strings. Gotta go fast 
a fully bp array implementation would go so hard
i can already imagine calling add unique
void UCombatComponent::Reload()
{
if (CarriedMagazine > 0 && EquippedWeapon->GetMagAmmo() < EquippedWeapon->GetMaxMagAmmo() && CombatState != ECombatState::ECS_Reloading)
{
if (!SoldierCharacter->HasAuthority()) UE_LOG(LogTemp, Warning, TEXT("client reloading"));
ServerReload();
}
}
void UCombatComponent::ServerReload_Implementation()
{
if (SoldierCharacter == nullptr && EquippedWeapon == nullptr) return;
CombatState = ECombatState::ECS_Reloading;
HandleReload();
}
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Unoccupied:
HandleReload();
break;
case ECombatState::ECS_Reloading:
if (bFireButtonPressed)
{
Fire();
}
break;
}
}
void UCombatComponent::HandleReload()
{
SoldierCharacter->PlayReloadAnimation();
}
void UCombatComponent::FinishReloading()
{
if (SoldierCharacter == nullptr) return;
if (SoldierCharacter->HasAuthority())
{
CombatState = ECombatState::ECS_Unoccupied;
UpdateMagazineAmmo();
}
if (bFireButtonPressed)
{
Fire();
}
}
animation and reloading is only happening on server
not on clients
also, finishreloading is called by AnimNotify in Montage
this is PlayReloadANimation
void ASoldierCharacter::PlayReloadAnimation()
{
if (Combat == nullptr || Combat->EquippedWeapon == nullptr) return;
UAnimInstance* AnimInstance;
if (IsLocallyControlled())
{
AnimInstance = GetFPSMesh()->GetAnimInstance();
if (AnimInstance && FP_ReloadWeaponMontage)
{
AnimInstance->Montage_Play(FP_ReloadWeaponMontage);
FName SectionName;
switch (Combat->EquippedWeapon->GetWeaponType())
{
case EWeaponType::EWT_AssultRifle:
SectionName = FName("Rifle");
break;
}
AnimInstance->Montage_JumpToSection(SectionName, FP_ReloadWeaponMontage);
}
}
else
{
AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && TP_ReloadWeaponMontage)
{
AnimInstance->Montage_Play(TP_ReloadWeaponMontage);
FName SectionName;
switch (Combat->EquippedWeapon->GetWeaponType())
{
case EWeaponType::EWT_AssultRifle:
SectionName = FName("Rifle");
break;
}
AnimInstance->Montage_JumpToSection(SectionName, TP_ReloadWeaponMontage);
}
}
}
i'm following TPS/FPS method for my FP game
for a "bank" that would act as a storage for each player separately, would i just use a simple contianer with an items array as like a component on game mode or game state? or player state? or character? lol
this data would be infrequently interacted with, so maybe i could use a savegame file , but im more curious where i should put this logic
definitely not game mode as thats server only.. game state also doesn't seem like a good choice.. id say player state or character.. player state if you dont plan on having AI with inventories
Playerstate probably
nice that's actually a bit easier to visualize, i was only thinking somehting like gamestate/gamemode as they aren't the character but i suppose the reasoning was about the charcter not having direct access without the validation but yea a non-issue to worry about. i like player state
Also depends on if this is meant to be replicated or more of a query /response thing
in the bank case, i'd see it as just a server validated client UI represenation of an external place to store additional items
Component on playerstate will work
so don't really see it needing to replicate to anyone other than that owning lcient, but invenotry/storage is diffetn
you can restrict it to only owning client
yea prob will that will give a nicer response time for the immediate pull up lol
I'm interested in (at least beginning to start) learning client side prediction. I have a project where some of my player character scene components need to use absolute world location instead of local transforms and are updated to match the player's world location through blueprint. This works flawlessly as the host but all other clients experience jitter as the components slightly lag behind their position.
Tricky to really help here. The Character class with the CMC already has client side prediction built in. If you have SceneComponents on your Character that aren't "relative" to the Transform of the Capsule (or at least the MeshComponent), then they won't be part of the existing client prediction.
Right, that part i understand. How would i begin creating a prediction blueprint for those world locations? I know at the very least i need to take into account linear and angular velocity as advised by a friend
Hm. I'm not sure tbh. If these SceneComponents aren't* solely based on the Capsule/MeshComponent (Transform-wise), you would be fighting the CMC's existing prediction and smoothing.
What defines their "Absolute World Location"?
Every scene component has a dropdown arrow next to location, when you open that there are 2 radio buttons 'local' and 'world'. When you switch it to world, location now displays as absolute location
That wasn't my question. I want to know where the values come from that you use.
my player character scene components need to use absolute world location instead of local transforms and are updated to match the player's world location through blueprint
This part. Why do they need to be Abs World Loc and get updated from outside?
What updates them? To what are they updated?
'VInterp To' 'Get Actor Location'
Okay, so I don't think there is much about "client prediction" you would be doing here. I would advice ensuring that these Components are updated individually on all clients, so don't replicate their transform additionally. And then make them VInterpTo the MeshComponent and not the Actor (CapsuleComponent).
I don't really know what kind of components those are and you still haven't explained why you even do this.
It's difficult to help if you aren't answering the questions :P
I'm very sorry I'm trying my best
I'm affecting 2 scene components separately and thus their children. The two affected parents are a second collision capsule and a spring arm. The reason I'm doing this is to have something similar to camera lag but only adding lag to the z location
Are there still other questions i haven't answered?
are there any screenshots I need to send?
No. So if they are "camera lag" related, I assume they are local client only? Or do other clients need to be aware of those? If they are local only, then I would continue to suggest simply VInterping to the MeshComponent and not having any additional replication for the transform going on. They MeshComp's Transform should already be smoothed.
it is a similar effect to camera lag but it is not using that built in system at all. As for replication it did not work for clients at all unless I set up the blueprint that sets their world laction to start with a run on server event and multicast event
the basic use case of the system right now is the character uses two separate collision capsules, the built in one with the dimensions of a crouching character, and a second using this custom system to extend out from it to make up the remaining standing height. As the character steps up onto a ledge the top capsules X and Y are meant to stay 1 to 1 with the X and Y of the actor but the Z interpolates instead of snaps making the character appear as if it compresses when stepping up. The same principle is being applied to a spring arm and all cameras attached to it.
I'm handling this code in a custom actor component which has been added to the player blueprint alongside the existing CMC
the dimensions of either capsule never change, when crouching the top capsule just moves down into the bottom one. This was done so the player can run over very jagged terrain while the top have remains relatively level, similar to how car suspension works
the custom suspension component doesn't need the replication box enabled but the scene component its configured to affect does, like the capsule and spring arm
I assume that capsule is not supposed to affect the movement, or?
in what way? the bottom capsule is still the player controller and does all of the built in cmc function like the Is Falling? check. The top portion is additional collision and I have a skeletal mesh parented to it because in the future I will handle crouch animations with IK instead of dedicated crouch animations.
Well, let's assume the player walks towards a low ceiling that the actual Capsule, being only "CrouchHeight" high, would fit below, but the additional capsule above doesn't,
Is that supposed to block the player's movement?
yes
crouching would sink the "head" capsule into the main crouch height one allowing the player to crouch under
I can send two videos on why and how I'm doing it that way
Right... that probably ain't gonna work properly and also explains why you get problems with it. Everything that affects the Movement Simulation has to be built into the CMC or at least be based on already synced events.
A second capsule can work, but not if driven through Blueprints.
right now everything is functional except for jitter on non-host clients. It still properly affects their movement, its just that the camera (using the same thing because of the affected spring arm) is nauseating for those other clients
except for jitter on non-host clients.
Then it's not functional :P
Also you are not taking into account corrections that aren't handled properly like this.
In theory you'd need to "record" the Z offset in SavedMoves to ensure the CMC properly recreates the state when replaying moves.
that's why I'm seeking guidance
Well, are you able to use C++?
I have minor experience outside of unreal but haven't used any in this project thus far
Hmpf. So, there is a lot going on inside the CMC. Almost all of the simulation, including the Prediction, the Correction, the Reconciliation and the Smoothing/Interpolation is all happening in C++ and heavily tied together.
It's all very much relying on the concept of the Client performing a move locally, saving all sorts of information about the move to a local buffer an sending the minimum of information via the CMCs ServerMove RPC to the Server. And the Server then performs the same move and compares the endlocation which the Client also sent via that RPC. If that location differs, it will correct the client, which will throw all older moves away, apply the server data as the truth and replay all currently still pending moves.
If you start messing this outside of that "loop", it won't be working properly, especially not in actual network conditions.
In 95% of cases, one needs to inherit from the CMC in C++ and add custom functionality the way the CMC needs it to work, so it's part of said "loop".
If you start doing things outside of the CMC, then there is no guaranteed anymore that the move the client did locally will be the same move the server does after the RPC.
I'm going to sound really stupid but I can't just predict where the player will be?
And there is also no guarantee that the client can replay the moves after corrections.
In a very naive way, yes. Location + (Velocity * Time) would give you where it will be. But that is only feasable if that doesn't affect the actual simulation.
the simulation isn't breaking or desyncing right now
Are you testing with ping and potential package loss?
Cause it usually looks fine in PIE if you have that disabled.
Either way, you'd need to base the XY location of the additional stuff on the XY location of the player. The SimProxies probably don't even need this, as they just get the Transform replicated anyway. And if you update the additional capsule to match the other capsule every frame on Server and Client independently (no additional replication), then it would probably also match in the "live" world. You still might not have a fun time if you get corrections.
The Z interp stuff is a different story.
Cause there is no way you can guarantee that this is in sync.
yes, the lag is bad but it hasn't broken collision detection and hasn't allowed the character to phase through or under stuff they shouldn't
It wouldn't do that. It would just jitter like hell
do what?
phase through stuff
i just said it doesn't?
And I said it would also not do that.
As in, there is also no expectation that it would cause the player to phase through anything.
wouldn't it if the two capsules desynced from each other?
You are still updating the location every frame after all. They won't really desync that much. The bigger problem is the Interpolation stuff you do isn't in sync.
Inside the CMC, the Server performs the Move with the DeltaTime that the Client used. The Client tells the Server the DeltaTime via the ServerRPC.
If you interpolate some float on Server and Client, they can have different FrameRates and will interpolate differently fast.
So when the Server moves, the second capsule might not be at the same location due to interpolating differently.
also apologies I misread that as "I wouldn't do that."
All good.
If my best course of action is to modify a default component with C++ at this point would I just be better off modifying camera lag to only lag for z movement?
Client performs Move X, sends result to Server. Server performs Move X.
Now the additional capsule isn't synced here, as you aren't doing the interpolation INSIDE the CMC.
If that results in the same behavior for you, then 100%.
Multiplayer is difficult. Client Predicted Movement in Multiplayer is one of the high end disciplines. Blueprints can do a lot, but this stuff usually has to be handled in C++. There are some things that work out of the box with Blueprints due to things naturally syncing up (like stepping onto a jump pad, as Server and Client will step on it during the same "Move"), but something as "core" as the collision is probably not gonna work well.
im working on an open world game and im exploring ways to save, load, render and keep harvestable world objects (trees, rocks, ore deposits) synced for all clients. this is what i ended up with:
- separate the world in chunks, each object is assigned to a chunk based on their location. everything goes into an array
- when the world is loaded, use a server-side subsystem to calculate the necessary chunks around all players and create an actor on the server for each chunk (chunk actor)
- each chunk actor will receive a list of objects to render, i implemented this with a
FFastArraySerializerin the actor. once the list is received a dynamic ISM component is created for each type of mesh - this process repeats when the players move around the world, creating the necessary chunk actors
the entire thing relies on my understanding that the chunk actors created by the subsystem will correctly replicate to all clients, including the fast array. so if a chunk is modified (tree removed), this info first go to the subsystem, which will edit their version of the chunk actor and the fast array will replicate minimal data to update the clients
here is a video demonstrating how its working with a very small chunk size
my question is, is there a flaw or something wrong with my approach that i might be missing? am i reinventing something that already exists and would do the job way better?
Are you spawning and despawning replicated chunks as the players move around?
What is better for making simple shooter games in Low Poly? UE4 or 5?
i spawn the chunk actors only once, if you move between chunks i am reassigning the objects list and changing the actor position. if i end up with more actors than necessary they end up in a pool that can be reused when the players split in different directions
i did this because i read somewhere that spawning actors is very demanding and should be avoided if possible
now that you mentioned it, i didnt think about how i would implement dynamic objects yet
my proof of concept in the video is only for static meshes because i got worried about replicating millions of trees. i need to look into what i could do for actual separate actors (like a workbench or npcs)
i dont think i would be able to use a pool for that because they are all different classes
The only thing I will say is that since youâre moving the position, Iâm assuming the chunk actors are replicating movement. Also what it sounds like youâre doing is as the player moves around, youâre repopulating the fast array everytime the chunk is moved? (I assume youâre keeping the data that populates the chunk on disk or something similar), so it could hurt a bit if youâre essentially having to send the entire array back again everytime a chunk is loaded. You could also ditch the ISM for just using raw scene proxies but thatâs a whole different topic.
youâre repopulating the fast array everytime the chunk is moved?
yes, when you move the actor to a new chunk i need to change the position and re assign a complete different value to the array
Honestly before making assumptions I would definitely profile with insights, you can profile networking directly on there. Rather then a stranger on the internet telling you whatâs up without knowing your code đ
technically the same chunk actors doesnt go from chunk x to chunk y, it work more like this:
actor is created to render chunk 0,0
player moves away
actor is moved to pool (no position change, array is set to [])
the subsystem needs a new chunk
actor is changed to render chunk 1,1 (position change, array is set to a new big list)
yeah for sure, i was mostly wondering if i was reinventing the wheel and a solution already existed for my use case, im still new to unreal so theres a lot to learn
i am gonna search about raw scene proxies, i havent seen this mentioned yet
I think clearing and resending the array could hurt depending on how big it gets, but again. You wonât know (and neither will anyone else on here), if it is actually a factor to be worried about in your specific use. Only thou profiler knows all
yeah that might be the worst part of the solution, i am not sure how i could optimize it because the array is entirely different for each chunk
im gonna keep using it and if it starts lagging a log in the real map i will debug with the profiler
thanks for the comments 
There's also some default things in UE to consider like Replication Graph (and now Iris) if you feel like looking into them
i didnt know about the replication graph, i will add it on my list to read later 
i read about iris a few weeks ago but it sounded a bit experimental so im afraid to use it and run into issues i might not be able to fix myself
for client recorded demos (not server recorded), what's the best approach for properties with skipowner, and for things like certain unicast rpcs to the main player controller that don't make it to the demo recording player controller (server doesn't know about it)?
most skip owner stuff I want to make sure to record is normally set locally, then set on server
Hey all.
Timing question in regards to replication.
What might you suggest for a trap system, such as a swinging pendulum.
A simple like current anim time, that is inital only.
So, on inital replication the timing should match.
But, various factors would influence that.
Should I re-sync every couple seconds, or minutes?
I had thought about making this one instance, client driven, to feel more "correct"
Given its just a simple obstacle, and not some large fight that being able to god mode cheat in would affect much.
Can anyone help?
Seems, pretty obvious?
Server is setting the var "wrong" in this context.
ECS_Unoccupied is what calls HandlReload
But, your setting it to ECS_Reloading, which is used for Fire
Reload -> ServerReload -> CombatState = ECombatState::ECS_Reloading
But, it should be ECS_Unoccupied with the current setup.
If heâs asking for help with a problem, do you think that he would consider it obvious, and did stating that you found it obvious help?
Your right, it must not be obvious if no one else helped.
But, that is bad wording on my part.
I'm not used to helping in this discord.