#multiplayer
1 messages ยท Page 592 of 1
Listen server or dedicated server?
Listen
What sort of framerate is it running at?
I have tried on multiple machines, this specific one was capped to 60
You can try reducing the network tick rate to start with, as 60 is probably too high - and you don't want the listen server running at whatever framerate the client can support anyway:
[/Script/OnlineSubsystemUtils.IpNetDriver]
InitialConnectTimeout=120.0f
MaxNetTickRate=60
NetServerMaxTickRate=60
LanServerMaxTickRate=60
NetClientTicksPerSecond=60
bClampListenServerTickRates=true
MaxClientRate=10000
MaxInternetClientRate=10000```
Otherwise it'll just be hammering out packets as fast as it can, the default for many actors (stupidly) being 100hz
one problem with listen server running slower
if you lower that tick rate, and you have a client with inadequate machine
animations for that player's pawn will lag on server
ah yeah that is true
and its very noticeable when your game is otherwise running smooth
@winged badger do you mean you see them animating stopmotion like
?
I have noticed that with some testers
like his animations will be capped to the net tick rate
while everything else runs fine
ok, i can find a compromise there i guess, my issue right now is that the game is basically unplayable, everything lags very hard if i get the ai in
we have one tester that insists on using old laptop and wireless connection
its a disaster ๐
as long as i keep the AI count down, everything is fine, @chrome bay i will try your config values
so he can't run the game at more then 15-20 FPS
and his pawn on server suffers for it as well
Understood, thanks for the help guys, i will come back with my findings.
420Hz is impossible for a single Actor instance
yeah.. doesn't make sense
no, they are more than 1
Ah kk, couldn't work out what you were looking at
Probably another issue with root motion animation as well
Since they're going to be always moving and therefore always need to send network updates
Along with all the additional animation info
I'm using the Gameplay Ability System, the rootmotion sources to dash and stuff. I'm not sure my locomotion animations are using rootmotion thoe
probably not
and the GameplayTasks should be well optimized, they are used in Fortnite
(what it uses for the root motion)
yes i'm aware ๐
hehe
so anything i could do about the rootmotion ? AFAIK, i only use the root motion sources
funny how UE dev requires you to stay up-to-date with fortnite features
any system thats in fortnite is stable and optimized
any system thats not is a coin toss
hahaha yeah, i checked out the optimizing fortnite videos online but i can't do all that stuff they are doing
it would take me ages
i don't know if its root motion, 4,7kB is super high for 8 AI
then again, if there are only those 8 AI on the level, or very few other replicated Actors
what would you suggest for a stable bandwidth usage for, the whole game i guess.
and you didn't touch the crazy default NetUpdateFrequency of 100Hz
so i can target something, i'm not sure what to expect
its... plausible
It does seem insane ๐
AI don't need more then 12 or so Hz imo
yeah, thought so too, wasn't sure thoe
20 if you have slack
i reduced the net update rate on the AI from 100 to something lower, i think 20
You're not doing something like calling RPC's etc on tick or something are you?
but if that's the case, adding few hundred replicated Actors to the level
the properties are only a small part of the picture ofc
would reduce the usage of AI
as they wouldn't be able to replicate whenever they want, but would have to wait their turn instead
listen server has a CPU time cap on how long it can evaluate Actors for replication each Tick
i have other replicated actors, but as long as you don't interact with them, they should be dormant
so if you have few enough Actors to replicate, it will manage to evaluate the AI each Tick
they only 100% replicating actors are the characters, AI and Players
btw, funny story
our designer accidentally changed the NetPriority of one trash mob to 100 once
i never saw the network perform worse mid game
xD
basically, when there was 50 of them active
actors with normal Net Priority
and lifetime of 2-3 sec
didn't even have enough time to panic to increase their NetPriority enough to replicate while they were still alive
so client's couldn't see stull like AoE projectiles, which we replicate
at all
yeah sounds rough xD
after that we made an editor utility widget that goes through all the Actor classes
and shows us their NetPriority and NetUpdateFrequency
and other replication settings
do you think it's good practice to just set all actors to say 10 netupdatefrequency and only make it higher if necesary ?
i guess characters are fine at a higher rate (players)
depends on the Actor
those that very rarely change can have it down to less then 1, and ForceNetUpdate
if Dormancy is not an option
and its not if they can change while out of someones relevancy
then go Dormant, then they wouldn't update when they became relevant again
hmm i see, what about the bandwidth, what would be a good target or budget ?
for the whole thing i mean, i can see the server getting to 20 KB/s i get that is a lot
listen servers?
how u guys test and debug a multiplayer game with 50+ players ? do u have 50 developer or ?
just the whole company plays
@winged badger yes listen server, if you know for dedicated servers would be interesting to know as well.
@rose egret we just get the whole team to play or maybe most of the company.
listen servers are kinda worry about CPU, bandwidth will be fine unless you do something crazy situation
Pretty much, there's not really any good way to emulate that kind of thing. Can't support 50+ players without testing that many
Though if you can get access to enough machines, sometimes simple things like having "bots" that are really clients that just apply random input can be useful
it helps when you have player community from previous game(s)
yeah totally
with enough hardcode fans
although, i got the steam beta mail few weeks ago
so that could probably be used for it
yeah that actually looks quite useful
community is still better, as you can count on them showing up
I also wonder if there are any marketing/PR implications from that if it all goes wrong too..
hardcore fans might be more understanding ๐
I am thinking about simulating clients, a kind of AI that plays the game. but I wonder how many clients I can simulate per machine , it takes lots of ram and CPU
as long as it has the right feel, no matter how unpolished
hardcore fans are hardcore
Hi, I'm using a character movement component and movin via AddMovementInput nodes but my client gets terrible lags for both his and servers pawn. What could be the cause of this?
couple reliable RPCs running on Tick?
All of the ones I made are unreliable but Imma double check this
is there a way to look for all of the rpc calls?
Is it constant 'lag'. Like a high latency?
yup
Persists more than twenty or thirty seconds?
But does it keep happening for up to a minute after you've started testing?
there were times where he could walk around without any corrections and it happened after a while but our testing sessions aren't long usually
Your input is client side? Just ButtonAxisEvent->AddMovementInput?
yes, plus a few calculations and if checks
I'd assume either your server is running incredibly slow. It actually is a latency issue, or you have some crazy replication overflow going on like Zlo said. Either way too much replicated at once, or something like a lot of reliable RPCstoo often.
What is the "IsLocallyControlled()" equivalent for non-pawn classes? I need it for multicast.
Yeah thats what I thought and was scared of, guess I'll go optimize now
thanks, to both of you
Does the client own the version of the object that you're calling the multicast on?
@kindred widget I think so, it's created in the character class.
Is that not a check for if the game instance is client?
one is the role of the actor, the other is if the game instance is client, correct.
hence the "or" and the depending... bit.
If "GetLocalRole() != ROLE_Authority" the actor is locally controlled?
no it means that the actor is not authoritive (ie actor on remote machines not the server)
(if replicated)
I have this BP that is attached to the player and I want to destroy it when the player dies. Now it works fine on the server (It is destroyed on the server side) but on the client side it is still vissible. I destroy it using multicast and I am out of ideas? Anyone got a clue how I could fix this?
there is no IsLocallyControlled really for an actor.
only thing you can do is GetWorld()->GetFirstPlayerController()->IsLocalController() or w/e
but i have never needed to do that
{
UE_LOG(LogTemp, Log, TEXT("[Drain] ABaseWeapon::Attack()"));
Internal_Attack();
if (!GetWorld()->IsServer())
{
// CLIENT
Server_Attack();
}
else
{
// SERVER
Multicast_Attack();
}
}
void ABaseWeapon::Internal_Attack()
{
if (m_AttackSound != nullptr)
{
UGameplayStatics::PlaySoundAtLocation(GetWorld(), m_AttackSound, GetTransform().GetLocation());
}
}
void ABaseWeapon::Server_Attack_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("[Drain] ABaseWeapon::Server_Attack_Implementation()"));
Multicast_Attack();
}
void ABaseWeapon::Multicast_Attack_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("[Drain] ABaseWeapon::Multicast_Attack_Implementation()"));
if (/* What does here */)
{
Internal_Attack();
}
}```
I need to check if the actor receiving the multicast is the one causeing it?
why you doing GetWorld()->IsServer?
If it is server, multicast, if not, call the server?
regardless, you need to decide how your input is working.
It's getting passed down from InputComponent on the character controller. Then to pawn, then to this actor.
Basically, if you want to know if the actor is locally controlled, you have to walk up it's owner tree to find out if GetPlayerController(0) is the owner. Pawn class does pretty much the same with IsLocallyControlled.
So i need a reference to the pawn and then just call IsLocallyControlled on that one?
thing is he doesn't need to check that here
You have to check the Owner pointer in the pawn. If it's null, it's owned by the server. If it's set, you have to check what owns it. If it's not the controller, you have to keep walking up the actor's Owner tree to find out if the owner list is eventually owned by the local controller.
That's the only way to emulate IsLocallyControlled on a normal non possessed actor.
What exactly is this actor, why does the owning client need to do something different in this multicast than other connections?
I'd steal the int counter rep that FPS games use for guns and just up that per call instead of multicast and set the replication to skip owner.
{
if (!ActorToQuery)
{
return false;
}
AActor* TopOwner;
for (TopOwner = ActorToQuery; TopOwner->GetOwner(); TopOwner = TopOwner->GetOwner())
{
}
APlayerController* Controller = Cast<APlayerController>(TopOwner);
return Controller && Controller->IsLocalPlayerController();
}``` i mean.. you could make a function like this in a static library
and call it..
Then i wouldn't be able to do traces on the server? How would i then make it secure?
the server does the traces (if you want secure)
or client does the trace and tells the server (less secure, but can be secured with server checks before applying damage, etc)
weapons can be quite complex for a decent implementation
That's what I'm doing - @kindred widget would just use rep notify, but don't get how to make that secure?
My point was just about the cosmetics. The Int counter just allows non owning clients to play the same cosmetics like sounds.
How i can disable NetCullDistance for Actor?
I have a small map and I want it to be always loaded
@kindred widget & @meager spade couldn't i just do this when the weapon is spawned (in the pawn) and then check that in the multicast?
CurrentWeapon->IsLocalWeapon = IsLocallyControlled(); The images is so freaking wrong xD
@gritty pelican bAlwaysRelevant
@chrome bay thx
Do I need to replicate "Play Sound 2D"?
@nocturne iron I mean, it really depends on how nuts you're going to go on the Owner chains for other actors. My initial suggestion would be to just make a simple library function like Const said and just check if the owner of the actor is either PlayerController(0) or PlayerPawn(0) and if not dedicated server.
If yes, how can I test it working lol ๐
@peak sentinel Typically no. Multicast and have clients play it themselves, or replicate a property and have the repnotify play it.
Okay thanks
Weapons are surely 'owned' by something, so just casting that owner to a pawn and checking if it's controlled locally should be enough
How do i make an actor have authority (weapon on client) and is it secure?
@nocturne iron That's what the Owner variable in AActor is for. You set it on the server to a server version of their controller, or something their controller owns.
Make the clients player controller or pawn it's owner
Usually pawn IMO, since pawn is often the thing carrying the weapon
That owner chain is what allows clients to call RPCs on actors.
Right - just wondering are there any great multiplayer demos?
ShooterGame is a pretty good example project from what I've heard. Haven't quite gotten around to looking through it myself.
yep. pretty comprehensive
Is it a bad idea to assume that world time is the same on the client and server? Or do they slowly desync from oneanother?
GetServerWorldTimeSeconds is relatively synchronized I believe. But in general, it's probably a bad assumption to make, or to rely on the travel time of any form of RPCed or Replicated data.
the one replicated in GameState by default is fairly inaccurate
so best to periodically send a Server_RequestWorldTime(float ClientTimeStamp); to which server immediately replies with Client_SendWorldTime(float ClientTimeStamp, float ServerTimeStamp);
when client receives the reply, it can assume that half the difference between its current worltime and ClientTimeStamp is time it took for reply to arrive from server
and from there calculate a ServerWorldTime accurately within few miliseconds
it then saves the Delta, and when you request ServerWorldTime on client you just return WorldTime + Delta
interesting
I've been using ExactPing so far for prediction purposes and it was worked well enough, but knowing this about World Time helps
it has*
ExactPing is fine for travel time
but if you want server world time
late joining client can have half an hour delta
but will probably have at least few seconds, even if it seamless traveled in
Yes, I see that now, I am not sure I want to use world time for what I'm working on, but it might be interesting to test it. It may be I can do the same thing and use ping for my calculations but I will need to experiment.
its good for syncing montages
and OnRep stuff like say EDoorStatus::Open
if its sent bunched up with a timestamp
you know if you should just set the door open or play the opening animation + sounds
and multicast here doesn't cut it, as anyone out of relevancy has the door in wrong state
Indeed, it does make for some overhead with all these floats bouncing about though, no?
in my experience, few floats don't matter
CPU time evaluating actors for replication is the main chokepoint
on the client?
hmm, what do you mean by evaluating actors?
if 800 actors want to replicate in a single tick
doesn't mean they will
official docs page for that is a bit technical, but good
do you have the link? or a search term? I'd like to read it.
A detailed description of low-level Actor replication.
Thanks
I'm getting my name like this in a widget blueprint
on the server side the name displays correctly
but the clients get no name
except their own?
not even their own
the widget is created on begin play, and represented char is exposed on spawn
doesn't matter
your PlayerState usually won't replicate as soon as your PlayerPawn does
if thats a widget component
i would recommend moving the widget component itself to PlayerState
and attaching the PlayerState to PlayerPawn
makes life so much simpler
@winged badger this is where net dormancy and relevancy come in right ?
and net priority
true
btw the stuff we talked about earlier helped, not seeing as much lagging as i did before
๐ ty
yw
do you think being aggresive with the net dormancy is a good call ? using force net update with actors getting attached and such ? we have pickable items that only realy change network whise when attached or released
Hey, how do i replicate character movement like dashing ?
@mighty zinc look into Gameplay Ability System, i use it for that
they have AbilityTasks that use RootMotionSources for it
#gameplay-ability-system is all about that
problem with dormancy
is it won't figure out the new connection becoming relevant
we only use initial dormancy on pickups
until they are interacted with
so having it be on DormantAll and using FlushNetDormancy is not worth it ? i recall a VOD where some developers talked about it being a good option if you dont really need to send info more than on events or something
if you can figure out when to flush it accurately
its fine
but if your actor changes, goes dormant, then i walk into relevancy range
that becomes a serious problem
hmm, in my games context, you can't really walk into relevancy range, rooms are small.
everything in it is basically relevant, if i understand correctly what relevant means
Have to be careful with NetDormancy btw
everytime an actor wakes from dormancy it sends all it's properties again
As far as network is concerned, it's like a new actor
Can be a good CPU saving but not so useful for bandwidth
discovered this the hard way with pooled projectiles
How can i use My own sever for Multiplayer?
Can you elaborate what is the problem with that?
it changed, but i was not relevant when it did
so i don't know about the change
i walk in, its still dormant
so i see invalid state
wow it's really like that? I thought the actor will replicate the changes and go dormant automatically
and how would it know that it needs to snap out of dormancy
and for what connection
that is not an easy test to make
@winged badger Let's go with example
so if one player for which tree is relevant will cut it down and we will change the tree to dormant the other players which were not relevant after coming to that tree wouldn't see felled tree?
I thought that server when changing actor to dormant would save non-relevant connections for that actor and replicate it just once for every connection when the actor is relevant again for them.
@twin juniper you can start by reading this documentation. https://docs.unrealengine.com/en-US/Gameplay/Networking/HowTo/DedicatedServers/index.html
How to set up and package a dedicated server for your project.
Thx
@winged badger @chrome bay I'm testing some more stuff and got it down quite a bit
89 hz & 1.21 KB/s for 8 AI characters and 2 players
so basically 1 client to send this to
does this seem ok ?
yes, with stat net i see about 4KB/s per client
haha yes i'm sure that would be an issue hehe
What about the RPC size ? is this normal ?
sorry for asking about everything it's my first time submerging myself in this
Hi guys, can someone clarify how I can set my Dedicated server session 'name' up so that clients calling FindSessions() can get it?
I'm using the Steam online subsystem.
Is the GetFName of an actor the name on every client - will a, like the pawn, on the server and the client have the same name?
and when getting all the sessions reading it
@tawny mason using this member of FOnlineSessionSettings?
/** Array of custom session settings */
FSessionSettings Settings;
@nocturne iron characters on client and server will have _C_0 at the end for local characters and have a count up _C_1..._C_N for every additional character, this is not supposed to be _C_1 on client and server for the same character.
@silent valley i'm not entirely sure, but there is a generic list of session settings where you can add some params in form of Key <-> Value
yeah I was looking at that but it looks like the Steam OSS strips out anything it doesn't expect
that would be great thanks, otherwise I'll just try and see what happens
but it's a bit of a pain to add the code, build, deploy to server etc
if I knew what to do in advance it goes a lot quicker!
@silent valley btw are you using the Advanced Sessions plugin by any chance ?
I have a test project using it, yes
if your BP requires the plugin that's fine I can figure out what it's doing in the background
ok
do you pass it in as ExtraSettings into CreateAdvancedSession ?
perfect, thanks!
then i read it and put it on the session umg widget
nice yw!
I have been dealing with this for 2 hours now... I think it's a simple problem, but I'm super new to UE networking (and yes, i have looked in the network compendium). I think the problem has something to do with ownership but I'm not sure how. I have two classes ABaseWeapon(actor) which is created on BeginPlay() from APlayerCharacter(pawn). What i want to happen is that the pawn can call a single function on the weapon (ABaseWeapon::Attack()) and then the weapon handles the replication. But i don't get how this doesn't work:..
Result (client):
LogTemp: [Drain] ABaseWeapon::Multicast_Attack_Implementation()```
Expected Result (client):
```LogTemp: [Drain] ABaseWeapon::Server_Attack_Implementation()
LogTemp: [Drain] ABaseWeapon::Multicast_Attack_Implementation()
LogTemp: [Drain] ABaseWeapon::Multicast_Attack_Implementation()```
Result (server - which is what i want / correct result):
```LogTemp: [Drain] ABaseWeapon::Multicast_Attack_Implementation()
LogTemp: [Drain] ABaseWeapon::Multicast_Attack_Implementation()```
ABaseWeapon:
```c
void ABaseWeapon::Attack()
{
if (!GetWorld()->IsServer())
{ // CLIENT
Server_Attack();
}
else
{ // SERVER
Multicast_Attack();
}
}
void ABaseWeapon::Server_Attack_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("[Drain] ABaseWeapon::Server_Attack_Implementation()"));
Multicast_Attack();
}
void ABaseWeapon::Multicast_Attack_Implementation()
{
UE_LOG(LogTemp, Log, TEXT("[Drain] ABaseWeapon::Multicast_Attack_Implementation()"));
}```
.
.
APlayerCharacter (where the weapon is spawned):
void ABasePlayerCharacter::BeginPlay()
{
Super::BeginPlay();
// Spawn Weapon
if (PrimaryWeaponClass == nullptr) PrimaryWeaponClass = ABaseWeapon::StaticClass();
FActorSpawnParameters SpawnParams;
SpawnParams.bNoFail = true;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
FTransform SpawnTransform;
SpawnTransform.SetLocation(GetTransform().GetLocation());
SpawnTransform.SetRotation(FQuat(FRotator::ZeroRotator));
CurrentWeapon = GetWorld()->SpawnActor<ABaseWeapon>(PrimaryWeaponClass, SpawnTransform, SpawnParams);
if (CurrentWeapon)
{
CurrentWeapon->AttachToComponent(FirstPersonMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
}
}```
@winged badger Ok, now i don't have weapon reference on the client, how do i get that?
void ABasePlayerCharacter::BeginPlay()
{
Super::BeginPlay();
if (!GetWorld()->IsServer())
{
Server_SpawnWeapon(); // CLIENT
}
else
{
Internal_SpawnWeapon(); // SERVER
}
}
void ABasePlayerCharacter::Internal_SpawnWeapon()
{
// Spawn Weapon
if (PrimaryWeaponClass == nullptr) PrimaryWeaponClass = ABaseWeapon::StaticClass();
FActorSpawnParameters SpawnParams;
SpawnParams.bNoFail = true;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
FTransform SpawnTransform;
SpawnTransform.SetLocation(GetTransform().GetLocation());
SpawnTransform.SetRotation(FQuat(FRotator::ZeroRotator));
CurrentWeapon = GetWorld()->SpawnActor<ABaseWeapon>(PrimaryWeaponClass, SpawnTransform, SpawnParams);
if (CurrentWeapon)
{
CurrentWeapon->AttachToComponent(FirstPersonMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
CurrentWeapon->SetOwner(this);
}
}
void ABasePlayerCharacter::Server_SpawnWeapon_Implementation()
{
Internal_SpawnWeapon();
}```
UPROPETY(Replicated) ABaseWeapon* PrimaryWeapon;
and corresponding entry in GetlifetimeREplicatedProps
You can replicate a pointer?
and no
BeginPlay if (GetLocalRole() == ROLE_Authority) SpawnWeapon();
you know it needs to be spawned every time
so no point in making the client wait for it
- this is simpler, and therefore, better
I don't get this? How does it make sense that you replicate a pointer?
@chrome bay Sorry to ping you, but if you don't mind; how does hit detection work on HLL?
clients simulate the projectile locally, notifies the server if it's hit something
the server rewinds all players to their past positions based on ping and resimulates the bullet
and either validates/rejects the hit
And do you just check the capsule collider on the server or mesh based? If the latter, couldn't the animation position mess it up?
We don't use the mesh because we don't run animations on the server
I'm doing a PvE game, and my thought was to do what you just described, except on the server, just count a hit against the capsule collider as a registered hit.
and even if we did they wouldn't be in-sync anyway
But we don't do hits vs the capsule because we don't physically move the players when rewinding
We validate as a line-line intersection with a tolerance radius
A capsule can just be represented as a line and a radius from that line
So a line-line intersection test it easy
But server hit test on meshes works greeeeat. Just ask ARK. Dodo birds running around with arrows in their head.
Alright - highly appreciate the info. I've been splitting hairs over this for a few days now and Authaer pointed out last night the sync issues with mesh based collisions.
@nocturne iron its not the pointer that gets sent, its the weapon actor's NetGUID
yeah mesh-based is a losing battle
which client can resolve as a pointer to its instance of the weapon actor
If you want per-limb damage, my advise is to send an enum to the server, and either trust the client on that detail, or add some extra validation
@winged badger Thx, that makes more sense!
we validate headshots but nothing else
Because this is just a co-op game with 0 intention of any competitiveness, I'll probably just trust the client.
i'd actually name the bones to be compatible with GameplayTag hierarchy
yeah you could do that also
then i would send the Tag, not the enum or Name for bone hits
Enums are terrible for systems that evolve
well
we treat thigh-below as "leg" and shoulder-below as "arm", so the hit is always either head, torso or limb
you wouldnt do that
and Names don't replicate efficinetly
So just 2-bits
you would have a map, BoneName to GT
But yeah, I definitely want per-limb damage, because I imagine, then, I would be able to do hit responses properly.
As it stands, I'm not sure how I would go about doing a hit reaction using the line-line intersection (I need to figure out how to do that as it is, lol)
yeah we don't go into per-bone detail, just distinguish from head, limb and torso in our case
well all the hit FX are played locally on each client
so you can't get shot in the arse? ๐
haha
meh in my pet project, all hits are client side
We replicate the health state and "last damage event" together in a struct for each character
server does some validation, but no re-winding ๐
So they just play the hits/responses that side based on when they receive damage
yeah we had to do rewind once we moved away from hitscan weps
all you weapons are projectile?
my hitscan sniper had drop off, and timed hit based on distance
has*
still WIP though, not touched any of that in months ๐ฆ
Yeah - I have that set up properly. It's just been the hit detection that I've been struggling with. Making sure it lines up properly. But once I get this wired up sometime this week (I wish I had more time to work on this project), the next challenge would be to get the right hit reaction, so if the hit is on the shoulder versus the arm for example.
Maybe I could send the bone hit and let the server figure it out with the line-line test? ๐ค
Projectiles as data in a projectile system?
yeah
Just spawn the particles in the world, then the projectile manager updates their transforms after bullets have all been updated
think TRS2 does a similar system
it does
also very fake "not-hitscan"
1 particle system per projectile tho or 1 global particle sim with each projectile getting a trail?
@dark edge one for each bullet
they won't inflict damage immediately to remote targets
But many bullets don't have particles too tbh, we only show the local players' ones and big snipery / MG ones
Yeah we needed things like shot lead and ballistics etc, so delaying the hit wasn't suitable ๐ฆ
Would have made life easier though ๐
you're doing WWI, we're doing Mars, not the same feel there ๐
haha
@chrome bay I got you. Yeah I implemented this type of setup with a subsystem and it performed really well. I take it you just do a line Trace per tick and adjust the line Trace based on position, velocity, acceleration?
pretty much
the good thing is you can spawn/despawn/simulate as much as you want without having to worry about actor lifetimes and stuff too
only projectiles i use is for Rockets/Grenades ๐
ah thats one thing i need to tackle, when i get free time (not any time soon..), penetrating weapons
Yeah that was... not enjoyable
I guess effectively it's doing the same thing as the projectile movement component, but with line traces instead of shaped traces, and in parallel instead of each actors update
Had to duplicate a lot of the engines' code to trace backfaces and such ๐ฆ
it's quite a simple system but trying to distinguish between "entry" and "exit" was the challenging bit
my idea was to trace on a certain channel, and overlap to grab the stuff
Damn level designers and their overlapping geometry and modular stuff ๐
and only allow penetrating on certain things
yeah we did it based on physical materials
wouldn't the normal dot direction work, be positive for exit, negative for entry?
ah yeah it does, but I just wanted to do one trace for each segment, and not have to back-trace to find the exit locations etc (for particles/decals)
So I ended up with a "multi-block multi line trace" sort of thing
Which returns all the blocks on a given segment, rather than stopping at the first one
Then yeah use dot product to work out if it's forward/backward face
when i enable "use controller rotation yaw" for TPS rifle mode, in client side, the server character always faces client camera forward
is there a work around this problem, or a better way to do it ?
That's not default behavior. UseControllerRotationYaw is only supposed to apply to that pawn's Controller's rotation. So unless you're updating the other pawn's controller's rotation somewhere?
no
if I have an actor that has the same velocity and physics settings on the server and the client then its trajectory should be the same on both and the server should never need to correct its position so there should never be any lag to its movement is that correct?
Quick question, I replicated my weapon, but when it shoots, it comes out of the other character?
always use a relative path over static one
if you're calling that from controller
GetControlledPawn is the same Pawn GetPlayerCharacter[0] on client
but its the same pawn you intended to shoot with on server, as well
and GetPlayerCharacter[0] on server is host's pawn
hmm
paired with the fact that whatever is connected to ServerRPC executes on server
you begin to understand your problem
and if GetPlayerCharacter[0] is connected to a node executing on server, it gets evaluated on server, as well
i see
im shooting from host with getplayercharacter
so i need something thats not so specific
from which blueprint are you shooting?
Im shooting from my weapon BP
is it spawned at runtime? show me how
It comes out of the Listenserver's character's weapon.
ok, easiest solve for your access character from a weapon
add a variable of your character's type to weapon
after you spawn a weapon
call SetOwner, giving it Self as a reference, and also set your OwningCharacter variable on the weapon
make that OwningCharacter variable replicated
result: weapon can access the character holding it from both client and server directly
and
it can also call RPCs
i can tell ๐
haha
so i would cast from my third person character
but what variable would I make?
not great at this lol
wait no get player character smh
nonono
weapon gets a variable CharacterOwner
which is of same type as your character
your SpawnActor node for weapon has a return pin
thats a pointer to your weapon
you pull from it and you do SetOwner(function) and SetCharacterOwner(variable) (replicated)
and as you are spawning weapon from a character
you put Self as input for both of those nodes
so character owner is the non specific way of saying third person character bp?
oh wait i get it
I set a variable for my weapon
I connect the variable to the return pin in my Third Person BP under spawn actor
you'll have to screen it, as you're really bad at describing it
lmao ill map it out and send it
blue prints are one thing
but replicated blueprints are a different breed
imo
lol
Is the PlayerCharacter spawned before or after the PlayerState?? (I would personally say after but want to check)
before on server, usually after on client ๐
That's good enough for me as I only need to use it locally
(to be spawned on client the actor has to replicate, and it has lower net priority by default then pawn)
so it replicates after pawns and controllers do
which makes it usually after in client
and sorry
edited above
PlayerState is spawned from APlayerController::PostInitializeComponents
which is by default, and almost always for custom spawning, before the Pawn is Spawned
I will have to start referring to PlayerCharacter as Pawn ๐ and no worries, yeah I guess I can just override it and do what I need to do in there.
HandleStartingNewPlayer
is a good hook for most spawning logic
you have a PC reference provided, PS is already valid by that point, and can be accessed via the PC
Parent/Super call calls RestartPlayer, which spawns the PlayerPawn
(GameMode BlueprintNativeEvent)
I will most likely need to dig deeper as there are a ton of useful methods that I don't even know about, but thanks for the explanation so far.
Also just wondering is there some sort of method that can keep players from spawning on ServerTravel until all the clients have travelled to the new map (Since not everyone would have the same hardware)
im looking up a lot of tutorials but it looks liek thjeyre doing it from the character bp
is that whats making it harder for me?
Are you just trying to set the owner of the Weapon once spawned?
๐
and i just really dont have a clue ๐
idk why there isnt any tutorials on set owner
im a very visual person thats why
Everyone is to a certain extent ๐
Left side would be the weapon you spawn and that's all you have to do to set the owner (This is if you're spawning it off the PlayerCharacter)
Ah i see now that makes a lot of sense
Now if you spawn it from a different blueprint you should be fine by just doing this
Now if you spawn it from a different blueprint you should be fine by just doing this, I've never done it via BP and I've done multiplayer about 3 years ago and just started again so forgot a loooooooooot of things. I might be wrong in saying this is one way of doing it as it might not be.
Ill take a look at both, but what you showed me was a step in the right direction because the lines end at my cross hair
But the origin is still coming from the other characters weapom
Then you're problem is when you AttachActorToComponent as it's referencing the wrong Mesh
So you're spawning it from the Character BP??
well, you did connect Owner now
fuck i think i am
Also try to print out the Parent see if its actually referencing the wrong Mesh
you also want the SwitchAuthority before you spawn the weapon
not spawning extra one on clients
and you can then access your character with Cast<ThirdPerson_BP>(GetOwner())
from the weapon
im checking it out rn
Is there any documentation on what is on the server and what is on the client? For example PlayerController vs Character. I'm still new to unreal, and I can't find any good info. Most of the sv -> cl stuff I done is winsock and just sending bits across
@winged badger do you mean switch has autority?
Is there a difference between that and HasAuthority?
nno
IsServer and HasAuthority can vary in output
in case you spawned the Actor locally on client
then client has authority over it
the netmode is still ENetMode::NM_Client
that what I tried for the line trace but it still comes out of the original players gun
wait im dense i dont think i replecated the blueprint itself
like the mesh
@carmine citrus Natively, I believe all the major actor classes are normally replicated except for PlayerController and GameMode. GameMode isn't actually replicated and only exists on the server. PlayerController only exists on it's owning client and the Server. So Client2 has no way of accessing Client3's PlayerController without going through the server. Which means that on a ListenServer, each client or the server's PlayerController0 is always the owning client's controller. Everything else I know of exists one on each machine.
Yea that all makes sense. I am still reading the doc @winged badger gave me, thanks again. For a practical example, should things like the player's inventory and weapons live in the player controller as that is on the server and owning client, and not the character?
Inventory depends on your system. If you don't care about other players knowing about the inventory, probably place it on the Controller. Otherwise PlayerState is an okay place for it. Alternatively if you want it to remain on their corpse, you can place it on the Character as well so that it's where it needs to be.
Weapons, I'd personally place on the character class and make the weapon replicated so the client can RPC through it.
Well, attach a weapon to the character class I mean. It being it's own replicated actor.
The more you know.gif. OK, thats where I was confused when looking at the shooter game example, and talking to an old classmate. Thanks for clearing it up.
And giving a real world exmaple
I place inventory stuff in Components myself. I have a main ActorComponent that I can attach to anything in the world. Character, Shelf, crafting station, etc. I use the main component for most everything except for the player. I didn't want players looting one another, so I made a child of the inventory component and made it only replicate to the player owning the character to avoid network traffic to the other clients.
i keep inventory in playerstate
so it can survive disconnect and reconnect
on an actorcomponemt
So does the PlayerState remain even after player disconnect? If so for how long?
Also worst case you can duplicate the inventory and have it on the Character as well if its a sort of survival game where players can pick other players/
@hidden thorn Depends which game mode you're using. One of the implementations will destroy the playerstate after some amount of time disconnected. If reconnect happens in time it'll copy the properties from the inactive state to the new one... so you need to override that copy function to include your new stuff you've added. I don't recommend using AGameMode unless it maps well to what your game requirements are. Otherwise use AGameModeBase and make it do exactly what you want. Trying to shoehorn non-arena based multiplayer (ala Unreal Tournament) into the GameMode by overriding its virtual functions is a recipe for spaghetti code bug fest.
it feels like I asked this because this question has been burning for me for quite some time now but I don't recall if I did
Can wolrd subsystems do any form of networking / sending RPCs?
Anyone here have any issues with networking functioning very poorly through steam vs editor? I put editor settings to 400 ping and 5 packet loss coming and going and it seems mostly fine. When I package the game and play online with a friend through steam it is very choppy and I get a lot of server corrections with no packet loss and ~70 ping.
2 things I want to ask,
1: Is it a bad thing passing an Object Pointer e.g Character as a parameter to a Server RPC ??? Would it be better to pass an ID and let the server find the player and grab it.
2: Just trying to remember how RPCs work really, if I press a Key e.g. 'E' I send an Server RPC call and I then call some methods on the Object I passed such as setting it to be a ragdoll and then call a separate method on it that he is dead (The Boolean is Replicated so this should be fine) do I need a multicast to let the other players know that he is a Ragdoll now or if it happens on the server it happens on everyone's machine? Or should I send a Multicast RPC not a Server RPC
- it is fine to pass pointers
- you have to (from the server) send to other clients that he should ragdoll.
You can do that with a multicast RPC, or a replicated property (OnRepNotify). Which one is best depends a bit on your project condition, as well as how long the Ragdoll character will stay alive (whether or not you are calling DestroyActor on it)
Multicast RPC only works if you call it from the server, you can't call it from client. If you need to communicate something from Client A to other clients, you have to go through server first. So Server RPC is the right beginning.
Yeah that makes sense thanks, also thanks for pointing out the duration of the Ragdoll Character, as I will not be destroying the actor I guess I will have to simply freeze the character so its not a ragdoll anymore but still in that position (This is one for another time)
how i can serialize movement location, rotation and velocity?
in a NetSerialize override of a struct
or just pass those values straight in as function parameters
if thats what you meant
I have a pawn (player). I send location, rotation, linearvelocity, angularvelocity to the server from the client on event tick
What do I need to do to serialize these values
then its just ServerReceive(FVector Location, FRotator Rotation, FVector LinVel, ... etc)
the engine automatically serializes it for you
if you want custom serialization, then place all of those in a ustruct and override NetSerialize()
UFUNCTION(Server, UnReliable)
void Server_PassMovementInfo(FVector_NetQuantize NewPawnLocation, FRotator NewPawnRotation, FVector_NetQuantize NewPawnLinearVelocity, FVector_NetQuantize NewPawnAngularVelocity);
void Server_PassMovementInfo_Implementation(FVector_NetQuantize NewPawnLocation, FRotator NewPawnRotation, FVector_NetQuantize NewPawnLinearVelocity, FVector_NetQuantize NewPawnAngularVelocity);
that should work then
yes, it's work
then what else do you wana do?
But I think this is too much data.
these are already compressed by the engine
the only way to lower bandwidth is if you have some special assumptions based on your pawns movement
Would it be better to do this in a structure and pass one structure?
for example if its in some state, then you dont need to pass linear velocity, in which case just flag it with a single bit etc
it would be cleaner that's for sure
and that way you can net serialize it yourself per your specifications
see for example how FHitResult is net serialized
How does unreal package, say a vector, over the network?
Does it just serialize then send?
Or does it somehow cut the precision of the vector
they use
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
can i use FRepMovement?
or override ReplicateMovement?
Should I do the same? UPROPERTY(Transient)
USTRUCT()
struct ENGINE_API FRepMovement
{
GENERATED_BODY()
/** Velocity of component in world space */
UPROPERTY(Transient)
FVector LinearVelocity;
So just had some issues with ServerRPC and MulticastRPC I also left the print logs just for easiness, they all get called expect the ones inside _Validation
KillPlayer gets called on key press.
void UCharacterIntruder::KillPlayer()
{
if (IsValid(OwningPlayer) && IsValid(OwningPlayer->GetPlayerInRange()))
{
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), OwningPlayer->GetPlayerInRange()->GetActorLocation());
if (_distance <= 200)
{
Server_KillPlayer_Implementation(OwningPlayer->GetPlayerInRange());
}
}
}
void UCharacterIntruder::Server_KillPlayer_Implementation(AIntruderCharacter* player)
{
UE_LOG(LogTemp, Warning, TEXT("Server_KillPlayer_Implementation"));
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), player->GetActorLocation());
if (_distance <= 200)
{
UE_LOG(LogTemp, Warning, TEXT("Server_KillPlayer_Implementation - DistanceValid"));
Multicast_KillPlayer_Implementation(player);
}
}
bool UCharacterIntruder::Server_KillPlayer_Validate(AIntruderCharacter* player)
{
UE_LOG(LogTemp, Warning, TEXT("Server_KillPlayer_Validate"));
if (!IsValid(player)) return false;
UE_LOG(LogTemp, Warning, TEXT("Server_KillPlayer_Validate - ValidPlayer"));
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), player->GetActorLocation());
if (_distance > 200) return false;
UE_LOG(LogTemp, Warning, TEXT("Server_KillPlayer_Validate - ValidPlayer - ValidDistance"));
return true;
}
void UCharacterIntruder::Multicast_KillPlayer_Implementation(AIntruderCharacter* player)
{
UE_LOG(LogTemp, Warning, TEXT("Multicast_KillPlayer_Implementation"));
if (IsValid(player))
{
UE_LOG(LogTemp, Warning, TEXT("Multicast_KillPlayer_Implementation - ValidPlayer"));
// This doesn't work
ACharacterState* playerState = Cast<ACharacterState>(player->GetPlayerState());
playerState->PlayerDied();
// This works, the player can't move anymore
player->GetCharacterMovement()->DisableMovement();
// This doesn't work
player->GetMesh()->SetAllBodiesSimulatePhysics(true);
player->GetMesh()->SetAllBodiesPhysicsBlendWeight(1);
player->GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
}
}
PlayerDied declaration & implementation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated)
bool bIsAlive;
DOREPLIFETIME(ACharacterState, bIsAlive);
void ACharacterState::PlayerDied()
{
bIsAlive = false;
OnIsPlayerAlive.Broadcast(false);
}
Yes
public:
UFUNCTION(BlueprintCallable, Category = Player)
void KillPlayer();
UFUNCTION(Server, Reliable, WithValidation)
void Server_KillPlayer(AIntruderCharacter* player);
UFUNCTION(NetMulticast, Reliable)
void Multicast_KillPlayer(AIntruderCharacter* player);
Even the print log inside the Multicast gets called and the DisableMovement seems to work as well the player can't move anymore after that.
@hidden thorn u need to add this
UFUNCTION(BlueprintCallable, Category = Player)
void KillPlayer();
UFUNCTION(Server, Reliable, WithValidation)
void Server_KillPlayer(AIntruderCharacter* player);
void Server_KillPlayer_Implementation(AIntruderCharacter* player);
UFUNCTION(NetMulticast, Reliable)
void Multicast_KillPlayer(AIntruderCharacter* player);
void Multicast_KillPlayer_Implementation(AIntruderCharacter* player);
Hmmm, from what I know after one of the version can't remember which one declaring _Implementation wasn't necessary anymore. I will give it a try but i doubt as it compiles just fine.
try to add
bool Server_KillPlayer_Validate(AIntruderCharacter* player);
bool Multicast_KillPlayer_Validate(AIntruderCharacter* player);
under Implementation
Another thing I tried is set the Mesh to Component Replicates, when called from the Server the client would go down but the bones wouldn't blend, it was still STIFF as a stick but on the ground. When called from the Client it seems the Server isn't affected.
I will try those now
@plush wave can i disable bool ReplicateMovement and send FRepMovement from Client to Server? and for other client call GetReplicatedMovement() for get Location, Rotation etc?
@gritty pelican That didn't do it
Maybe you should put the "validate" function higher than the "implementation"
bool SomeRPCFunction_Validate( int32 AddHealth )
{
if ( AddHealth > MAX_ADD_HEALTH )
{
return false; // This will disconnect the caller
}
return true; // This will allow the RPC to be called
}
void SomeRPCFunction_Implementation( int32 AddHealth )
{
Health += AddHealth;
}
Although I don't know if this makes sense
That's prob not going to make a difference, all the other calls I have Validate is after Implementation, thanks for the help anyway, I will go have some sleep and try again tomorrow ๐
can I use this structure to replicate movement? or i need to add something?
USTRUCT()
struct EXTREMEARENA_API FRepExtremePawnMovement
{
GENERATED_BODY()
/** Velocity of component in world space */
UPROPERTY()
FVector_NetQuantize LinearVelocity;
/** Velocity of rotation for component */
UPROPERTY()
FVector_NetQuantize AngularVelocity;
/** Location in world space */
UPROPERTY()
FVector_NetQuantize Location;
/** Current rotation */
UPROPERTY()
FRotator Rotation;
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
};
template<>
struct TStructOpsTypeTraits<FRepExtremePawnMovement> : public TStructOpsTypeTraitsBase2<FRepExtremePawnMovement>
{
enum
{
WithNetSerializer = true,
};
};
it really doesn't
What would cause my clients not being able to cast to a game mode? (Server has no problem doing it)
Does anyone know how the ClientTravel command works? I am trying to implement a travel using EOS and am getting the following error:
[2020.11.26-00.04.11:942][738]LogNet: Browse: EPIC://000260a3badb42808d1f8a910f7cd066:0/
[2020.11.26-00.04.11:942][738]LogNet: Warning: Travel Failure: [ClientTravelFailure]:
[2020.11.26-00.04.11:942][738]LogNet: TravelFailure: ClientTravelFailure, Reason for Failure: ''
Steam's implementation of the OSS has a port set, where mine is 0 which may be a problem? Also, Steam also has a map of travel and mine does not
Maybe ask in #epic-online-services you may need to transform it into a URL the game can understand.
thought this would be more relevant, since it is engine-specific but can do
@fossil spoke would running the code via a custom event set to server-reliable all clients to communicate with the game mode? (trying to set up a menu for respawns that are requested from the game-mode)
got it, thank you.
Ok. Time to ask a complete noob question. I have put this off for so long because I haven't needed to address this yet: From what I've read in here I know that I'm eventually going to need some custom logic in my PlayerController, GameState, and PlayerState, so I've just created C++ subclasses of each and then created a BP version of each. When I assign these BP's inside the custom GameMode BP, all of my movement, animation, and pretty much everything else just breaks. I believe this might have something to do with me now needing to define specific actions for spawning and possessing? What specifically do I need to override to get things back to normal?
you paired GameMode with GameStateBase or GameModeBase with GameState
and your output log is also complaining about it
You really have seen it all....
So do you recommend I use base for gamestate?
Or should I be forcing both to be non base
don't use base ones
Damn tutorials I swear to god
gives you better control about match start
Thanks man.
@shut gyro Example
FString Port = FString::FromInt(Result.pfServerDetails->Ports[0].Num);
FString URL = Result.pfServerDetails->IPV4Address + ":" + Port + "?PlayFabId=" + PlayFabEntityKeyID;
UE_LOG(LogTemp, Warning, TEXT("OnPlayFabGetMatchSuccess | Connect to URL %s"), *URL);
GetWorld()->GetFirstPlayerController()->ClientTravel(URL, ETravelType::TRAVEL_Absolute, false);
@winged badger got rid of the error but I still don't appear to posses my character and no inputs work still. Anything else you can think of?
Inside your character, there is an AI controller class
no super call on beginplay - gamemode, gamestate
and possessing method
Those are all required overrides? I thought not overriding would essentially use the super classes.
Yea I just have the subclasses completely empty right now and it's not working.
Unless the BP version does something bad like that
the fact that you rebased them
doesn't mean your world settings on that level are set correctly now
Gotcha. Will start overriding
@steel vault One of the options:
in gamemode create "event handle start new player", then call spawn actor from a class, select your class, then you can possess NewController(from event) to spawned character
Also, to get the coordinates for the spawn, you can call "FindPlayerStart" from the NewController(from event)
@gritty pelican this is not a my pawn doesn't work, this is nothing works situation
where World didn't call BeginPlay at all
What I find very strange is that when I switched them out, I switched them back to regular again and nothing worked still.
To my custom one that I subclassed from GameState yea.
If you mean when I tried to reset, then I believe so, I can try it again to see if it fixes everything or not.
Did u select GameMode in WorldSettings?
WorldSettings? I have it selected in maps and modes for project settings.
So, correct me if I'm wrong but did you send an RPC of the URL before you called OpenLevel on the server with map info, and then your clients, upon receiving that call the clienttravel method? Is that the order?
I just tried to override it and that didn't do the trick. What I can tell you is that now it appears I am spawning separate to the other character. It appears to be a problem where I am not possessing the character that I see
I am using a custom eos plugin based solution for listen servers and am wondering if I need to put the port in at all since your approach seems dedi-based, hm
So I have no body or controls, but I can see a character fully built near me who does
@shut gyro You might be better off using "ServerTravel
for server
@steel vault add this code to GameMode
If you did everything correctly, your character will spawn where the player start placed
@gritty pelican problem is I am using beacons so I think I have to destroy the beacons after I get the RPC so that I don't crash in the next level - at least that's how it was in steam - but I will give it a try
yea, I'm aware. AFAIK though wouldn't that persist the actors across levels though?
or can I turn that off
I had problems in the past with it because I think I tried to use it with persistent levels and my pawns would fall through the floor
I do not know this. I had no problem with this, I used this about two years ago
@winged badger can i pass structure values like this?
USTRUCT()
struct EXTREMEARENA_API FRepExtremePawnMovement
{
GENERATED_BODY()
/** Velocity of component in world space */
UPROPERTY()
FVector_NetQuantize LinearVelocity;
/** Velocity of rotation for component */
UPROPERTY()
FVector_NetQuantize AngularVelocity;
/** Location in world space */
UPROPERTY()
FVector_NetQuantize Location;
/** Current rotation */
UPROPERTY()
FRotator Rotation;
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
Rotation.SerializeCompressed(Ar);
return true;
}
};
UFUNCTION(Server, UnReliable)
void Server_PassMovementInfo(const FRepExtremePawnMovement & NewRepExtremePawnMovement);
void Server_PassMovementInfo_Implementation(const FRepExtremePawnMovement & NewRepExtremePawnMovement);
Server_PassMovementInfo(FRepExtremePawnMovement{RootCapsuleComponent->GetPhysicsLinearVelocity(), RootCapsuleComponent->GetPhysicsAngularVelocityInDegrees(), GetActorLocation(), GetActorRotation() });
Will it be automatically set in order like in a structure?
FRepExtremePawnMovement{RootCapsuleComponent->GetPhysicsLinearVelocity(),
RootCapsuleComponent->GetPhysicsAngularVelocityInDegrees(),
GetActorLocation(),
GetActorRotation() }
@gritty pelican your possession code works to possess a new player, it just doesn't fix my issue. Thanks for the effort though. Gonna try a couple more things that Zlo suggested to see if it helps.
@gritty pelican Crash when I try to server travel.
Getting objects with a null outer is no longer supported. If you want to get all packages you might consider using GetObjectsOfClass instead.
have you ever gotten that before?
@shut gyro Yes, it seems to test "ServerTravel" you need to package the project
Yeah that too
yea getting that "falling through floor" problem
I guess I would have to set the collisions up in the transition level hm
I do
or, in game mode call event handle start new player
and
in your controller
on begin play, make delay
and after you can spawn character and possess
Hi all! I am using SpawnEmitterAtLocation, however I am aware that it doesn't replicate. How should I go about replicating emitters over the network? Cheers!
Ok. Managed to get things working. I just ended up doing a source control reset of everything I changed besides my new custom classes. It appears that the error using GameState with GameModeBase completely biffed the blueprint or something so when I started fresh with that knowledge and set everything properly it all works @winged badger @gritty pelican
@slim mist Hi, replication of sounds, emitters are not supported
you need to call SpawnEmitter or SpawnSound in MulticastEvent
Thanks @gritty pelican, TIL about MulticastEvent! I'll find out how to use them
woohoo!
thank you so much!
you probably saved me hours
I imagine C++ equiv isnt too different
thank god for blueprints
So I'm running a simple preliminary multiplayer test, just 2 players both controlled by me on a listen server (I think that's what it's called?)
Wanted to test to make sure that when Player 1 is looking at an object and has it highlighted, that Player 2 doesn't see the highlight. This works. However, Player 2 doesn't seem to be able to highlight objects at all. Anyone got a guess as to why?
It's just a basic continuous line trace that puts a post-process outline on any physics object the player character is looking at.
anyone got any idea why when I attach an actor to another actor in multiplayer, it shows fine on the local client, and the listen host, but the attached actor is at the origin of the scene on other client
@cinder lily Check that the function runs on the client
@gritty pelican The line trace works, its just the post-process that doesn't seem to be working
You need to attach an object using the multicast event @cosmic badge
or you can make Variable OwnerActor (RepNotify) inside attached actor
and in OnRep_OwnerActor function you can make attach to actor
yea, I am @gritty pelican I think the issue is something unrelated now after some more experimenting, but thanks for the reply ๐
After that, to make the object attach, just set OwnerActor value on server side
yea, thats exactly what I'm doing actually, using a replicated actor ref, setting it on the server, I think I figured the problem out, it was related to some physics junk I was doing to smooth things out over the wire
it was fighting with it, I wouldnt have thought it would have done THAT, but sure, haha.
all fixed now ๐
@cinder lily that sounds to me like something that needs to be done locally on each client itself and not replicated at all. Line tracing just to highlight is a non multiplayer feature if you are doing it correctly.
@steel vault I haven't even touched replication yet. I was doing everything single-player so far and just wanted to test multiplayer. Thought it was weird that the highlight works for player 1 but not player 2. I should mention this is blueprint, not code.
example from google @obtuse moon
USTRUCT(BlueprintType)
struct FStructWithMap
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TMap<FString, FString> StringMap;
TArray<FString> StringKeys;
TArray<FString> StringValues;
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
if (Ar.IsLoading())
{
// Move data to Map
Ar << StringKeys;
Ar << StringValues;
for (auto It = StringKeys.CreateConstIterator(); It; ++It)
{
StringMap.Add(StringKeys[It.GetIndex()], StringValues[It.GetIndex()]);
}
} else {
// Move data to Arrays
StringMap.GenerateKeyArray(StringKeys);
StringMap.GenerateValueArray(StringValues);
Ar << StringKeys;
Ar << StringValues;
}
StringKeys.Empty();
StringValues.Empty();
bOutSuccess = true;
return true;
}
};
template<>
struct TStructOpsTypeTraits<FStructWithMap> : public TStructOpsTypeTraitsBase2<FStructWithMap>
{
enum
{
WithNetSerializer = true
};
};
I read about that one, but also read that it's for simple types?
Or it's just been tested with simple types
I swear I lose so much time on some shit sometimes... I'll have to refactor things because of not knowing tmaps didn't replicate
I think you can replicate anything in a struct if you can serialize it
You would have to show a snippet of what you're doing then to try and help. There should be no difference between the two traces and highlights if you are running a listen server with no replication logic written, because like I said, each character should trace and highlight locally. Are you clicking the arrow next to the play button and selecting Listen Server with 2 players?
Alright thanks I'll check this out tomorrow I've been on this all day
I don't see an option to select Listen Server with two players? It says the default is that Player 1 acts as the Listen. I'm on 4.24
@cinder lily if RunDedicatedServer disabled - it's listen server
and first player will be server and second will be client
The basic jist of the blueprint is that the player character is constantly doing a line trace and if that trace hits a physics object, a post-process effect is turned on to highlight it. Stop looking at it, the highlight goes away. pretty simple. But when I try the multiplayer, the 2nd player (client) only does the linetrace part - it's not doing the highlight
This is the blueprint function which highlights the object
@cinder lily when do you use the outline start function? can you capture it so i can find the problem
@open jacinth Outline Start is called as part of the continuous LineTrace, if certain criteria is met
try printing string in fail cast to gamemode, and see what it comes first
I set it to show the linetrace, the little red laser, so I know the linetrace is working fine
no, i mean in the outline start function, in fail node, try create a print string
cast to treasurehuntbase
Yes, its printing on failed to cast
does it fail on client or server, i guess it on client
Client
then the client can't use that function, you need to work around that
my opinion is creating a rpc to server rather than a function, when criteria is met you call rpc to server, then server call a rpc to owning client, but i still dont know what your gamemode does, maybe you dont need to work with it
since client can't cast to game mode that why you dont have outline in client view
@cinder lily pretty sure your code isn't working because you are calling things from the game mode and only the server owns the game mode so that is why you aren't seeing it on the client. I don't know much about the post process stenciling but you should find a way to do it elsewhere.
I stored the variables in the GameMode because it seemed like the easiest and best place to store variables that would need to be called by multiple different things. Is there a better alternative, one that could be accessed by the client?
@cinder lily GameMode only exists on the server and can never be reached from any client machine without going through the server version of their owned actors. PlayerController only exists on the owning client and the server, thus client 3 cannot get ahold of client 2's PlayerController. Every other actor like GameState or PlayerStates, or possibly PlayerCharacters, exist one copy per machine.
If you need a game wide variable for all clients, consider GameState. If it directly relates to a specific player, consider their PlayerState or PlayerCharacter. If you need something private for a client that other clients should never see, consider PlayerController. If it's something that needs secured on the server only away from any client's reach, GameMode.
Hey can anyone help
https://answers.unrealengine.com/questions/997722/view.html
Sounds like I've got some reconfiguring to do. Thanks for all the help everyone!
Don't suppose anyone knows much about terraform do they? ๐
Hey!
Hi
can anyone explain what is session in multiplayer
i mean i am trying to find about it and no one is talking about what is it exactly.
there is no mansion about it in basic multiplayer, so what exactly it is?
From Characacter A can I check if a variable on Character B's player state is true or false (the variable is marked as replicated) ?
If you have a reference to Character B, yeah
So I am calling a ServerRPC from A passing B as parameter and Grabbing the PlayerState and changing a variable (Marked as Replicated), when I am doing it that from Client or Server it seems to only work on the Local Player and not on the server for some reason.
Hmmm another weird thing is I added a AddOnScreenDebugMessage on the server and it seems that the LocalPlayer has it displayed on screen not the server
is it ok to do ~1000 reliable rpc,s in a frame as a one-time thing? with each rpc having FName + 32 bits of data or should i do one really big rpc instead? idk wich is better
@fiery badge a Session is a collection of meta-data stored about a multiplayer game. The Online subsystem can use this Session data to search for games using Matchmaking system.
So if you don't use Session then when you create a game no-one knows about it and you have to give them the IP to join.
If you register a Session when you start your server then people can discover it without knowing the IP address.
It does some other things too but that's the key part.
I am really struggling with making a Server RPC call from the Character, what I am doing is call Server Method -> Set Replicated Variable From Player State -> OnRep_Notify should be getting called but it isn't. It works when I am making the call from the Server but not from the clients.
Show your RPC from the client?
1 sec just putting it together now ๐, OwningPlayer is set in BeginPlay from GetOwner()
void UCharacterIntruder::KillPlayer()
{
if (IsValid(OwningPlayer) && IsValid(OwningPlayer->GetPlayerInRange()))
{
if (GetOwner()->HasAuthority())
{
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), OwningPlayer->GetPlayerInRange()->GetActorLocation());
if (_distance <= 200)
{
ACharacterState* playerState = Cast<ACharacterState>(OwningPlayer->GetPlayerInRange()->GetPlayerState());
playerState->PlayerDied();
}
}
else
{
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), OwningPlayer->GetPlayerInRange()->GetActorLocation());
if (_distance <= 200)
{
Server_KillPlayer_Implementation(OwningPlayer->GetPlayerInRange());
}
}
}
}
void UCharacterIntruder::Server_KillPlayer_Implementation(AIntruderCharacter* player)
{
float _distance = FVector::Distance(OwningPlayer->GetActorLocation(), player->GetActorLocation());
if (_distance <= 200)
{
ACharacterState* playerState = Cast<ACharacterState>(player->GetPlayerState());
playerState->PlayerDied();
}
}
bool UCharacterIntruder::Server_KillPlayer_Validate(AIntruderCharacter* player)
{ return true; }
void ACharacterState::OnRep_IsPlayerAlive()
{
AIntruderCharacter* owningCharacter = Cast<AIntruderCharacter>(GetPawn());
if (IsValid(owningCharacter))
{
owningCharacter->GetCharacterMovement()->DisableMovement();
}
}
void ACharacterState::PlayerDied()
{
// When calling from the client it comes into this method but doesn't get past the if statment
// When calling from the server it passes the if statement
if (HasAuthority())
{
bIsAlive = false;
AIntruderCharacter* owningCharacter = Cast<AIntruderCharacter>(GetPawn());
if (IsValid(owningCharacter))
{
owningCharacter->GetCharacterMovement()->DisableMovement();
}
}
}
// UCharacterIntruder .h
UFUNCTION(BlueprintCallable, Category = Player)
void KillPlayer();
UFUNCTION(Server, Reliable, WithValidation)
void Server_KillPlayer(AIntruderCharacter* player);
// ACharacterState .h
UPROPERTY(EditAnywhere, ReplicatedUsing = OnRep_IsPlayerAlive, BlueprintReadWrite, Replicated)
bool bIsAlive;
UFUNCTION()
void OnRep_IsPlayerAlive();
What I don't get is why when called from the Client inside PlayerDied I had 2 prints 1 outside the if and 1 inside the if the one outside was getting displayed but not the one inside. Am I not calling PlayerDied from the server properly? From what I get I shouldn't have got either of those prints since its called on the server.
I'm fairly certain you only have to call the Server_KillPlayer(OwningPlayer->GetPlayerInRange()); without the Implementation part that you declared in the .h file. At least I never had to. That is just for the generated file to handle stuff as far as I was aware. I'd also place a print right before that and check that the print is working from the client when it's supposed to in the same way it works on the server.
So I had prints before every call (I removed them for simplicity) and everything is getting called from both the Client & Server except what I mentioned above inside PlayerDied
I'm fairly certain you only have to call the Server_KillPlayer(OwningPlayer->GetPlayerInRange()); without the Implementation
How is this even possible ๐ฆ ๐
That worked
I literally spent yesterday afternoon and today (last 4 hrs) trying to figure this shit out.
Haha. Yeah. I had that issue myself with BlueprintNativeEvents and the _implementation a while ago. Assumed it was the same for RPC calling.
It's probably something that Unreal does before or after calling the Implementation event when you call the normal one. It'll run the normal one, but the generated file adds code around your functions. So it's likely that reason that it wasn't networking, but was working on the server.
hey, is there a way to show a splash screen or some widget while joining a listen server ?
or does everything just get destroyed no mater what ?
I was wondering if there was a way to show some sort of loading screen or something while joining a friend on a server or something, like seamless travel.
I think you just answered your own question, using seamless travel and a Transition Map.
Who can help with serialization? For some reason, I get zero values on the server and on other clients
MyStruct
USTRUCT()
struct EXTREMEARENA_API FRepExtremePawnMovement
{
GENERATED_BODY()
UPROPERTY()
FVector_NetQuantize LinearVelocity;
UPROPERTY()
FVector_NetQuantize AngularVelocity;
UPROPERTY()
FVector_NetQuantize Location;
UPROPERTY()
FRotator Rotation;
FRepExtremePawnMovement()
{
LinearVelocity = FVector::ZeroVector;
AngularVelocity = FVector::ZeroVector;
Location = FVector::ZeroVector;
Rotation = FRotator::ZeroRotator;
}
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
Rotation.SerializeCompressed(Ar);
bOutSuccess = true;
return true;
}
public:
FRepExtremePawnMovement(
const FVector& InLinearVelocity,
const FVector& InAngularVelocity,
const FVector& InLocation,
const FRotator& InRotation)
: LinearVelocity(InLinearVelocity)
, AngularVelocity(InAngularVelocity)
, Location(InLocation)
, Rotation(InRotation)
{}
};
template<>
struct TStructOpsTypeTraits<FRepExtremePawnMovement> : public TStructOpsTypeTraitsBase2<FRepExtremePawnMovement>
{
enum
{
WithNetSerializer = true,
};
};
Well only the rotation will ever be serialized
Since that's the only property you're writing to the archive
@chrome bay Wouldn't the FVector_NetQuantize be serialized automatically?
no
When you create a NetSerialize function only what you put in there will be sent
You lose UPROPERTY() serialization and per-property comparisons too - so the full archive is sent everytime
Could you tell me how to do it right?
Well it depends. Do you want to send the full struct every time?
I just started learning about serialization yesterday, so this is a new topic for me
yes
If so, you just need to add
AngularVelocity.NetSerialize(...);``` etc
... replacing the params ofc
also, as long as you don't need roll, Rotator goes through the network just fine as FVector_NetQuantizeNormal
right?
bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
LinearVelocity.NetSerialize(Ar, Map, bOutSuccess);
AngularVelocity.NetSerialize(Ar, Map, bOutSuccess);
Location.NetSerialize(Ar, Map, bOutSuccess);
Rotation.SerializeCompressed(Ar);
bOutSuccess = true;
return true;
}
yeah pretty much
in my pawn i add this
protected:
UPROPERTY(Replicated)
FRepExtremePawnMovement RepExtremePawnMovement;
UFUNCTION(Server, UnReliable)
void Server_PassMovementInfo(const FRepExtremePawnMovement & NewRepExtremePawnMovement);
void Server_PassMovementInfo_Implementation(const FRepExtremePawnMovement & NewRepExtremePawnMovement);
in cpp
DOREPLIFETIME_CONDITION(ACPP_ExtremePawn, RepExtremePawnMovement, COND_SkipOwner);
Seems okay, just bear in mind the full struct will be replicated everytime too
and on tick from client to server
const FRepExtremePawnMovement RepExtremePawnMovementLocal(RootCapsuleComponent->GetPhysicsLinearVelocity(),
RootCapsuleComponent->GetPhysicsAngularVelocityInDegrees(),
GetActorLocation(),
GetActorRotation()
);
Server_PassMovementInfo(RepExtremePawnMovementLocal);
but tbh, since the default engine replicated movement works that way too, probably not worth worrying about
Lots of room for optimisation there
I heard that replicating with one structure is better than each value separately
well it's not "better" as such
i don't know if it's true
But more convenient a lot of the time
You probably do want to avoid sending an RPC on tick though, even an unreliable one
even CMC does what it can to avoid that
Yes, I use linear interpolation to smooth movement on the server and other clients.
my sync movement function
void ACPP_ExtremePawn::SyncMovement(float DeltaTime)
{
FVector NewPawnLocation = FMath::VInterpTo(GetActorLocation(), RepExtremePawnMovement.Location, DeltaTime, ClientSyncSpeed);
FRotator NewPawnRotation = FMath::RInterpTo(GetActorRotation(), RepExtremePawnMovement.Rotation, DeltaTime, ClientSyncSpeed);
FQuat NewPawnQuat = NewPawnRotation.Quaternion();
SetActorLocationAndRotation(NewPawnLocation, NewPawnRotation, true);
FVector NewPawnLinearVelocity = FMath::VInterpTo(RootCapsuleComponent->GetPhysicsLinearVelocity(), RepExtremePawnMovement.LinearVelocity, DeltaTime, ClientSyncSpeed);
FVector NewPawnAngularVelocity = FMath::VInterpTo(RootCapsuleComponent->GetPhysicsAngularVelocityInDegrees(), RepExtremePawnMovement.AngularVelocity, DeltaTime, ClientSyncSpeed);
RootCapsuleComponent->SetPhysicsLinearVelocity(NewPawnLinearVelocity);
RootCapsuleComponent->SetPhysicsAngularVelocityInDegrees(NewPawnAngularVelocity);
}
FYI RInterpTo / VInterpTo are not linear
And interpolation is all well and good, but it means you can't accurate get an position of an object
meh smoothsync
If you must smooth, it's probably better to smooth visuals only
I also suspect that too much smoothing, especially linear/angular velocity, will result in overall worse sync
Just send less, don't send on tick
Otherwise you'll be hammering the server with packets at whatever framerate the client can run at
this kills the server
Sending at a fixed rate, and lowering that rate when the value hasn't changed is a good start m
Oh, exactly. Thanks, I didn't even think about it
fps 200 = 200 RPC
for example i can make this on tick
MyPrivateFloat -= DeltaTime;
if(MyPrivateFloat <= 0.f)
{
MyPrivateFloat = 0.1f;
Server_PassMovementInfo...
}
I tend to use world time seconds / real time seconds
and cache a "last sent time" or something
hello, what is the current state-of-the-art way to wait for a PS to be ready from a PC so that I can initialize a VOIPTalker appropriately? I'd rather not do a delay loop with an isvalid switch...
override OnRep_PlayerState?
Right. unfortunately BP only. Maybe I'll set up a custom event for this one.
(I mean expose to BP an event called from OnRep_PlayerState)
thanks
no it's ok I can add it in C++
is OnRep_PlayerState on playercontroller?
ok thanks
If I update a Replicated variable and I then want to broadcast a delegate what is the best way to do it? I tried to broadcast it from OnRep.... but wasn't successful.
@winged badger just wanted to say thanks, i've been using rider for all of 24hr and i'm hooked
@hidden thorn OnRep would be the way, assuming you want the delegate to be broadcast on the client
If on the Server, then broadcast as soon as you change it
It would be both the clients & server (ListenServer), I will try it again
Does the delegate need to be marked as Replicated?
You can't replicate delegates, they're local only
If you want both, then you'll have to broadcast from both places
When changed, and in the OnRep
Oh ok, I am able to get it on the Server but not Client, I will try it again though
//.h file
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnIsPlayerAlive, bool, bIsAlive);
UCLASS()
...
UPROPERTY(BlueprintAssignable)
FOnIsPlayerAlive OnIsPlayerAlive;
//.cpp file
// bIsAlive ReplciatedUsing = OnRep_IsPlayerAlive
void ACharacterState::OnRep_IsPlayerAlive()
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("OnRep_IsPlayerAlive")));
if (AIntruderCharacter* owningCharacter = Cast<AIntruderCharacter>(GetPawn()))
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Broadcast")));
OnIsPlayerAlive.Broadcast(false);
}
}
void ACharacterState::PlayerDied()
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("PlayerDied")));
if (HasAuthority())
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("PlayerDied - HasAuthority")));
bIsAlive = false;
OnIsPlayerAlive.Broadcast(false);
}
}
So it works on the server but not on the client
Broadcast does get printed on the client when called.
Do you ever set bAlive to true?
In the constructor
And the actor itself is replicated I assume
Hang on, you said 'Broadcast' does get called and printed - so it is being broadcast
I didn't set it personally but since everything works, I have 2 methods in there (which I removed for simplicity) which makes the character turn into a ragdoll which works on clients
The word Broadcast gets printed, when calling AddOnScreenDebugMessage.
Yeah, so it must be working then
I would guess you don't have anything bound to OnIsPlayerAlive on the client
I did bind it to a Widget and when its true or false it should display something on the screen which it doesn't do on the client.
If it's printing 'Broadcast' and the code above is accurate then the delegate is being called
So the only option really is that the binding isn't setup
I would put some breakpoints in and step through
But if it works on the Server doesn't that mean that its setup properly?
not at all
For example, the widget might be valid before ACharacterState is
So it can't bind to it
etc.
Yep that was it, I just added a 10sec delay and now it works
oof ๐
You have to get used to making the codebase resilient to things not being available straight away
Delays are the fast, but extremely unreliable approach
Something I really need to get used to, I just keep bouncing in and out of making games and never really got a good grasp of UE4
Definitely, it was just a quick way of telling if that was the issue ๐
Yeah it takes some time to figure out. There's some helpful design patterns you get used to doing after a while
adds to blogging backlog
To be fair every time I come back and start using UE4 I learn something new that I haven't used before ๐
There really arenโt enough good materials out there on this subject especially for UE4. You guys are the real heroes helping out with such things. Would love to see more content on design patterns and the like.
Are there any design patterns specific for UE4 ??
I'm not sure if there's anything specific
Or rather what the official names are if there are any
Fair
I think a lot of it just comes down to the individual or company. It's just one of those topics where there's a lot of right ways, and a whole lot more wrong ways.
I'm not making this OnRep_PlayerState event work, it doesn't get called in BP.
I have:
// Event PlayerState replicated
virtual void OnRep_PlayerState() override;
UFUNCTION(BlueprintNativeEvent, Category = Character)
void OnPlayerStateReplicated();
void AFECCharacter::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
OnPlayerStateReplicated();
}
void AFECCharacter::OnPlayerStateReplicated_Implementation()
{
}
this doesn't get called
any hints welcome, I'm a real, real noob in C++.
Have you logged or printed in the OnRep to make sure it's running before the BlueprintEvent is called?
apologies.
this is actually working. it's not being called on the server obviously since it's in C++
where can I call it though, to ensure that the server also has this event?
i'm basically trying to get on a character when the playerstate has been replicated, in BP.
You're trying to get to the server version of the character that belongs to the same player as the playerstate?
Longer story: I'm using a VOIPTalker on a character, but that needs the player state to be ready so that it can be registered.
so instead of checking in a loop that the player state is valid, i'm trying to make proper things by having an event when the PS has been replicated
I basically want to avoid this crap
so I'd rather have the second part here called on an event
do i have to also override void APawn::SetPlayerState(APlayerState* NewPlayerState) and call OnPlayerStateReplicated() from there?
(which is not overrideable unfortunately)
Never worked in a professional environment only by myself, I applied at a few jobs at game companies but ended up botching the C++ technical interview ๐ so not exactly sure how it is. I currently work as an App Developer and I can say that I do enjoy working in a team as there is still a lot that I can learn and it helps having more senior devs around me.
I have never personally worked in a professional environment myself. I'm only here because I have a serious love of game design. I find I love putting stuff together. I tried Unity a while ago, and many years ago dabbled with UDK but nothing more than plopping static meshes into a level. Before November of last year, my whole software skillset was HTML, and LUA UI design. Not sure how I'd handle a professional environment though. Interesting thought. I love problem solving and working around things, but I also love working on my own ideas too.
@ember needle I'm not finding much to help with that really. My only thought is that you could use something like the controller as a "register". Make each class call a function in the controller to let it know they're ready for use. It'd allow you to refresh the character if you kill it off and destroy it too. Controller would probably have to query when it first spawns if either of those two are active and set them up too just one time.
Either that, or you could mimic what the Pawn and Playerstate are already doing with your own functions to get the replication the way you need it.
Hey guys, I'm looking for a bit of wisdom on how large a multiplayer map could responsibly be on a single server. I was hoping for at least 32km2, is that a pipedream? If need be, I'll scale down, just trying to understand the constraints and where the painpoints are.
In terms of actor count and characters I have a fairly decent understanding of what's expensive, but I'm surprised there's theoretical limits with world composition. That is to say, I'm a bit oblivious as to why a large world would be an issue for a server to handle (not withstanding any extra actors).
Nah, that's why you'd have to have the controller check as well when it first starts. Controller checks once when it's created. If nothing exists, they'll register when they are. If they are created, it can set them and when they query to the controller it would be invalid and not set anything, but the controller would handle it when it's spawned. After that it'd probably just be the character registering itself on spawn.
i'm probably not following, but both your character and your controller don't know when the player state is replicated and ready
and the player state, doesn't know when the character is ready as well.
moreover the PC could be created before / after the PS
so there are 3 assets here and the only sure thing is that the controller gets created before the character (AFAIK)
If you only set this stuff on the server. Ignore clients. They don't need to do anything but get replicated to for the setting part. Controller can have two RepNotify variables. One for Pawn, one for PlayerState. One scenario is that controller spawns first. It calls a quick function to see if PlayerState or Pawn exsits yet. Nothing. No variables set. PlayerState spawns in. Calls it's own function on the controller and registers itself. Character spawns, registers itself. All things are now set and both variables should not be replicated to clients for them to do with what they like. Alternative start. Playerstate spawns in. Calls it's function on Contoller, controller doesn't exist so it doesn't call it. PlayerController spawns, checks playerstate, it exists, it sets Playerstate on itself since it's valid. Character spawns in and registers itself in the controller. Mind you this is all happening on server.
Now that the setting is taken care of, all that's left is client's work. Both variables having a repnotify means it can call the same function on the client when they change. If one thing is invalid, ignore. If both are valid, set up your stuff on the client.
"PlayerState spawns in. Calls it's own function on the controller and registers itself" player controller might not exist yet.
you may actually have a race condition
where both PC and PS get created almost at the same time but they are not set yet so PC->PS is none and PS->PC is none
but they both exist
AFAIK obviously...
It's possible, but with Pawn also calling this function to update stuff, it's highly unlikely to fail.
beginplay is called on PC and on PS but their PS on one and PC on the other are not yet set.
I've actually seen it quite often unfortunately
in logs
ah sorry not with the pawn part.
what do you think about this:
- I use my custom
OnPlayerStateReplicatedon all clients. - On server, I use the
Possessedevent... it looks like when this is called the PS is set: https://github.com/EpicGames/UnrealEngine/blob/1eb5d965b994b4bd59f31ec4158d42f13137ab1f/Engine/Source/Runtime/Engine/Private/Pawn.cpp#L497
void APawn::PossessedBy(AController* NewController)
{
SetOwner(NewController);
AController* const OldController = Controller;
Controller = NewController;
ForceNetUpdate();
if (Controller->PlayerState != nullptr)
{
SetPlayerState(Controller->PlayerState);
}
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (GetNetMode() != NM_Standalone)
{
SetReplicates(true);
SetAutonomousProxy(true);
}
}
else
{
CopyRemoteRoleFrom(GetDefault<APawn>());
}
// dispatch Blueprint event if necessary
if (OldController != NewController)
{
ReceivePossessed(Controller);
}
}
Is there anyone who is good at the character movement component who would be interested in doing some consulting work for a few hours at a good rate until I am able to get my custom CMC working? It needs to work in multiplayer, I posted on #freelance-jobs. DM me if interested
Could very well work. I didn't think about possession events.
thank you @kindred widget for listening and helping
FYI this works
the possessed event gets called only on server
Careful with that then. It'd only work for the Listenserver character.
IIRC I put logic in the reset function override because itโs basically ensures that everything else had been set up first. Would have to go back and research again to explain why though.
Wouldn't you want it to work for the owning client of the character though too?
@steel vault are you talking about the PS situation here?
ouch. You might be right
I was referring to making sure the possession had occurred at least. I donโt know if playerstate is or is not setup by then but I would assume it is because reset I believe is for the owning clientโs player
so it's probably just