All 3 of you are kind of saying something different , which furthers my confusion on the topic.
But thats what I believe, they should be independent, but ive noticed in testing that if a game is running at 30 , less time passes compared to running at 60. unless im not understanding how timelines are meant to be used in this context. im using a very simple float timeline - time in seconds - print string.
#multiplayer
1 messages · Page 274 of 1
I just worded mine all goofy. 😛
but, same 1 second should pass, but of course at faster or smaller increments. (That’s why delta time exists)
You’ll need to provide code, or info, cuz your doing it wrong, or miss-understanding.
understandable,this is the timer set up i use, and its just a time in seconds node to read in UI
That's a timeline component, it is not framerate independent. It gets updated on the game thread
@shy gust Just did a test for you
Cmd: t.maxfps 60
t.MaxFPS = "60"
Cmd: t.maxfps 0
t.MaxFPS = "0"
LogBlueprintUserMessages: [NewBlueprint_2] Server: Total Execution Time: 5.000018
Cmd: t.maxfps 30
t.MaxFPS = "30"
Cmd: t.maxfps 0
t.MaxFPS = "0"
LogBlueprintUserMessages: [NewBlueprint_2] Server: Total Execution Time: 5.00005
This is the difference
5 second timers
at 60 fps and 30 fps
Theres the BP for you as well
No joke.
Timelines are dependent of FPS?
I always thought they were super cursed delays/ timers or something.
i guess i should be using set timer by event instead then
ive been told those timeline components were independent , so it makes me wonder what timelines people are actually referring too.
ive noticed that after a few minutes theyll be pretty inaccurate, not as noticeable in a few seconds. but there could be other issues in my implementation, but my timer logic really is just this
Timelines are only good for doing weird interps. They shouldnt be used for complex things.
I certainly wouldnt use them for long periods
Running timelines for minutes just sounds like a bad idea.
Reject timelines - embrace FCTweens https://github.com/jdcook/fresh_cooked_tweens
gotcha, so would setting a timer by event for 1 second then adding 1 to a float be a more accurate method?
Just use tick at that rate?
Id trust that more than a timeline
Also whats this got to do with #multiplayer this should be in #blueprint no?
so then a delay that just adds 1 ever seconds.
?
Timers also tick on the game thread as an FYI
Just add the delta time to your time value.
Or, use the base engine handled time, if you simply just need a second on some UI.
Unless it some clock.
i see , I appreciate the insight, sorry I didnt mean to sideline the channel.
sidenote but the example here is crazy unsafe
there's like, probably no scenario where you'd do IsValid(this)
since it doesn't protect against dangling pointers
should probably be
FCTween::Play(
GetActorLocation(), GetActorLocation() + FVector(0, 0, 50),
[WeakThis = MakeWeakPtr(this)](FVector t)
{
if (WeakThis.IsValid())
{
WeakThis->SetActorLocation(t);
}
},
2.0f);
It would be interesting to see what the lambda is. Cause if that's not a weak lambda, then you still crash upon call I assume :D
In the original example I don't see anything that passes an object to test first.
my fixed one should work since it's a weak pointer
Yeah, capture UObject as ref is unsafe. In early development, Our project crash alot due to capture UObject in lamda.
so it would defo crash
That's why you use weak lambdas or pass in this as a weak pointer in the capture
Right.
Yes timelines are FPS dependent, they're just running tick internally the same as any actor component.
Timers also do this but the timer manager tries to account for the Fps as best as it can, but it's not true independence
Mover is currently trying to put in a solution for this by running on the game thread but ticking at a specific framerate causing it to be independent from regular game thread ticking
That's not Mover. That's NPP.
Mover is just using NPP.
And it's questionable how much effort Epic will put into supporting NPP.
i have a reload animation which is running on server and all clients but sometimes my server is not calling animnotifies for finished reloading during lag but my clients are calling it, is there anything i am missing overhere
is the server ticking the montages on the skeletal mesh?
what?
what ticking option is set on the skeletal mesh components on the server?
the skeletal mesh component of whatever plays the reload animation
always tick pose and refresh bones
if so then I assume it actually is skipping the anim notify call
you can just directly read the anim notify position from the anim asset and use a simple timer instead if you want
https://github.com/Vaei/LocoTips/wiki/Anim-Notifies an article on anim notifies
one thing you have to be careful about is if it can be cancelled or change speed etc
the timer would need to have the same behaviour i guess but cancelling one is trivial
can try making it branching point too I guess but its still a ticking time bomb of issues
any better option as also my server calling animnotifes two times but my montage is playing one time
read the article
the answer is: don't rely on anim notifies and make some simple timer instead
Hello. Does anyone know why increasing the max player amount isn't working? I changed the max players from the default of 16 to 20 in the game engine's ini file but it doesn't work, the game still only allows up to 16 connections. What am I doing wrong?
Hi everyone, I'm having trouble with the initial setup step to test my multiplayer game. I'm stuck in VS 2022. When I switch to the Development Server and then build, I see these messages in the Output Log. How can I fix this?
If you have access to C++, check the GameplaySession class. Iirc that handles this.
You want to show the actual output log and not the error list.
Also do you have a source engine build or did you download UE via the Launcher?
This is what I see in VS 2022's Output Log.
Build started at 11:18...
1>------ Build started: Project: Sito_OASI, Configuration: Development_Server x64 ------
1>Using bundled DotNet SDK version: 6.0.302
1>Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" Sito_OASIServer Win64 Development -Project="C:\Users\Computer\Desktop\Sito_OASI\Sito_OASI.uproject" -WaitMutex -FromMsBuild -architecture=x64
1>Log file: C:\Users\Computer\AppData\Local\UnrealBuildTool\Log.txt
1>Creating makefile for Sito_OASIServer (no existing makefile)
1>Total execution time: 0.46 seconds
1>Server targets are not currently supported from this engine distribution.
1>C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.MakeFile.Targets(44,5): error MSB3073: The command ""C:\Program Files\Epic Games\UE_5.4\Engine\Build\BatchFiles\Build.bat" Sito_OASIServer Win64 Development -Project="C:\Users\Computer\Desktop\Sito_OASI\Sito_OASI.uproject" -WaitMutex -FromMsBuild -architecture=x64" exited with code 6.
1>Done building project "Sito_OASI.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 11 up-to-date, 0 skipped ==========
========== Build completed at 11:18 and took 01,157 seconds ==========
If you're referring to the fact that I downloaded UE version 5.4.4 from the Epic Games Launcher. Yes, I did, but to get everything to boot, I'm doing it from VS 2022.
You can't build a dedicated server with the launcher engine
see:
1>Server targets are not currently supported from this engine distribution.
Okay, I tried following a tutorial online, and it showed me that the first step was to create a .cs file (Server and Client), then set it to Development Server and build it. But it gave me the errors I shared in the previous image.
yes I know what goes into building a dedicated server. and again, you can't do this from the launcher engine
"I tried following a tutorial online" and a vague description of a c# file we can't see doesn't help us
I'm sure it'll mention a source build somewhere
its fair to look stuff up but in order to help we need to see what you did and not a description of why you did it I guess
Ok, since as you say, I can't run it from the actual engine, I'm trying to go to Github to get the Unreal source code (as per the documentation they created), but the page tells me "Error 404"
...
yeah, because you have to link your github account
this is source engine 101 stuff
and I'm really curious what tutorial you're following
I connected my account following the steps on the Unreal website. Still, it gives me the error.
did you accept the email invitation
Page per Server:
https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-dedicated-servers-in-unreal-engine?utm_source=chatgpt.com
Youtube:
https://www.youtube.com/watch?v=Aj-CaWwSPJg&t=940s <- Now for simple Test
or
https://www.youtube.com/watch?v=DrkG3W8a_ls&t=2s
Building Dedicated Servers with Unreal Engine 5
00:00 Intro
00:49 Create New Project
02:34 Create Main Menu
08:12 Level Blueprint
10:03 Project Settings
11:26 Server and Client Build Targets
14:37 Packaging builds
16:24 Launching and Connecting to Local Server
Links:
Setting Up Dedicated Servers
https://docs.unrealengine.com/5.2/en-US/setting-...
In episode 17 of the UE5 game development series, we'll configure the project to build a dedicated server and standalone client. We'll show how to cook content for each of these configurations, as well as run them both in the debugger and from the command line. We'll then fix a bug that comes about when the client and server tick rates do not ma...
so yeah it did say it
and you have to be also logged into the github account you linked
and it's been a while so I'm not sure if you have to accept an invite on the GH side
Now I don't know why Gmail put it in Spam.... The mysteries of Gmail
Thanks anyway everyone for the help
Hi, i have a question; should I avoid using pointers in RPCs?
I’m still new to this, and it kind of scares me
why would it be scary?
it's not sent over the network as a memory address
you might want to show what you're doing/thinking
you really push through with incorrect method. Don't write code that don't work
so i just did a rpc on the player state
works great
well it works really well
exactly what i wanted, and there won't be alot of logon/offs
it's only meant for a group of people
Only use RPC for event based. I've said this dozens of times.
Many people new to networking use RPC for stateful things, ends with bugs on their end because RPC get dropped or players have yet join so obviously the RPC don't get run.
youtuber tend to do this and show that it "works"
until they don't
but I guess sometime, one has to actually experience the failure to accept that it's the wrong way to do it.
incrementing a replicated variable in a multicast don't make sense too.
what can fail with the rpc ?
i changed that lol
RPC set Hp to 5 at the start of the game. Then player 2 join 2 minutes later. Obviously the RPC never run so the HP is not set to 5 for the late joiners.
well
i don't need a state like this
I already paste a working example
i just need a event when they log off/on
nothing else, just log on/off
it's not really much of a state, because the cards are not premade
they are built each time
so i'm not toggling the state of a card
but rebuilding all the cards when someone logs on/off
Doesn't matters if they are pre-made or dynamically created
if the cards need to be retain the same values accross all machine
then that's a state.
Using Multicast = waiting for game to break.
and adding unncessary complication for something that surely just goonna fire back at you.
i don't see where it will break, but ig i'll find out lol
i'm used to finding out things like this, been programming since before the web was a real good informative source
but i understand your point
onrep > multicast
no, that's not my point
U use each of them where you need to use them.
One time event = RPC
stateful things = replicated variables
Broadcast hello world = RPC
ddealing cards = replicated variable
i mean it works so i'll use it untill it breaks
thanks for the information though
i'll keep this in mind
Honestly if it doesn't hurt performance i'm not concerned
unless it breaks, in which case i'll have to fix it lol
I was actually thinking the opposite of “it’s not sent over the network as a memory address,” which is why it sounded scary. If that’s not the case, that’s really good to know. But still, if this pointer points to an actor, wouldn’t that take up a lot of bandwidth?
what do you think it would contain? UObject references are typically networked as the path
I feel like I should only transfer primitive types (TArray, bytes, and others like that) in RPCs 😊
i write a lot of code that don't work, then i figure it out later lol
i'm just used to trial and error
Do you pass actors/pawns in RPCs?
I keep thinking in a dedicated server mindset :/
So I feel like I should only send primitive types.
I imagine the server just doing calculations for other players.
That’s why I don’t want to put something like a skeletal mesh pointer in an RPC.
Plus, that stuff would take a lot of bandwidth.
Honestly, I don’t even know how I should be thinking about this 😕
?
sorry for bad english :((
a USkeletalMesh reference will be sent down as a path to the asset
by default, it'll do a sync load if not already loaded by the client
there's a cvar to make it async
That makes perfect sense
what about the chat box ?
i use multicast
If you don't care about history, RPC is good for chat
right because the onrep fires when then the player joins
i'm not concerned about history at all
but i see if i wanted it to load when the player loads into level then onrep
If the chat box always present just create them at HUD begin play.
also what about the chat box specifically?
well i was wondering rpc or onrep of an array
this is broad, what part of the chat box specifically.
if you don't need to store chat history, then you can just RPC the msg.
ya thats what was mentioned
to create the widget, just create them locally at begin play.
ya thats what i did, it works fine
Hey, do you think this approach is “scalable enough for a prototype”? I’m going to dive deep into C++, but for now I just want to make a prototype that’ll let me test different variations/mechanics with my friends while doing the C++ course, I want to do it as painless as possible.
I’m using GameMode to track all the important variables/logic and handle match phase changes. Then I’m using blueprints with inputs that are sending these variables to GameState, and with a switch on an enum that afires multicast, or rep notifies, to call event dispatchers (like in the first screenshot, inside those rep notifies, there’s just a dispatcher call).
On my playercontroller or in widgets, I’m binding custom events to those dispatchers like in the second screen.
Seems fine
Just be sure to read up a bit, what ColdSummer was talking about re: RPC vs onrep.
For any persistent state (i.e. most gamestate) you should usually use a replicated var and onrep.
For one shot events, RPC is usually best.
im not following, how will the elapsed time be known to late joiners?
ElapsedTime = GetServerWorldTimeSeconds() - GameStartTime
The phase stuff should probably also be an OnRep. You also suffer from not having access to the previous value in BP OnReps, so might want to keep track of that locally. Can always be that the data is dropped or not sent and you skip a state on the client.
And how should I use that previous value? Compare the current one with the previous on the client every time? Then, if it’s different, override the current one on the client?
If you want your system to be robust by default I'd design around Repnotify as the core and just sprinkle in a few multicasts where it makes sense
almost anything you'd want to know on a client is state or can be derived from state
Hello, I have a character component which has an OnRep which accesses the player state of the said character to do stuff. It works fine, but if there's a hot joiner, the character with the component might get replicated before PS which makes it access none inside the OnRep. I thought about listening for PS replication from that component to do what I wanted to do inside the OnRep, but it's annoying. How do you guys usually go about this?
idk if it's legit, but i just do a delay and try again on fail
if it's a guaranteed to be valid thing it works
i just usually put a print string in there so i can see if it's infinite
I've been using "Do N" to make sure its not more than N times is similar scenario
that makes sense but this limits things, if its a guaranteed thing i just go for it
The only issue is that there might be multiple OnReps in the same component that want to do something that toggles it back and forth. It might happen that it wants to toggle, let's say, a bool to true, but PS is invalid, so it would set up a delay, but while the delay is ticking, it would receive an OnRep which wants to set it to false, and PS might be already replicated, so it'll set the bool to false, and then the delay would be over, and it would set it to true, effectively ruining the state.
One can obviously replicate the variable altogether, but some times there might be things that are more than just a variable
That's how you do it. You could also just set a timer to check every quarter second until the PS is valid and then cancel the timer when you finally get a valid reference.
Alright, so no easy way to go about it, thank you for confirming 🙌
its how i got everything to sync while testing
so when all four windows pop up
i synced everything so the order doesn't matter
lots of try
but i do that on what i believe is "guaranteed"
It's more about detecting gaps.
Imagine you have states like this:
0: StartCountdown -> Shows UI
1: EndCountdown -> Hides UI
2: StartMatch
And the client now gets stats 0, and the next one it gets due to network conditions is state 2.
At that point state 1 would be skipped, and the UI would remain visible.
If you have "PreviousState", you can detect the gap and go from 0 to 1 to 2 instead of from 0 directly to 2.
That is if you use an OnRep for this. An RPC isn't a good idea as the GamePhase property is the very definition of a "state" and should use a replicated variable + OnRep if you need a callback for the property having changed.
Imagine you are already at state 2 and someone gets a disconnect and reconnects. Or connects late. They will never get the StartMatch event again.
I typically do something like "UpdateCountdownDisplay()" and inside you just switch the current state and do what needs doing... if the state is 1 or 2 (in the example above) you hide the UI.
But with the OnRep, the client will call the OnRep_State with state 2 again, where previous state is probably an invalid one (might want to use enum value 0 for "invalid").
It's an example. I can probably find one in your final implementation that can break similarly.
It doesn't break when you write it in a way that makes no assumptions about prior data or passing through previous states
(it's a pattern I've used on multiple shipped titles, in multiple engines)
The only requirement is that the Update function is run whenever a dependency is changed... e.g. player state is replicated, CountdownEndTime changes, etc... which is generally pretty simple to do via delegates when necessary. If you're doing long running things like animated transitions it's a bit trickier.
Compare to current time.
If it started at 10 seconds, and current is 20.
Then 10 has passed.
If ends at 20, and current is 10
Then 10 seconds left.
I’m not sure if it’s what you meant, but yeah, I changed gamephase to rep notify and I’m just calling the “change phase” dispatcher with output. Now I can use simple logic in the widget like that, and it feels better for me ‘cause I don’t have to make it visible and collapsed separately, etc
That's roughly the idea. It might not be applicable in this case, but I'm not sure what the BP starts to look like if you add more dependencies though; for each one you'd need to trigger the same dispatcher.
Imagine you have another GameState or PlayerState variable "FooBar" that you need to reference when deciding to update visibility; ask yourself what it looks like to implement that into your BP, how easy is it to maintain, how easy is it to add more dependencies, etc...
In the case of a PlayerState dependency, you need to call your update function both when the existence of PlayerState changes and when the value being accessed on PlayerState changes.
In the case above, you've called the event "ChangePhase..."; you might be better off thinking of the event as "what does this event do" rather than "how was this event triggered". That way multiple places can trigger the same event without it feeling strange
So you might call your event "UpdateTimerVisibility()" instead, which currently only triggers when the Phase changes, but may also need to trigger in the future when something else changes
How would the quest/mission system work?
Like I've a level, linear mission but level is open to explore such as military base.
Currently, all player has an object/mission to fix generator and generator shows that there's a part missing to start/run it. To find it, players will search around the base.
Now the thing is, when player goes to evacuate at last. A player out of other will have to stay or etc based on mission and that objective will be shown to that player or like that and once he stayed, other escaped. A Cutscene trigger/objective updates and mission end.
IMO/POV, I'll make
MissionDataAsset which will have array objectives (ObjectiveClass containing logic for each objective such as fix generator, gather the intel etc).
Each MissionDataAsset is associated with gamemode (per level) and Mission Manager will be inside GameState that'll handle the mission progression and mission related stuff
Yop, sounds like a good start.
Hi, I have replication functions that trigger on outfit change. Since I’m using GetPawn there, everyone only sees the change on their own character. I’m confused - how could I make this more flexible?
void ACoopPlayerState::OnRep_HeadOutfitId()
{
ChangeOutfitPart(EOutfitType::HEAD, HeadOutfitId);
}
void ACoopPlayerState::OnRep_BodyOutfitId()
{
ChangeOutfitPart(EOutfitType::BODY, BodyOutfitId);
}
void ACoopPlayerState::ChangeOutfitPart(EOutfitType Type, int32 Id)
{
ACoopCharacter* CoopCharacter = Cast<ACoopCharacter>(GetPawn());
if (IsValid(CoopCharacter))
{
CoopCharacter->OnChangedOutfitPart(Type, Id);
}
}
is this happening on distinct playerstates that all share 1 pawn or all on one playerstate?
Sorry, I didn’t understand what you mean
Here is the section on character classes, that's all: https://paste.ofcode.org/35szYdxbcprzH6FDWtbGjrn
the question is if ChangeOutfitPart is called all on different objects or not
not sure how else to describe this
need to see who calls SetOutfitPart
I cannot tell what "Owner Character" actually is from a screenshot
you need to prove this is being called on distinct characters with logging or a debug watch window
there is only 1 owning player
this is OwnerCharacter
a widget ONLY exists on the local player
the owning player is the LOCAL player
can you try just logging what calls Set Outfit Part with a simple print string and showing which sides log which objects?
sure, let me a few secs
In case you want to see these
I think I wanted to see the log of playing, not 200kb of the entire log
I only marked [CLIENT] and [SERVER], the relevant ones
that is a 205kb text file, I don't know what you "marked"
I can see them though
looks like it's being called twice for each player
but that seems intentional
you did not specify how many players there are either, I have to figure this out without much context
it looks like OnRep_BodyOutfitId is being called on 2 different playerstates, which seems like what you would want?
with 1 listener player and 1 client player tested
also notice the
GetOutfitData - NOT found for Type: 1, Id: 2 (Cache has 0 items)
I just said I guessed the issue might be because of using GetPawn
and you don't ensure or log if GetPawn is invalid
which could be another issue
my advice would be to use the callbacks for when the playerstate sets the pawn or add some if you don't have any
so you can listen for when the pawn is set
When I talked to the AI, it told me the issue was that the datatable cache is only valid locally for each player. But isn’t that how it’s supposed to be?
not sure I am super concerned about what a chatbot told you? what do YOU think from what YOU can see from debugging?
is CacheOutfitDataTable called on all clients? do you log if it isn't cached? why isn't it called? what should call it?
for starters do not silently early out in functions like this. these failing should at least log an error
or cause an ensure
if they are supposed to work
if you have logs, you can see for yourself what failed
which is helpful in situations like this
Oh, I think this might be the problem:
void ACoopCharacter::BeginPlay()
{
Super::BeginPlay();
ACoopPlayerController* PC = Cast<ACoopPlayerController>(GetController());
if (IsValid(PC))
{
DormHUD = Cast<ACoopHUD>(PC->GetHUD());
CacheOutfitDataTable();
GetController will never work on simulated proxies (outside of really weird situations like if you created a controller locally... unlikely here)
Only the local player has a controller for themselves (on a client)
the server has all of the controllers
make sure you check out the resources in the pins, they help with learning about this stuff
Alright, I’ll try to find the issue using these logs. Thanks for taking the time 🙏
you should probably just move CacheOutfitDataTable(); to outside of that if statement
why does it care about the player controller?
hopefully that helps
thank you :))
Doing this was enough to fix the problem 😁
thank you 🙏
getOwner->getController is better for pawns
I must've missed the context
since I thought it was the conversation immediately above, which was on a character
Hello, is it possible to have multiple relevancy origins for a player? I need to make a CCTV that translates what it sees to other part of the map where the player is, but things around the CCTV which is pretty far away will be irrelevant to the player looking at the monitor
tony i would increase this value by alot
i think the default is 15000cm
(15000^2)
if you are replicating stuff and its not appearing on the client unless you get close this helps
I don't want to replicate everything else on the map though, only what's around the cctv and the player
is the map dynamic or fixed?
It's fixed
Looking at the IsNetRelevantFor callstack, it looks like I could make use of this
/** valid only during replication - information about the player(s) being replicated to
* (there could be more than one in the case of a splitscreen client)
*/
UPROPERTY()
TArray<struct FNetViewer> ReplicationViewers;
the NetDriver uses to call IsNetRelevantFor
if its fixed you shouldnt need to replicate anything should just be able to load it on the client and everything should be there
When player is far away from, let's say, a door, they won't see the door replicating anything, e.g. it opening or closing, as it's irrelevant. The door will be there, yes, but the player won't see it opening/closing
you might need to replicate your doors then
They are replicated, they aren't relevant to players that are far away
so make the doors always relevant with the increased distance
What's the purpose of relevancy then...?
to be able to adjust the network communication. you could use it to determine what is more important or how to efficiently communicate about networked game objects. really you need to adjust it so that your game works with the least bandwidth.
In the case of replicating all your doors its definitely okay
It's more than just doors. It was just an example. It might be other players, players dropping things on the floor, players interacting with other objects like doors. It would mean replicating the entire map to the player watching one single area through the CCTV
replicating everything dynamic
anything interactable
heres the thing if its out of range, and say you add a new player as your cctv that can be possessed, when you possess a new camera the objects will all take a second to load, which might kill immersion.
rather if you ensure everything is loaded (from the start) then theres a more seamless experience
I couldn't find any proper entry point for non-local players viewers, so had to hack it a little bit. Since it clears AWorldSettings::ReplicationViewers every frame before checking the IsNetRelevantFor, I had to take any virtual function which is called in-between the clear and checks. I went with APlayerController::SendClientAdjustment. This works, at least in the editor
void AMESS_PlayerController::SendClientAdjustment()
{
Super::SendClientAdjustment();
AWorldSettings* WorldSettings = GetWorldSettings();
for (TObjectPtr<AActor> AdditionalNetViewer : AdditionalNetViewers)
{
if (IsValid(AdditionalNetViewer))
{
FNetViewer NetViewer;
NetViewer.InViewer = AdditionalNetViewer;
WorldSettings->ReplicationViewers.Add(NetViewer);
}
}
}
Couldn't just add custom logic to IsNetRelevantFor? e.g. let actors know if they're near/within view of the CCTV and then return true if they are
Or set force net relevant for objects near/in view of your CCTVs via overlap, etc...
I would need to inherit actor with that custom logic, to then inherit that custom actor everywhere, and make sure not to forget that
True, but that seems worth it to me. I generally have a custom base actor for everything anyway
This could also work, but it's more complex compared to additional net viewers I came up with
Agree, but the override is a bit of a hack 😛
The CCTVs are monitors in the world based on the original description
Yes, they're a monitor. Originally I was changing the entire view, but now I want it to be on a monitor
I've a question, why if it's Client1 instance, then it is considered also server aka standalone? even when there is client1 and client2?
like if I run this node then it tells me Server: client1
Client: client1 (or whatever I have connected to standalone & client exec pins
Not sure I understand your miss-understanding?
Your saying playing in a server is also triggering standalone, or that your confused why standalone says server?
like, if i am running client1 in pie editor then client pin will never run at all
What mode are you running PIE in?
Yeah, what mode like they said.
Theres the 2 different modes.
One is a dedi server, where your a client.
The other is the local hosted server, where the player is the server.
i thought this would be client only and server would be in the bg
Hmm, ok.
What about where is that graph at?
Does it even get ran at all?
(aka, put a print before that switch, does it even get ran?)
yea it does, its from lyra blueprint utilities or smth like that
but its inside GameplayAbility
if i connect standalone then it works in client but idk why its like that
shouldnt it be client only
I'm not too aware of how gameplay ability stuff is setup.
It may not have valid world context, so it can't correctly check network mode?
(thats just a guess, someone more aware of gameplay abilities would know)
I would say double check on some basic begin play on a spawned actor.
Like the player pawn
If that has the issue, then something else is weird
tested on a character rn, beginplay executes the client pin twice and says Client 1: Hello
standalone doesnt get triggered at all
thats really weird
that x2 might be bc of the way pawn is setup to call beginplay but it works just fine in the pawn
Why would standalone get triggered in client mode?
so idk why it does this in the ga
was expecting same behavior as in GA but behavior was as expected
Yeah, GA may lack world context, thus can't correctly get network stuff.
Given the difference of behavior.
Or, perhaps how that specific one is used, lacks world context.
Since, can't GA's spawn actors, so they need world context sometimes
makes sense, thanks
Anybody have tutorial on how to make multiplayer match timer in blueprint ~~ not match countdown~~
just replicate the start time to clients once the game begins
clients can calculate the time since start themselves as long as they know when it began
I've been banging my head on my desk for an hour now...
What determines whether a variable will be replicated JIP?
I have 2 Actors:
ADoor and ALightSwitch
Both have a boolean, which uses push model to replicate. They're completely identical in code.
Changing the boolean on door will be reflected instantly on clients joining late, however doing the same on the light switch does not.
Any idea why?
UFUNCTION(BlueprintSetter, Category = "Light Switch")
void SetLightsOn(const bool LightsOn)
{
bLightsOn = LightsOn;
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, bLightsOn, this);
}
did you make sure both actors are replicated?
what does the DOREPLIFETIME look for each property?
- Yes
- Here's a snippet:
void ALightSwitch::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
FDoRepLifetimeParams Params;
Params.bIsPushBased = true;
DOREPLIFETIME_WITH_PARAMS_FAST(ALightSwitch, Lights, Params);
DOREPLIFETIME_WITH_PARAMS_FAST(ALightSwitch, bLightsOn, Params);
}
Changing it after the client has joined works, it's just JIP not replicating properly.
Adding a log to the OnRep_XXX() will:
- Print on the door if you open it before someone joins
- Not print on the light switch if you toggle it before someone joins
I've taken screenshots of the replication properties on each BP just to make sure and everything matches.
it could be dormant for some reason
Is that the bAlwaysRelevant?
no, relevancy controls whether or not an actor replicates at all to a client
dormancy controls whether or not property updates are sent to clients
Tried changing it but no matter what I set it to, the issue persists.
It seems to be due to the instance being set to true, and it being false by default in the class.
Is there a recommended approach to remedy this? I tried marking it as dirty in the BeginPlay but that didn't seem to do much.
so, the class default is false, and in the instance placed in your level its marked as true?
is it placed in your level in the editor or spawned at runtime?
if its already in the level i dont believe theres any replication occuring
Placed in level.
I figured marking it as dirty on beginplay on the server would update the net driver, but apparently not.
Admittedly my brain is exhausted 😅
with it already being true in the level, are you trying to replicate a false state? or that initial true?
Imagine this scenario:
- Playing, turn off light (that are on by default, as well as the boolean being
true) - Player 2 joins
- Lights should now update to be off (this never happens)
next to no info on this online lol
im wondering if push model disables replicating the state of that property to clients during the initial bunch? that would be incredibly dumb if true
You said the class default is false, but the instance is true? I wonder if it's just that when a client connects networking is seeing "bLightsOn == false == default, so don't send over network"
It does sound reasonable, however doing this on the door doesn't seem to prove this right.
I am so confused and defeated 
The door instance is also different from the default state?
Hmm, I need to double-check tomorrow actually. You could be right.
My brain is fried right now after staring at this for so long.
Thank you!
that would be such a silly bug if true
I'll give it a go in a few minutes actually, I know I can't sleep without trying.
All PushModel really does is say “don’t compare this property until I say so”. It’s really more of a server-side optimisations to avoid expensive property comparisons - the savings are minimal at best.
Worth noting though that all parameters are initially considered “dirty”, so it will send at least once (if it differs from the CDO’s default value)
If that's correct, that would mean since your instance value differs from the CDO by default, turning it "off" makes it match the default when the player connects, meaning it won't replicate I guess
CDO?
class default object
Cheers.
Yeah, then it does sound logical. I'll have to figure out a way around it at a later stage, I guess.
every time you make a c++ or bp class in unreal engine theres a constant version of it that acts as a template for instances to copy from
the savings are minimal at best.
Is that really true?
depends on use case
Objectively, no, since what plinyvic said applies
but no, every benchmark i've seen shows pretty decent performance improvements
If you have 10k replicated actors it's probably pretty good savings... if you have 10 replicated actors, less so
not as significant as some other networking optimization techniques, but push model basically requires 0 change to how you normally design classes
Programmatically it makes more sense to me to force values to update rather than letting the engine check so often.
However, I've apparently hit one of the limitations with it as well. I assume this is not an issue without PushModel.
well, you could always disable it and see if it still occurs
would help narrow down the issue
I'll give it a try, I guess. Gimme 2
Still an issue with normal replication.
I wonder how I'll work my way around this 😅
Just call on rep on begin play.
Its what I do.
With or without PushModel?
on rep wont change the fact the client has the wrong value
Did I miss-understand the issue?
I thought it was that default is false.
Current is false
On rep doesn't occur, so false isn't applied
Default is false
Set to true on instance
Disable it while running
Player joins late with JIP, doesn't see the new value
OnRep is just a callback when the new value replicates down
Spaghetti
Yeah, disable.
Which means false.
Which matches the default.
So, justy call on rep, to apply the false?
Or, do I just whole miss-understand?
The client doesn't get this new value
Because it assumes it's now the CDO of false, so shouldn't rep I guess?
I'm not sure if I'm lost, or who.
So, default is false
Its set to true.
Then, what is "disable it while running"
Does that mean setting it to false?
Correct
I don't think you're understanding the issue I'm facing.
[This](#multiplayer message) explains it
Imagine this:
CDO = false
BeginPlay: Set to true on server
While running: Disable it (set to false)
Client 2 joins: It is still on
Should it not be false for the joining client?
Did you turn off that client loads or whatever bool, so the clients version is 100% replication.
Rather then half replication, half map actor?
this?
Yeah
Changing it had no affect, tried on and off
My assumption was that regardless of default or not, the client would always receive the latest replicated state on JIP
Weird.
I had expected that would fix it. 😛
Did you change that bool in the defaults, or the instance?
I'm not sure which "works", or if both work.
I always just edit the defaults
im like 99% sure this is the intended result for replicated properties
Are you setting it to true in BeginPlay? That's not quite the same as setting the instance value
This was just for testing.
Gotcha
My plan is for my level designers to be able to put down the light switch and the connected lights, and set a default state on the instance, if that makes sense.
I mean, what you're dealing with is pretty indicitive of my UE experience over the last 5 years... /sigh
Sorry, long day and it's almost midnight so it's getting harder to express myself.
Sounds like the cursed fix should be.
Have a special bool for per instance
And, it just sets the actual bool on begin play.
No weird replication on the actual bool, and still an instance value
So an extra bool just for the instance?
sorry, are you positive the value isnt changing to whats intended and its not just the OnRep not getting called?
Yeah.
Its only used on begin play server side, so normal bool works like normal
It's not getting changed either. I checked the props panel.
Let me try.
ok im fairly sure now that setting NetLoadOnClient to false should fix this
Yeah, I'm pretty sure of that to.
But, they said they tried that, so. 😛
I guess we'll see what cursed 2nd bool does.
If still has issues, then that narrows it downm
Just to make sure, this is what you meant?
if (HasAuthority())
{
SetLightsOn(bDefaultLightsOn);
}
Yeah.
That suggests its something unrelated to replication then.
Put a log on every set of that lights var.
Cuz, I do something similar to what you just tried, and never had issues.
(I rarely ever use instance defaults)
Only one call:
Warning: ALightSwitch::SetLightsOn called on Server
And that's from BeginPlay()
Just to see.
Flip it.
Default true
Instance false
Issue flipped, or?
Cuz, yeah.
This ain't making any sense even more.
Flipping them works 
a this point just send code
I don't even
All the relevant code is above, I can resend it.
constructor?
void ALightSwitch::BeginPlay()
{
Super::BeginPlay();
if (Lights.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
}
if (HasAuthority())
{
SetLightsOn(bDefaultLightsOn);
}
}
UFUNCTION()
void SetLightsOn(const bool LightsOn)
{
LOG_NETROLE(__FUNCTION__, this)
bLightsOn = LightsOn;
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, bLightsOn, this);
// run on server as well
OnRep_LightsOn();
}
ALightSwitch::ALightSwitch()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
bReplicates = true;
}
UPROPERTY(ReplicatedUsing = OnRep_LightsOn, VisibleInstanceOnly, Category = "Light Switch")
bool bLightsOn = true;
UPROPERTY(EditInstanceOnly, Category = "Light Switch")
bool bDefaultLightsOn;
So... I can't reproduce the problem if I flip the booleans.
I guess I'll keep it like this for now, with the dirty fix. Thank you 😄
show your rep virtual
maybe Params.RepNotifyCondition = ELifetimeRepNotifyCondition::REPNOTIFY_Always; might help
This one?
#multiplayer message
@olive orchid Default value of the boolean is true. You are setting it to true. That won't trigger the OnRep. Change the RepNotifyCondition to "always" like Omnicide suggested and it will work. Or change the default value of bLightsOn to false.
I will try the Always route, thank you.
I do want to note that you are basically creating the "default value" twice here, which is your actual problem.
You basically have a variable bLightsOn, which can have a default value set already. The existence of bDefaultLightsOn is redundant.
I know, it was added for testing.
RIght okay.
I would suggest you simply remove bDefaultLightsOn and you replace this:
void ALightSwitch::BeginPlay()
{
Super::BeginPlay();
if (Lights.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
}
if (HasAuthority())
{
SetLightsOn(bDefaultLightsOn);
}
}
with this:
void ALightSwitch::BeginPlay()
{
Super::BeginPlay();
if (Lights.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
}
// Handles initial bLightsOn value to be applied.
OnRep_LightsOn();
}
Yeah, I am just used to different behavior since I come from a more low end background where I've done most of the logic myself, and to me logically it would always rep regardless of state, and I couldn't find any documentation stating otherwise until it was pointed out here. 😄
It does Rep
We tried this but the behavior remained.
But the Client doesn't call the Notify if the value is the same already.
There is a path for prediction in multiplayer after all
And if the client predict the value, there is no need to call the OnRep again.
That shouldn't happen tbh.
I thought so too.
You#d need to change bLightsOn to be editable in Blueprints of course.
I think the simplest would be the Always for me in this scenario. I am going to give it a try in a bit.
And you might want to put a HasBegunPlay() check into its OnRep.
True, I'm just trying to point out that you are potentially creating the issue by overcomplicating the setup (yes yes, 2 booleans isn't complicated, I know).
I usually have a setup like this:
// Header
UFUNCTION()
void OnRep_SomeVariable(const int32 PrevValue);
UPROPERTY(ReplicatedUsing = OnRep_SomeVariable, EditDefaultsOnly, Category = "Settings")
int32 SomeVariable = INDEX_NONE;
// Cpp
void ASomeClass::BeginPlay()
{
Super::BeginPlay();
// Initial setup on BeginPlay. Also covers default value.
OnRep_SomeVariable(INDEX_NONE);
}
void ASomeClass::OnRep_SomeVariable(const int32 PrevValue)
{
// Called too early by replication.
if (!HasActorBegunPlay())
{
return;
}
// Handle new SomeVariable value.
}
At least when I actively need this kind of setup.
There is an actual bug in the Engine if you have a scenario like this:
// Header
UPROPERTY(..., EditAnywhere, ...)
bool bSomeVariable = true;
// Cpp
void ASomeClass::BeginPlay()
{
Super::BeginPlay();
if (HasAuthority())
{
bSomeVariable = true;
}
}
- Place an instance of ASomeClass into your level. (It might be that this needs a Blueprint child class of ASomeClass to be created and placed into the level.)
- Set bSomeVariable to false on the instance.
- Press play.
Expected Result: OnRep_SomeVariable calls, because the Server sets the value to 'true' while the default value on the instance is 'false'.
Actual Result: OnRep_SomeVariable won't call, even though the default value on the instance is 'false' and BeginPlay sets it to 'true'. For whatever reason, UE compares the value initially against the "archetype" of the instance, where the value is 'true' by definition.
This is what I was trying to do initially when figuring out I had the problem.
Yeah I saw that years ago here on the server where someone had the issue with a BP for one of those car blocking poles that come out of the floor.
I'll give this a try right now.
The parameter for OnRep, can you always implement it like that? E.g. if I pass the boolean, will it always pass the old value by default or how does that work?
The boolean controlled if the pole was up or not and when they set the default to false but the class had it true, only to then set it back to true on BeginPlay, it wasn't going up for the Client.
Yeah, C++ OnReps can optionally pass you the old value, which is super handy if you have a system where you need to know if something is skipped.
E.g. void OnRep_CurrentState(const ESomeState OldState);
5 tutorials and no one mentioned this
I might actually be guilty here too. Lemme check.
Did I have to spot a typo in my compendium.......
Yeah I'm also not mentioning it. I should add that.
Man I really need to set up the automatic publish sh*t for this page. Docusaurus is great but not being able to edit it live on the spot is sh*te.
So... is this the correct approach?
void ALightSwitch::BeginPlay()
{
Super::BeginPlay();
if (Lights.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
}
OnRep_LightsOn(bLightsOn);
}
void ALightSwitch::OnRep_LightsOn(bool OldValue)
{
if (!HasActorBegunPlay())
{
return;
}
// logic...
}
UPROPERTY(ReplicatedUsing = OnRep_LightsOn, VisibleInstanceOnly, Category = "Light Switch")
bool bLightsOn;
UFUNCTION()
void OnRep_LightsOn(bool OldValue);
Yeah I butchered that somehow
Gotta change the VisibleInstanceOnly around
Yeah, was just gonna say that. Not specifying the default of bLightsOn doesn't actually make it "nothing", so you can just set it to false at that point in C++.
But yeah, that should be fine.
So, if I wanted to change this to true on an instance in the editor, would I not need EditInstance?
Yes you do.
The idea behind the HasBegunPlay part is that BeginPlay isn't really a fixed point in an Actors lifecycle, yet some things rely on the Actor having begun play. The initial "bunch" that replicates with the Actor can, however, trigger OnReps before BeginPlay calls. By calling it by hand on BeginPlay and by early returning if the Actor hasn't begun play yet, you also capture that problem as an added bonus.
I wouldn't be able to list you what stuff fails if you are trying it before BeginPlay, however, as Epic made sure this just silently fails and f*cks up your day.
Maybe I'm being obtuse but this doesn't resolve the problem.
I set it to true in the editor now, join as host. Turn off the lights (it's now false)
Join as client, lights are still on BUT the OnRep ran and logged:
ALightSwitch::OnRep_LightsOn called on Client
Can you print the value inside the OnRep?
Sure
In theory, if the Client joined after bLightsOn got set to false, that value should be part of the initial data that is replicated. The only thing I can imagine is that having NetLoadOnClient active on the LightSwitch causes the Client to load it in with the wrong value.
3rd arrow is client joining
Yeah, can you disable NetLoadOnClient for that LightSwitch please.
Wizard 
NetLoadOnClient means the Client loads the Actor from Disc when the map is loaded. That will load true initially. Beats me why the false never makes it to the Client.
GetDebugStringForWorld is useful for stuff like this
Disabling it will treat the LightSwitch as a runtime spawned Actor that replicates down to the Client and spawns then.
I had that issue with looted chests in The Ascent.
I mean it being loaded from disk is fine, it's still stably named and can replicate things
they would just need to call the onrep manually, right?
They are.
Should I've tried the override for the "NetReady" or whatever it is
Yeah, not sure if this is maybe just a PIE thing, cause it joins in the middle of everything.
PIE?
play in editor
Play in Editor
Ah
You could try the late join feature to see if that also happens in a more natural flow.
I am doing JIP right now, if that's what you mean?
I add the client later, manually with this. Is that not the same?
this is referred to as "join in progress" in some circles edit: time for bed, they literally said JIP in the message lol
Ok, good. Sorry, trying to learn and it's a lot to take in 
Yeah, JIP apparently. Am I getting old?
Yeah, I am used to the old ARMA term "JIP"
HOT JOIN
we call it JIP, RIP and DIP
r being rejoining if you support a persistent state from the first join
Well, I've gotten some insight in the problem now. Fortunately not a lot of the actors are static on the map... I've just got to figure out how I want to deal with this architecturally.
I appreciate your time and effort, a lot.
I would probably be able to figure out why it doesn't just work with net loaded actors, but I don't really have the time atm.
I need a break for a day or two 
And I wouldn't be able to fix it either, so yeah.
yeah I admit 99% of the time I deal with runtime created actors
I cannot recall the last time I have dealt with replicated data in a stable named level actor
besides just like, pointing to it
it makes sense to have stuff like a button you can push or that light just kinda there... I'm susprised this is so wacky to do out of the box
Yeah... 😓
probably my longest-standing issue with unreal netcode: how can we tell when objects were omitted from a broadcast due to bandwidth reasons?
I'm getting close to the point where I might start adding events to the engine network tracing or something because it's insane to me how you have no way of telling wtf is going on
Basically you just kind of... visually look to see if things are moving oddly
there isn't really like a strong indicator of "we are capping on bandwidth!! omg!!" I am aware of
of course capping on bandwidth is not an ERROR per se, the idea is you have a rate and you hit it
but to me if an object starts to get skipped from a send in a way that goes to like sub 50% of their net update rate it seems like I would want to see when that occurs
you can measure each packet in extreme detail, but you can't really see WHY a packet was the last one or what was skipped!
Apply root motion source from GAS sometime cause net correction. Any idea to solve it. 
- Ensure Client has a valid Prediction Window.
- Any Latent Node breaks the Prediction Window and needs a new NetWaitSync call.
- This also needs Server Moves to be flushed once more, which GAS does by itself for the initial Activate Ability call, but needs to be re-done if you delay the RMS by some latent node.
- Ensure Client and Server 100% agree on the same values that are passed into the RMS. Differences in starting location etc. can cause differences in end location.
it drives me nuts that this is even an issue
there should at least be a toggle to make the actor server only
I thought that's what NetLoadOnClient does but I legitimately couldn't tell you what that does now
IIRC, if you set bNetLoadOnClient = false on an actor in the map, and it's replicated, the client will "spawn" it from replication as if you'd spawned it manually.
that's also what I believe which is why I'm so confused how that didn't fix the issue @silent @olive orchid was having
fuck
sorry
Lol no worries. It's good info 
if it's not replicated yeah it's server only
if it's replicated and false it should basically spawn the actor on clients like any other runtime actor
Is there a recommended way that someone would have to make it so an AI controller takes over a character when a player isn't controlling the character?
This is our current multiplayer set up
How could I go about setting up an AI player to go along with this set up? Would it be best to create an Identical but separate AI player to spawn in only if there isn't a controller connected? Or can I just add the AI controls to the player character as is?
anyone know why an animation would not be applying root motion on the client only?
Hey I’m making a spectator mode using Set View Target. It works for left/right, but not up/down. I’m using the first-person template, any idea why that might be? When Im printing Pitch from "GetControlRotation" it looks good
Up/down?
Are you saying the spectated player looking up/down isn't visible to the spectator?
is it safe to using SetTimerForNextTick() to show the character information in the hud such as health? it is hard to know which time fully initalised the character, character stat infromation which is attacted to the character and HUD in both server and client.
hard to say anything about your timer with no information on what it does or why it has wait on something
"character stat infromation"??
is is a separate object in the actor? a property? another actor?
Character stat is separated as the UObject, but attached to the component the character has.
how about an if statement
each of the different things calls CheckInitialization
which just... checks for those things being present
this is how init states work in modular gameplay
I don't see why the stat can't just report itself showing up to the owner or something
delaying it by 1 frame would only be meaningful if you already knew the object was 100% doing something already but just needs 1 tick to start
delaying just because you THINK it will show up soon is a bad practice... but might work if you don't care about it breaking occasionally
"HUD in both server and client" is also not meaningful for multiplayer
the HUD is a local thing... you are not replicating the hud object
unless you just mean that it's FOR the hud
ah you right in the hud
cause I miss out Hud isn't replicated, but it means HUD in the client player and server player (it runs in the listen server, still HUD is remain in the local though)
there might be some cursed thing that can replicate properties on a hud for all I know but that would definitely be unorthodox
hud actors are spawned locally, so yeah no replication
wdym about cursed thing?
they are also extremely legacy things, but honestly still useful especially for widget management
also from my experience I would say my ideal for the player being "ready" is a lot more than just "it is here" unless you want
- character and player state present
- playerstate is ACTUALLY AWARE and has the current playerstate set as its "get playerstate" and vice-versa
Just beacuse the playerstate and pawn are present does not mean they are mutually set on each one. They should also be AWARE of one anotyher unless you want subtle issues where GetPawn randomly doesn't do anything despite both having begun play
Beginplay != set in places you would expect to obtain the object
which in this case generally occurs right after they begin play which is actually a situation where a 1 frame delay would help if you can observe in the engine code it's going to assign it soon (better to just have some delegate that fires after each one I guess)
I'm sure someone is thinking "maybe you shouldn't rely on GetPawn from the playerstate"... hmm yeah let me just fix the 200 places that do that lol
Most of my UI leverages something like this to determine whether common actors are "ready" and accessible
https://github.com/TheJamsh/UnrealSnippets/tree/main/Code/Network Event Subsystem
Gets annoying writing the same event-binding boilerplate in every widget class you create
it's nice to have a sort of boilerplate BindOrCall thing
where you either call immediately if X thing is already present or it calls the delegate later once it appears
yeah it's kinda universally useful especially when you can't control object init order
I tried to templatize it recently but I can't really think of a nice setup that would not just make it more confusing for users
I have one hellish function that is like 6 chained delegates together to make damn sure that ~4 objects are present before doing anything
has anyone tried using AnimNotifyState in multiplayer where, at Notify Begin/End, you send a gameplay event to the actor? The idea is that a gameplay ability is waiting on that event, and when it receives the tag, it executes its logic.
My problem is that I put a debug print on Event Received and noticed that on the client it prints multiple times, as if the event is being triggered too many times. I even made my own AnimNotifyState class and routed the gameplay event through a server RPC so the event is only sent from the server, but the client still prints multiple times.
Is AnimNotifyState just not reliable for multiplayer? Because when I do the same thing with a regular AnimNotify, everything works fine: the client receives the tag, and the debug prints only once per notify.
Yeah, turning left right and location is visible correctly, but up and down rotation of camera is ignored. I thought it might be something with replication
It probably is. If the Camera uses ControlRotation, then you will lack the Pitch. ControlRotation isn't replicated. The left/right comes from the Actor itself rotating.
Yeah, thats what I thought, but I have no clue how to fix this. Do you have any idea, that wouldnt require messing with replication system in c++?
if you use APawn's GetBaseAimRotation() function, it should take RemoteViewPitch into account when being called on a client
though i dont remember if theres extra steps to make the server replicate RemoteViewPitch
Hi all, I'm building a project on top of GAS, one of the conceptual problems I find myself running into again and again is how to provide instantaneous feedback on client for actions that are ultimately server-authoritative. So for example, dealing damage to an enemy and instantly seeing their health bar go down and a flinch reaction play without having to wait for network delay both ways.
I was wondering if Unreal has anything ootb to help with this kind of scenario since I'd imagine it comes up a lot in multiplayer game dev.
While not knowing much about GAS.
Isn't this the entire idea of client prediction?
Client legit just does it too, and when server does it, any variables are replicated to there correct value (aka health in this case)
right, just wondering if GAS has an implementation of client prediction for its gameplay effects/cues systems.
maybe I'll ask in GAS channel
As far as I understand it does come with client prediction (GAS)
But, yeah GAS channel is probably gonna be better
You shouldn't do damage for client prediction
Because players will feel cheated when the see the health drop and then go back up because the server corrected it.
Players feel cheated, even with the client prediction of blood splatter and stuff. lmao
I see rage about it like every day
how often are client predictions actually wrong though? my gut sense was that it's pretty rare for a correction like that to actually happen
Could be wrong, or just different.
my intuition says better to be immediately responsive and get it wrong 1% of the time rather than wait for network delay 100% of the time?
but idk I'm not a networking engineer, idk what the industry standard solution for something like this is
FX are mostly predicted
important stuff like headshot hitmarker can be server authoritative
in GAS you can use predicted abilities
when the client asks to run it, it starts on the client, and the server also runs it in parallel
clients get instant feedback and the server runs it to validate it
typically things like damage you don't want to predict
predictions can be wrong a lot depending on what triggers them
if you're raytracing a bullet on both client and server, good chance it doesn't perfectly line up
imagine getting a headshot in counterstrike on your client but missed in the server
I'm surprised it's not normal to predict damage... running my almost brand-new project with network emulation on and net settings set to average, the delay between hitting an enemy and getting the hit reaction is very palpable and it feels terrible
Its normal to predict the effects of damage.
But not the "damage"
oh I see... interesting.
You see blood fly out, and some do predict the flinch animation.
But, never seen any predit the stat going down
interesting
Especially since, some code (I know base UE, and MAYBE GAS?)
Gate damage behind authority, so you need to go through extra/ special hoops to actually affect the HP.
Just so many factors, especially with a complex game.
Does client even know of some of the metrics that affects the damage, or what if the damage is random?
I think that the client would probably have a pretty good sense of all the metrics that would determine the damage dealt, but if it's weird to predict damage then I probably won't go down that route
what I'm wondering if I can do is predict the health bar changes at all, maybe making use of the inherent delay in layered health bars to make wrong predictions / corrections a little less jarring
Depends on the game.
client has no reason to know about the server value of maybe some boss rage, or some inate boss damage decrease perhaps.
It very much depends on the game.
I would assume it probably applies to MMO's a lot more, cuz you'd have to save as much network as you can
interesting
my gut tells me that all the different vectors of immediate visceral feedback for dealing damage are some of the most important things to be instantaneously responsive when you hit an enemy to make the game feel good, and I felt like seeing the health bar start to chunk down or highlight the portion of it that's about to deplete was part of that
but if that's not the industry standard then I'm probably not gonna try to invent some new networking system to make it work that way
I appreciate the insight! 
one other question I had - all my character classes get a ranged attack, and for the petmaster character their ranged attack is basically to send their pet to dash at the target and damage them, essentially like a living projectile. similarly to the previous question, I want the pet to leap immediately so that it feels responsive, like firing a gun
I'm wondering if it makes more sense for this pet to be a server-controlled AI, or be an autonomous proxy more like the player character that can predict its movement on client side
To me.
Since this sounds like a unique case.
I might spend a bit of extra time.
and, have the attack make the actual pet invisible, then spawn a predicted projectile that looks like the pet and all that jaz.
Shares code with the other characters, and the pet doesn't need weird projectile type collision or something.
yeah that general approach makes sense... I had been looking into something like it but wasn't sure if it was too hacky. I think the biggest headache I had was trying to align the positions when switching between the client and server version
I do a similar very cursed thing, when I wanted to implement casting magic spells.
My weapons just shoot a like 10,000 speed projectile.
No reason to re-make the weapon, just to be a line trace.
Sure, spawning a whole projectile that then gets destroyed in like 1 frame might be a bit much to some people.
But, it works, and doesn't have issues. 😛
depending on relevancy and where your ability component lives, certain clients might not have access to the attributes of another player
ehhh high speed physics objects have a lot of issues compared to a simple linetrace
Well, it works well enough thankfully. 😛
and thats all that matters
yeah, re: this ... how would I do predictive hit reactions if the magnitude of the hit reaction can be modulated by various effects?
like if a boss is in a rage mode that negates hit reactions or something
you can still potentially calculate damage locally for use in cosmetic effects
the boss's ability component would need to be relevant to the client
thats probably the case unless you've meddled with it
client and server should calculate identical values
at least good enough for cosmetics
hmm... if hit reactions can knock back an enemy and interrupt their current state though, i'm not even sure they can be thought of as cosmetic...
that's what I have right now and it literally looks terrible with average net settings, I struggle to believe that this is standard for multiplayer games
if your projectile isn't a full-fat object then it totally makes sense.
If it's a full object then pool them.
Shooters nowadays are typically "favor the shooter" in matters of latency, and I wouldn't be surprised if many of them just used clientside hit detection with server sanity checks
what is "average" for you?
our game is pve so there's more reason to do that, just wondering if this philosophy is easily supported by GAS
it's unreal's average net settings profile, I think it's like 50ms ping but I have to double check
you could predictively move the model of the enemy on the client
I 1000% see that in the Rainbow Six Siege cheating videos I see. 😛
and, they don't have very sane server checks. 😛
reconciling what happened when you have 3+ different versions of reality is very very difficult
siege also has irredeemable net code
At a given time, all clients and the server see different things. And it's not just that the clients see the same things later, the game gets into different states on different machines if you have prediction. That's the core of the problem.
So it's a tradeoff. You need to decide if you want to allow shooting a thing on your screen and nothing happening, or being shot on your screen when you're sure you were around a corner. Can't have it both ways.
our game is PvE so I'm definitely happy to be on the side of favor the client
just trying to figure out how to make that GAS compliant
reconciling what happened when you have 3+ different versions of reality is very very difficult
More so in Unreal than say, Source engine. The lack of fixed tick and snapshot based networking massively increases the difficulty
Maybe UE emulation is going super crazy with it?
I play ARK, with it doing like a billion million things, on like 100 ping, and you barely see issues.
That be damage, items, moving, etc
Takes like 200 ping to start to feel it.
they also definitely predict a lot
Not saying they don't predict
Is this no prediction at all?
Or, does it have the hit anim prediction?
no prediction at all. the little temp hit fx happens immediately cause it's a cue
That looks like no prediction except for the little gold stars VFX on the hit location
is this the sort of thing that we could use prediction for? cause it's an entire state change, it's not just cosmetic
seperate the change of state and the cosmetic so that the client can safely apply the cosmetic
but like if the enemy is mid-attack and I flinch them out of it, how am I supposed to only play the cosmetic half of that?
Just play the anim?
^
right but that would interrupt the attack and potentially spare the player from getting hit
Different parts are easier/harder. For the health bar, it's pretty typical to draw the damage you just did (which would be predicted) in white/yellow, and then have it disappear after a short delay. The actual knockback might be hard to predict and could end up popping, though you could split that into an additive flinch on the client and leave the knockback on the server
no because its purely cosmetic
the attack is still occuring on the server
though ideally the player's attack goes through, changes the state on the server, and it lines up exactly with the client
oh, I see what you mean
don't use Everyone
because you're pretty much adding 240ms of latency here (RTT)
takes 120 ms to go from server to client, and vice versa
ah, I figured I might be doing something wrong for emulation
what should I be using instead?
/ I'm still a little concerned about this problem regardless
simulating just client lag is probably a fair test
or just half the values currently in there
regardless some cosmetic prediction on the client will help
GAS is pretty much designed around that
It's still a fundamental reality of prediction
If you have clientside prediction you by definition have different views of the world on all clients. The hard part is hiding that
Oh I'm aware... the last game I was on added fixed tick to our engine (UE 4.27) for just that purpose, but it was a huge undertaking. It's just that snapshots make it MUCH easier, and fixed tick makes snapshots much easier. I'm surprised they're not really there in UE at all, outside of something like Snapnet.
there was an attempt to add a generalized prediction system
i believe it used a fixed tick kinda thing
rest in peace NPP
deprecated?
ehhhh more like, never finished
don't remember if they're still working on it but it wasn't looking good last I checked
Yeah, I see it here in the 5.6 docs
i believe the main dev working on it left the company
F
EPIC
Clearly we just gotta set a timer for/ on tick, to 0.01 seconds.
Fixed tick done. 😛
Note that during rollback, all fixed rate instances are rolled back and resimulated as a global operation.
Well that could get expensive..
I mean yeah, but some predictions matter less than others. Like, if your weapon recoil vector mispredicts but doesn't have any side effects/dependencies on movement (and visa versa), it's pretty painful and expensive to resimulate all of the movement code
if movement state isnt dependent on recoil it wouldnt resim
It sounds like it would from the documents... unless "all" doesn't mean all in the quote above
Yeah, definitely sounds like all:
A RollbackFrame is identified depending on
whichever was the earliest frame among all instances that requested a rollback, and then ALL fixed rate
simulation instances are rolled back to that frame, and stepped forward in the correct
ENetworkPredictionSortPriority until we are back to the predicted timeline.
I use GMC (general movement component) as a plugin for movement, and it permits doing stuff like shooting and all inside the move frames
However you can do it in "AncillaryTick" which is after movement updates and isn't affected by those
I like it since you pretty much sync up movement and shooting on client prediction & server validation
You can do it with the CMC but it's a lot harder IMO
Ouch.. $599 for that component?
Seems cool, but maybe a bit steep for a hobby project 🙂
incredibly cheap compared to making it yourself
True
My game project uses a tilemap plugin I'm developing, and It'd take me like $5k worth of time to redo this, even knowing exactly what I want to do.
I'm not going to bother selling it, I'll just slap it on Github.
per seat!
I think a big detriment of marketplaces like Fab and the Unity store, is they create the perception in regular peoples minds that writing code is meant to be cheap.
When in reality, its extremely expensive.
Especially good code.
You could probably just generalize that more and say "systems" instead of just code.
Its complex, time consuming and expensive to develop good systems.
For me it's a combo of things; 1) Overkill; I don't doubt that GMC is worth every penny, it's just more than I need (not doing competitive/PvP), but I still like to work with solid, future-proof systems. 2) No evaluations; many plugins are of unknown quality until you download them and look under the hood, so the more expensive the plugin the bigger the risk. I've seen a few plugins that were quite expensive ($350+) that have demos, and the demo instantly convinced me that it was NOT well made... but it's still $350 with a 4.8+ rating.
Yeah not saying to jump onboard the GMC ship
But it's an example of how you could do it
I have a large array that I need to replicate to clients when they join. I'm going to batch it and call a run-on-owning-client rpc with a delay in between to slowly replicate it out to that client, but I'm unsure how to call the roc rpc on the specific client that connects? I only have access to blueprints.
Never done anything like passing a large array so unsure what's a proper workflow. I personally don't think using RPC to sync variable is a good idea.
But that aside, server have access to every players in the game. One of the event you can hook up is OnPostLogin, that will give you the joining player on server side.
A large array of what data type?
normally large array are handled with FastArray
it should be good enough for things like inventories
It's a struct array of collated data from actors in the world. About 30k entries.
Any reason why said actors can't replicate data down themselves?
But yeah what ColdSummer said, use PostLogin, it's available to blueprints
Several reasons.... Primarily most of the time most of them are not loaded on the client.
Why not let them send their data when they load on the client?
Because the client needs a small amount of data for all actors in the world, including those that are not currently loaded on that client.
Hi I followed this tutorial (and many others) but they never work. Are the tutorials wrong? The issue i'm having is that newly joining clients aren't seeing the other player's info (only their own), but the server/host correctly sees everything properly https://www.youtube.com/watch?v=DQziq6oA6qA
🛖 Check out my advanced Building System:
🪚 https://www.fab.com/listings/e4d59e7c-cb75-408f-86c0-c69f72357c83
How a player can determine an own player name and how to replicate name tags so they load up correctly when players are joinig a server.
🔷💬Join my Discord Server: https://discord.com/invite/eX3p5q6
Basic Advanced Session (...
I skipped through it a bit. Saw they check IsLocallyControlled on BeginPlay, closed it. Yes they are wrong. Probably even more throughout the rest of the video.
I think they also used an FText for the player name...
Damn, figured. Checked comments to no avail. Every video tutorial i've found on the subject is all the same, i run into the same problem everytime.
I personally run logic off of OnPostLogin so i ignored that BeginPlay part
youtube multiplayer bp tutorial is full of straight up wrong practices.
you best reading the pinned material over and over again. Then practice your self until you understand how replication work.
I've gotten many things working i'm just having a mental block with this particular thing i've been at it for a few days, constantly trying new things, researching new info, reading forums wikis, the refferundem thingy getting nowhere
I'm failing to comprehend it frankly
do you have access to C++?
I need to see it working once then work backwards I think
Of course
Names are stored locally on each client? like from a save file? or game instance?
in anycase, if the data (the name for example) is on client side.
OnAcknowledgePossession-> Send Server RPC with the player's name.
OnRep (Name) -> Set Widget text to the Name.
Yes, from locally from GameInstance or SaveFile, either way
Is this on PlayerController?
either way, all you have to do is send the data from client to the server
then server replicate that variable down to all clients
where client react to the new value with OnRep
What if that value is already set before they join? Because I feel like i'm doing this already
Have you went through the pinned materials?
how would the server know the name of the clients
One sec
You should read the pinned material and understand how to communicate between networks.
Like you set the name in your computer, then you join my game where I am the host.
Ok you have that set in your own G.I or where ever, but how would my computer knows that value?
You will have to send the data to me (the name), only then I can use that information to replicate the name to all other clients.
Okay so OnPostLogin (from gamemode) I fire an event down to the client to PlayerController
Here I get the Username from the computer then after Pawn is posessed, I fire an event on the server on the pawn to set the replicated variable with the username
Then on the Pawn on the RepNotfiy function, I update the widget info
But this has the issue
I think its because clients arent allowed to RPC to server from PlayerController maybe?
They can
Clients can call RPC on objects they owned. By default it would be the possesed character and their controller.
Do you see an immediate problem with my logic
let me rewrite my message
As GameMode
Event OnPostLogin > Cast to PlayerController > PlayerController Event "Very Epic" (Owning Client)
As PlayerController
Event "Very Epic" > Set Username (from Computer Info) > Wait Until Pawn Posession > Cast to Pawn > Pawn Event "SetUsername" (Server)
As Pawn
Function OnRepNotify > Get Widget from Widget > Cast to Widget Class > Set Widget Info
"Wait until Pawn posession" how exactly are you doing this?
waiting until its valid lol
I confirmed this works
With other events
so why not just use AcknowledgePossession? That's run on client and the pawn is guaranteed to be valid at that point.
Oh I will switch to it but i wasnt aware of it until you've told me here
So where is the replicated name are kept?
But yeah this has the problem of, newly joining clients not seeing other's usernames. Whereas the server client player host whatever you wanna call bro, can see everyone's names perfectly
Sounds like you never replicate the name then.
The replicated variable is on the pawn, where the RepNotify is and the widget (above character head)
show the codes
not by writing what you think you do.
just paste it here, bp or cpp.
Actually I lied, the replicated variable and function is on the player controller, in the onrep function it gets the pawn then calls a function to update the widget. Sorry ive been messing around with it so much i forgot i changed things
One sec
That's the problem already.
I think your task today is just to look at the pinned material. It really saves you time from guessing.
Client only know their own controller.
While server have everyone controller.
so if you have the name in the PC.
there's no way that Client 1 can know about Client 2 name or properties.
because Client 2 controller doesn't exist in Client 1.
Okay. I have read through a lot like a lot but i just seem to fail comprehension on this specific thing, like i said ive been at this for days trial and error, research, tutorials
I will keep going though
Yeah, personally take me like dozens of re-reading, practice, fail, until it click.
With the previous information about Unreal Engine's Server-Client architecture and the common classes we can divide those into four categories:
So now, you have to move the name else where. Either in player state or the pawn.
I would just have it on the player state since name normally doesn't interchange while pawn may be switched around (who knows what game you are making)
Lmao i saw this ages ago and I guess ive misremembered. In my mind the pawn was furthest away from server lol because i started thinking of it hierachy wise like GameMode > GameState > Controller > Player State > Pawn. Ok let me cook
Game mode only exist on server.
Game state is replicated, everyone has a copy.
Server has everyone's controller. Client only have their own local controller.
Player state is replicated, everyone has a copy.
Pawn is replicated, everyone has a copy.
Yeah and I knew this the entire time lol
Multiplayer cooking my brain
Ok hold up
is AcknowledgePossession exclusive to C++?
ok ill expose it to bp
just run Blueprint impelmentable event
don't want to touch engine's code
Override in your custom controller, call super then call BIE
Holy McMoly it's all working
Okay so I actually DID understand it the entire time I just forgor about the controller vs pawn thing lmao
Thanks for your help big time
I have a problem: Wanted to use the AdvancedSteamSessions plugin in my c++ UE5.6 project, but I have my own custom c++ GameInstance with a lot of variables defined in c++ which I need in the GameInstance in my RTS game. Hmm. Can I in c++ inherit from the plugin version AdvancedFriendsGameInstance some way, in c++/project?
Or should I go the heavy route of learing steam c++ stuff and make my own solution.. IDK. I've been procrastinating the Steam multiplayer stuff, I got multiplayer listen server working for my game though, so a lot of multiplayer stuff "working" locally in PIE.
@dark parcel If the user has access to C++, there is no need to send an RPC with the Player Name.
Managed to derrive my custom c++ gameinstance from the advancedsessionsfriendgameinstance, nevermind 🙂
@spiral ravine @dark parcel
When connecting to a Server, the Client will use a URL, which can have options provided via ?Key=Value.
By default, you should already see that one of those is ?Name=.... This is what's being used by UE to assign the PlayerName on the PlayerState.
You can see that in the log, e.g., LogNet: Browse: /Game/Maps/SomeMap?Name=Player.
Where does the name option get applied to the URL?
This is done within UPendingNetGame::NotifyControlMessage, where it calls ULocalPlayer::GetNickname and adds the option to the URL.
After that it sends a Login message to the Server, which ultimately ends up calling all the AGameModeBase::PreLogin/Login/PostLogin stuff.
ULocalPlayer::GetNickname first tries to grab a name for the specific platform and if that fails it will fall back to grabbing a name via the online backend.
So that results in your PC name by default, or in your Steam name if you are using that (or any other OSS).
ULocalPlayer::GetNickname is virtual, so you can inherit from ULocalPlayer and override the method, passing in whatever you want.
You could grab the UGameInstance here and take a name you stored there, or your Widgets where players can type in a name can already just set a custom property on your own ULocalPlayer class and you return that.
Bonus info: You can also override ULocalPlayer::GetGameLoginOptions to pass even more info to the Server.
Where does the Server grab the name option from the URL?
The Name keyword is being grabbed inside AGameModeBase::InitNewPlayer:
// Init player's name
FString InName = UGameplayStatics::ParseOption(Options, TEXT("Name")).Left(20);
if (InName.IsEmpty())
{
InName = FString::Printf(TEXT("%s%i"), *DefaultPlayerName.ToString(), NewPlayerController->PlayerState->GetPlayerId());
}
ChangeName(NewPlayerController, InName, false);
AGameModeBase::ChangeName will ultimately set the name on the APlayerState, where it's replicated.
This also offers APlayerState::OnRep_PlayerName, which you can override, as well as APlayerState::HandleWelcomeMessage.
--
This ensures that:
- The whole name/nickname/playername stuff stays within UEs framework.
- You don't need to create any new replicated properties.
- You don't need to send any additional RPCs.
Awesome, good to know.
Can someone explain me how does loadout work and persist across server and map?
If I load something on begin play, that's one for each player on the server and clients ?
So it would load four times ?
Begin play of the player
Would this be a good time for is locally controlled ?
you can store the information in player state. Player state data can "presist" on seamless travel.
From Menu level to server?
depends on your game?
maybe more helpful to say, where you obtain the data.
e.g RPG game where the data is stored in online data base will have different mean to obtain it with games that let user save locally and let them send that value to the game they joined
Depends on the Actor existing on everyone. An Actor that exists on everyone will call BeginPlay on everyone. If you have 2 of those, it calls twice on each game.
Given you ask about IsLocallyControlled, you are probably in a Pawn or Character. BeginPlay is too early for IsLocallyControlled in that case.
Soldier game, fps.
You have one loadout which can be configured by you, not 10 loadout like COD. Then you go into your selected map (host/join) then select the character (soldier character), and play the game with that loadout + equipment which are prefix for the level.
Such as NightVision and Flashlights are given basis on level, can be set inside loadout
Like authoritative that checks if the values are correct then proceed and if not, replace with correct values
could use a save game object and just load it and then RPC the data when successfully connected
But the game is listenserver so it's more likely locally saved and no authorative database
you could have the server RPC verify the loadout and if its invalid, send an RPC back to the client in which the client would update its save object.. even if its a listen server host, send the save object through the RPC function and verify it just as if its a client.. RPC functions will work as expected, they're just treated as local calls if its dealing with a local player
Curious about this and could just be me bad at Google.
But everything I find only shows FastArray is good for changes.
Wouldn’t the initial actor creation rep nuke the client?
I want to load something on the character only , is controller index 0 ?
if i use index 0 it won't load on everyone right ? but will it load multiple for every player ?
Index 0 is relative to where you call it.
Is it worth just making the swap to iris and learning that instead of going forward with the "legacy" replication system?
Depends on how far along into your project you are
Early and plan on working on it for a few years? Probably
Late and plan to release soon? Nah
Oh
FAs dont keep the order between clients and server
It reps a changed entry, added entry, removed entry. Doesnt matter any other stuff
You get a per-entry callback so you know what changed/got added/removed
You save up bandwith for arrays larger than hundreds
See https://notes.hzfishy.fr/Unreal-Engine/Networking/Types/Fast-Array for impl and how epic devs explains why it can be useful
I’m not curious of order.
But order is good to know
I was curious of initial replication.
Is that in chunks?
Like when the actor with the variable is replicated.
I know that.
I just wasn’t sure if FAs do that by default automatically.
I couldn’t find anything that said that, and GPT was un-helpful
FAs sends different data than a regular array, but data is sent like anything else
GPT is shit at UE so i wont expect anything good from it for more deep subjects like replication
Yeah.
I was just curious if it could find any info.
I got the answer I wanted/ needed from you thankfully.
But don’t think I am/ was asking correctly.
Np
Also whatch out that replicated objects inside the entries might replicate after the OnAdd event
It will trigger the OnChange event
The more I think about this.
The more it confuses me. 😛
cuz you guys suggest this type makes sense for inventories, and items.
But how does that work with replication?
Cuz, the clients would 24/7 know of all nearby items when not needed.
Since in the past I have asked about per player replication of a var and got told it’s not possible.
Or is FA special?
uh
Do you want clients to not know whats in the nearby chest until its opened ? For example
Correct.
I don’t.
Mh
Then you can have a rep condition
A custom one
And only rep to nearby actors
Never done it but its possible
I thought conditions were global?
For all players.
Thats probably still the case, iris wants to change that buts its beta in5.7
But each player has an unique actor channel
So maybe you can do it per player
You will have to get an answer from some more experienced networking devs
Yeah, no worries.
Cuz I have a working method.
But this talk of FA and apparently it already being used for inventories sounds a ton better
If you ever find the way to do this im interested
Yeah if I had some free time, I’d “TRY” to mess with it. lol
so if i call it in begin play on the server it won't make a copy ?
if i get index o and set a value
each one will just have there own seperate value right ?
and it won't replicate unless i specify that
I would never go near beginplay events if i need controller or pawns
Hi everyone,
I decided to create a multiplayer 1v1 card game in UE5.
Basically there will be 8 active slots (like in inscryption) and rest of the cards will be in player's deck.
So the issue is that physically player's are on the same position in the world, so they see the same image and logically I want every player to see his own cards on the bottom line and enemy's cards on the top and I don't really know how to make this game logic. I have 8 physical slots on the table where cards can be placed, I have the card data structure that contains all the data, I already have a working multiplayer lobby you can join, but I don't know how to display cards differently for each client and still be able work with them and add some features in the future.
Any suggestions how to implement this logic into my game? Many thanks!
so are the cards in the world ? or as a ui ?
In the world as I want to make complex logic with them later. Maybe I should spawn them only on the clients and have all the data inside a GM, but it sounds like a huge pain in the butt, so will be glad to see how others would create this logic
Think in terms of rules.
This is easy.
The rule is "The local player is in this place with this orientation, and the other player is opposite them"
just make sure the location of the pawn is NOT a replicated property and it'll just work.
The pawn should be replicated, but its movement should not be. The movement (position rather) is a function of whether or not they are the local player's pawn on a given machine.
Srry, but I don't get you. I don't care about the players pawn positions, they are just cameras, that are looking at the table from the same perspective. I care about card actors on the table and their positions should be different on the clients
Sure, just have all the positions be relative to some WhereThatPlayerIs transform, and have THAT transform depend on if that player is local or not
that transform is effectively their place at the table
on my screen, I'm at 0 facing X and you're at 100 facing -X
on your screen, I'm at 100 facing -X and you're at 0 facing X
On all screens, the local player is at 0 and the other guy is at 100 facing the opposite way
You shouldn't use GetPlayerXYZ(0) in most cases.
There is no need for it.
Just use an Event that ensures the pawn has a valid Controller.
Some more in-depth googling suggests a "replication graph", which as far as I know is very complex, and like source engine stuff.
and, my only experience with a "replication graph" in any capacity, is that it makes ARK modding very buggy at times. 😛
But, its at least a starting point.
We'll see if anyone sees this perhaps.
But, now that I think of it more.
Seems like everything is goofy?
Sure, we fixed the FA.
But, what about the replicated UObject?
Wouldn't those still replicate to everyone (I guess maybe the replication graph could also handle those?)
What is it you want to do? Have a chest that gives loot independently to each client?
No
Clients only know of items they access.
No reason to know of the like 1,000 stone in each box, when you only wanna access 1 box
But, default replication has no form of per client sending, just all or none (apart from the special owner case)
If the goal is to hide information per player basis then you can just use the controller class
e.g card games where client doesn't have the information of other client cards
so even if they hack the camera, they still won't know the cards other player hold.
How would that work, in a case like this.
In the context of a card game, that makes sense, cuz you only ever have 1 deck of cards, not 5,000 decks of cards.
In the context of MMO game, bunch of programmers will come with custom solution.
No MMORPG I know built with unreal usses unreal replication system as far as I know.
Ok.
Thats what it was seeming like.
But, just see peole being like yeah, just use FA's for inventories, and profit
you are not making mmo though?
most of us don't either
also people handle sending large data by batching.
you don't have to send 5000 entiries in a single frame
No, not an MMO.
But, the items are still an issue in this case.
I already have a working custom solution, but without any I guess "cool" UE5 tech. 😛
with FA only the delta got send
What would be the issue?
Essentially an MMO amount of items I guess is a good way to put it.
It'll probably be the most complex part of the game.
Being able to place like 50 boxes down, and each box has like 300 items in it.
So, without blocking FA, or item reps, that'd be 15,000 items just from standing near it.
Even like 10 boxes, thats still 3,000
I don't like reaching but if that's a requirement on my end, I would probably just ask for the data when I opened the box / chest.
and if a chest has 300 items, that sounds like a game design issue.
no one has the time of day to browse thousands of items.
Correct, and that is my current setup.
Ask for data on open.
But, just the talk of FA's, and replicated sub-objects made me wonder if/ how I can switch to those.
But, the idea of custom handling those, seems like it adds even more I guess "base" complexity to that method.
Meanwhile my current method is probably a similar amount of complexity, but spread out.
when making replicated doors that update to new players, doing 1 door , 2-3 even, is easy enough, have repnotify bool for the doors, but what if i have like 15-20 or maybe more , how would you go about keeping track of that many doors in 1 actor? i'd say a bool array, but then im looping through the all the doors to change the 1 door that was interacted with. i've thought of a custom struct array, but i still would see the same problem with it being that i'd be having to loop through all the door when updating just 1 door. is there a better approach or another method that might suit me here? i basically have a building where there's a lot of interior doors throughout it
you're gonna have to loop regardless i think
it's hardly an issue though
that or you do something like a bitfield, and find out which bit changed, using that as an index
but then again you're also having to loop through the bitfield, probably
Why can't the door be it's own actor? In which case, you probably just need to deal with relevancy, (door that are close to the player).
a door should almost definitely be an actor instead of a component
There is a world in which replicating a lot of state in the form of a NetBitArray is a really good idea. But I agree, that the doors should probably be their own actors.
unlesss these were changing EVERY frame
like if it's just 20 things flipping on and off occasionally them sending directly to the network object will be far cheaper than sending all of them to 1 thing with 19 extra bits of information
definitely situations where a bitarray makes sense but the order of 20 things we don't know the rate of change of seems overkill
I don't really understand "having to loop through all the door when updating just 1 door"
Why would you have to loop through all the doors ever here (except for like late joiners)? do they not declare when they are changed somehow?
Would have to loop through an array of bools to figure out which changed ig
ah they did mention that
not true unless the change cannot be tracked
the change should just say "hey manager thing, I changed to open"
Going with their original message which seemed like they wanted to replicate an array of bools
You'll still have to loop through the old/new values with that
ah I guess it would not be clear which ones were actually different
you'd kinda have to use the rep notify's previous state
pretty sure the change event is an array of indices, so still looping. In the end I doubt there's a solution that doesn't involve looping (seems like it's what they're trying to achieve) except just having one actor per door
making "network managers" or just "manager of thing" in general is a good idea imo but this seems unneeded for this scale
yeah
looping over only the changes though
notice how the text here says "all the door"
this means more than just the changed elements
yeah a little better (not like looping for this is going to break the performance budget anyway)
and if you have one building actor that contains hundreds of doors, you're gonna have other problems to handle than just loops heh
I assume their houses are made of mesh components and the doors are individual meshes.
once you get to that scale then I think going fancy might start to eclipse the cost of each one being a distinct network object
So the house actor keeps track of all door states
another thing with network objects is that they are kinda more overehead of they must be polled, which ironically is looping over them and bonking their properties
And this might even be a blueprint and no c++
can you not address the sub components? I forget
you can
Yeah they are stable
as long as they're stably named which default subobjects are anyway (or replicated, but considering this is a building blueprint it's probably the former)
of course if they are replicated you can but I wonder if a replicated actor with a defaultsubobject can be stable sent over
Yes
yea
where you target x subobject on x actor
They resolve via the house actor
you can even send over non replicated actors & their subobjects as long as they're stably named and exist on both sides
yeah of course, I guess my question is if the root actor describes the shape of the default components on both sides
which of course it does but idk if unreal Just Works ™ for that
Yeah aka almost every pre placed actor in levels

