#multiplayer
1 messages · Page 277 of 1
There's a GetServerTime that stays in sync across clients that is useful for this.
AGameStateBase::GetServerWorldTimeSeconds()
The problem will be that just one time won't be enough.
Or rather, seeing it as one truthful value isn't enough.
It becomes more obvious if you exaggerate the individual pings of two clients.
If one client has a ping (RTT/2) of 1.0 seconds and the other of 0.5 seconds, then the position of the Pendulum will be 1.0/0.5 seconds behind for the specific client. So they already see different pendulum positions if you were to overlap their views.
If the client with 1.0 seconds ping now starts walking when the pendulum is not blocking their way, the client may dodge the trap locally, but the move will take 1.0 seconds to reach the server. At that point, the server's pendulum will already be 2.0 seconds ahead of what the client saw and reacted too.
To keep it simple, let's assume the Pendulum needs roughly 2.0 seconds from center to outer edge. And let's further assume the first client started walking when the pendulum is at the outer edge from its point of view. At that exact moment the pendulum is already 1.0 seconds ahead on the server and on the way back to the center. 1.0 seconds of time for sending the server move, and the server will walk the client right into the pendulum that is now in the center on the server.
And since client two has a different ping, you can't adjust the time to only match one client.
So the tl;dr of this is that you will need to take the individual clients ping into account. Or you need to make it client authoritative if you don't care about cheaters.
Surely the replicated server time is already in sync on all clients, regardless of ping. So if everyone starts the sequence at server time 100.0 they should all start at the same time?
Its not millisecond accurate, but its pretty close.
Isn’t there any entire website dedicated to how not well in-sync the network time is?
Pretty sure it's just an average value of a bucket of times that gets reset every few entries.
Yeah there is a pinned post about a better one iirc
Is it possible to replicate physically simulated actors welding in 5.7? (by welding I mean "weld simulated bodies" option in attach actor to actor node). I tried new physics prediction and it seems to work okay, but the welding still doesn't. In lego fortnite it's possible to assemble moving objects so I suppose there's some way, maybe not attach actor to actor but something else. Anybody knows?
i'm pretty sure lego fortnite uses UClusterUnionComponent under the hood.. not much documentation about it besides the comments in the source code but i think its usable in blueprints
I never heard about it, will try to figure out
Do you know how to use it? I created a cluster actor and added 2 sm comps under the cluster component, then added their names to the cluster but they just break apart like 2 separate physics objects. I'm not even in multiplayert mode yet
hmm i seem to recall a modular vehicle component example adding the components at begin play with the "Add Component To Cluster" node..also i think it takes an array of bone id's which for static meshes was a single entry of 0
and pretty sure you want to add the components as authority only for networking
but i've never used it personally so there might be more to it lol
do you need to replicate the whole component to get a single variable on it to replicate ?
on the player state*
Ok, after some code digging I think i start to understand how it works. First, you need to use AddComponent because the array of comp references is not handled correctly in their code. And second, it doesn't works with SMs, but works with geometry collections, because SMs are missing some physics body id or something like that
And the array can be empty, it means everything in the GC is added to the cluster union, otherwise you can add only selected GC parts, identified by their bone ids
And it replicates if Physics Replication Mode is set to one of the new modes
Pretty cool stuff!
I have a Actor Component that takes Data Assets that provide values on how an item is held, how much it sways, if you can aim, etc. This AC can be added to any item and then when you equip the item animation will update based on the data assets that AC has set. Does it make sense to keep this AC on every single item or would it be better to put it on the character and when an item is changed just update the DA that the AC references?
I have an issue with using Listen server, when the host dissconects i destroy the session, afterwards clients cannot join or create a session due to them being still in an session as what i see in the logs: [FOnlineSessionSteam::JoinSession] Session (GameSession) already exists,can't join twice, added my disconnect logic and made a mutlicast to see if that changes anything wich it didnt, any suggestions?
Just destroy it before doing a search for a new session. (or when the main menu widget loads, or etc)
Cuz, if this is meant to happen when the host disconnects, it would never work?
Cuz, the host would be long disconnected, by the time the multicast works?
normally when the host destroys the sessions the clients should be disconnect right? but somehow still be in that session, so disconnect them first?
I believe "disconnect", and "session" are 2 separate things, but I could be wrong. 😛
But, I just destroy the session when my main menu loads.
Works fine, and has no issues.
No need to handle session in the active lobby, cuz various factors can/ will just skip that (aka, unintended disconnects, lag with your current method, or etc)
i know they are different meant it in a different way but ill try to destroy session on loading the menu, thanks for the advice!
Any website, or understanding of when you should do a major version, that forces the game version to match to play?
Should you do it any time an RPC is changed, and when a replicated asset is added/ removed?
hard to say but basically if serialization of properties would bitStream overflow
etc
some things kinda bake their "settings" into the serialization but some don't
I would say it's better to be safe than sorry here
sometimes I have had situations where we wanted to fake a version id to connect anyways given we knew it was mostly okay but that was mostly for debugging
Is there an obvious way to know when this happens.
Or, just gotta know?
Such as, adding a new replicated var would probably change this bitStream?
well, you will disconnect and get a nasty error message 😛
I feel like you are trying to gauge when it's okay to accept a different version but I think there are too many things
basically changing the "shape" of the serilization where it reads
- something different unintended
- it reads MORE than the original message sent (adding a new thing that the sender didn't know about)
will break
as the project gets going I think the amount of shape changes will decrease over time
I feel like games reject different versions connecting for a reason though
if you deploy a server side only code-only fix that doesn't affect replication shape at all it might be okay etc
How about stuff like un-replicated variables?
Would that change the shape, simply be existing.
(like if I add a new one)
or, does the shape only change from things being marked for replication
wellll
it would depend on how it is read and sent
the only things that change the shape would be the things that end up in the serialized packet
and HOW each side READS AND WRITES said packet
let's say you have a user that upgrades from version 1 to 2
version 1
int32 OGVar
version 2
int32 OGVar
int32 NewVar
They receive a packet describing the state of version 1
they read the bits of OGVar and all is well, but NewVar ISN'T THERE and the reader overflows the packet buffer if they are reading it sequentially
this can depend on a lot of things like bitmasking and delta serialziation or whatever
But, wouldn't that only happen for replicated vars?
I'm just talking about an un-replicated var.
Or, would the literal order of var decleration mess with it?
the non replicated variables should not affect replication
unless they change the order somehow from shifting things around
but idk how actor channels or iris orders members (it might be stable)
you can read the source or use network insights to see the shape of each packet
Oh, ok.
Didn't realize that.
Just working on shit, and haven't messed with any of the new debug tech. 😛
network insights is like 5 years old now afaik
Most of my experience is on UE 4.05.1, so. 😛
that is oddly specific... are you reverse engineering another game?
Modding. 😛
Well, was
Moving onto actual game dev.
But, most time was spent on 4.5.1
So, curious for anyone who sees this.
and, maybe I just missed the entire old convos of it.
Cuz, someone told me it happened/ affected to base Unreal Engine as well.
That, apparently bool, and/ or default value replication was super buggy and glitchy around the UE 5.2 - 5.5 range.
Specifically in the capacity of:
Default = false
Some player ROS changes it to = true, perfectly normal all the time
But, if a player ROS then changes it back to = false.
The clients just wouldn't receive that false bool replication?
Same with ints, and supposedly every type.
(not involving structs, or special stuff, just a normal bool var)
This surely seems impossible that base UE was affected by such as drastic, and "bad" issue?
Just replication not working as designed, with all the value checks, and the fact that var changes are reliably sent to clients.
There is one special case where this happens but despite that it should work fine.
Also not sure if that's still the same with Iris by now
void AHitScanWeapon::Fire(const FVector& HitTarget)
{
Super::Fire(HitTarget);
APawn* OwnerPawn = Cast<APawn>(GetOwner());
if (OwnerPawn == nullptr) return;
AController* InstigatorController = OwnerPawn->GetController();
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
if (MuzzleFlashSocket && InstigatorController)
{
FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
FVector Start = SocketTransform.GetLocation();
FVector End = Start + (HitTarget - Start) * 1.25f;
FHitResult FireHit;
UWorld* World = GetWorld();
if (World)
{
World->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility);
if (FireHit.bBlockingHit)
{
ASoldierCharacter* SoldierCharacter = Cast<ASoldierCharacter>(FireHit.GetActor());
if (SoldierCharacter->HasAuthority())
{
UE_LOG(LogTemp, Warning, TEXT("Damage being applied"));
UGameplayStatics::ApplyDamage(SoldierCharacter, Damage, InstigatorController, this, UDamageType::StaticClass());
}
if (ImpactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(World, ImpactParticles, FireHit.ImpactPoint);
}
}
}
}
}
void UCombatComponent::Fire()
{
bool bIsValid = bFireButtonPressed && EquippedWeapon && EquippedWeapon->IsMagEmpty()==false && !(SoldierCharacter->GetSoldierMovementComponent()->GetIsSprinting());
if (bIsValid)
{
ServerFire(HitTarget);
StartFireTimer();
}
}
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarge)
{
if (!EquippedWeapon) return;
if(SoldierCharacter)
{
EquippedWeapon->Fire(TraceHitTarge);
}
}
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
MulticastFire(TraceHitTarget);
}
void UCombatComponent::OnRep_CarriedMagazine()
{
Controller = Controller == nullptr ? Cast<ASoldierPlayerController>(SoldierCharacter->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedMagazine(CarriedMagazine);
}
}
void ASoldierCharacter::BeginPlay()
{
Super::BeginPlay();
if (HasAuthority())
{
OnTakeAnyDamage.AddDynamic(this, &ThisClass::RecieveDamage);
UE_LOG(LogTemp, Warning, TEXT("Damage Binded"));
}
}
void ASoldierCharacter::RecieveDamage(AActor* DamageActor, float Damage, const UDamageType* DamageType, AController* InstigatorController, AActor* DamageCauser)
{
UE_LOG(LogTemp, Warning, TEXT("RecieveDamage Called"));
if (Attribute) Attribute->TakeDamage(Damage);
}
the issue is character is not taking any damage from hitscan weapon, so i cannot see my blood screen on the UI.
first of all you should not use the actor damage system.. it is getting removed eventually (annoying, but making some simple component or interface should be simple enough)
"issue is character is not taking any damage from hitscan weapon I have NO idea which one of these functions is firing or what is in them
I cannot compile or run code just from looking at it
Yeah, that’s what I assumed.
No special case, just actor + bool + ros to Change it.
I found it near impossible that UE would be so crippled for even 1 version, let alone at least 3 in this case.
That specific issue exists since forever. But yeah.
Huh?
How so?
To me, it seems so wildly broken, that I wonder if you miss-understand what I’m saying?
Seems crazy to me that basic type replication is broken “since forever”
The thing I mean is this:
- Replicated Actor Blueprint
- Add Boolean Variable
- RepNotify
- Instance Editable
- Default Value: False
- Override BeginPlay
- SwitchHasAuthority
- Set Boolean Variable to False
- Add PrintString to the OnRep function of the Boolean
- Add Boolean Variable
- Place an Instance of the Blueprint into the level
- Set the exposed Boolean on the Instance to True
- Press Play
- With 2 Players, ListenServer
Expected Result: Server and Client will call the OnRep and print the PrintString, because the Instance has the Boolean True and the Server sets it to False on BeginPlay.
Actual Result: Client won't call the OnRep as at the time of receiving the data it will compare the Boolean value to the Archetype of the Blueprint, where the Boolean value is False. And since that equals the received value it won't call the OnRep.
@halcyon ore
No.
Not that at all.
I did recently see that.
But, that’s not what I’m talking about.
Right, then I don't know of any other bug of this degree.
Yeah, that’s what I expected.
Cuz, what this person is reporting as a whole engine/ UE issue is.
Replicated actor, replicated bool
Spawn at runtime.
Server changes to true, all normal
Server changes back to false
Any new relevant clients are fine.
but any clients currently relevant during the change, just have a 50/50 chance of not receiving the false change, and being stuck on true.
No special instance stuff.
Just as simple as GameMode spawning an actor on startup, and changing the bool every 1-2 minutes has the issue.
UCombatComponent::Fire calls for server RPC in case the fire is being called from client. Then the server would call fire from the EquippedWeapon which has only job to spawn casing, muzzle flash etc but hitscan weapon is a child class of weapon so it overwrites the fire mechanics and do the line trace with some extra extent to detect the hit bone/actor. Then the applydamage would be called.
Take damage is binded in character which calls Take damage from attributecomponent containing code for COD style health system when hit, timer will start and if player get hit again, it'd start again but if player is not hit and timer complete, the regeneration of health start
I do not think that extra context describes which part of this code doesn't do what it expects you to
what part of this works? what part of this doesn't? does the rpc reach the server? does the linetrace hit?
showing the code is great but I can't just guess what part of these 200 lines isn't doing what you want
debug it
Ig the line trace maybe issue, I'll check it out.
FIXED
this is the kind of stuff you should check yourself
I think you are doing fine but putting in a decent effort to debug it first will save a LOT of time
Yes, and actually found the second problem and debugged it. Though not a proper solution, as I'm having 2 mesh and 1 weapon mesh. So during fire, the line trace is hitting it self and when I added actor to ignore it include all same type of actor such as player 2 (clients & server both)
So I'm looking at it now.
In blueprints, If I mark an event reliable that guarantees the event itself will be called but it doesn't guarantee that any subsequent events or functions called by this event get called, right? They would have to be marked reliable themselves as well to guarantee its called? So in BPs I cant guarantee any function actually gets called I would have to make it an event to mark it reliable, yeah?
reliable means the communication between client and server can be relied upon for that RPC or property change.
anything that isn't networked depends on the reliability of a RPC.
if I send a reliable RPC to the server, everything that RPC triggers is guaranteed to happen. if the RPC triggers another RPC, then everything else depends on the reliability of that RPC.
reliability only matters when going over the network
if you call a function or event locally it's always going to occur (it would be impossible to make a program otherwise)
IMO, if you have RPCs triggering RPCs, might be best to evaluate design
void AHitScanWeapon::Fire(const FVector& HitTarget)
{
Super::Fire(HitTarget);
APawn* OwnerPawn = Cast<APawn>(GetOwner());
if (OwnerPawn == nullptr) return;
AController* InstigatorController = OwnerPawn->GetController();
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
if (MuzzleFlashSocket && InstigatorController)
{
FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
FVector Start = SocketTransform.GetLocation();
FVector End = Start + (HitTarget - Start) * 1.25f;
FHitResult FireHit;
UWorld* World = GetWorld();
if (World)
{
World->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility);
DrawDebugLine(World, Start, FireHit.ImpactPoint, FColor::Red, false, 5.f);
if (FireHit.bBlockingHit)
{
ASoldierCharacter* SoldierCharacter = Cast<ASoldierCharacter>(FireHit.GetActor());
if (SoldierCharacter)
{
UGameplayStatics::ApplyDamage(SoldierCharacter, Damage, InstigatorController, this, UDamageType::StaticClass());
}
if (ImpactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(World, ImpactParticles, FireHit.ImpactPoint);
}
}
}
}
}
when i fire, the player hit itself instead of player at which gun/weapon is aim at. then i tried to use FCollisionQueryParams in which ActorIgnore i added GetOwner(), then it made all player character to ignore the line trace.
where do you ignore the player in the line trace?
i tried before it didn't worked well then i removed it
if you don't do that you're pretty much guaranteed to hit yourself unless it's on a different layer
i did that then the line trace was ignoring the other player too
did you add the other actor to the ignore list?
i added GetOwner()
that shouldn't ignore the other player then
so something else is causing it to not collide
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(GetOwner());
World->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility, QueryParams);
this is my code when i added Ignore Actor
Also, i have 2 mesh
1 - full body (for simulated proxies to see)
2 - Arms only (for player controller)
like cod
but the weapon is attach is single mesh based on IsLocallyControlled
how are you calculating start and end?
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
if (MuzzleFlashSocket && InstigatorController)
{
FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
FVector Start = SocketTransform.GetLocation();
FVector End = Start + (HitTarget - Start) * 1.25f;
what is Hit target?
Send via this
HitTagret is being calculated in Tick calling CrosshairTrace function which is doing LineTRace per frame
void UCombatComponent::CrosshairTrace(FHitResult& HitResults)
{
FVector2D ViewportSize(0.f, 0.f);
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(UGameplayStatics::GetPlayerController(this, 0), CrosshairLocation, CrosshairWorldPosition, CrosshairWorldDirection);
if (bScreenToWorld)
{
FVector Start = CrosshairWorldPosition;
FVector End = Start + CrosshairWorldDirection * TraceLength;
GetWorld()->LineTraceSingleByChannel(HitResults, Start, End, ECollisionChannel::ECC_Visibility);
if (!HitResults.bBlockingHit)
{
HitResults.ImpactPoint = End;
}
}
}
so your linetrace end is dependent on that line traces end?
that does not make sense
// Called every frame
void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (SoldierCharacter->IsLocallyControlled())
{
FHitResult HitResults;
CrosshairTrace(HitResults);
HitTarget = HitResults.ImpactPoint;
}
}
you are trying to linetrace from your gun to shoot something, right?
CombatComponent is doing line trace each frame even if u don't have weapon.
once u click fire button, a multicast fire is called from server rpc. that fire will call EquippedWeapon->fire(HitTagret)
the other player
yes
why does it trace each frame?
to change the color of crosshair
which i'll add once i found a texture of crosshair
and interactions (future interactions such as door, etc)
does this cross hair trace work correctly?
like I'm fairly certain the end point of the trace isn't being calculated right
it should just be Start + RotatedUnitVector * length
yes
wait i'll retest it
gotcha, line trace again messed up
does anyone know what is the best way to replicate a actor component in the player controller to the HUD/user widget
currently I have the onrep trigger a delegate to broadcast to the huds but since HUD is on the client it doesn't recognize the delegate as bound and doesn't send( if I understand it correctly)
I thought maybe replicate from the player controller to itself so I can access it client side for whatever I may need. although I'm not sure if this is a good idea or seen as a bad way of doing it
"doesn't recognize the delegate as bound" what?
is it bound or not
the player controller is a fine place to replicate things if they are intended for things that are only for you and the server
you can't see other player's player controllers as a client
a HUD should just represent game data
how the game data gets there is not the hud's problem
the onrep of course would only do anything to the hud when the hud is actually there
I add dynamic the delegate in the HUD and when I broadcast in controller isbound returns false
do you bind anything to it?
can you gaurantee that the binding occurs BEFORE the onrep?
if the binding can come later the first binding must also trigger the whatever the onrep was supposed to do
debug it
you may want to read up on the basics of multiplayer in unreal if you are trying to cross over data between multieple player controllers
I am not sure what you are doing here between other players or what changes the onrep
not between player controllers
just one player controller and his hud
independent from each player
if that makes sense
and what is the onrep?
the onrep just calls my delegate to be broadcasted with the updated variable as argument
what order does the hud and onrep happen in relative to one another on each side?
in multiplayer stuff you cannot make assumptions about order much
well my character walks up to an NPC presses a button which sends rpc to adjust the variable and onrep broadcasts delegate
if the onrep happens before it can be bound on the local machine the binding later can just also pretend the onrep just happened if the data is already there
pretty common pattern
the delegate is bound on beginplay
like 0.5f afterwards via timer or whatever it's called
and isbound returns true
upon begin play
never use timers to "fix" netcode...
if that's for the button itself that's fine but you need to not rely on this randomly being .5 seconds
you have still not answered my question about the order of the binding relative to the onrep
I'm not quite sure what you mean by that question
just add a print statement or something... sheesh
I have done that
the delegate gets bound on beginplay
the onrep gets called during play
which broadcasts the delegate
I don't see how you bind it
going off of your description piece by piece is extremely difficult
show the declaration of the binding, the thing that binds it, and proof something actually binds it and the onrep is called on the client
use GetDebugStringForWorld(GetWorld()) to get a nice log that changes for each client/listen server
you need to bind the hud's delegate locally on their machine of course (well, world in the editor)
I have PC->OnMoneyUpdated.AddDynamic(this, & namespace::functionname) which is proceeded by an if statement checking isbound returning true. done in the player HUD
"I forget?"
I'm not at my pc
I don't really think I can help much without seeing the actual code here, sorry
okay no problem
at least I can say consider using AddUniqueDynamic to make sure it's not repeatedly binding but this should not be an issue here
on begin play this returns =bound for both server and client. when called during play returns false
but I can send full code at later time
Well, do you unbind it? is it actually the same playerstate?
Also I am confused
you said this was in the controller
this is a playerstate
remember: I can only read what you show me so leaving stuff out makes this harder
yea this is old picture but same thing copy pasted into player controller
I am not interested in seeing old information and imaging what it looks like...
yea sorry I'll try to post proper code when I can
does the object that representsd the bound delegate get destroyed?
my understanding is the player controller on the server does not know of the HUDs existing. so my thoughts were that because the delegate is bound in HUD it doesn't work
why would the server controller care about the hud?? (for non-local players)
you need to bind this on the local machine's player controller when they have a hud ready
the server of course has all player controllers on it
the hud only exists for you locally
yea
but everyone has a local player controller
if you are only binding this on the server this of course will... only work on the server I think
yea but from the server how would I bind to the HUD if it doesn't know it exists
you wait for it to exist by overriding/binding to various hud related things
LOCALLY
it would be easiest to just do it in the beginplay of the hud itself
which I cannot see and you have not described...
.
snippet
anyways I can post full code at later point I'm sorry I can't now
you said "the delegate is bound on beginplay" which I suppose makes sense to be the hud but I am having trouble tracing through the 40 different messages to piece this together
Help us help you, kinda thing
lol
ye I'm trying
I'll redo
in the playerHUD on begin play, the HUD binds to a delegate located in the PC which is then checked Isbound and returns true. in playtime, I call adjust component via RPC. now In playercontelllerwhich and successfully adjusted the component. Onrep is called. which broadcasts the delegate which fails cuz Isbound returns false.
it works for the server not for the client
So its not bound on the client
yea when called during play it returns not bound
yeah which is why I asked multiple times to see if the onrep was before the hud beginplay or not (the binding I suppose)
Calling the onrep keeps it local to the caller
yea that's what I'm thinking
also initial onrep might not happen if its unchanged
E.g. if server calls on_rep -> the function executes om the server
If client calls on_rep -> the function executes on the client
onrep on client can be called manually by you if you want but otherwise it is from replication only
it's fine to locally call an onrep as a way to make sure it gets called
does it? I thought onrep was specifically server side
What also confused me when i first got i to mp was that i somehow imagined delegates being bound across client/server.
But client and server have seperate sets of these delegates, and must be bound accordingly.
I have. maybe my most recent statement is false but when the onrep is called it's running on server. it says server:delegate not bound
not client:delegate not bound
Then its not bound on the server
so is the onrep ever firing on the client or not?
so how so I bind it to the HUD from playercontelller if server playercontelller doesn't know of hud
You normally dont
the onrep never fires On the client
You need to do it through a replicated actor
then you aren't replicating anything
E.g. playercontroller
we could have saved 45 minutes here by leading with this man
I think at this point I need people to fill out a form proving each log they have fires on both client and listen server or something
the reason it's not firing though if it is on a valid replication property on a replicating object could be that it doesn't think the notify is different etc
read the page I linked
I already have
what do you mean notify is different
maybe it's time to read the page again
Onrep only calls on difference, doesnt it ?
if this entire time this wasn't actually a replicating property I am going to say don't refer to it as an onrep
also you don't NEED to bother with notify always... the actor can just call the onrep function itself locally on beginplay etc
that way you can kinda "respond" to the initial state
you can even override onrep functions from parents if they are virtual in c++
yea i believe the onrep is called initially just to get something but I may be mistaken.
since you have said both that it does fire and that it doesn't fire I think I'm going to go do something else for a bit until you can actually show what is happening
I get it if you aren't around the computer or whatever but I can't really help like this
well I never said it doesn't fire I said it always fires on server but yes I'll post codes when I can and thank you for the help and sorry for the trouble
the reason I asked right before this about the order it happens on both sides (client and server)
was to see if it also fires on client at all
I ask these questions because I want to help
yea just I had no idea it had to fire on the client
like I said in multiple ways before
the server is a separate computer
the server does not see your hud on your client
the client is a distinct physical machine
so in order to use the local hud it kinda needs some kind of callback from either replication or just reading local data as-is
I think it might be interesting to make a simple article/post on how to make a widget work in multiplayer stuff because it seems like an extremely common problem for new people here
Indeed it is
long story short the widget exists LOCALLY on the machine and just reads incoming replication data or does things in response to it on real gameplay objects
in most cases
the widget itself won't be replicating etc
yea
that's why I first asked because I knew something wasn't right because otherwise this would be working to instead replicate the variable to the controller itself instead of sending it to the widget
I tend to push mine through the playercontroller, albeit i dont reaaaallly like the design after a while
if the player controller is getting too crowded you can always make a replicated component on it
or the playerstate etc
Hey, when I'm replicating a variable that's an object reference, am I only sending the address to that object? I'm not sending the size of the object itself, right? This object is replicated in its Blueprint.
(First screen is from the object, and second is from the character blueprint)
Depending on what it is, you're either sending a NetGUID, or a String
For obvious reasons you're not actually sending a memory address
Yeah, I just wanted to make sure it’s not sending the size of the blueprint itself, just the "identifier"
essentially yeah
i am getting this very unsusual kind of behavior
which i am not able to understand from why this happening
like i just opened ue and it start happening
it was working finely befor
i did clean rebuild
the weapon was expected to collide the floor and stay on it
not to dissolve itself inside it
If the player picks the weapon, it should pick it up for the weapon fps mesh on local but on Tp mesh for Simulated proxies
I can't remember if attachment replication is something you can turn off or not (one of those things where I'd have to be in front of a computer to go check, but I'm watching baseball at the moment 😁). But if you're making the attach call on the server, then that will probably replicate down to clients IIRC. So whatever you attached it to would be what it ended up being attached to on clients. Though if you did turn it off, you'd have to make sure that the logic that attaches purely client side, is run when someone joins in progress.
Tbh if you have shadows in your game you'll probably want both a first person and third person mesh for your weapons. (So that you correctly see the shadow of the third person weapon attached to your third person character in the shadow)
I think this is the third time I've asked this question. I use OnlineSubsystemSteam for multiplayer. My engine version is UE5.6.1. I used the method in this video to fix the connection issue. https://youtu.be/Pk_Ki8rV8Wo?si=NaNsplMx2GE_1Qzn
Now I can only join the game through friend invites. The search function doesn't work. However, there's another major issue: if anyone quits the game, the server crashes. The crash log is in crash.log. I've followed other people's suggestions and modified it to the current Blueprint method, but it still doesn't fix the problem.
- Enable OnlineSubsystemSteam AND SteamSockets
- Replace the NetDriver definitions in your DefaultEngine.ini file with the one below!
UPDATED - 7/16/2025
[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefi...
The game map and the default menu map use different controllers, and the picture shows the controller of the menu map
Does anyone else use UE5.6 + OnlineSubsystemSteam?😭
does anyone know why I have this issue with replication:
If I have a character BP enemy that turns into a ragdoll when I shoot it, after I shoot it a couple times once it's already a ragdoll, it's position won't replicate when it moves around from being shot, but if I grab it and move it around it will replicate perfectly
if I have an actor BP, with the same exact logic, it will replicate perfectly
is there a specific difference between character bp and actor bp when it comes to replication?
all the checkboxes and settings for replication are exactly the same in both BPs
maybe the actor has the mesh as the root component where the characters root component would be a capsule
the fully simulated ragdoll would detach from the capsule
Are us using steam sockets?
the error indicated something with the netdriver
when it ragdolls its not attached to the actor so it moves free, thats why the location varies, i use a function timer to get the location and replicate that since the players in my game needs to be revived so the location stays the same
but why its different from when using an actor bp i cannot say
yes
Because the ragdoll physics are on the character mesh, which is not replicated and doesn't replicate physics either (by default it can't either, because non-root components cannot replicate physics). Character position is replicated from the capsules position. Replicating ragdolling players isn't trivial
There are multiple ways to do it, but the way I've done it is a custom movement mode that makes the capsule follow the ragdolling mesh on the Server, and replicating extra info about the meshes rigid body state to clients, and feed that into physics replication locally.
how do you usually handle gameplay relevant replicated ragdolls? like interacting with one to loot it or something
I replicate data from a few rigid bodies form the server and apply it to clients. Not much too it really
If you just pipe the rigid body states into physics replication and switch to predictive interpolation mode, it pretty much does it all for you
Don't need it to be perfect, just close enough
Could you elaborate on that please? I've made my ragdoll replication using physics control to interpolate certain rigid bodies to server location/rotation, but I don't really like how it turned out
How do you replicate widgets?
I am tryna make a health bar like in League of Legends where everyone can see everyone’s health above their head and the bar is also coloured for if they are on team red or team blue.
I am having an issue where every player can only see their own bar updated and the other players just have the widget set to default, so the text block just says insert text.
Anyway around this?
you don't
you replicate the data the widget uses
Locally, on all machines, you color the widget based on the units team compared to the local players team
A healthbar depends on 3 things.
- The units health
- The units team
- The local player's team
assuming you want your team to be blue and the enemy to be red
I have already replicated the data for the health bar(as of now it’s just the team because I wanted to focus on one thing before I added health)
But I don’t know how to use that data properly, I am trying to update all the widgets for the characters with the data I have about them, the team, but I’m stuck to be honest.
show code
I'm assuming this is a widget component that displays the widget in 3d space
Im not at my PC right now, but even if I was it’s a massive spaghetti mess. I call so many things from so many places I don’t think it would help that much.
Could you just tell me how you would do it(if you know how of course)?
Simplest approach is just to have the widget know about the unit it's meant to show the hp of, and be fed that information on begin play.
Then the widget can tick and read its units hp and such and update itself. There's certain optimizations about not wasting work ticking if your hp isn't changing but get it to work first before trying to make it work efficiently
From the POV of the widget it's like this:
Tick -> if MyUnit is valid -> update self based on MyUnit.Health
it has to be told what MyUnit is from elsewhere, you'd do it in begin play of the unit, just pass a self ref to the widget components widget
I am doing that already, and on begin play it’s doing that and working fine, the problem is that when a widget changes and updates(like a health bar does) that change isn’t reflected to the other clients.
The server can see it all fine and on the server side it works perfectly but it’s not replicating to all the clients, the widget just stays how it was when it was first initialised.
the widget should only change and update in RESPONSE to some replicated data changing
widget is the end of the chain
nothing depends on it
first make sure that data is getting replicated correctly
widgets don't replicate, the only way you and i see the same widget is if it was constructed and updated based on the same underlying state which lives somewhere else
I'm guessing you're either not replicating something you should be, or your widget isn't caring about the right unit
Okay, I was (trying) to replicate the team state(I have it as an enumeration), but I guess it’s not working properly then.
Do I need to make an on rep notify event for my team variable on the player state which then calls a function in the widget?
Start with the widget just ticking and reading information
don't worry about talking to the widget at all right now
later you can handle that
don't tell the widget anything besides who it cares about, have it poll and get data on its own to make sure it actually works.
Tick -> if MyUnit is valid -> do stuff based on MyUnits health -> do stuff based on MyUnits team -> ??? -> profit
Eventually yes once you've got this working, however I wouldn't have your PlayerState calling directly into the widget, I'd have an event on the PlayerState that the widget listens to. That way the PlayerState knows nothing about the UI.
The player state triggers the event, it doesn't know or care who is listening to it.
(Or a delegate if you're writing this in C++)
Okay, thanks for your guys advice.
I am thinking that(when I get back to my PC), the first thing I should do is bind my widgets bar full colour a function that gets the enum for my team variable from the player state and updates the bar accordingly. Then later try and make it a bit more optimised.
Is that a good first step?
Yeah that'd be a good way to prototype it. Plus you'll know right away if the team enum is not replicating for some reason
Does a unit have a team or just a playerstate?
What do you mean exactly by unit?
Im new to multiplayer so I’ve never heard that terminology before,
If you are talking about each player then every player has a team which is stored on the player state, although to be fair I move it around quite a bit it’s starting to get a bit messy 😂
Hello 👋
I hope someone can help me out as I cannot find a solution to my issue.
I have a packaged game on Steam which has co-op elements.
I am currently running into an issue where I am not able to normally start up a round in coop with 2-3 players.
Loading into the lobby works fine for host and clients. As soon as I start the gameplay map, either all players or all except the host receive a "Fatal Error" message and the game crashes.
I think it used to work fine but does not work anymore nowadays, even though I believe I have not touched anything regard the multiplayer logic in BP.
Could someone help me out? It would be greatly appreciated!
I launch the game here when the host presses the launch button.
Image 2: Here is the Server Travel logic.
Image 3: This is the game manager in the new map which then does logic stuff.
Thanks!
Are player pawns the only things that have team?
I thought you were talking about a MOBA, where there's creeps
No, it’s just the players
yeah so anyways, it's that simple.
Somehow get the widget to know what playerstate or pawn or both it cares about, and let it pull data to update itself. Get that working.
Then later you can worry about doing it in response to dispatchers etc.
I’m tryna do it now actually but I can’t get it working.
I am trying to just do something basic but it’s not working.
My current system is just when I press 1 update the team and have it replicate but the server is the only one that is seeing a consistent change but on the server it’s updating all 3 widgets even when it’s one person pressing the key.
I made a blank project to test the absolute basics and I got it working there but it’s just not transferring 🤦
show code
Bro, it’s literally the biggest mess ever haha. It’s over a few blueprints as well
I just made this, with the health being replicated and there is a wiudget that just binds to healkth.
So far, for this part it works 100 percent fine, but when I try and integrate it to the actual health bar... it doesnt exactly work
The first one is from the player character, I dont hold the team on the character but rather the player state so thats why I call to the player state. The secvond is what gets called on the player state. The thirtd is ther bind I have on the widget. The fourth image is how we send the player state to the widget. I have two widgets because I did them as world and put them back to back but thats just a stylistic choice it makes no difference here
Start with what I said.
Give the widget a variable for ThingItCaresAbout and let it do the data pulling it wants.
in your widget BP, give it a playerstate or pawn reference and set it from outside. From then on you don't have to talk to it at all ever
Also this is bad
the widget doesn't care about player state 0
it cares about the player state that it's meant to represent the health of
anything with get player state by index or get player controller by index should just be deleted from your project, it's 100% barking up the wrong tree
why is get match player state REF an interface anyway?
The honest answer to that is I just did it and went with it, I didnt really look to much into it cuz it worked.
As for getting the player state, I thought if I got index 0 it meant get the player state of the thing we are in, but if thats wrong then how would you get the player state of the controller/character you are in? Can you just say get reference to self then drag off and search for player state?
Btw I fixed the issue and got it working, I moved the replicated team variable from my player state to my player character, I still sort of store it in the player state but when I update it in the player state I also update it in the player character. I also found that my re notify event wasnt actually firing every time I updated my variable so a made a custom event that changes my variable and fires the necessary events. This probably isnt the best wayb to do things but at least now its working I can start optimising
Without the actual error message and a potential callstack, this will be pretty hard to debug.
How do i get the current size of a FArchive?
(I need to get the size at the beginning and end of a NetSerializer to log how many bits i serialized)
Pawn and Controller have a PlayerState member variable, yes.
So between these two I need to use the one on the right? its kind of obvious now I am looking at the side to side cuz ones marked as replicated
Yes, but it has nothing to do with the replicated part.
Imagine, in real-life, you have 5 people standing in a row.
You ask all of them to place their phone onto the table, one next to the other, but in a random order compared to how they are standing.
While they do this you aren't allowed to look.
After they are done you have two options.
- Ask a specific person to take the first phone.
- Ask a specific person for their phone.
GetPlayerState(0) is option 1. it will give you the first phone/PlayerState in on the table/in the PlayerArray, but you can't be sure that it's the phone/PlayerState of the person you asked.
Using the PlayerState variable (or a getter of the class) directly, is option 2.
who stores this list then? it makes sense that there is a list but where is it? is there some behind the scenes global list of all the player states?
Yeah, for PlayerStates specifically you have the GameState's "PlayerArray".
While it contains all PlayerStates, they aren't necessarily in the same order, because the PlayerArray isn't actually replicated. It gets manually filled due to each PlayerState replicating down to the individual player. So the order can differ.
class APlayerState* UGameplayStatics::GetPlayerState(const UObject* WorldContextObject, int32 PlayerStateIndex)
{
AGameStateBase* GameState = GetGameState(WorldContextObject);
if (GameState && GameState->PlayerArray.IsValidIndex(PlayerStateIndex))
{
return GameState->PlayerArray[PlayerStateIndex];
}
return nullptr;
}
If you can read a bit of c++, this is what that node does.
Gets the GameState. Gets the PlayerArray from it and grabs the matching PlayerState for 0 (or PlayerStateIndex). Or nullptr (nothing) if that index is invalid.
Using those GetPlayerXYZ(Index) nodes is always rather rare.
You usually want to make sure you stay relative to the actor you are in if possible.
That makes good sense, thanks for explaining👍
Let's assume you have a Weapon Actor Blueprint that you spawn for a given Player. Since your Weapon Actor isn't a Pawn or Controller, it has no PlayerState variable by default.
If you want to know the PlayerState of the Player that "owns" the Weapon, you usually want to forward either the Controller (if it's only needed for the local player), the Pawn (if it's needed for everyone), or fwiw just the PlayerState of the Pawn/Controller directly to the Weapon.
So you build that "link" yourself by just forward the relevant data further and further.
Weapon fires a Projectile Actor? Same story. Weapon can give the Projectile Actor the Pawn/Controller/PlayerState.
In most cases, for Multiplayer, you usually specify the "Owner" pin on the SpawnActor node.
to be honest my main point of confusion was I thought that when I got index 0 I was getting the local, I thought the list started at 0 from whatever you were on, so you would get the list in a new way relative to where you are. I know that doesn't really make sense nown I know how it works but I guess thats what learning is😂
And forward the Controller that way. You can then also use the "Instigator" pin for the Pawn for example.
Gotcha, yeah my point is just that you should try to not use those nodes unless you specifically know that what it returns is what you want.
Haha, I am just happy its working to be honest. This is my first time touching multiplayer so the fact it works is good enough(for now)
GetPlayerController(0) is something you will see a lot of beginners fall back to and tutorials plaster it everywhere. And then people don't know why they are starting to get the wrong PlayerController when they try to respawn Client 42 on the Server and the Server grabs its own PlayerController the whole time....
I looked into the exact shit that goes on when that node is used, in case you want to learn that.
Also please read the Network Compendium if you haven't yet.
#multiplayer message
there arent enough good multiplayer tutorials, they all basically stop after the very basics, none of them really explain sutff in great detail. To be honest I think youtubers dont want to cuz they probably dont even know themselves haha.
Yeah, although I would say that a lot of people that make tutorials do this cause they want to share their knowledge and not because they want to do anything negative.
The problem is that they themselves often aren't aware of the stuff they do wrong.
And that starts a domino effect.
Oh, I wanted to ask something about that at some point, since I'm not sure I understand. So on the client side it is safe to assume Controller(0) is always the local controller?
Or can this also differ sometimes
Yeah, I mean I wrote that in the list I linked iirc
Genuinely - the people who do know, most likely don't have the time to do it.
true
I do a tutorial every here and there and even then, it takes up a lot of my time that I simply don't have. Having to also plan a project around teaching someone? That would be extraordinarily long. Especially one that covers production level issues.
I know a lot of peeps like learning via videos and audio. I probably also like that more, but this format has a huge problem: You can't easily update it.
So if I were to make tutorials in the future, I would probably only do more written ones.
Written ones take more time for me 😅
I've been meaning to sit down and write one for the State Trees as well. But guess what? NO DAMN TIME
Yeah, I wrote a lot of documentation for NPP and Mover for my client.
Can't recall if I was allowed to transfer that into a blog post.
Will probably ask in the future.
by the time I will, NPP and Mover will probably be dead

So, if I were ever to do a tutorial on networking stuff - it'd only be concepts and potential pitfalls with the most basic of basics of projects.
Aka the YouTube tutorials oliver doesn't want.
Well - it'd certainly cover the networking of Unreal more than that
I'm talking about not doing rollback or perfect client prediction, etc...
Touché
What I would be interested in making one or more tutorials for would be "Gameplay System Designs".
So like, if one were to make Gameplay System XYZ, how could a few variations be structured to fit nicely into UEs framework and why.
Cause that seems to be one of the biggest problems for beginner and intermediate level. They might understand how to replicate a variable, but they can't connect the dots yet.
Just put everything in the GameState. It's all the state of the game after all.
Easy architecture
Good luck browsing 🥳
*Reliable Multicast everything.
Reliably on tick
I will never forget that one client I had (some VR ArcViz stuff), where they weren't able to spawn a chair anymore and they didn't understand why. Took a me a bit back in 4.idk to find the reliable RPC on tick that was causing nothing else to replicate anymore :D
I'm playing around with replication stuff and I'm seeing a property being replicated without use of DOREPLIFETIME macro. If I add Replicated in UPROPERTY, it seems to replicate without issues (if I remove Replicated, it doesn't replicate at all, of course).
I'm testing this with listen server, 2 clients.
Is that expected?
By now, yes.
What do you mean by that?
At least iirc, Epic changed it so DOREPLIFETIME isn't needed anymore unless you want to do something specific.
Oh nice! You're right, just found that in 5.6 release notes: "Replicated UProperties no longer need to register themselves via DOREPLIFETIME in GetLifetimeReplicatedProps."
This is great, thanks!
oh shit I missed this one, that's nice
but I'm usually opting into push model these days
I'll say I honestly might still prefer to just getlifetimereplicated props
it's kinda nice how it has everything in one place arguably lol
but that is a good change
no need for the boilerplate if you aren't changing anything
Is there an event that i can hook into for when 'any' data was replicated in a UObject ?
or any BP property is replicated ?
PostNetRecieve and PostRepNotifiesseems interesting for this
Hmm nah that didnt work apparently. Never getting called
Hmm. Maybe it is
Im looking for a method that's called only if a replicated property is changed
I can use bp repnotifies but i was hoping to avoid that
PostRepNotifies
is called
only for repnotify tho, not classic replication (i think)
I'd want something for just regular replicated properties aswell if something exists
the point is trying to avoid forcing the user to handle the repnotify updates themself
i am using HasAuthority in most places such as ApplyDamage inside Fire and FinishReload (called via AnimNotify) due to which both system doesn't work and i don't want the clients to do work which can come handy with cheats
such as here
void AHitScanWeapon::Fire(const FVector& HitTarget)
{
Super::Fire(HitTarget);
APawn* OwningPawn = Cast<APawn>(GetOwner());
if (OwningPawn == nullptr) return;
AController* InstigatorController = OwningPawn->GetController();
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
if (MuzzleFlashSocket && InstigatorController)
{
FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
FVector Start = SocketTransform.GetLocation();
FVector End = Start + (HitTarget - Start) * 1.25f;
FHitResult FireHit;
UWorld* World = GetWorld();
if (World)
{
World->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility);
DrawDebugSphere(GetWorld(), FireHit.ImpactPoint, 12.f, 12.f, FColor::Red, false);
if (FireHit.bBlockingHit)
{
ASoldierCharacter* SoldierCharacter = Cast<ASoldierCharacter>(FireHit.GetActor());
if (SoldierCharacter)
{
if (HasAuthority())
{
UGameplayStatics::ApplyDamage(SoldierCharacter, Damage, InstigatorController, this, UDamageType::StaticClass());
}
}
if (ImpactParticle)
{
UGameplayStatics::SpawnEmitterAtLocation(World, ImpactParticle, End, FireHit.ImpactPoint.Rotation());
}
}
}
}
}
Low end thing is bunches
But idk how you read them to know if its a RPC, replicated var or other
My context is a quest system. Where i want a quest task's replicated property to sutomatically update the tasks UI through a delegate
Being subclassed and freely used in bp I was hoping for a method to allow for it to 'just work' with replicated bp properties aswell
I believe there's a post receive bunch or something
It really sounds like you just need a OnRep tho
I mean as long as the client isn't sending manipulated data to the server they can't cheat
Perhaps WithValidate can filter that
And make sure those manipulated players are removed
I just want to remove the hazzle for the person implementing it, having to onrep all properties with manual delegate calls
Though I never found a good example of WithValidation use case
With validate will kick even if a player has a accidental bad data send
So what would be the best way to secure/filter it?
Idk on you to figure that out
Maybe better to use some sort of compositional approach then? Instead of subclassing with replicated properties, have a TMap of data or something
Tmap doesnt replicate. Guess i gotta dive deeper and see if theres anything i can catch somewhere
Its purely for convenience that i wanna make this handled automatically
You would probably want a fast array so you can get per element callbacks
Was hoping Cedric had some awesome wisdom to share on this topic
i mean what kinda data is this
@hoary spear
its a bit vague what your trying to do
maybe a bit more context
does anyone know if spawning actors (a projectile) can work in a predicted gameplay ability. the only results i managed to get is 1. the projectile only spawns on the client, or 2. the projetile spawns twice on the client who fired it (but once on other clients). should i not use a gameplay ability for it? since i might not need prediction for it since that aspect is partially client authoritative (and is partially validated by the server)
abilities dont do any prediction regarding actor spawns etc
if you want predicted projectiles then you should make functions to do that
this is not something supported in abilities out of the box
Hey there! I can't seem to find crash dumps for our Linux dedicated server. I can find logs just fine, but no dumps. Is there something I'm missing?
you ability can call functions to spawn projectile, but you should manage the "prediction" side of that projectile yourself. you could listen for the ability being rejected from server and destroy client side projectile, or accepted, etc.
(if multiplayer isn't the right place and #linux is better, I can post there instead :P)
Its just any user defined or native property that is set to replicate
I want to know about it and handle some callbacks
PostNetReceive
should handle it
COREUOBJECT_API virtual void PreNetReceive();
/** Called right after receiving a bunch */
COREUOBJECT_API virtual void PostNetReceive();```
in pre you could get all the rep properties
cache the value or w/e
then in post see if that value changed
or w/e
Hmmm that might be it yes! Thanks 🙂
Hmm but these wouldnt trigger server side ever, right ?
I could just solve that elsewhere tho , should be fine
Npp isn't dying bro. Epic is supporting it. Publically encouraging others to use it. Makes no sense to have a talk in unreal fest this year specifically about NPP if they are not promoting it or it's out of support .
Mover is already in fortnite granted the chaos one but it's still same component, if it's in UEFN already it's not so "experimental" is it!. Do you have some insider info public isn't aware of , or this is personal opinion?
The message you are quoting was a joke about me not having time to write docs.
NPP always seems to be in this awkward state of almost not happening despite being used in mover
for example unless they fixed it recently it doesn't serialize correctly in iris
it has kinda changed hands multiple times as people leave epic here and there
at least since a few years ago
I swear i saw you say the same thing many many times. Might be mistaken 😅
it's a complicated problem of trying to make a generic prediction system that somehow meshes well with the rest of the random gameplay codebase
they have a lot of cool tooling at least
i have a fire function which do line trace from muzzle socket. It works perfectly for the server but on client the logs are this
LogTemp: Warning: Hit : BP_SoldierCharacter1
LogTemp: Warning: Hit : Floor
LogTemp: Warning: Hit : BP_SoldierCharacter1
LogTemp: Warning: Hit : Floor
LogTemp: Warning: Hit : BP_SoldierCharacter1
LogTemp: Warning: Hit : Floor
LogTemp: Warning: Hit : BP_SoldierCharacter1
LogTemp: Warning: Hit : Floor
Note* weapon is doing automatic fire. Also, it should apply damage which isn't.
void AHitScanWeapon::Fire(const FVector& HitTarget)
{
Super::Fire(HitTarget);
APawn* OwningPawn = Cast<APawn>(GetOwner());
if (OwningPawn == nullptr) return;
AController* InstigatorController = OwningPawn->GetController();
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
if (MuzzleFlashSocket && InstigatorController)
{
FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
FVector Start = SocketTransform.GetLocation();
FVector End = Start + (HitTarget - Start) * 1.25f;
FHitResult FireHit;
UWorld* World = GetWorld();
if (World)
{
World->LineTraceSingleByChannel(FireHit, Start, End, ECollisionChannel::ECC_Visibility);
DrawDebugLine(World, Start, FireHit.ImpactPoint, FColor::Red, false);
if (FireHit.bBlockingHit)
{
UE_LOG(LogTemp, Warning, TEXT("Hit : %s"), *FireHit.GetActor()->GetActorNameOrLabel());
ASoldierCharacter* SoldierCharacter = Cast<ASoldierCharacter>(FireHit.GetActor());
if (SoldierCharacter && HasAuthority())
{
UGameplayStatics::ApplyDamage(SoldierCharacter, Damage, InstigatorController, this, UDamageType::StaticClass());
}
if (ImpactParticle)
{
UGameplayStatics::SpawnEmitterAtLocation(World, ImpactParticle, End, FireHit.ImpactPoint.Rotation());
}
}
}
}
}```
Fire function called like
Fire() -> RPC Server Fire() -> Set Combat State to Firing then EquippedWeapon->Fire same to OnRep.
Personal opinion would be that Mover is probably gonna be used. NPP on the other end I don't see evolving. We have a feed on commits for that plugin and since May this year, the only changes were either global engine changes or their attempt at getting the InputCmd to the SimProxies, which they reverted.
As far as i know only 1 dev made it and he left. Now a really small group of dev working on mover touch it from time to time. But yeah it feela like no man's land but they are promoting it and not burying it
you are leaving out what it is expected to do
for server, it do LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
LogTemp: Warning: Hit : BP_SoldierCharacter_C_1
but for client, it hit server then floor
draw a debug line for both cases
compare the results
also comapre the current physics scene in both with the chaos debugger
it is expected to do the damage which it isn't doing
what's the other case?
not sure what else I could be referring to
you are asking to compare two things
compare them visually and the surrounding area
They did add the smoothing 🤣, yeah i get it feela like there's no NPP expert is there. But am sure they are not abandoning it. I'll sbmit more PRs maybe that will get the ball rolling. But am sure it's not dying
i gotta check that chaos debugger firs.
the chaos debugger is extremely throughal and will show both the collision scene and the queries
so it should help
it's under debug
Honestly, Chaos Mover does sound like the better approach by now.
Having dealt with Chaos Vehicles + NPPMover, it would make things a lot simpler.
what does Chaos Mover do? is it the character constraint or just moving the cmc to tick inside of chaos?
Tools > debug > Chaos debug
Gotcha
I'll check and report back
In simple terms, it ticks the Mover Component through Chaos.
Aka it's part of the Physics Sim on the Physics Thread.
It means nothing for non physics gameplay. No game thread means making sims using it is not that simple. Something for the game thread is a must.
I am doing my own crazy stuff (Jolt/ and going COMPLETE fixed tick without any actors. every transform is smoothed in parallel during render frames etc)
but I have not gotten very far with reconciliation and rollbacks working well
Imagine GAS in another thread..
at this point I am getting a bit fed up with the complexity of full rollback and I kinda want to just do something simple
I don't do everything in parallel and I don't use any of the gameplay framework
the ideal is if you can simulate everything on both sides there is no need for complexity
Megafunk, I couldn't find a good yt tutorial/video. Do you any for Chaos debugger?
but in practice it is absurdly difficult to get a stable sim in a 3d game
don't use youtube videos to learn stuff like this
I'm sorry but you really should just google this
NPP nr 1 goal is to make this simple and you don't have to think about every detail. Once sim is built, 99% of implemented logic is just like single player. No special cases
Okay
yeah but you still have to be specific with replicated data and the storage as unique structs
my stuff is similar in some ways but the entire simulation is stored at once
besides a few rendering-specific things
the main complexity comes from animation and navigation stuff which is hard to make stable and where I kinda gave up on making it perfect
That is part of building the sim. Deciding what "state" (replicated dat) it needs , putting it in struct with cystom net serializer and that is prettt much all. From that point on , it's like singe player.
Example: mover, new mode = decide what replicated data you need, make struct , use struct in your mode and done. Can't get simpler than that
but with npp you don't NEED perfect results I guess
much like quake and all the others it's non deterministic, just very close
I can get detereministic physics already but the surrounding things are a bit too much
if I was making a 2d game it would be fairly simple to make a fixed point math setup that fits all cases and works on all platforms
but I need animation blending so... rip lol
so the idea is something where you have the predicton as a "good enough" approach and the server constantly sends new info
Valorant's way of dealing with the animations to get as "deterministic" result as possible ia pretty good. It's enough for riot should be enogh for us
yeah I don't need anything quite as fancy as encoding blends based on nodes
I just make my entire animation graph fully "immediate"
there are NO results based on previous bones if I can spot them
putting it in struct with cystom net serializer
Does that take Iris into account?
the animation state is ENTIRELY described in a single struct. this is restrictive because of course blends are insanely useful
no
unless they added that recently
so good luck lol
Iris serializers are immensly tedious but aren't that complicated ultimately
Well I know about NPP + Iris. We have that long fixed and working.
Btw, how do you guys hack your own game or do the anti cheat work? Like if I've a project and I want to find the vulnerability to exploit it and fix those bugs/patch them. How do you guys do that for multiplayer?
I don't
Such as ESP, MaxHealth
I'm not an anti cheat engineer
There's a GitHub I saw called UE-Dumper
I didn't fix it, but we yeeted the FReplicationProxy setup.
Can you explain to me why iris support is such an important thing? To me it has 0 meaning. I added my own 100% deterministic delta serialzation to NPP . Iris has meaning is huge world with many replicated actors as it has better push model and performance on the server side. If you're not making a MMO it barely makes a difference
Yeah, it's better to just add EasyAntiCheat ?
Correct me if am wrong
don't ask me lol
not being insanely slow
supporting future versions when iris is the default in a few versions most likely
Iris isn't really fancy about custom NetSerialize methods. So once UE moves away from the current system, you'd need to write Iris Seriliazers, which is a huge pain. We aren't using any NetSerialize method for NPP anymore.
if you don't have a slow netbroadcast /read you might not need to care
IMO they really should have a "I don't care if it's slow, give me a virtual callback" serialize setup as a fallback
but that said I rarely need to make a serializer
default struct serialziation is great
I have my own vector quantize thing becuase the built in ones aren't the right size for me
but it's simple stuff for the most part
The most annoying thing about the built in ones is that they don't have a conversion getter built in :D
also you can just make your own dumb as bricks "send as a uint32 and make a getter that makes it the real type"
there is RARELY a need for a custom serializer for pod types
You still need to write the iris serializers for your own struct tho. And delta serialization is not what i am hoping for. Either send property or not. Is not same as send changes in property only. Specially if that property is 1 single big struct with all sim data.
delta serialization is optional
completely based on settings
atomic serialization is the ideal of course
you will still want to merge multiple properties into one struct for a real fast-paced game (gauranteeing the same frame read)
for example it even delta sends TArrays
you still need fast arrays for a nice callback though
also Iris lets you extend and add your own ID exports in 1 template and even sends gameplay tags over one
basically turning a giant amount of data (a string) into an id based on a negotiation
that is more advanced though
for a larger game with a lot of polling network objects using iris will be kinda required to not have godawful perf I think as repgraph is deprecated
We never had a reason for property-level DeltaSerialization.
Most types we send are already so small that DeltaSerialization gains almost nothing. Per property is totally enough.
And no, we don't have any Iris Serializer or NetSerialize for NPP anymore iirc.
and yeah delta on the individual property barely makes sense for anything but really huge structs and containers
Arrays is what it mostly makes sense for me.
Non deterministic replication is not ok for a prediction system.
As far as i know delta serialization in engine now can cause phantom states, as states on client that never happened on server due to mismatch in replicated deltas. I don't k ow if this is addressed in iris. I stayed away from iris and NPP because it doesn't offer any significant upgrades for a pvp past paced game that doesn't have 100 players. Something like a moba or valorant doesn't need iris at all
you maybe missed the part where I said it is ENTIRELY OPTIONAL
you can turn it off on a per-class basis
you have a fair amount of control over iris replication behaviour
and yeah with a low playercount you might be totally fine
That's all good, but UE will sooner or later move to Iris by default.
What you do in your own project is a different story.
I'm mainly sharing that we have NPP Iris going quite smoothly by now without any problems to outline that NPP can be altered to work with Iris and most likely will if they want to keep it around.
In the context of a simulation and a sync state. It's a singular property with bunch of data.
if it helps unless you have a LOT of custom netserialize or somehow need repgraph the transition won't be too bad
it's mostly literally a cvar (well, or 3)
Unless you littered your code-base with NetSerialize overrides.
which is still useful because replays need those 🥹
Yaaa, DemoNetDriver rest in pieces.
it still works
it can work entirely alongside iris
which is absolute madness but it will work
it will cause a lot of subtle issues though lol
so if you need replays yeah... iris will not help you much right now
Yeah, I can't recall but I think replays are broken on our end. Don't know why anymore though. I vaguely remember that it crashed in NPP but we don't use replays atm anyway.
1st ever epic fix for npp since 2019 was the replay crash along with smoothing for my PR. I think still has something weird with sim.proxy but i don't remember.
Queation: what effect did you see from changing npp to iris? As in gains in perf or bandwidth is actual use case.
Bandwidth I can't tell, cause I never saw the traces for that. Performance increase mainly. But we also have some stuff in Iris multithreaded by now.
Iris multithreaded in main is only for the writing side
arguably it could thread reads but it would be fairly minor of a difference imo
the onrep callbacks cannot be threaded normally
From my experience Biggest bottleneck for sims is the bandwidth The delta serialization i added to NPP is publically available. And to be honest an ability system simulation in any state based prediction system will need proper delta serailization to be realistic.
I think I could add a simple parallel onrep read scheme that is an optional flag for when you know it's okay
but it would be... rare lol
Ya, think someone added it for the read part.
We don't really have any bottleneck at the moment in terms of Bandwidth for 100 players.
yeah its easy enough but the hard part is making it work with the profiler... oof
So I think we are doing fine with what Iris offers.
Hot take: Unreal quantization would be instantly cheaper if you could define play area min and max
you would instantly be able to preclude a giant swathe of bits
it would only be reasonable for VERY specific types
I don't think it was that easy. I know it took a while and touched 20 or so files in the end.
Mover alone user 600bits min per client per update. With net relevancy and all other stuff you don't really replicate all 100 players at once but it can get bit high.
what exactly is it sending in the net profiler?
I've heard it's rough but that's a lot of bits lol
and no I do not mean stats, I mean the actual insights packet view
-DisablePython
-TraceAutoStart=0
-NetTrace=4
-tracehost=localhost
-trace=net,default,task
If you want a tl;dr on how to do that launch with this
edit: also if it doesn't show up in PIE stop and start an empty trace before playing... why does this help? I don't want to spend 2 days figuring it out to fix it lol
the first two are unrelated but still nice
Mover has couple of stuff in its replicated state, they add up. I wanted to kniw how iris helps with this. But it seems it does nothing. just for server pref when having big amount of enteties.
Stock Mover also sends the MovementBase Location and Quat lol.
Keep in mind we heavily modified lots of stuff.
I would say you could compare raw transform sending in an empty project to compare
it should be fairly simple to turn iris on and off outside of mover
here's an example of me sending some float vectors and quaternions as floats
You still seem to be stuck on thinking that I'm suggesting that moving to Iris for NPP and Mover is something everyone should do.
That isn't my point. My point is that the Engine will move towards Iris being the default, at which point custom NetSerializers might become a problem.
If Iris doesn't help your specific project, then that has nothing to do with what I meant.
I am hoping epic fixes the lack of correct serializers in npp instead of forcering everyone to do this
I think it would be fair of them to assume epic will resolve this on their end first
They probably will, yes.
No no, i am asking for personal info , so i know, what differences are there, why this and not that. Checking if i am missing anything.
I would need to trace bandwidth again to answer that. All I can say is that:
- Our Mover is changed a lot. E.g. we aren't replicating MovementBaseLocation and Quat anymore.
- We are running 100 player matches just fine in terms of Bandwidth. Mover/NPP isn't the only thing in the Game either, as one can imagine with 100 players.
as for bandwidth I am not sure I can compare them too closely
I am not familiar with actor channel network id sending/path export etc and if it packs the same way
I will say sending quats isn't THAT slow/huge (they can use only 3 numbers) but it is a bit silly to send an entire quat when you ONLY change the yaw
of a character rotation for example
Quat replication is the worst.
In most cases it's enough to send a packed FRotator.
in the above image you can see it literally being smaller than a position in this case
but yeah a rotator will probably beat it...
16 bit rotator is PLENTY
even for first person
A compressed short is what epic uses for rotation rep is 99.99% of cases.
But that's already the Iris NetSerialize for FQuat, right?
Yeah, idk why Dave Ratti replicates an FQuat for the MovementBase. Let alone why he replicates them at all.
it does quantize the normalized float but it doesn't send 1 number for a yaw only rotation
Mostly asking cause I wonder how the normal one looks like.
hell.. why am I even sending these lmao
I think I am just too scared of converting it to a euler rotation as it's a physics object here
so it being wiggled around is probably not going to end well
this is intended as full 100% reproducable state here
wait... could you not lookup table the most common raw rotations at certain angles?
argh... probably not enough to be worthwhile at the scale here
I've been trying some insane nonsense for positional replication involving cheesing the mantissa bits but I should probably leave rotations alone
man i use custom net serializers so much.. i really hope they figure something out for that
good news is honestly you barely need them in my opinion
for example if you want to have a thing that is marked by a bit for reading/writing you can just make it a nested struct and it will inherently be bitflagged away
which is of course not so nice in the resulting code sometimes
so yeah I am praying they make a MUCH less insane boilerplate Iris netserializer
Hello, how can you identify whether a client has disconnected normally or not? E.g. is there any entry for me to see that the player didn't crash/lost Internet connection/something else?
I want to allow players to reconnect to the game without losing their progress, in case they do that within a certain time period. More specifically, I want to leave the player character pretty much standing where they got disconnected.
However, if they leave the game on their own through the ESC menu, it's considered as they're not willing to play anymore, so the character should get destroyed immediately.
I worked on a rejoin feature at a previous studio, and the main thing that helped out is the client sent an RPC when they voluntarily left
Alright, I was thinking about it, but I wanted to make sure I'm not missing something that engine already comes up with. Thank you 😄
I assume you pretty much did that from the player controller, right?
Also, in that case the disconnect procedure is unchanged? E.g. the client is the one forcing the disconnect on their end, so no server instigated disconnect after the RPC?
what can be the reason for EquippedWeapon is not valid in OnRep_EquippedWeapon() ?
but when i call OnRep_EquippedWeapon() with a .5sec delay everything works fine
void UWeaponManager::ServerSetEquippedWeapon_Implementation(AWeapon* NewWeapon)
{
EquippedWeapon = NewWeapon;
OnRep_EquippedWeapon();
}
void UWeaponManager::OnRep_EquippedWeapon()
{
if (!IsValid(EquippedWeapon) || !IsValid(EquippedWeapon->GetWeaponItem()))
{
printf("EquippedWeapon is not valid"); // <--- this prints
}
}
There's no guarantee for the actor to exist on the client
even if the property is replicated
the actor can replicate & spawn on the client before or after the property does
If the Weapon was just spawned, then the Variable can replicate before the Actor spawned on the Client. So it can call with a nullptr. It will call again once the Actor also replicated and spawned on the Client.
oh rep notifies are called when the property gets mapped?
dunno how I missed that all this time
You only really encounter this when spawning something and setting the variable instantly.
I do it quite a bit, I just generally have the other actor notify the owner on begin play clientside
guess I never noticed the rep notify gets called automatically, weird
this is how I spawn it and after FinishSpawning calling SetEquippedWeapon
void UWeaponManager::SpawnAndEquipp(UWeaponItem* WeaponItem, bool bTargetIsOnHand)
{
if (!IsValid(WeaponItem))
{
return;
}
FActorSpawnParameters SpawnParams;
SpawnParams.bNoFail = true;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
SpawnParams.Instigator = OwningCharacter;
SpawnParams.Owner = OwningCharacter;
SpawnParams.bDeferConstruction = true;
FTransform Transform = FTransform::Identity;
if (AWeapon* NewWeapon = GetWorld()->SpawnActor<AWeapon>(WeaponItem->WeaponClass, Transform, SpawnParams))
{
NewWeapon->WeaponOwner = OwningCharacter;
NewWeapon->SetWeaponDataItem(WeaponItem);
NewWeapon->FinishSpawning(Transform);
if (bTargetIsOnHand)
{
SetEquippedWeapon(NewWeapon);
}
}
}
Yeah. So multiple OnRep calls with nullptrs have to be expected.
Or I guess 1 nullptr 1 valid.
@thin stratus I have to use delay or is there any other clean way to make sure the actor is valid on first onrep call?
its a dedicated server setup that's why manualy calling onrep
but there's no way to guarantee it to be valid on the first rep notify call
and a delay wouldn't guarantee it either in extremely bad scenarios so don't use them that way
never ever use delays to fix stuff like this. (unless its something ALWAYS (gauranteed) done after later in the stack so it is always on the next frame) make your code reselient to this coming out of order
LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_SoldierCharacter_C_1. Function ServerFire will not be processed.
LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_SoldierCharacter_C_1. Function ServerFire will not be processed.
happens when i called this on server
If the actor is invalid on the server then it didn't spawn and you don't have a replication problem.
For the client having it invalid on OnRep you don't need to use a delay. The OnRep should call more than once, eventually with a valid actor.
You sure that's on server? This would print if a client tries to call a ServerRPC on an actor it doesn't own. E.g. another players character
yes
for client, it doesn't print this
LogNet: Warning: UNetDriver::ProcessRemoteFunction: No owning connection for actor BP_SoldierCharacter_C_1. Function ServerFire will not be processed.
Why are you calling a ServerRPC on a Server?
Possibly on the other players character?
Given the _1 in the Actor name, I assume the Server is calling a Server RPC on the Clients Character.
that's what i am not able to understand.
Although, outliner seems to indicate it's the Server's Character.
Can you confirm that this is being called on Server or Client ?
Fire() -> ServerFire() which then calls the actual fire from weapon
Print the NetRole of the Character
okay, wait
Simulated Proxy
void UCombatComponent::FireButtonPressed(bool bPressed)
{
bFireButtonPressed = bPressed;
if (bFireButtonPressed)
{
UE_LOG(LogTemp, Warning, TEXT("%s"), *UEnum::GetValueAsString(SoldierCharacter->GetRemoteRole()));
Fire();
}
else
{
ServerStopFire();
}
}
void UCombatComponent::Fire()
{
if (bFireButtonPressed && EquippedWeapon && !EquippedWeapon->IsMagEmpty() && bCanFire)
{
ServerFire(HitTarget);
}
}
void UCombatComponent::ServerStopFire_Implementation()
{
CombatState = ECombatState::ECS_Unoccupied;
}
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
if (SoldierCharacter == nullptr || EquippedWeapon == nullptr) return;
CombatState = ECombatState::ECS_Firing;
EquippedWeapon->Fire(TraceHitTarget);
StartFireTimer();
}
You need to print "LocalRole" not "RemoteRole".
RemoteRole of the Server's Character is expected to be SimProxy, as that's what other Players will have as a LocalRole on that Character.
LocalRole checked on the Server should be Authority.
Remote and Local Role are a bit confusing at the start, as the value changes depending on who looks at it.
Server Character
- Server
- LocalRole: Authority
- RemoteRole: SimProxy
- ClientA
- LocalRole: SimProxy
- RemotRole: Authority
ClientA Character
- Server
- LocalRole: Authority
- RemoteRole: AutoProxy
- ClientA
- LocalRole: AutoProxy
- RemoteRole: Authority
- ClientB
- LocalRole: SimProxy
- RemoteRole: Authority
Unless I mixed something up, that's how it should look like (given the Character's are possessed).
okay so yes it printed Authority and also, i have fixed that issue with line
if(SoldierCharacter && SoldierCharacter->IsLocallyControlled()) ServerFire(HitTarget);
adding it in my Fire Function
Hm, if that fixes it then you are calling the RPC on the other Character after all.
Something is fishy.
How are you getting to UCombatComponent::FireButtonPressed?
void UCombatComponent::FireButtonPressed(bool bPressed)
{
bFireButtonPressed = bPressed;
if (bFireButtonPressed)
{
UE_LOG(LogTemp, Warning, TEXT("%s"), *UEnum::GetValueAsString(SoldierCharacter->GetLocalRole()));
Fire();
}
else
{
ServerStopFire();
}
}
void UCombatComponent::Fire()
{
if (bFireButtonPressed && EquippedWeapon && !EquippedWeapon->IsMagEmpty() && bCanFire)
{
if(SoldierCharacter && SoldierCharacter->IsLocallyControlled()) ServerFire(HitTarget);
StartFireTimer();
}
}
void UCombatComponent::ServerStopFire_Implementation()
{
CombatState = ECombatState::ECS_Unoccupied;
}
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
if (SoldierCharacter == nullptr || EquippedWeapon == nullptr) return;
CombatState = ECombatState::ECS_Firing;
EquippedWeapon->Fire(TraceHitTarget);
StartFireTimer();
}
void UCombatComponent::StartFireTimer()
{
if (EquippedWeapon == nullptr || SoldierCharacter == nullptr) return;
SoldierCharacter->GetWorldTimerManager().SetTimer(FireTimer, this, &ThisClass::FireTimerFinish, EquippedWeapon->FireDelay);
}
void UCombatComponent::FireTimerFinish()
{
if (EquippedWeapon == nullptr) return;
bCanFire = true;
if (CombatState==ECombatState::ECS_Firing && EquippedWeapon->bAutomaticFire && !EquippedWeapon->IsMagEmpty())
{
if(SoldierCharacter && SoldierCharacter->IsLocallyControlled()) Fire();
}
else if (EquippedWeapon->IsMagEmpty())
{
Reload();
}
}
void ASoldierCharacter::FireButtonPressed()
{
if (Combat)
{
Combat->FireButtonPressed(true);
}
}
void ASoldierCharacter::FireButtonReleased()
{
if (Combat)
{
Combat->FireButtonPressed(false);
}
}
And that comes from a binding?
Do you haev any OnReps that trigger Fire?
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Unoccupied:
break;
case ECombatState::ECS_Firing:
//Fire();
break;
case ECombatState::ECS_Reloading:
HandleReload();
break;
}
}```
but i see that fire() don't need to be called on the OnRep since server is calling and working on client too
Yeah, so it's not the Server that calls the RPC
It's probably the Client that gets the property replicated and then also tries to call it.
at first i was calling ServerFire everywhere including timer, then i tried calling the fire with that if case inside the Fire function
then it fixed
Yeah, make sure you don't accidentally call your RPCs on SimProxies due to OnReps.
btw how can i make ADS? Aim Down Sight?
In theory, you'd do something like this for the Fire RPC stuff:
// LocalClient/ListenServer
// Only called by Input.
void UCombatComponent::OnFirePressed()
{
if (SoldierCharacter->HasAuthority())
{
Fire();
}
else
{
ServerFire();
}
}
// Server (Dedi/Listen)
void UCombatComponent::ServerFire_Implementation()
{
Fire();
}
// Server (Dedi/Listen)
void UCombatComponent::Fire()
{
if (!SoldierCharacter->HasAuthority())
{
return;
{
// [...]
}
That's without Client Prediction fwiw.
No clue. I never implemented that myself.
no idea how to fix it without breaking the flow as shown in this image
circled in red are the places where weapon is invalid on client instantly
.05sec delay fixed it, which is the only solution works for me right now
Delay is still wrong though.
You wanna fight that battle?
Do you reaaaaaally wanna fight that battle
Missty is just gonna be back with an even larger headache if they use a delay now.
I know but I don't know any other way to solved it
Dump a 42KiB code file, nice
// Call only on Authority (in this case Servers).
void AFooBar::SpawnActor()
{
if (!HasAuthority())
{
return;
}
ASomeActor* NewActor = GetWorld()->SpawnActor(..);
SomeActor = NewActor;
// Manual call for Authority.
OnRep_SomeActor();
}
// Called on Clients and Server.
// Client can call this with an invalid SomeActor if the Actor hasn't replicated fully yet
// Client will call this a second time once the Actor is valid.
void AFooBar::OnRep_SomeActor()
{
// Can be invalid on Clients.
if (!IsValid(SomeActor))
{
return;
}
SomeActor->DoStuff();
}
That's how it is, so you just gonna expect and handle this.
I'm already doing the same
this does not give any actual context for what is happening and I don't think I want to read a 1500 line code file to figure it out
Who needs context? Dump code and wait for the answers to flood in
it starts at line 69 bool UWeaponManager::EquipWeapon(UWeaponItem* WeaponItem) few functions
posted the whole class to see how actually system works
Yeah, but then you should be good. The OnRep should call with the valid weapon eventually.
as you can see I'm using delay in ReplaceAndSpawnWeapon() for equip/left/rights ... without delay it fails
Yeah I'm aware. You said that multiple times now
so does it eventually onrep a valid pointer or not?
relying on the first onrep to always be what you want is not useful
I told you how it's supposed to work. Repeating to me that you use a delay to solve it doesn't change things.
Remove the delay. Put UE_LOGs into the functions and give us more info.
The OnRep should call with a valid Weapon eventually. You never told us if it calls more than once or not.
"it fails"... WHAT FAILS??
weapon is nullptr in OnRep_EquippedWeapon();
I logged it all, on the client the weapon is nullptr
But, he said why
how i'm supposed to know it?
am setting
weapon = newweapon;
onreapweapon();
I’m out
it calls once only
no pushmodel usage? not marking net dirty?
also I cant' see anything stopping the local client from setting equipped weapon
yeah this is why I'm so confused, even testing locally the client fails to set it
why would you EVER want the local client to set a replicated variable?
you should make a separate variable if you desire having a local value
this kind of thing will be hard to deal with if the local client can just change it as they please
I mean server is setting for client is failing instantly
leave replicated variables alone on a client
I'm sure there's some strange situation it is okay to do so but here it does not make any sense
yeah and will be more problematic, I don't like delays in such cases
I can see there is no issue in the code flow, but it still needs delay likely something is not yet finished or the actor is not fully spawned or initialized
and that delay giving the actor some time to fully initialize before server can set it for clients
the weapon actor is like setting 50 variables in the ctor when it is spawned
this can be the reason?
I feel like you are ignoring the last few things I posted
which things?
if you instancing this no pushmodel usage? not marking net dirty?, yeah the weapon is spawned from a replicated UObject data
try marking the network object dirty
it is already
also you should try forbidding non authorities from calling SetEquippedWeapon
this flow is started by server
this function is part of it
No. You NEVER use a push model setup OR call ForceNetUpdate (at least in this massive code file you shared)... this would at least ensure unreal is aware of the replicated change no matter what asap
why does that matter? the code actually doing what you expect is what matters
at least ensure it's on authority only or something
This is just the stuff I would try first at least
you are free to ignore me and go "ah, well I don't need that" I guess
I'm looking in the class to make sure it was on the server only
It's totally possible I missed something and it's something completely different
yeah it is
bool UWeaponManager::EquipWeapon(UWeaponItem* WeaponItem)
{
if (!OwningCharacter->HasAuthority() || !IsValid(WeaponItem) || !IsValid(WeaponItem->WeaponClass))
{
return false;
}
PickupWeapon(WeaponItem, false, EWeaponPosition::E_Left);
return true;
}
we write ensures in code to ENSURE something DOESN'T happen
EquipNotifyHandle is not protected by authority
it is, let me find it and show
void USurviveNotifies::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
if (!MeshComp) return;
AActor* Owner = MeshComp->GetOwner();
if (!Owner || !Owner->HasAuthority())
{
return;
}
if (ASurviveCharacter* Character = Cast<ASurviveCharacter>(Owner))
{
CustomNotify(Character);
}
}
also OnRep_EquippedWeapon depends on the anim instance being loaded and valid among other things (why?)
when most of it is not strictly anim instance related
this is very brittle and will silently fail if this is not there
notify base weapon state change in animation
anim instance successed, the next check for weapon fails
instead of hoping users do not call this on authority it would make more sense to add the authority check in the set equipped weapon itself
instead of just hoping all callers protect by authority
also not sure you ever proved the onrep NEVER gets called with the correct weapon pointer
without the delay
I logged it without delay, it says weapon not valid
show the code logging it without being protected by random unrelated pointers
void UWeaponManager::OnRep_EquippedWeapon()
{
if (!OwningCharacter || !OwningCharacter->GetMesh()) return;
UCharacterAnimInstanceBase* AnimInstance = Cast<UCharacterAnimInstanceBase>(
OwningCharacter->GetMesh()->GetAnimInstance());
if (!AnimInstance)
{
UE_LOG(LogTemp, Error, TEXT("AnimInstance is NULL or wrong type!"));
return;
}
if (!IsValid(EquippedWeapon) || !IsValid(EquippedWeapon->GetWeaponItem()))
{
UE_LOG(LogTemp, Warning, TEXT("No valid weapon -> Unarmed"));
OwningCharacter->SetCharacterPlayType(EPlayType::UnArmed);
AnimInstance->UpdateWeaponState(nullptr, false);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Equipping weapon: %s"), *EquippedWeapon->GetName());
UpdateWeaponsDisplay();
OwningCharacter->SetCharacterPlayType(EPlayType::Armed);
AnimInstance->UpdateWeaponState(EquippedWeapon, true);
}
}
once again: our goal is to see EVERY time this onrep happens
not when every single one of 4 other pointers is there
if you are just baiting me gg I guess... I am trying to help
onreps do not care about your init order
onreps do not care about anim instances
onreps show up from packets early in the frame whenever they feel like it
for this kind of thing in my experience you will want to make this code resilient to the other things showing up in any order
which generally means them arriving will read the current value of the other things and then listen for it later
Will try to do it now, will inform if the issue gets solved or persists
I am not telling you to do one thing, I am telling you to both log this and not randomly early out and skip logging stuff
the "doing it the right way" can come after you figure out what is wrong
this stuff is hard and can be difficult to track down
I do wonder if setting the owner on the weapon is needed
I would also say the weapon being an entire actor is unneeded as well but that's kinda up to you... it has its benefits
I removed that early returned, it still prints not valid weapon on client
even after the weapon is replicated and the variable is set on the server AND never set different on the client AND you manually mark the actor holding the onrep net dirty as I mentioned earlier?
its a heavy actor, with 7 skeletal mesh components
so?
what does that have to do with replication?
you can send an int32 and spawn a skeletal mesh on the each client that receives it if you want... I don't see how that forces you to replicate a second actor at all
if it's just easier to add new things that way, sure
yes its marked dirty for replication
more actors = more net objects = more network polling = more overhead and more complexity
but it is easier to add new behavior to things I guess and this should be working fairly okay if everything is set up okay
I thought it needs time to initlialize all props before I can use it?
I care more about the code than what you claim at this point because the code earlier doesn't do this ever
why?
and even if it does you can just check for everything when each new one shows up similar to how init states work in the modular gameplay framework
void UItem::MarkDirtyForReplication()
{
++RepKey;
if (OwningInventory)
{
++OwningInventory->ReplicatedItemsKey;
}
}
void UWeaponItem::SetEquipped(bool bNewEquipped)
{
if (bEquipped != bNewEquipped)
{
bEquipped = bNewEquipped;
OnRep_EquipStatusChanged();
MarkDirtyForReplication();
}
}```
what does increasing this random thing I can't see do?
please just use ForceNetUpdate (on the object with the onrep)
it was just my guess cause with other actors i don't have this issue
server is doing it, when character interacted with an item it tells the server to spawn that interacted item
sometimes waiting 1 frame is meaningful for rendering stuf I have found
note I when I say ONE frame I mean THE NEXT frame... not a random number of frames from a delay
a random delay is like... the last resort
or for example when your callback is from a function and the thing you need set is later in the scope. you have no reasonable way to wait on that without engine changes in many cases
this doesn't seem like one of those times
a TON of changes I have to make to gameplay classes is just adding new delegates to be able to react to things that are normally overrides in things
is it ok to add ForceNetUpdate(); to the server beginplay of the weapon actor?
I mean calling finishspawn will call beginplay of the actor and it will be synced if i'm not wrong
add it to whatever the weapon object is inside of
Does anyone know a good article, documentation or video on
Client prediction and server reconciliation?
I'm trying to implement a physics-based grabbing mechanic but can't get it to work. On the client (right window) it doesn't seem to do anything at all whereas it spazzes out but doesn't move the object on the listen server (left window). The input and Server_GrabObject are in the player character. The pickup object has Replicates enabled.
i dont use the physics constraint component personally but i feel like the object's mesh component thats being picked up should be plugged into the "component 2" pin of "Set constrained components" node
I forgot to connect the pickup component to Component2. But now when I grab it on the client, it works fine on the listen server but not on the client itself. And when the server grabs it, it also works on the server but not the other client
the situation is same even after adding this.... I will go with a delay since I have no other choice for now....
Hi, I'd like to have a knockback on a player without any jitter/rubberband. What is the right way?
Using GAS? Maybe SavedMov in CMC?
Not Unreal specific, but I often recommend this talk to folks that are looking to understand network replication in games.
In this 2011 GDC session, Bungie's David Aldridge discusses the programming that drove Halo: Reach's online networking.
Register for GDC: http://ubm.io/2gk5KTU
Join the GDC mailing list: http://www.gdconf.com/subscribe
Follow GDC on Twitter: https://twitter.com/Official_GDC
GDC talks cover a range of developmental topics including game des...
The section about how armor lock works from a client/host perspective is relevant
I understand the basics the thing I'm trying to see is practical examples such as code snippets or some practical application of the client prediction and server reconciliation. Such as, I fired a bullet. Effects and audio played for the client but the damage is not applied because on server, the server haven't line traced and confirmed the hit yet to apply damage. So something like this.
I don't think it has source snippets, but it has concrete examples of features that shipped in a big AAA title, you're not going to get much more practical than that, unless you're looking specifically for details of how to do it in Unreal rather than more generally
The unreal tournament ue4 remake's projectile setup is an example I suppose
getting this error for packagin on windows
I'm making a Ability system in unreal engine 5.6.1, i'm trying to create a cooldown system in cpp, anyone can help me?
What do you have problem with?
you can use GAS #gameplay-ability-system for the ability system + the cooldown.
I can't use in this project, i need to make from scratch
not sure why you want to re-invent the wheel, so what exactly are you having trouble with?
I'm trying from scratch again, i have the ability system. But I already tried to create a cooldown system, but the timer only existed on the server and not on the client, so the client could spam the skill. The netmode that needs to work is "Netmode: Client".
Ability system with cooldown
You kinda have to decide your approach. If you are going for Authority check then there would be the problem with delay.
If you don't care soo much about cheating, you can just let the client to book keep it's own cooldown.
you can still check on server, if the ability get casted faster than it should, if cheating is a concern.
Tldr, you can just keep the cooldown/timer on the caster machine.
There's a way the player and server have the timer, so the server only check if he's able to use it
you said the client spam the skill, so I am assuming the ability is client predicted. Which in this case, you should just have the timer solely on the client.
and if cheating is a concer, you can just check on the server if the time between last and current spell < cooldown.
Yeah, that's the case
So, how i would implement this?
run it on the client
¯_(ツ)_/¯
of course if you need the timer on simulated proxies for showing something visual they might need to either run it on their end as well or get given some visual cue/event etc
the answer here is vastly different depending on the actual needs of the project imo but since we have no context = I am going to guess
The problem is that I can't "see" how I would do that.
I can give in pm
no thanks
if you cant give vague details like whether it is co-op or not why would you be able to reveal that it has cooldowns?
we don't need the elevator pitch.. just some surface level info I guess
It's a pvp game MVP for a tech test
not sure why it being for a tech test matters here... I guess you want something easy to make quickly?
With 4 abilities, and all will have cooldown, some of their will have area of effect and one will have a time of effect
moreless, it's more i haven't a north, i don't know why wasn't working, so i'm a bit lost
Don't think AOE have anything to do with what we are discussing.
Depending on your design, you can just couple a cooldown/timer for each ability.
not sure how any of us are supposed to know what isn't working with 0 info on what you actually tried
You said the timer is run on server. Well I would suggest to run the timer on the casting player machine.
and the casting player simply just check if the timer / cooldown is not 0 to decide if it can cast the spell or not.
ServerActivateAbility
well I don't have 2 cent if you want server auth casting. Personally I just use GAS, it already have prediction option with rollbacks.
>UnrealEditor-Core.dll!FName::ToString() Line 3356 C++
[Inline Frame] UnrealEditor-Survive.dll!UObjectBaseUtility::GetName() Line 423 C++
[Inline Frame] UnrealEditor-Survive.dll!GetNameSafe(const UObjectBaseUtility *) Line 864 C++
UnrealEditor-Survive.dll!UInventoryComponent::ItemRemoved(UItem * Item) Line 440 C++
UnrealEditor-Survive.dll!UInventoryComponent::execItemRemoved(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 957 C++
**FName::ResolveEntry**(...) returned 0x7FF8.
void UInventoryComponent::ItemRemoved(class UItem* Item)
{
if (!IsValid(Item)) {
UE_LOG(LogTemp, Warning, TEXT("Item is not valid."));
return;
}
AActor* Owner = GetOwner();
if (!IsValid(Owner)) {
UE_LOG(LogTemp, Warning, TEXT("Owner is not valid."));
return;
}
FString RoleString = GetOwner()->HasAuthority() ? "server" : "client";
> UE_LOG(LogTemp, Warning, TEXT("Item Removed: %s on %s"), *GetNameSafe(Item), *RoleString);
}
any idea why resolving name to string fails?
FORCEINLINE FString GetNameSafe(const UObjectBaseUtility* Object)
{
if (Object == nullptr)
{
return TEXT("None");
}
else
{
return Object->GetName();
}
}
so the game is trying to resolve name at address 0x7FF8
interesting why if (!IsValid(Item)) also don't works at this point
unrelated but why do you have class keyword before the ptr? Don't we meant to only do that for forward declare?
Sorry to intterupt the ongoing question, is there an event that is called before Begin play? And if the server set something there, will the replicated actor on the client side guaranteed to have the modification?
nah, its fully included
in the cpp
that class comes from .h
I mean i have this void ItemRemoved(class UItem* Item); when created the definition the class was added automatically
any hint on the call stack?
all i can say is bad memory management
cause its not crashing all the time
it crashes 1/20
other 19 times it prints the name of the item was removed
I am facing the same issue when I destroyed the item on the server and client needed to still have access to the item to clean up on it's own end.
Just yapping atm, but I got the band aid by just hiding the item and giving it a decent life time like 2 - 3 seconds.
If the InventoryComponent itself isn't garbage at that point, then this smells like a stale pointer.
yeah IC is not garbage
seems like I have to cache the name of the item before removing it and pass that directly instead of passing the item
BeginPlay()
OnItemRemoved.AddDynamic(this, &UInventoryComponent::ItemRemoved);
bool UInventoryComponent::RemoveItem(class UItem* Item)
{
if (GetOwner() && GetOwner()->HasAuthority())
{
if (Item)
{
OnItemRemoved.Broadcast(Item);
Items.RemoveSingle(Item);
OnRep_Items();
ReplicatedItemsKey++;
return true;
}
}
return false;
}
it seems like i'm printing it before removing it
seeme like resoving FName to FString is a heavy operation
it takes long time and the item is removed before it resolves
code isn't async, that shouldn't be the case?
nah, it crashes on server
have to figure it out first before moving to client side
try doing a log print inside RemoveItem with Item->GetName().. maybe the pointer is already stale inside RemoveItem
OnItemRemoved is broadcasted before removing item
basically its same, in the end it will call GetName before reaching Items.RemoveSingle(Item);
sounds like RemoveItem is getting passed a stale pointer
int32 UInventoryComponent::ConsumeItem(class UItem* Item, const int32 Quantity)
{
if (GetOwner() && GetOwner()->HasAuthority() && IsValid(Item))
{
const int32 RemoveQuantity = FMath::Min(Quantity, Item->GetQuantity());
ensure(!(Item->GetQuantity() - RemoveQuantity < 0));
Item->SetQuantity(Item->GetQuantity() - RemoveQuantity);
if (Item->GetQuantity() <= 0)
{
RemoveItem(Item);
}
else
{
ClientRefreshInventory();
}
return RemoveQuantity;
}
return 0;
}
I think that IsValid(Item) protects against stale pointer
Na, it can't.
set a breakpoint on the line calling the RemoveItem function and check if the values are all weird
The idea of a stale pointer is that it's valid in the sense of not being a nullptr, but the thing it's pointing to is not what it's meant to be.
if the ptr is stale, it will be crashed when removing from inventory
IsValid can still return true for a stale pointer.
removing from inventory never crash, logging the name of the item which wants to remove crashed
Where are these Items stored?
inventorycomp
UPROPERTY(ReplicatedUsing = OnRep_Items, VisibleAnywhere, Category = "Inventory")
TArray<class UItem*> Items;
So, something triggers ::ConsumeItem(), that then triggers ::RemoveItem(), and that triggers ::OnItemRemoved and ::Items.RemoveSingle(Item)?
Where is ::ItemRemoved(..) being called from?
One thing you should try is to enable GC every frame (console var), to test if that makes the issue happen every time.
The note that it only happens "sometimes" makes me wonder if the order of what you are doing doesn't take into account that the GC could be nuking the object.
OnItemRemoved.Broadcast(Item); inside RemoveItem()
not happening every time, behavior is same as before
So you enabled GC every frame and removed items and it doesn't crash every time?
yeah, I have this already gc.TimeBetweenPurgingPendingKillObjects 0 in my ini files