#multiplayer
1 messages · Page 292 of 1
where velocity comes from the authoritative sim
(along with transform)
but this is incomplete, due to how my setup works. the general approach will probably still be the same, but i dont have a consistent coordinate system between clients because i bake parts of their motion into kepler equations.
because of that it currently only works when they're in the same "orbit" bubble
wouldnt mover solve this
Mover is just the movement simulation. The backend is the more important part
I'm using a Timeline to handle aim down sights logic for a project, which involves variable speeds for aiming- Issue is, when running the Timeline Playrate update function on server, it doesn't seem to get broadcasted back to client so the duration is flattened to 1.0 seconds and thus does nothing
Apparently making it reliable fixed it??
i wouldn't use timeline to be hones
also server really shouldnt be running it? why does server need to run the aim down sights timeline?
does server really have to zoom in?
Well the aim down sights does move the physical transform point from where the bullets come out of
I am noticing a few issues with it since it's tied to a boolean input so if you have a better alternative I'm happy to hear
instead of knowing about the entire timeline why can't they just see WHEN they started aiming and go from there?
if they both do the roughly the same thing on both sides from starting or stopping aiming the actually useful inforamtion is when it began
Ahhh I see what you're putting down...
also for a co-op game etc it might not even matter much aside from sim proxies (I add this caveat every time but this advice is still relevant for sim proxies at least partially)
I wanna avoid some visual delay of aiming on the client so doing it all in server doesn't feel right
then don't do it on the server that way
the client can just report they started aiming and shooting as a series of "commands" and the server can more or less accept them as long as they seem okay or even play them back
client prediction for shooting is more or less the standard for every fps game out there
how the server does things on their side or simulated proxies is a secondary problem... shooting should at least be partially predicted in almost every fps game
Even if it's they can predict shooting and aiming but not the final damage etc
Right... For one I think it's fair to predice some stuff like, if the server knows the player was aiming when they sent a shot, then it should spawn it from the aiming location and whatnot
Also tested my implementation of replicted camera pitch under high ping, and even with packet losses at 10% it's decently reliable
Only issue is moving the camera too much seems to cause issues and stuttering at high intensity scenarios
@nova wasp Sadly I think I will need a more detailed explanation here. Not exactly in a great spot...
so instead just have them send where they are aiming I guess
why introduce randonmness from the server and replication rtt here
needing to replicate the transform here is the issue at all
that is a tremendous amount of information to send instead of just
- which weapon is equipped
- where you are aiming
- if it is aiming or not
if that's just for simulated proxies, sure
remember: our goal is to worry about information
the actual "instructions" to get a similar result
replicating random arbitrary things is good if you can't easily describe their states with other more simple things
but for something this simple it does not make sense to me
unless they can really like, move the gun around in 1000 different positions that can't be described in a simple way
Okay then so run the function in client and send over the data to server then yeah?
depends on what "the data" is
void ADulceWeaponActor::ShootProjectile()
{
// Set SpawnParameters for the projectile we're shooting.
FActorSpawnParameters SpawnParameters;
SpawnParameters.Owner = Owner;
SpawnParameters.Instigator = GetInstigator();
FVector TargetLoc;
FTransform OriginTransform;
// Run this only if the weapon is owned by a player (So it shoots where they face rather than a predefined point)
if (bIsPlayerOwned)
{
// Establish parameters for the line trace.
APlayableClass* PlayerPawn = Cast<APlayableClass>(GetInstigator());
FVector Start = PlayerPawn->Camera->GetComponentLocation();
FVector End = Start + PlayerPawn->Camera->GetForwardVector() * 100000.0f;
FCollisionQueryParams Params;
Params.AddIgnoredActor(GetInstigator());
FHitResult Hit(ForceInit);
if (GetWorld()->LineTraceSingleByProfile(Hit, Start, End, FName("BlockAll"), Params))
{
// If Line hits anything, make TargetLoc that position.
TargetLoc = Hit.Location;
}
}
OriginTransform = ADulceWeaponActor::GetProjectileOriginTransform(TargetLoc);
// Here we spawn the actual Projectile Actor.
AActor* Projectile = GetWorld()->SpawnActor<AProjectileBase>(OriginTransform.GetLocation(), OriginTransform.Rotator(), SpawnParameters);
// Establish Shot Times to ensure we may fire as fast as we want to.
LastShotTime = GetWorld()->GetTimeSeconds();
NextShotTime = LastShotTime + ShotCooldown;
// Run a timer only if weapon is Auto.
if (FireMode == Tag_WeaponFireModeAuto)
{
GetWorldTimerManager().SetTimer(TimerHandle_Shoot, this, &ADulceWeaponActor::ShootProjectile, ShotCooldown, true);
}
}
This is the function I have for spawning projectiles, for now.
In this case the data would be where the bullet should start from, where it faces. It could send them with some delay but they would try to go where they're meant to go at least.
what scheme can i use to replicate a variable from a client, back to the server, then back out to all clients other than the origin?
client rpc -> COND_SkipOwner property
or just... don't do anything in the onrep if you can see it's not intended for you
was hoping to just utilize the in editor replication for this one
i'm assuming that works the same way
ok, thanks
woops I cut off the line I wanted to show...
note that this relies on network ownership
so this will generally only apply to things like your possessed pawn and other owned actors etc
you can also use netgroups I guess but that is not needed here imo
also COND_SimulatedOnly might even make more sense
this is just spawning a projectile actor. I can't tell what the actor does or if it is replicating
which is not so great for prediction (if is replicated)
Right right... This one replicated but I did an update
Client function does calculation, and a server function that does the actual spawning.
If you wanted to you could actually spawn a local "fake" actor and interpolate between the real one and the fake one if they are slow enough (how unreal tournament works)
this way the responsiveness is immediate but the results are still server authoratative, which is nice but will mean ping still matters
That's what I end up doing, but I haven't interpolate yet.
to me a big part of the decisionmaking is how cohesive the hit has to be relative to the visuals
if you need a perfect visual of the thing going from point A to B it changes what I think about a lot to be more "delayed" and done as a single "start from here to there"
but if the sort of like, result can be offset and survive you can get away with not caring as much
also sim proxies as always are a different problem generally and can be faked a LOT
I personally don't really see the point of an entire new actor for a simple bullet unless it is very complicated and has many rendering things attached
that's fair, I'm not saying you have to figure out everything in one go
I am still grasping on stuff like, how to exactly do prediction and such
it's really just... doing the same thing on two sides
and having a way to deal with what happens when the diverge
a very open-ended problem that can get really really complicated but generally we can get away with "close enough" in normal replication
Yeah I understand the concept of replication, keeping two machines handling as similar numbers as possible and filling the blanks when needed to make up for lag, packet losses etc
What I struggle with is the actual coding all that in part
one problem here is that you are relying on random external objects to be replicating and those are not going to ever show up in the order you care about... unreal does not order replication for random properties like that even if they are on the same object
they can show up in random frames
having a single holy property that represents more than one thing about the firing state might help reduce the complexity here with random stuff showing up
remember: the information is what matters here
in order to make a bullet fire on both sides you don't need to replicate a bullet... you can replicate THAT IT WAS FIRED
sometimes it is useful to have the actual "in-flight" thing be tracked as a separate thing if it is very slow though for sure (or can change direction somehow)
Any ideas on how to effect movement in networked CMC? Thinking of having a black hole ability that sucks nearby objects.
Would it be as simple as applying impulse / force by the server?
Okay, could you go over the steps to do that...?
client rpc says I fired from here to there, server considers if that makes sense
client can already visualize the fired bullet
server could if you want be the only side that actually does damage to things
simulated proxies get either some kind of onrep saying they started firing (burst counter style etc) or just an rpc
I still have to touch on simulated proxies
Well I have a new issue after running into bugs
I'm not getting the correct Player State to assign ownership so a lot gets messed up..
how are you getting the playerstate? are you waiting for the actual playerstate to show up?
I am using the Pawn Get Playerstate node
I am am waiting until well after the actor plays and input takes effect
the actor?
The player pawn
This is unspecific and doesn't describe the when or where this happens
on the server? the client? what callback on the pawn?
"waiting until well after" ?
So once the Player Pawn spawns, and the player can apply input to it
I have a basic function that tries to fetch and print the PlayerState assigned to that pawn
This is a Local function, not on server, only client
so? when is it called?
this is a very specific question
is it after every single time they press a button? once early on?
It's just called at an arbitrary point after spawn for testing purposes
Because I realized that the player state was not grabbed correctly
at that point they should indeed have a playerstate set
Since when the player spawns an. it's supposed to assign the Owner to its own playerstate for score tracking purposes
but you have to be 100% clear on how your getplayerstate works in order to understand when it is safe to call it fwiw...
basically sometimes it will try to get it from a cached member ptr, which might be set AFTER the playerstate triggers some callbacks
for example APawn::SetPlayerState might be called after the playerstate begins play
If all else fails and you can't figure out a good callback to use a 1-frame delay is possible but should be a last resort (and not a random delay with no retry, that is a massive mistake I see way too much)
I tried all that
It just doesn't get the player state no matter how, where, when I do it.
The correct player state is visible in the outlier, so it exists
you have not given specifics on how you do it so I can't help much
which node is this? is it a typical pawn?
I'm trying to but my pc only seems to work in 10 second intervals
My pc has about 4 to 6 different issues across hardware / software
It's a laptop with a busted screen, so now I gotta keep it plugged to a monitor...
Of course, the only way it can fit on my desk with this setup is by making the heat exhaust face directly at my face.
because of course.
I am thankfully getting a replacement this week after battling to get the last piece I needed, so just a little longer...
@nova wasp OKAY I think I found the source of the problem finally.
So the method I used for the player state was rooted in the PlayerController, right? Since it's all defaults.
So it turns out that while Play in Editor creates 2 Player States, it does still create just 1 controller. And since it cannot have more than one player state, one player state is unusued thus a lot of odd behaviour starts to happen
That's unheard of
I'm not sure what even is the reason or cause for this
can't tell without seeing anything.
though a pawn would have a reference to it's own player state.
it will be null if you try to access it when player state is not replicated yet but otherwise you shouldn't get error.
So for starters the Outlier shows 2 pawns of the Playable class, 2 player states, but just one controller
keep in mind only YOUR controller is replicated to you
So this creates a very weird set of rules
each pawn have their own player state...
the outliner can be changed to display the various PIE worlds and you have not described the pie settings
You need to select the world the outliner is showing
while client only know their own controller.
so if there are 2 players in the game. As client, you will have 2 player states in your world.
(the gear in the top right of the outliner)
I'm aware of that yeah...
1 for your own character, the other for who ever's playing.
so what's the confusion and what's with "unused player state making odd behavior"
if you know what which object exist in what machine, there wouldn't be an issue.
Okay so for starters when I check the Outlier while in PIE
While it is set to update
I only see 1 playerController
This is the server outlier btw
Wait...
I just realized it
So not only the controllers are not aware of eachother, but they also always share the same name on the client?? No ID before getting to server?
I feel so dumb now... That explains too much
also technically for a split second you have a local playercontroller that isn't the final one replicated from the server in some cases
Right no matter what the client's will always be newer
no, I mean it can be a separate one created locally
so try to make sure it's like, actually the one you expect
Ah, fair yeah
I am having some issues on one thing now still
So I have this setup in the player actor. The PlayerState should get assigned correctly since I fetch it from the variables of the Pawn... But it doesn't properly work here, at all. When trying to read the Owner state in the Actor spawned it just throws an error
"should get assigned correctly"
why would it be set on beginplay?
Yeah I did some checkups...
Tried to do it on Server instead but that may not be as reliable
So probably OnRep_PlayerState instead
To like be 100% sure it's accesible
I might have to do that in c++ cuz idk if it's doable in bps, I'm just testing here
onreps do not run on the server to be clear
I would suggest asking to see if the playerstate is set and using it if it is
And if it isn't just try again until is?
waiting for a callback ideally like APawn::SetPlayerState calling OnPlayerStateChanged
if all else fails repeatedly trying with a timer is possible, but it is very nasty
I can imagine...
the playerstate BP does have an OnPawnSet event
but otherwise this is an example of why multiplayer in bp is really just a bit of a struggle because a lot of these callbacks don't exist
Yeah and it does not seem to actually work on the automatic possess that happens when running the game
Yeah I was mostly hoping to nai ldown the logic to carry over to C++ anyways...
I feel BP's just faster enough I can cut down the time spent and focus on understanding stuff a bit better. Granted, I am learning- Just not fast enough to not run into issues
I did run into a major issue with this method that causes a crash regarding accessing the ASC though
yeah it's absolutely fair to try to do stuff in bp first
It's funny though, I think I am starting to get along with Unreal and the next walls shows up. Kinda fun to always have something new to learn
the key is to have the sort of ability to reason about what happens and NEVER guess
some stuff is hard to track down but as long as you can track down how something happens by just rooting around and using the tools at hand it's a lot easier instead of just hoping for a tutorial etc
you don't need to understand like 100% of it but having a rough idea of the general order things happen in the frame is crucial imo
I also find most UE tutorials a bit lacking tbh
Lots of repetition mixed with less ideal practices
And tweaking PIE settings makes me find so so many bugs too
Like I have a lot of them caused by forced packet losses rn
like the number of people that don't just profile their frame one astonishes me... you don't need to know about 100% of it if it's not hurting your project but like it's insanely useful to know the general order stuff happens in
Ngl I sm still trying to get my head wrapped around the profiler in general
are you aware of like actual real world packet loss scenarios here?
the 5% the editor has for "bad" is like beyond insane
like disconnect tier packet loss
It's a very unorthodox way to visualize.
insights is the least confusing profiler I have ever used
Yeah I'm aware the values used are generally extreme, and a full on disconnect will have a failsafe attached to ensure the game can go back to normal if recconected
I guess maybe the unity setup is a bit easier to just use instantly and insights does have some "oh you pressed a key and it hides everything" footguns
and i say this not because you have to make your game run at 1000000 fps as much as just
using it to simply see.. what happens and where
you can for example see when packlets for networking are actually sent and read and what that means for when your onreps happen etc
I get you, optimization is a very important step of a commercial release
And involves understanding what you're making
this looks very wrong.
- Player state is not replicated yet,
- Pawn may not be controlled yet by the client.
Why do you even pass player state around?
Yeah I have realized as much
Yeah I figured as much, just wasn't sure how to do it since I never did it before
the rpc from the client with their own local things that might be set there is weird, yeah
it's not a bad idea to have a sort of rpc between the client and server to sort of ack that they are actually ready
but passing in pointers that the server should have around locally is not meaningful
Right, I mostly thought about doing it that way since I knew they existed in server, but wasn't sure what the better way to access them was
what I mean is not to just "optimize" but to actually just... see what happens so you can intuit why things happen in a certain order that right now might appear arbitrary
I actually changed it to this method instead.
Which I suppose in theory should work since the Controller is just as good a way to access a PlayerState
Nah, by the time begin play called on the pawn in the client. Controller may / most likely still be null.
Beginplay will never be reliable. You can't expect that the controller and the player state to be already replicated.
Yeah I saw that when running a test on simulated lag
even without lag you are probabbly lucky if it work.
and with tiny lag its already a guarantee to break.
You can run it on OnAcknowledgePossession.
Your controller and player state should be ready by then.
OnAcknowledgePossession is called by server to client.
basically when the server already done the possession, it tells the client to run that function.
You can do some initialization there.
but this is for weapon?
On my end, I just have a ptr to an item for the weapon.
OnRep_Weapon -> CreateMesh()
the visual actor (the sword / the gun) isn't replicated.
server just inform clients and proxies in client, what item they are equipping.
spawning the visual stuff can be done locally.
Well it is for a weapon in the sence of the physical actor that handles spawning the projectiles and unique logic and whatnot
But it's important that I pack this sorta stuff in the player since the player state holds the ASC and inventory data, so is needed to initialize most mechanics...
Is it safe to assume the PlayerState is ready as soon as the controller is?
Equipment should be hold in the equipment component.
sure it can talk to another component, equipping bits will be the responsible for equipment component.
Well I just have the inventory data in the player state since I was gonna need to handle pre-match item management
yea that don't matter.
you can have the ASC and the inventory data in player state, not an issue.
my ASC and inventory is also in the player state.
equipment is in the pawn though.
the owner shouldn't matter, the system should work agnostically. It should work for player or A.I all the same.
Oh yeah, you mean physical items?
I have them as actors with references in the player pawn
The actor per se isn't meant to be replicated, but the bullets it spawns are.
I don't need to worry about fancy spectator mode stuff so I just went for what worked
Hello everyone,
I have an inventory system, and it is component-based. This component is attached to my PlayerController.
After packaging the game and starting the server, I join a world. However, sometimes the hotbar and inventory UI do not appear at all, sometimes they appear with a delay, and sometimes they show up immediately.
What do you think could be causing this issue?
Need a lot more context. You just said you have an inventory on your player controller and that sometimes your packaged UI shows up late or never or immediately. Need connection between these, like what is responsible for the UI showing?
auto start
Now we need context for what these settings are for.
if this is some random marketplace plugin we can't see what it is doing
It works normally in Pie or standard standalone mode, but when I connect to the server and try it, sometimes the UI doesn't appear, or sometimes it appears late.
if I had to guess my assumption would be something is not aware of the order of replication objects appearing that changes unexpectedly in a built game
it could also be async loading etc
debug it
and check logs too in the case it never appears
hi, Whats the best way to manipulate movementspeed in MP, changing players /Npc movementspeed (slow, sprint) Etc ?, i remeber someone said u should now change the CMC Walk movementspeed but i dont remeber why probably cuz on desync issues ?
https://discord.gg/uQjhcJSsRG
In this video I setup a new project and create a custom character movement component. I also implement movement safe sprinting which works at any ping.
https://github.com/delgoodie/Zippy
0:00 Create New Project
1:02 Setup File System
02:50 Create Custom CMC
04:43 Saved Move Class
08:37 Compressed Flags
13:35 Client...
hm only bp 🙂 ?
for server auth can't do.
you can turn off correction entirely but that will cause deprecancy in location.
and ofc anyone can cheat.
hm
CMC Multiplayer stuff needs C++, in theory. Pretty sure you know that :D
So I have this slight issue.
I'm trying to set up a Timeline for an Aim Down Sights' zoom effect in an online coop game, but the Event Possessed is not cleanly applying the timeline length to client. Even using Multi events called from Event Possessed won't work
I'm not sure if possessed runs on clients
I would have to see which one you are actually mean
yeah one sec
So I tried to add this Event On Possess to test it out. Everything works, BUT when I get to the Set Play Rate for the timeline it only works correctly in the Server player and only there.
what does "only works correctly" actually mean
does this get called on both?
I think no (at least possess is server only in this case, idk what is calling set play rate)
remember: I can only see what you show us here
is the timeline not the value you expect on the client?
why is there an rpc telling you to use a replicated value? there's no way that will always be the intended final value if it was just changed...
Well only the Server player's pawn gets the Play Rate updated, I mean that.
I tried making OnPossess call an event to: On Local, Server, and Multi that does that Set Play Rate logic, none worked to fix it
why can't this just be an onrep or something
if this is about a replicated value changing
also if ADS time changes rapidly this will not work well... ideally it should be locally derived from prediction etc
ADS time only changes on one shot events at occasional times.
In an ideal out of testing scenario each weapon would have its own assigned ADS time
// Called when the game starts or when spawned
void AProjectileBase::BeginPlay()
{
Super::BeginPlay();
AActor* ProjectileInstigator = GetInstigator();
InstigatorASC = UDulceAbilitySystemGlobals::GetAbilitySystemComponentFromActor(ProjectileInstigator, true);
}
While we're on the topic I had this snipped of code in my projectile actor but, for whatever reason it can only get the Instigator's ASC in the Server version, not Client.
debug it and find out?
either the instigator is not there somehow or it could not find the asc from that call
for example this silently allowing null is probably bad
Yeah I found the issue, incorrect init setup
I did the method for when the ASC is stored in the pawn rather than in a state
@nova wasp Well I tested most of what I could think of, I fixed plenty but the core issue is, in the C++ code, on begin play, fetching the ASC from Instigator doesn't work
But doing the exact same in BP makes it work just fine. Huh.
debug it
find if it's happening to early etc, then maybe consider moving it to another callback or something
why doesn't it find the asc? just add a breakpoint or an ensure
Okay I know what is going on know.
It can indeed find the ASC, it's loaded and it exists, and can fetch it as normal when using the GetASC functions.
The issue is that when setting it to the pointer, it does not actually exist in the server...
The weird part is, Client's versions of these actors WILL correctly have their Instigator ASC parameter assigned.
I'm not sure how exactly it is created here and if it will show up from replication or just exist already from being a default subobject etc
I am not 100% clear on how subobject init works with replication either
I'll share how I declare it, sec
//.h
protected:
// Stores the ASC of whoever this projectile belongs to.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated)
TObjectPtr<UDulceASC> InstigatorASC;
void AProjectileBase::BeginPlay()
{
Super::BeginPlay();
AActor* ProjectileInstigator = GetInstigator();
InstigatorASC = UDulceAbilitySystemGlobals::GetAbilitySystemComponentFromActor(ProjectileInstigator, true);
}
@nova wasp y'know what I'm just gonna bruteforcei t.
Rather than pull my hairs at making a pointer variable I will just use a Get function
this pointer is replicated but you also just set it on beginplay?
don't replicate things you write on every machine
replicated = let replication modify the value
unless you are the authority or it's a non-replicated object
Would it be better to make only the server bullet get the ASC then?
no, both of them should have it
I am not saying "don't use the asc"
I am saying don't add "replicated" for no reason
note the replicated here refers to the property itself
not whether the object it points to is replicated
I started to get cleaner info when going from 2 to 3 players too. Didn't realize each client had its own index for player states and the only absolute one was Server.
So then that's used so one change is broadcasted to server and other machines automatically?
And so it sees no use if the value is set on Begin play and thus consistent gets updated by itself
whate is this referring to?
On Replicated UPROPERTY
replication does not mean it goes TO the server ever
replication is ONLY from the authority to clients (for replicated properties)
but yes if the client can just derive the value on beginplay from something they already know replication is pointless... might still be convenient though but the more random objects interacting from replication you have the weirder ordering will get (maybe it's not around yet etc, in the case of a replicated dynamic object ptr)
Ah! So if I run a server function that modifies replicated properties it automatically updates it for every other object that also holds it on every machine.
yes, if it is replicated and the ptr points to a valid replicating or stably named object (this will not be validated and will silently fail if it isn't one)
the ONLY way a client can tell the server anything is from RPCs from client->server
aside from control packet internals which are kind of not for gameplay code etc
I would personally just have the ASC cached locally if the pointer can be derived from the instigator
Remember: I can ONLY see what you put into discord and I have no clue what you are actually doing
I will show you more as soon as it loads
But honestly the issues are have are all around the snippets of code I showed
are you familiar with how to debug c++ code?
InstigatorASC's reference is all that seems to be off
Yeah, gotta run in debug mode for something cleaner than logs and all
cleaner? okay I do not think you are aware of what I mean
put a breakpoint and step into it
see what it's doing
Sure, reloading
this should be step 1 almost every time
when you show some c++ and say "It didn't work" I can't figure out what happened at all without any context or local memory showing what it is doing
but you can
Okay collecting data
void AProjectileBase::BeginPlay()
{
Super::BeginPlay();
AActor* ProjectileInstigator = GetInstigator();
if (ensure(ProjectileInstigator))
{
InstigatorASC = UDulceAbilitySystemGlobals::GetAbilitySystemComponentFromActor(ProjectileInstigator, true);
ensure(InstigatorASC);
}
}
for starters silently failing is very sad... ensures here might at least help make it annoying when something failed
if it is expected to not always have an instigator that ensure does not make sense, but if it is you want to fail early instead of breaking and pretending nothing happened etc
Oh didn't know about ensure
Okay something I found here...
I tried to look at the Instigator from watchers, and it's there with access to all varaibles
The instigator and all data matches up with the World outlier...
hey guys I'm still leaning multiplayer, I had a little doubt with RPC concept.
Lets say I wanna open door so in I use Open bool and set it to repnotify and in it's function I play door open animation. But here for some reason I also need to pass a variable's value at the same time (Char forward vector). But since repnotify does not have parameters how will I get that value while performing code in repnotify func?
a repnotify is only for that specific property
if you need more information then use some kind of struct for more information so you can handle it in one repnotify
okay, but making struct for every since logic can be so complex, is there any other way around?
I'm honestly at a loss here
Not sure what goes wrong, how to fix it, or what to do.
I am not built for online programming
f11 -> see what happens
I had a thought of using multicast but it doesn't works for late joiners
or is there anyway that later joiner can match the current state of the game before loading the map?
Don't use multicast for anything that needs to be in sync.
you could just have a second repnotify and pray they show up at the same time but a single struct with both will be more consistent
if making 1 new struct here is too difficult I don't really know why it is any different than adding arbitrary new properties to a bp
Also struct isn't complex, if you need to pack something together, use struct.
in networked game, the order isn't guaranteed either. So easy way to get data bundled together is with struct.
you could technically do something where the client requests information for each specific door but that is vastly more complicated than just using an onrep
So what am I looking for?
this is assembly and it means it can't figure out where to put the breakpoint in regular lines
are you actually compiling and running from rider?
are you using debuggame editor?
show the top of rider in a screenshot please...
your answer here does not match up with what I mean
I am talking about the buld target configuration
This here...?
as I suspected...
you are running with optimized code that can't be debugged easily without disabling optimization
always use debuggame editor (when adding new C++ code that you need to reason about) (it will make your project far easier to debug but keep the engine mostly the same)
you really might want to read the pins in #cpp
debugging will be a lot easier and you should be able to see exactly what happens
Ah....
it will run your game code a lot slower though but I doubt it's the majority of the frametime right now
Btw, did you have the other links you shared on replication...?
I misplaced them after a pc crash
basically compilers will mangle the hell out of your C++ code in a way that means it's not the same as the code you see on the screen
so if you disable optimizations they will basically stick closer to "as written" and be something you can follow with a debugger much more easily without reading asm etc
I don't recall which links those were
any details? I can try to find them
A blog post that talked in detail about sending events to server from clients and viceversa, had several pages about it, went over it in both bp and c++, dark mode with some red ish colors?
just go over the pinned material again, I'm pretty sure exi compedium and wizard multiplayer tips and tricks go over RPC.
but it's like dead simple.
Server RPC = Client telling server to run a function.
Client RPC = Server telling OWNING client to run a function.
Multicast RPC = Server telling everyone that has a copy of the replicated actor to run the function.
So is the build time supposed to be this slow when running in debug for the first time?
this is in the pins
and yeah the wizard ones are great too
Right thanks.
Okay there we go
So it's running the getASC function, that's expected
It correctly grabs the instigator pawn
also consider adding {,,UnrealEditor-Engine}::GPlayInEditorContextString to the watch window
so you can see who this is easily
(server/client 1 etc)
@nova wasp sorry to bother you, it's something that I want to do as well.
Just love the documentation when it's pure text and doesn't show where to click exactly.
like where is the variables pane / panel?
Eh weird...
And it's supposed to run multiple times over, once per client / server?
yes
remember the editor is pretending they are two different computers here in different uworlds
code will run multiple times
that runs on both sides
some sections will only run for the server and vice versa of course
Okay wait I think I saw something
try UnrealEditor-Engine!GPlayInEditorContextString
you can move the execution cursor up up the stack but you can't really easily do that for the entire tick
you just.. try again generally
thanks for the tip this is awesome, i was wondering about this yesterday 
this yellow cursor can be dragged back but be warned this will not always work well outside of simple stack local things
I do not really think it likes to deal with side-effects much but simple just if statements etc will generally be okay to redo
I'm not sure what restrictions moving the execution back really has in all honesty but I generally just... restart if I need to start from the top again
does it work for you?
what am I missing
I'm wondering if our dlls are different somehow
what is the name of the module in your engine uses?
yeah
if you have a custom source build you might be using a different name
I am also on the Rider EAP so it's possible I am using a newer syntax and forgot
{,,UnrealEditor-Engine}::GPlayInEditorContextString is the old way
if its relevant im on 5.7
there's also {,,UnrealEditor-Engine.dll}::GPlayInEditorContextString I guess? I have no clue what this syntax is lol
you should be able to see the module names in the stack window when pausing execution
or just in the module list
which is going to be a nightmare in unreal but it will end in -engine
it might be YourProjectEditor-Engine as a source build
right click that window and enable "show module names" at least just for a second here
ideally Rider would resolve this module name for you but it's a bit horrible at that
Any way I can specifically break at the Server version of the logic?
Since that is the one with issues
good question... honestly the simple thing is to just add a temporary if( HasAuthority) sometimes
or just a conditional breakpoint on something being null etc
k sorry for being annoying, I'm still not hitting the mark.
try the older fashioned way
{,,UnrealEditor-Engine.dll}::GPlayInEditorContextString
{,,AetherGlowProjectEditor-Engine.dll}::GPlayInEditorContextString
that did it. Tyvm.
yeah I think it might be me using Rider EAP that uses this somewhat nicer syntax
it's super new
I'm one version before they implement the A.I auto complete (copilot?)
I mean it's simple to disable if you don't want it
I want it :S
I have it all turned off for now
and it sucks because I bought the prepetual lisence
still got 9 months to go
but the moment I unsubscribe, I can't update anymore.
the main big ticket thing that actually matters aside from AI stuff is they made debugging stuff generally faster
aside from that I don't really know how much you lose being on an older version aside from plugin support
@nova wasp Okay so I watched it step by step, fetching the Instigator, the ASC- All exist, and are correctly referenced and can be accessed...
But server, still, for some reason, doesn't actually set it?
does the server hit this breakpoint and not do anything? are you considering the branches etc?
The server hits the breakpoint and do nothing, it just grabs random data and does nothing with it if HasAuthority is true, before setting InstigatorASC
How do you set the Instigator?
I inspected the data received and passed. The PlayerState, its ASC both exist in server, and appear in the watched data list.
HOWEVER once it finishes up confirming and fetching all the data, it fails to set it, only for Server.
but the issue isn't the ASC? you get null ptr on the instigator
I also tried with 3+ players, and all clients correctly have the InstigatorASC set
I don't get Null in the instigator
But in the Property that is supposedto store a reference to the instigator's ASC
that sounds weirds, why do I get the feeling that you spawn something on the client and expecting something on server?
Replication doesn't work from client to server btw. Anything the client spawn only stay in that client machine that spawn it.
Show the breakpoint.
what's the value?
This is how the actor is spawned btw
On IA start it calls Local, which then calls Server
The value is correctly the PlayerState0, when the Server player spawns its actor.
Go debug inside GetAbilitySystemComponentFromActor
and see where it failed / didn't get the expected result.
Actually when I looked into that, it worked perfectly fine.
Like it returned the data...
@dark parcel The weirdest part of it all is that doing the exact same logic in Bp just works for some unholy reason.
I don't know what logic and how it got anything to do with the ProjectileBase BeginPlay
as far as I can see the BP you showed me just have the client to tell the server to spawn a BP_Dulce_Test something
Also what is Projectile Data here?
Can't pass around UObject unless it can be resolved (exist in both machine, through replication or statically spawned).
It's just a collection of variables that tell the projectile how to behave
Speed collision radius etc
hmm I would just read that from a Data Asset or something. Or make it a struct if its mutable.
anyway I am still not sure what the actual problem on your end. You haven't describe what actually went wrong.
other than "it works fine in bp, but not in cpp"
So this is the reads from the function that handles getting my ASC.
And these are the results. For some reason, everything should work, but doesn't?
If I do f11 here, doesn't it just advance to the necr curly bracket and end the begin play logic?
hah, well I don't know what is wrong here
When I do the exact same logic, setting the variable in BPs on Begin play, it works.
is this still replicated?
BP beginplay fires afterwards generally I think
but I don't think it should matter much here
So that small delay is what matters
Therefore...
I should do OnRep_Instigator to set the ASC?
I'll try that and see what happens
it's not a delay, it's just calling it in a bp event after the c++ one
this is not happening a frame later afaik
instigator should... generally be part of the initial bunch of the actor but an onrep would not hurt
my confusion is why it matters here because afaik it's generally just happening one after the other
But I don't understand, why, or how the variable is not set SPECIFICALLY for the server
ah, what is the parent beginplay doing
I think actually the BP is before
AActor::BeginPlay called by the super would trigger ReceiveBeginPlay
The BP begin play is actually a function that by default BeginPlay does so
They are technically different things.
yes, but they are called in the same callstack
the only difference being that I guess ActorHasBegunPlay is set right after the BP call?
and whatever else the parent between this and AActor does in beginplay
I'm not really sure if this line of investigation matters though, I'm mostly curious
Yeah I get that... But
Nothing I see here tells me, why this works for the clients, but not the servers
Hm maybe it'd be better to simply expose this OnSpawn
And feed it into the actor
Show how you do it in bp
btw if you want to set something before spawn, use SpawnActorDefered
SpawnActorDefered will let you delay when BeginPlay happens until after you set some things
which is really useful for stuff like this
FRotator Rotation = (ProjectileTargetLocation - SocketTransform.GetLocation()).Rotation();
SocketTransform.SetRotation(Rotation.Quaternion());
AAGProjectile* SpellProjectile = GetWorld()->SpawnActorDeferred<AAGProjectile>(ProjectileClass, SocketTransform, GetAvatarActorFromActorInfo(),
Cast<APawn>(GetAvatarActorFromActorInfo()), ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
/* @TODO: Create and give the spawned projectile a gameplay effect spec */
/* Gets the ASC that own this ability */
const UAbilitySystemComponent* SourceAsc = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetAvatarActorFromActorInfo());
const FGameplayEffectSpecHandle SpecHandle = SourceAsc->MakeOutgoingSpec(ProjectileEffectClass, GetAbilityLevel(), SourceAsc->MakeEffectContext());
FAGGameplayTags GameplayTags = FAGGameplayTags::Get();
UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(SpecHandle, GameplayTags.Damage, BaseDamage);
SpellProjectile->ProjectileSpecHandle = SpecHandle;
if (Cast<APawn>(GetAvatarActorFromActorInfo())->IsLocallyControlled())
SpellProjectile->NetOwner = EProjectileNetOwner::ThisMachine;
else
SpellProjectile->NetOwner = EProjectileNetOwner::Server;
SpellProjectile->SetInstigator(Cast<APawn>(GetAvatarActorFromActorInfo()));
SpellProjectile->FinishSpawning(SocketTransform);
Huh, that's good to know
And the way I do it in BP is literally get get ASC->Set a non replicated ASC variable.
FActorSpawnParameters SpawnInfo;
SpawnInfo.ObjectFlags |= RF_Transient;
SpawnInfo.bDeferConstruction = true;
Connection->PlayerController = GetWorld()->SpawnActor<APlayerController>(ANoPawnPlayerController::StaticClass(), FVector(), FRotator(), SpawnInfo);
Connection->PlayerController->NetPlayerIndex = NetPlayerIndex;
Connection->PlayerController->NetConnection = Connection;
Connection->PlayerController->FinishSpawning(FTransform());
a random example from the engine
the important parts being bDeferConstruction = true and FinishSpawning after you finish setting things
Is this DeferSpawn useful if only variables set are Owner/Instigator?
okay I am losing track here so apologies if you have to repeat yourself
but is the instigator valid in ALL cases?
and it just can't find the ASC? (on the server?)
you may as well add some logging or something with GetDebugStringForWorld etc or just branch on the authority to keep it simple
Instigator and ASC are valid in all cases
The only singular issue is that the Server, specifically, cannot set InstigatorASC to the Instigator's ASC
And when I mean only the server I mean it. I tried with 3+ servers and logs showed that client 1 and 2 both could get their projectile's ASC assigned, but NOT the one on the Server
So it's less that it cannot find the ASC, but that it genuinely won't set it for some reason
won't set it?
like does this line of code assing the ASC pointer or not
does anything else write this member?
Well for some reason it will work on the clients but not on the server.
The line will try to set InstigatorASC to whatever it can get from trying to grab the instigator's ASC
@nova wasp Doing OnRep won't work either. Of course.
"whatever it can get"
what is "whatever it can get"
is it valid or not?
this is why I asked to see if it was actually set
I have shown direct examples of adding ensures
It got a valid instigator, then the player state
we want a valid ASC
does it get a valid ASC in all cases or not?
if it doesn't, find out why
find out by stepping into the lines of code.
Also when debugging, check whos running the code by checking the watch list Megafunk showed earlier.
You should be able to hit an ensure breakpoint and rewind execution to right before it asks for the asc
or if that's difficult you can just call the function again and step through etc
Okay I tried something else with ensure and found something weird.
When running an ensure condition, by creating a Local Variable of the ASC before assigning it to the actual ASC variable... It won't even get the instigator...
...This is even weirder
The ensure says it runs, and is applied correctly.
But when accessed later in actor lifetime it returns nothing
Wait
I think...
@nova wasp I did it.
I actually did it.
I finally found the reason why and it's so so bizarre...
Turns out it was a conflict caused by calling Super::BeginPlay BEFORE running custom logic...
what custom logic?
super call order mattering isn't very bizarre if it actually matters
Basically running Super::BeginPlay after trying to set ASC makes it valid and work as expected as soon as the actor spawns.
I'm assuming the beginplay is clearing something out that makes it work otherwise
I can't see what is actually going on here though so I have no clue why
YEah fair. But would it be an issue to do it that way? Not familiar enough with this to know whether it's a bad long term idea or not
I don't know because I can't see what you are doing
there are plenty of situations where you need to interject before a super call depending on what they super call does
it's not strange to re-order things around a parent call
generally speaking the super being first is just... the default for no real reason
as it's just consistent
Really wish I was better enough at this to give you a better explanation
I feel I'm talking in circles while you try your best to help me here, must be a headache
This is all probably overwhelming but I think you should really try to get into figuring out how to use the debugger like this more often to figure out how things happen in order etc
It's often quite difficult to track down WHY certain things happen in multiplayer but you can at least catch when things that are your own code happen in full detail
like, you went from not running in debug game to using a breakpoint on your own code pretty quickly
that is a lot of progress having not done that much before
this is the kind of thing most Epic C++ tutorials just assume you already know which for me was extremely frustrating but they kind of assume you have some knowledge of how to use debuggers etc
Yeah I learned quickly most UE video stuff is misguided
Like I had to figure out how casting worked separate from every tutorial that used casting, for example
to help dispell the myths
the reason people go "casting is bad" is not because casting is particularly slow... pretty much every BP node is slow (by nature) and that one isn't doing anything super expensive
youtube tutorials generally assume it is because of a perf reason etc
the real actual mechanical reason is because it creates an ASSET REFERENCE to the object casted to. Because the BP MUST know about the actual asset it casted to
so if you cast to your character bp and the character bp has many art assets, those are loaded together (even if nothing ever executes that node!)
the simple solution is to just keep heavy art references separated in either child classes or just soft references etc
"use an interface instead" is just... it's not going to be any faster but it might help for organizational purposes and adding it to random other things
Yeah I was familiar about that actually
Was there a helper macro to (de)serialize an array from/to an archive?
I feel like there was one
Or is Ar << Array fine
I have a question about global time dilation and server. I am assuming this command is executed on the server and it does a multicast to pass the new dilation to the clients?
It's a replicated property
Doesn't use an RPC to update, just sends it to all clients
Hey, the game I'm working on is meant for playing with 4 players but recently has been crashing when all 4 players are playing at once. It also crashes at 3 players but takes a lot longer to crash than it does when 4 players are playing. Any ideas how to fix it?
in 5.7 don't need to specify bUseIris = true in Target.cs?
I have the engine from the launcher and it seems like Iris should work in it
Why don't you give the crash report
it hasn’t been giving a crash report or normal errors it just says fatal errors and then crashes unreal or steam
So I have a problem, My On_Rep is firing when I add an item but not when I move an item within the inventory what could be the cause of this?
what is the replicated property and how is it changed? is it changed on the server?
my inventory items variable... not sure if its changed on the server or not.. Im trying to get my Refresh UI to fire and it wont
is it marked dirty with pushmodel?
I can't help with no context. You should be able to figure out if it is changed on the server via simple debugging and logging when it changes or just inspecting the outliner
in order to make a multiplayer project it is really crucial you understand what happens on each machine and can reason about it when things happen in a way you didn't expect
thanks ill keep trying. Aprreciate you taking the time to respond
You could share any info about how you declare this if you want help
remember: we can only see what you show us
Might be tired, but do clients know if they're connected to a dedicated server or a listen server?
or do they not have that info
yeah afaik that was local
Im trying to remember how we handled checking that exactly.
Mainly asking because I want clients to request an auth ticket from the server if it's a player, to validate their identity
ty
they could maybe go netdriver->ServerConnection ?
I'm not sure if it has the netmode on it directly on the client side or if you have to derive it from the url or something else
(the server connection's owning netdriver)
And if all else fails you could just toss in a quick simple replicated thing that says one or the other
oh well
Yeah but then it can be faked
faked how?
Server could just change that value to be wrong
No real reason to buuuuuut you never know
you don't control that anyways if it's on their machine?
I guess not
Depends how the net driver detects it
The less they can "easily" modify the better anyway
By that logic, couldn't it still do that?
Like, SOMEWHERE it says its a dedi, or listen server.
If anything its easier.
Cuz the engine source is accessible, while your game source isn't.
Also, what does this even do, that faking it could be "bad"?
not the end of the world
is it useful for them to figure out if it's a listen server?
im just not going to have clients ask dedis for an auth ticket to validate their identity
no real point
I could but it'd be a bit of a waste
There would be zero benefits to spoofing your dedicated server's identity on Steam
as a listen server however, you could make players think you're someone else as the host
well
you might need some kind of identity provider thing I guess?
I'm not sure how to set that up or what your actual goal her is
Steam
Listen server host gets an auth ticket from Steam, sends it to the client who wants it, client can validate the host's identity with Steam
not persistent data I just want players to be able to verify that a listen server host is who they say they are
I would kind of assume that's the steam connection's problem
like, ideally they don't accidentally click on someone pretending to be their steam friend? I don't know
They could spoof as anyone, that's not the point heh
And you can also just find listen servers in the server browser
I'm making a Steam plugin from scratch using OSSv2/Online Services and I'm just trying to improve it over OSSv1
Considering so far I'm pretty sure I could go get a bug bounty for a bit of OSSv1 Steam heh
If I ever feel bored enough to
On another note, is there no way to disconnect a connection from within a HandlerComponent?
the packet handler stuff
or does calling Packet.SetError() cause a disconnect anyway?
on the unreal-level an error will disconnect afaik but I'm not sure about that layer
you would have to try it
Seems like it should, but the thing is since my calls are async, I gotta be able to kick a player from within the handler component without a packet
which doesn't seem possible
unless I just send a bogus error packet and it disconnects them (lol)
idk why Epic didn't make it easier to do so, sounds like something you'd want
okay did some digging
seems like this is the best way to guarantee it
LocalAccountId = UserData.UserId;
if (!LocalAccountId.IsValid())
{
UE_LOGFMT(LogCrowbarAuthHandler, Error, "Received invalid SteamID from player, kicking.");
Packet.SetError();
Net::AddToChainResultPtr(IncomingPacket.Traits.ExtendedError, ENetCloseResult::NotRecoverable);
return;
}
And I guess if I want to force drop a connection without an incoming packet, I can just create a new packet & mark it as error with not recoverable before sending it to the client
But I'll test that in a month when I have the plugin ready for dedicated server testing lol
hmmm not sure if I can set the "NotRecoverable" trait on it
that's annoying
god forsaken engine can't add a "disconnect connection" function in the packet handler
(╯°□°)╯︵ ┻━┻
void FCrowbarSteamAuthHandlerComponent::Incoming(FIncomingPacketRef IncomingPacket)
{
// If we're in an unrecoverable error, mark the incoming packet as errored and unrecoverable.
if (State == ECrowbarAuthHandlerState::UnrecoverableError)
{
IncomingPacket.Packet.SetError();
Net::AddToChainResultPtr(IncomingPacket.Traits.ExtendedError, ENetCloseResult::NotRecoverable);
return;
}
this better work
why the fuck can't we grab the net connection that owns a handler component, from the handler component
it's stupid
I can grab it from a private delegate inside the packet handler
kind of
by grabbing the delegate's uobject
dirty as fuck but I guess it's all I can do without engine mods
not even sure actually
void FCrowbarSteamAuthHandlerComponent::DisconnectFromError(const FString& InError)
{
// Only allowed on the server.
check(Handler->Mode == UE::Handler::Mode::Server);
// If we have a valid owning connection, we'll try to close it that way first.
if (OwningConnection.IsValid())
{
Net::FNetCloseResult Result(ENetCloseResult::NotRecoverable, InError);
OwningConnection->Close(MoveTemp(Result));
}
// We'll also set ourselves to an unrecoverable error state, that way we do not handle anything else.
SetAuthState(ECrowbarAuthHandlerState::UnrecoverableError);
UE_LOGFMT(LogCrowbarAuthHandler, Error, "Disconnecting connection with error: {0}.", InError);
}
went with this
// This is hacky, but we can try and fetch the net connection that owns this handler through a delegate.
// Since it's a private member we have to be even hackier.
FPacketHandlerLowLevelSendTraits& Delegate = PacketHandler_Private::Get_LowLevelSendDel(*Handler);
OwningConnection = Cast<UNetConnection>(Delegate.GetUObject());
and this to grab the owning connection
we'll see if it works
Isn't the client supposed to generate an auth session ticket and send it to the server ? And then the server confirms that tickets match the steam id?
Hello, I have a question.
Assume there is two users in a session and lets say its level A. User A (host) and User B(client).
User A triggers servertravel goes to level B.
But User B (client) does not follow User A(host) to level b. User B goes back to initial starter map.
NOTE :
seamless travel is true (recommended by chatgpt)
this is the code snippet of servertravel.
FString URL = FString::Printf(TEXT("%s?game=%s"),
*Map.ToString(),
*GetGameModePath()
);
GetWorld()->ServerTravel(URL, false, true);```
@tidal cloak can you come again? You said user A was the host then after that User b is the host.
Which is it.
In any case only one map can be opened at a time.
If the game needs to travel to another map, simply have host call server travel.
Sorry. Typo I will correct it
Yes, host will call server travel and connected clients will follow host to new map. This is normal case
But in my case connected clients goes back to starter map. And host travels to new map
You sure you're calling this on the server? Calling ::ServerTravel() will not automatically route the request to the server.
Yes. I am using listen server architecture. And calling server on host machine. Which also listen server
Hmm that's a little weird then.
User B goes back to initial starter map.
Sounds like User B is getting disconnected. You could check the log to see why this is the case.
In clients machine I got the log like host closed connection
Then client goes to starter map
Btw using UE 5.7
Try checking the server log, it often has more useful info regarding disconnects
hey is there a way to make running multiple instances on steam work? or will steam just not allow that? i know if i launch the game from the exe while i have it running already it will launch the second instance, and i can press shift tab to get the steam overlay.. but the second instance can't see any servers
ok
None that I know of, although if someone figures it out I would love to know. I set up some VMs and secondary steam accounts for our games when I need to test multiplayer stuff
i have a feeling steam just hard limits online stuff to 1 instance per account
Yes, as far as I know that's true
hey. I have same issue. I m using non-seamless travel when the server player load savegame I call serverTravel functioanlity but It disconnects clients. Is it still best practice to use seamless travel for loading savegame?
Save games and seamless travel don't necessarily have anything to do with each other.
You should be using seamless travel for your server travels though, if possible
The client would disconnect even without the savegame. That's what non seamless does.
Yes, but I also want to do the opposite if the server is also a player
That way it prevents listen hosts from spoofing their identity
any tips for moving a player w/ client authoratitive movement from the server (eg having an AI grab said player)? can turn off client auth but then there's some jitter, and can also have the client attach itself to the AI but also fighting jitter.
Depends on what it is I suppose.
If its like an in place body slam or something like that, you can easily just lock both Actors in place and just animate or move the Meshes instead of the entire Actor.
If its like a pull from a distance, you can think of it in terms of the Player character performs a Root Motion Source to the Enemy, simulating a "grab" by the Enemy.
Might also be worth noting that you'd want to attach to the MeshComponent and not Capsule, cause that one isn't smoothed potentially.
Any tips on moving a lot of data from the game server to the clients? I'm talking about 50-70 Mb of procedural data on game init phase to generate the full level on clients.
I'm currently using replicated actors which works but I'd love to have a fire and forget similar to RPC to send the data instead to reduce the amount of resident memory used on the game server. Makes sense?
The only two ways I have in mind are:
- replicated actors which means I need to synchronize a cleanup after all the clients have used the data
- RPC with lots of data chunk (high risk of client disconnection from my perspective - 64 kb limit, max number of rpc sends per iteration, etc)
Would it be possible to have the clients generate the data themselves using the seed the server used?
50-70mb of data? what?
why does client need 50-70mb of data, even Minecraft doesnt do that.
if client needs FULL data to make the map, you designed the system wrong
our procedural maps == seed only, plus state changes
ie you send the data only of what the player sees (this is what minecraft does)
so if you need to send entire data in one go, somehting is wrong, and why is it so big?
That's a loooot of data. 😄 Like practically a decent sized map fully serialized and not compressed or anything.
Hi, I'm new to multiplayer, and have many questions don't know where to find answers.
I'm wondering why many friendslop games are using 4 players? instead of 5 or 6 or 3? Is that a technical limitation?
Are they using one player's device as a host and other players join it? Do they need server for it? If publish on steam, does it have some kind of free server for it?😯
Splitscreen on consoles essentially.
For the server part, usually one player is the server. Called a Listenserver in Unreal. Steam doesn't do servers. Steam manages being able to connect to a server, but doesn't host servers.
For the games like you're meaning, one player is host/server, other players join their game.
considering most of them are on PC, it's mostly arbitrary
but 4 people is a pretty easy group of people to get to consistently play coop
anything below that and it's too small, anything above that and you're trying to schedule 5 people together
systems like communication (voice) also break down in higher numbers
Data is generated through Unreal PCG on the game server and includes a lot of stuff including foliage, game items, etc etc. I think part of it is the unreal containers that reserves extra buffer to account for growth (so I will remove part of it) but for the sake of the question, even if I remove 30 Mb, I still have 40 Mb to transfer.
We use PCG too. But it's all local to the machine. Our clients generate a world of actors and set up their gameplay world locally via a single seed. Then we let server create replicated actors which all replicate to the client carrying the actual world state. Then we run PCG locally on the client. So we only ever actually pay for the gameplay actor replication and their state.
yeah PCG is very determenistic
its seed driven, as long as client has exactly what server has, and the correct seed, it will generate exact pcg
How can I client predict enemy death ? Player actions works well with GAS client prediction, but enemies that lives on server I don’t really know what to do, I need the death to feel instant because it use root motion to push it away, and if server does not agree with the death I roll it back, but the character movement don’t let me move it on the client, should I set replicate movement to false while the server don’t confirm the death ?
i think every bit of guidance ive ever seen is to not predict client death
It's not out of the question imo
It's definitely preferrable to not have to
I would say it depends on what "death" means here as if it's mostly visual you could just predict it in the visual sense
"character movement don’t let me move it on the client" is going to require overriding OnRep_ReplicatedMovement and maybe basedmovement along with anything else that comes down
I suppose ACharacter::PostNetReceiveLocationAndRotation might be more direct but I forget if that covers everything
Clients can play RM anims on simulated-proxies without changes (though they can still get net corrected)
GAS can't really locally predict abilities on simulated-proxies its kinda a strength and a shortcoming of it~~
I'm learning about multiplayer security in Unreal Engine and trying to understand how client-side vulnerabilities are realistically exploited.
What tools or methods are commonly used to intercept or modify client-to-server data in Unreal Engine multiplayer games?
Also, is there any good educational material, tutorials, or research about this topic available online?
This is for learning secure server-authoritative design and testing vulnerabilities.
@oak flower client are running their own instance, they can pretty much modify the data in their instance.
Using kernel level anti-cheat may help but I wouldn't bother with all of it.
General rule of thumb, you want to trust the client as little as possible.
You can probably go long way simply by having a good design.
like don't just trust the player informing the server that they have shoot some object. Check in the server machine if the shot is possible.
On the flip side vulnerabilities only really happen because the server just can't afford to do/check everything. That is why anti cheats are so important
i understand, i'd like to learn "what is possible" to improve my multiplayer code, maybe intercepting an RPC
players can modify anything they want in their client, you should consider basically any data coming from a client to be compromised
hello all, i just started a project on ue5.7 and im looking at UObject replication for my nested inventory system, but i notice the plugin for it hasnt been updated since 5.5 despite the author still maintaining other projects, since he has no discord im asking here:
how is UObject replication handled in UE 5.7? have the features of the plugin been integrated into the base engine? if not, is there another plugin i could use, or might it work if i just rebuild the plugin in IDE?
@visual ore https://dev.epicgames.com/documentation/en-us/unreal-engine/replicating-uobjects-in-unreal-engine
does it not work on 5.7?
testing it now, however im not confident that i can diagnose it myself given my inexperience with replication
Thank you! So in this way, it doesn't cost anything right? And even the random matching is in the same way?
Listenservers don't cost anything, no. Cause it's all ran on the consumer's machine.
Steam in this case is just essentially a replacement for connecting via a direct IP address. Any online subsystem is, really. This is true if you're using Steam, Epic Online Services, Playstation Network, Xbox Live, or whatever else.
The only downside to this is that you basically cannot make anything secure, cause it's not ran by you as the dev. But that doesn't really matter for a non competitive coop or whatever game.
A prime example that even some high quality games have is.
Such as the client being about to override your guns start/ end point for damage.
Or in more crazy cases, even the damage type, for some psycho reason.
But yeah like they said.
Any info going from client -> server should generally have safeties, or be limited.
Cuz they can change all of that.
Thank you very much! I'll look into it, if there's any good solutions for casual coop games. 🙂
just let players host their own game. Essentially who ever host the game is the server (listen server).
so in other word, it cost nothing for maintenance. You just have to cough up for $100 for the dev fee on steam to publish your game, which you will get back if you sell over $1000.
Oh, and a small question. Is that either choosing listen server or delicated server, I could use a same game system? The difference only exist in connection? I could use the same replicate methods right?
Same method but there are some consideration depending on the context.
dedicated just mean headless server (it doesn't render graphic).
Oh, so delicated server only calculate datas? And the graphics are all running on clients machines?
Every client is running their own instance.
but yeah you can think of dedicated server as a console command.
are you not familiar with Left 4 dead?
What about the maps, multiple players in a same map. That map update is also different instance in every client?
Yea a little, played long time ago
With networking framework that comes out of the box in unreal, only one level can be "shared".
think of it like counter strike.
Host select the map, everyone has to play in that map.
Out of the box, you cannot do multi world.
like player can't just go to Dungeon A, B, C.
Nu-uh, it's like counter strike, where everyone has to play the same map.
And yeah, MMO made in unreal engine is a thing. But they don't use Unreal replication framework, they roll their own backend.
well... technically you can host a fleet of dedicated server.
where each server host a map. When traveling to other map, just migrate that user to another server that host the map.
sound expensive as f though.
looking at AWS pricing calculator, I decide to do listen server.
I see, lol. Thank you very much!
any idea what causes this? 5.4 steam sockets + lyra
Yo, having a bit of a block using VOIP. The system is working fine in build, but I can't get any attenuation settings to apply. Everyone is just always heard 100% of the time. I believe I'm doing a fairly normal implementation, but it appears that the settings just don't apply for some reason. Any ideas?
(InitVoip gets called in Event BeginPlay on both Client and Server, and I did check that the attenuation itself does work fine with normal, non-VOIP sounds)
got sidetracked, but i finished testing and all the functions seem to work properly with no issue,
for anyone following the same question as me: the UObject Replication plugin works fine on ue5.7
Ain't a plugin. UObject can always be replicated through actor.
DOCUMENTATION -- DISCORD SUPPORTUObject Replication Plugin enables projects to replicate UObjects over the network in Blueprints, which is not supported by default due to C++ setup. The plugin will replicate your UObjects simply as replicating an Actor/Actor Component.Why should I replicate UObjects?They are lightweight to replicate, so they're...
I see someone just expose some of the func to a bp.
but for your question "have the features of the plugin been integrated into the base engine?"
That's not the case. The authour of your plugin simply use what the engine already done.
the base engine doesnt include blueprint exposition of the subobject replication?
not bp support
right, this plugin does that
Yeah but it sounded like you are implying that this plugin somehow become a feature in the engine.
i was asking if it had
I am just saying it's the other way around, the author simply expose functionality to bp.
@sinful tree I made a rookie mistake... everything was working already after I changed it to your suggested concept here: #multiplayer message
it was working immediately... just replication didnt... because i forgot to tick replicate on the 3D object i was interacting with, it was turned on on the Actor Component alone... well thanks for the help 😄
Mobile games networking architecture - games like Summoners War (genre) - are these using a dedicated auth server model? Or is thereanother light-weight way that pulls this off? My concern is the lack of support for multiplayer playerbase of 1000's/10's/100's even million playercounts? Who knows how many concurrent players there will be at any given time.
i'll safely assume that it is good standard practice to split to servers - where i have couple 100 per server - scaled dynamically. Think GLOBAL CHATROOM #66 - where theres N# of players per server... and a dedicated server appointed to this server. This seems the most scalable architecture i can think of - if i need to leverage DediServer architecture
Dedicated Servers will fall apart with more than 100 players, even with Iris.
i was thinking of Ark architecture with this... even how old that is - i dont know how its increased over the years....
Idk what Summoners War is, but if you need something more lightweight that isn't even utilizing the "live" gameplay that a DediServer offers, then you'll have to code it yourself.
ok
A Chatroom system is 100% nothing that should utilize unreal's networking. That makes no sense.
If the fights in that Summoners War game are asynchronous, then you most likely don't want to do this with Dedicated Servers. Idk what the gameplay is though.
it was an example of what hte game really is - most of it is single player gameplay (few instances of GUILD/SOCIAL based gameplay) but sitll needs authoritative stance.
Yeah, then I wouldn't use a Dedicated Server at all.
so i need to design my own authoritative stance - got it.
time to grab my Harry Potter wizard hat....
Last time I had to work on something like this we had a server written in Go. The player selected what units they played and where they were positioned. Backend knew if the player even owned those units. Go server then validated the placement, checked what level the player is in and simulated the fight. Then it send the client the instructions on how the fight went.
you just answered my questions. ok
Idk if that matches the gameplay of that Summoners War stuff, but Mobile Games that are "singleplayer" with auth state are mostly similar, so this probably aligns.
kind of - the game is turnbased with like 5 characters each. it could be a map/set of the turn & the results each character/enemy - so the client can just simulate the gameplay but it is directed by the authoritative stance.
Yeah, that's fine. Server still has to simulate it too, for rewards and such.
crits/etc could be calculate dby the server/auth ... sent to player as results and the client just animates teh combat with the results already pre-determined.
yah
ok
this makes sense...
But this is mostly a "request -> response" kind of setup. Not really live gameplay.
you're correct.
A socket connection to that (Go) server is probably enough.
right on - i'll go this approach - i like it.
Idk how to scale that setup, but I assume a simple server application will run 10.000x better than a Dedicated Server.
It's probably similar to having some webservice with a database that receives some requests.
i can setup to scale the server based on network bandwidth & CPU/MEMORY stats
that should be asily done.
Yus
ty Cedric!
what's the best way for ignition sound to play?
this is my current approach using a trancient component
void AVehicleBase::Multicast_PlayEngineEgnition_Implementation()
{
if (HasAuthority())
{
return;
}
if (!IgnitionSound) return;
if (TransientIgnitionComp)
{
TransientIgnitionComp->DestroyComponent(true);
}
else
{
TransientIgnitionComp = NewObject<UAudioComponent>(this);
if (TransientIgnitionComp)
{
TransientIgnitionComp->RegisterComponent();
TransientIgnitionComp->SetSound(IgnitionSound);
TransientIgnitionComp->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
TransientIgnitionComp->bAutoDestroy = true;
TransientIgnitionComp->Play();
}
}
}
will spawn sound at location makes more sense or it doesn't matter?
SpawnSoundAtLocation is more performant (it doesn't require an AudioComponent) but its not attached
So its more of different use-case kinda thing~~
I think for one time use case I should use spawnsoundatlocation
Could anyone help me out here? in a repnotify when the bomb is set to detonating it casts to the bomb timer widget to display the time text, but for some reason i cannot get the widget to access the float it always comes back as 0
trying to make things work even for players who join late
@rough dock If this is running on a Dedicated Server, the Widget wont exist for the Server.
yeah it runs on server
Are you using a Dedicated Server or a Listen Server?
listen server
its the same thing
value is fine in repnotify but in the widget it reads 0
i can get the timer to work fine with a multicast but i cant get it to work with repnotify
and this code works perfectly fine too
got it to work with this in the repnotify
its pve so i think its okay, i cant let the enemies be pushed with delay its feels so bad
on the unreal-engine-best-practices-for-networked-movement-abilities, it says that it can be done but i dont understand how
networked movement abilities in this case are mostly in reference to players moving around where responsiveness without jittering around matters
that said yes you could apply this advice to other "actions" in an abstract way
as for how to do stuff like this
there are things you have control over and there are things that I would suggest not trying to replace
unreal gameplay data replication is always from the server/authority to other clients
this includes the creation/destruction of objects (with some ways to "tear off") and replicated properties
I would recommend against modifying replicated properties on the client locally to try to predict things if possible. It is going to break some assumptions unreal makes
But what you CAN almost always do is choose WHY AND HOW those replicated properties are used. Especially in C++
For example, let's think about actor transform replication (in the basic sense)
The actor's root scene component transform represents where it ACTUALLY IS locally on the client. Notice how the actor transform replication is a different property?
see: AActor::OnRep_ReplicatedMovement etc
This is good news for us because this means you have two separate things...
- The replicated transform location: The server's most recent "idea" of where the actor should be on the authority which is a bit behind due to ping (which is why this jitters around a bit)
- The actual final local transform of the object
If you look at AActor::OnRep_ReplicatedMovement or ACharacter::OnRep_ReplicatedMovement if this is a character (note it OVERRIDES the parent)
you can see they choose whether or not they want to apply this
You can too
In fact, you could even just call OnRep_ReplicatedMovement whenever you want to re-apply it
The important takeaway here is that you can override virtual Onreps to replace them entirely, change what they do, or even just call them whenever you like
You can even directly disable specific replicating properties of a parent class with certain macros if need be (I generally do this in order to replace them with my own better ones that fit the project)
I'm not sure how your enemies work though, @sharp mason
take note for ACharacter there is a secondary codepath for standing on a moving platform (based movement) but for simulated proxies generally they just get the regular OnRep_ReplicatedMovement with velocity and a few other replicated properties to see if they are crouching or jumping
In reality their position is actually quite jittery
But the Character will smooth the position of the mesh relative to the base to make it look better with a small amount of extrapolation mixed with interpolation. You can control this behaviour as well and it's important to note here as it could change how it looks
My general impression for what to do here would be that you want to basically have the client say "No, we are definitely moving this way" for a bit and have it ignore new server onreps for a moment
How you do this is pretty open-ended I guess... I don't really know what the data relationships are between these two things or what the knockback can and can't do
I would say definitely don't completely destroy the actor for "death" until it's legit 100% correctly dead... You can't really easily restore a destroyed actor torn off on the client so hiding it ahead of time would be superior imo
Also rolling back might get confusing... You can do this in a ton of different ways and even be more "permissive" if it helps
basically the player can kill enemies in specific ways that will trigger a root motion animation that send them flying away, what i first want to achieve if possible is that the simulated proxies block the server movement for a while, play the root motion animation, IF for someway (only hackers i think) it did not die, i just revert it back to its position (it will be "bad" visually but responsiveness on my pve game is more important)
you have good judgement there I think... I would say most of us have more to worry about making a game anyone would care to cheat in than cheating
As the enemies are flung away does their state influence the world around them? can they collide into other enemies or block anything on the way?
no they only collide with static objects like wall, so it dont go inside the wall, otherwise its pure cosmetic
If they don't have an influence on the simulation after being sent flying it might matter even less to make it perfectly match up with what happened on the server and peers
Which is helpful for simulated proxies of other players I guess as it means you don't have to be quite as careful if they could end up in different spots without it really mattering much
(It's fair to want it to be similar anyways, just saying it might not be do or die)
For now i am trying to understand what is blocking my rootmotion to move the character, i dont if PerformMovement just simply ignore it on simulated proxys, or its just the server overriding its position
well
for starters you need to consider the root actor transform and the visual mesh relative offset as separate in some cases
they might be way off depending on what is happening... make sure you visualize the true capsule location just to make sure
Of course we mostly care about the visuals here but it might help illustrate what happens
I'm not really sure what root motion does to smoothing honestly, I've never had to mess with that codepath
Can you visualize what happens when you apply root motion locally on the client first? I'm not sure how this is happening etc
I guess FWIW
it doesn't matter how it moves as long as it works... you can do basically whatever
if you override all of the places the server tries to re-apply the final position you can absolutely take over the location
what is currently happening that i am not understanding how is, on my client i start the animation early it moves the character instantly back, then the server is playing the animation too and overriding its position, so i thought ok i just need to turn off movement replication, i turned it off and now there is no root motion at all
you probably only want to turn it off locally on the client when they predict the death
you still want them to replicate normally before that, riught?
remember: these are different machines in a sense
one downside though is that bReplicateMovement is replicated
oh yes but i tried the most absurd approach to see what happens, and what happened was not what i expected
you might want to override OnRep_RootMotion, OnRep_ReplicatedBasedMovement, and OnRep_ReplicatedMovement and add a new branch
so you can ignore the other things fighting over your new value
even with the on replicate movement false, those functions can still be called ?
well, you need replicate movement to be on before
note that bReplicateMovement is ironically itself a replicated property
I generally would advise against modifying replicated properties locally without having a way to restore the original value but you can if you want
Maybe i am trying to understand a problem that should not exist on a normal situation and i should give up , but for me its extremely confuse, set it to not replicate on editor, put the enemy on the map, shot him on the client it does not move with root motion, turn everything back on now root motion works but the server corrects it, like how is it no playing with no replication ?
Just leave that on for now... you don't want to disable replcating any movement
My guess is that root motion still works because of ACharacter::PreReplication
notice how it branches on either having IsReplicatingMovement or root motion
yes i am seeing it here, okay ignoring this strange behavior
I think for now focus on making the client "take over" the enemy character more or less during the prediction of their death
You can figure out how to make that work well on the server and other peers later
I now have what i want the root motion is playing on client, but the server also trigger the animation and move it back again, kinda playing it twice, should i override OnRep_ReplicatedMovement ?
I think you should be able to just set SetReplicatingMovement to false on ONLY the client when they start pushing them for now
note that even though this is false it doesn't stop you from RECEIVING data
it only stops you from APPLYING the data from the server
the most recent received transform will always be there. It can be restored at any point you want
I'm not sure about the root motion parts though and I imagine you might need to pave over the server's idea of root motion if it's getting stuck right before hand
but when i set SetReplicatingMovement to false on the client only, it stop playing the root motion locally too
thats where i dont understand
okay, well
I guess we can see if that root motion is being removed somehow...
If I had to guess it would probably be UCharacterMovementComponent::SimulatedTick
In which case...
I would have to debug it to see
I'm not sure which branch is being taken or if something is overriding the root motion source
yeah i think i can take it from here, so i dont take you more time on it
I would say for now definitely consider overriding what I mentioned earlier: #multiplayer message
You can mess around with having your own local boolean value that the client sets locally to override this
ok thank you
One crazy route you could take could potentially be copying a completely different object/state/component etc to serve to represent the predicted state but I don't think that will be necessary here
it's straightforward enough to override the state being applied here
I would say definitely take note that simulated proxies have a different codepath so... if you have a listen server they might need to just do this differently
the CMC is a lot of code but the simulated proxy side we care about right now is actually not that much... it's mostly some onreps as mentioned earlier
There are also things like OnRep_IsCrouched
yeah i thought about it to use an extra actor for the death, but I will need to copy the dismembered body parts, the material for the hitted parts and other states of the actor to have a copied death body, so is a tough route
If it helps you can actually ignore the server telling you to destroy an actor in certain ways
tearing off etc
this can be useful if you want to keep it around for visual reasons but don't need it on the server
yeah it would be fairly expensive to make a new thing as well unless it was pooled...
ideally you keep the same mesh somehow
i think i found why it does not work if replicated movement is false haha
if (CharacterOwner->IsReplicatingMovement() && UpdatedComponent)
and then it do the root motion
you saved me a lot of time
glad I could help
now as you suggest i should override this guys OnRep_RootMotion, OnRep_ReplicatedBasedMovement, and OnRep_ReplicatedMovement, right ?
That's what I would do to try to control the places the server will try to apply state on top
there might be more
The server might change the replicated movement mode or if they are jumping etc as well
so there is not a single place that all movement replication variables are applied, each replication function set a specific thing ?
i achieved a similar predited knockback with a custom FRootMotionSource and a few overrides in the CMC to ignore server corrections when this specific root motion task is running
since this is a death animation you probably dont even need to handle the smoothing when reactivating the server corrections
they are unfortunately a few different onreps. I agree with you that this is a bit annoying
One issue this can cause is sometimes the onreps can arrive on different frames and be offset which is frustrating
If you want you can replace them all with one holy onrep but it will require some more work
do you remember what CMC overrides you did ?
I would assume OnUpdateSimulatedPosition and or SmoothCorrection ?
yeah for now i dont want any big changes
but yeah I'm not clear on how root motion works so I will defer to their judgement
SmoothClientPosition (return when the RMS is playing) and SmoothCorrection (teleport back to the previous position and return while the RMS is playing)
you dont need a custom root motion source for this, you can use a simple bool flag on the client. i was experimenting with different solutions so thats why i had one
oh nice ty, i started testing overriding OnRep_ReplicatedBasedMovement but it alone did not work
bool UTerraCharacterMovementComponent::HasActivePredictedKnockback() const
{
for (const TSharedPtr<FRootMotionSource>& Source : CurrentRootMotion.RootMotionSources)
{
if (Source.IsValid() &&
Source->GetScriptStruct() == FRootMotionSource_PredictedKnockback::StaticStruct())
{
return true;
}
}
return false;
}
void UTerraCharacterMovementComponent::SmoothCorrection(
const FVector& OldLocation, const FQuat& OldRotation,
const FVector& NewLocation, const FQuat& NewRotation)
{
if (HasActivePredictedKnockback())
{
// The engine just teleported the actor from OldLocation (our predicted position)
// to NewLocation (the server's lagged position). Undo it, the server should end up
// in the same position once it catches up
if (UpdatedComponent)
{
UpdatedComponent->SetWorldLocationAndRotation(
OldLocation, OldRotation, false, nullptr, ETeleportType::TeleportPhysics);
}
return;
}
Super::SmoothCorrection(OldLocation, OldRotation, NewLocation, NewRotation);
}
void UTerraCharacterMovementComponent::SmoothClientPosition(float DeltaSeconds)
{
// Suppress server position smoothing while a predicted knockback source is driving this
// actor movement
if (HasActivePredictedKnockback()) return;
Super::SmoothClientPosition(DeltaSeconds);
}
fwiw i deleted all this code for knockback prediction so take it with a grain of salt