#multiplayer
1 messages · Page 489 of 1
looking at some comments in UCharacterMovementComponent it seems like this is done with RPC, but in replays i’m not sure that RPC works the same
i’m specifically talking about replays
How would I show a different widget on server connect and a different widget on clients connect?
Would I handle this from their PCs?
Why is this wrong?
theres no need for those to be RPCs since thats only running locally
also theyre both calling the same thing
When people put strange characters in their name in makes it impossible to tag them.
Character movement is replicated through replicated movement like any other actor.
Replaying "Moves" if that's what you're referring to is triggered when a client gets a correction - all moves are played instantly at the start of the tick before processing normal movement for that frame.
All Moves that are newer than the correction*
And Replays is probably meant to be an actual replay
Not the Moves
is there a way to replicate fast to the clients the new location that i set for the pawn on the server? (without waiting for the correction)
no
it gets there when it gets there
That's why you predict changes where possible on the client
How can I set a pawn and possess it to the logged in PC? What's the process?
onpostlogin from GM won't work as it only exists on the server
Calls 'Possess' on the Server for the player controller
You don't call' Possess' client-side anyway
Post Login is probably too early
So how?
The gamemode spawns a pawn for the player anyway and they will possess it automatically
No it won't
I wont different pawns based on if its a server or not
If you want different pawns you need to override 'Spawn Default Pawn For'
I'm sure I can, I've done it from a tutorial before where it checked what character there as selected and then spawned a pawn for it and possesed the P
PC
The server is in control of who possesses what
'Spawn Default Pawn For' -> IsLocalPlayerController* -> Yes (Server)/No (Client)
GetDefaultPawnClassForController is what you want to override
One of them yeah
Well, what if I want to change pawns in game?
Then you spawn a new pawn and tell the controller to possess it
So why won't the picture I sent you above work? What's wrong with it?
Because the default pawn will be spawned after that has run
And the controller will switch to that instead
But the server does get that pawn, why?
But the server does get that pawn, why?
What does that even mean
You are pretty vague in what you want
By default, functions like PostLogin call for Server and Client connecting (on the server).
Same for the DefaultPawnClass you can set.
Looks like it won't spawn a 'Default' pawn if the controller already has one
But still, overriding the default pawn per-controller is better
If you need custom logic for who gets what pawn, then you have to set the DefaultPawnClass to NONE and implement the function we mentioned.
I just want to create a function that would spawn an actor and possess it to the connected controller.
Okay\
The code you posted above would do that
But make sure you set the DefaultPawn to none in the gamemode settings
Okay it worked, but it needed a delay after onpostlogin
@chrome bay it’s weird because i spent a good portion of the day trying to see where this was occurring, i set a breakpoint inside the function which serialises the replicated properties but it doesn’t even get triggered on most frames of the playback so i don’t think that’s what’s happening
i also looked at the names of the replicated items and none of them were FRepMovement as you’d expect
@soft relic If you need a Delay, you are doing it wrong. Delays are a No-Go in networking
Fixed it, it's without a delay now
What do you mean by replay exactly?
I can't tag you because of the Char in your name
Are you talking about replay in the networking sense, or are you talking about replaying a full game?
Like the paragon/fortnite demo replay system
replaying a full game, as in with the demorec / demoplay commands
not sure if that’s what it is in fortnite
No replication occurs for that
There's no server etc.
The players movement is stored in a separate struct and saved off somewhere
it essentially streams packets from the replay file
When you do a replay you download a massive file IIRC
and you just scrub through
There's no networking involved
the massive file is just a list of packets
and it serialises it in roughly the same way as any other data from the network
there’s definitely replication
it’s as if the replay file is the ‘server’
but some things are different
my use case is that i’m trying to write a replay parser as an external tool
PreReplicationForReplay() seems to be what processes replay samples
I'm not 100% tbh now, I've never used the demo recorder etc.
yeah no i think i just realised what i need to do
welp
i was expecting it to be with the other rep data but it seems like it’s special cased and put somewhere else
not that you asked, but iirc demo recorder doesnt work in PIE
Does anyone know if you can delay the welcome process of UE4?
As in, usually you can deny a player in PreLogin and Login.
But if that's tied into an Async Call to the Backend, you can't deny there.
I know I could modify the engine to simply not execute the welcoming stuff until I say so, but I wonder if that's already possible without engine changes.
I previously tried to do that and found it to be impossible
Via Engine Modification?
that's what I ended up doing
Someone did do that though, at least if you can believe their PlayFab forum post
Ah
I suppose one way without a modification would be to use the beacon thing
It would be an easy engine change though
connect a beacon first, handle auth, get the ticket or similar that you can immediately accept, then do a normal connection
but that's unreasonably more complicated
You just have to give the user the option to call the stuff themselves
As in, whereever UE4 calls Welcome (if the ErrorString is empty), you'd just check if the Welcome is delay (boolean).
And then allow them to call the code themselves
That would be the easiest way
Welp, Engine Mod it is
What chat are you using with UE games? We use Photon, it kinda sucks - what other option?
Hello guys,
I got some problem with Variable replication using a Dedicated Server. I have two actors, owned by two different clients. When I set a variable on the server, only the server and the owner of the actor has the value replicated. Not the other non-owner client.
Is this intended behavior ?
@supple musk If you're the server then your Role is Authority So if you set at variable as the server/owning authority will have that variable changed for owning authority actors the second will be Owner Autonomous proxy will not unless you have a function the Server calls to set the variable for those Autonomous proxies specifically.
Think of it as permissions in a file system
the other actors are not part of Group Authority
I’m learning multiplayer, and I wanted to make sure my observations seem correct.
- When using one time input actions, say swapping weapon, using ReplicatedUsing=OnRep_SomeFunction would suffice since the Both the server and client would only update once, thus this action would only need to be checked once
An example of this implementation could be:
UPROPERTY(ReplicatedUsing=OnRep_Variable)
float Variable;
UFUNCTION()
void OnRep_Variable();
@graceful pumice When your variable is replicated from the server then On_RepVariable is called
then inside that function you can make it Server side or client
I believe I understand that part.
so in the case of your example with swapping weapons when say the client replicates a bool that says swap weapons then an On_Rep can multicast that the client or w.e swapped a weapon
Multicast meaning it updates both the server and all clients, right?
so if i multicast a fart
everyone connected to the server can smell it
it will broadcast it to everyone
Got it
So In Rama’s tutorial that I’ve been following
He calls his OnRep function inside his server function
That's different
But that’s unnecessary, correct?
When you call an On_Rep that just means you are doing the call back
So say you have a situation where you want to On_Rep function to be called when its tied to replicated value and you want to call it when something you did logically happens
you get the best of both worlds
The On_Rep will be called on replication but also you called it because someone farted
or w.e
Why would I call it back though? What’s this other benefit?
flexibility
or logic
w.e your code requires
You have it by default On_Rep for a variable persay
but say for some reason when a timer goes to 0 or something else thats not tied to the variable being replicated you want that On_Rep to be called you can just call it yourself
I think I get it.
So let me see if I’m following you
Using my weapon swap example
sure
I have a bool that replicates using OnRep
Yup
A have a button input that calls an equip function
That runs logic locally to determine if the player can equip
If the player can equip, I would call me server function, which sets my replicated bool to true
Inside that server function, I set my replicated bool and call the on rep function
Inside my OnRep function is the logic for actually equipping the weapon
Sound correct?
That runs logic locally to determine if the player can equip
That's a bit risky
You change that variable on the client to say true.. it gets replicates... then On_Rep is called your logic get executed.. Now for the case of your equip logic I am gonna assume you are validating that bool on the server if it's allowed its replicated then that user can equip w.e item so server says ok. Now for example lets suppose you have the logic coded up and your On_Rep does all that equip logic takes in who its to be equipped to the item etc... Then lets continue on this logic lets say you have a mechanic where if you get a kill streak you get a super weapon or something but its not something the user has access to you can Call On_Rep by the server and pass that super weapon object to the function and the user you specified will get it.
@fluid prawn i don't quite get what you explained. To me, for a variable to be replicated on every client I just had to set it on the server, regardless of ownership
@thin stratus @fluid prawn So even the check to see if the player can equip should be on the server? If so, then that means I would have my input directly calling my server function. Is that okay?
@twin juniper Sure you can have the variable on server or you can have the variable on Client. Depends on what you want to do but if its on client you have to decide what you want to validate because the client can hack that info
LOl cedric did you just draw that up now XD
Once you know how that works it's pretty quick to draw ¯_(ツ)_/¯
lololol
So I would have the input call a client function
Yeah just a function
That checks if it can equip
LET ME SHOW YOU NETCODE
Then the client would send it’s request to the server, which I would do by calling the server function
Correct, but only if the Client already switched
If the server says yes, then update the bool
it's predicted basically
ya that function should exist on the server
Generally speaking, you'd have some sort of OnRep variable that says what is equipped
Like CurrentWeapon
for validation only if you want it to be responsive you can have the client equip it and then ask permission from the server
Right, well I’m not to the actual equipping part yet
Basically I’m focusing on the rotation of the character
You wanna draw out the whole process though
Otherwise you just do it over and over again
That diagram is sound
What I’ll do, then, is write out some pseudo code and send it
Start out small
I’m on mobile, so typing sucks lol
just make a variable replicate it and do a UE_LOG
to see if it works
like tie it to an input like when you press E
Kk
all that matters is the flow of data you can do the logic after
Set a variable to bool say bHasFarted
then tie input to E to fart
and then UE_Log("Server Smells your fart")
a lot of games (including fortnite) are NOT predicted equip/pickup
@meager spade I assume that's the case because its well defined what objects are allowed to be equiped
i think pickups more than equip are not predicted
equip might be local, tell server, server disagrees, client rpc back to unequip it
else server equips which replicates out
i dislike calling OnRep from a server function, i prefer the onrep to call a function itself
@meager spade So don’t call the OnRep at all?
you would have a function
that the onrep and server call
like void Equip();
which you call from server and the OnRep
but i do my equip differently
i don't use OnRep, i equip it locally, tell the server, server either then equips or client rpc back telling the client to unequip, which returns the player back to the previous weapon
Could you show me a minor example of what you mean?
Well let me take a step back here
Let me send something real quick
@meager spade And what do you do with the simulated clients?
We only use OnRep for them
Attachment is replicated
Was I close? Lol
Okay let me redo this real quick
only thing i replicated out, is the ActiveItem
and thats so simulated know what item they have
for animationbp, etc
Sorry that client_equip() in the server function needs to be unequipped
@graceful pumice nope
Dang it lol
So what’s the benefit of doing it this way rather than using an OnRep?
I just thought Kaos was saying he prefers to have the server call the same function OnRep calls in lieu of having the server call OnRep for readability, not to avoid using OnRep
yeah
I personally prefer to use the OnRep because its always clear where its coming from
OnRep should just run another function or do very basic things, if server and the onrep need to do the same thing, it should be a function call
One less thing to chase
but also can cause headache
Input()->EquipWeapon(SomeWeapon);
// Generic Equip Function called by Server and owning Client
void EquipWeapon(NewWeapon)
{
if(CanEquip(NewWeapon))
{
// Perform Equip
SetCurrentWeapon(NewWeapon);
// Tell Server to do the same
if(LocallyControlled() && !HasAuthority())
{
Server_EquipWeapon(NewWeapon);
}
}
// Server found out we can't equip
else if(HasAuthroity())
{
Client_ForceUnequip(NewWeapon);
}
}
// Server RPC
void Server_EquipWeapon(NewWeapon)
{
EquipWeapon(NewWeapon);
}
// Client RPC
void Client_ForceUnequip(Weapon)
{
UnequipWeapon(Weapon);
}
// Handy Setter
void SetCurrentWeapon(NewWeapon)
{
CurrentWeapon = NewWeapon;
// Handle Attachment
}
// Simulated Only
void OnRep_CurrentWeapon()
{
// Handle Attachment
}
void UnequipWeapon(Weapon)
{
if(Weapon == CurrentWeapon)
{
SetCurrentWeapon(NULL);
}
}
like ah i need to fix equip, you have no equip function cause you shoved it in an OnRep
What if the client doesn't have the weapon currently equipped that the server rejected 😛
I was implying you should pass the weapon through the unequip client RPC and check current weapon == that weapon
You can do that, correct
items and weapons in my game share the same 5 slots
There
i originally built it to only be weapons, changing it to be both, with the hud working, was a nightmare
So let me see if I got this right
I do like bananas
Check on Client, Do It, Tell Server, Check on Server, Do it, Replicate to Simulated OR Don't do it and correct original client call.
May it be equipment or the CharacterMovementComponent
It all works the same
You could even go as far as saving equipment calls in a list
And replaying them in case the client changes fast
idk
It's really all the same
Would it be wrong, in this case, to prefer OnReps instead of RPCs because OnReps will eventually replicate down while RPCs can be dropped?
That and you have late joiners or people who are far away and out of relevancy range
That is a good point too, yeah.
A state change should always be an OnRep
But you need to cut stuff in half
e.g. you have a door
bIsDoorOpen is the state
So the OnRep would mark it as open.
But the animation isn't relevant for someone who comes in late
So the animation of it opening can be an RPC
So RPC are primarily used for checks, and OnRep to run the logic after all the checks are done
?
RPCs are fire and forget. You fire it, whoever is relevant gets it and then afterwars the story is over
Hmmm
I’m going to tinker with this and post what I have later on
To make sure my understanding is correct
There comes a point to where the best way to learn is to just do it
At least for me lol
Alright
So this is what I got
Now the purpose of this function is to update the character's rotation
So not even equipping yet, just changing the rotation.
The issue is that OnRep is never called as the character's rotation never changes
So am I using OnRep incorrectly?
Ah disregard. I just noticed the comment in @thin stratus sample - I am supposed to handle the logic in both the set function and the onrep function
Yes, the idea is that the OnRep only calls for Simulated
And the Set function for Server and owning client
You'd mark the varaible as repnotify with the condition Simulated only or skipowner or what it is
Just be aware that if you use C++ it doesn't call on the Server (OnRep) while it does in BPs
Yep that makes sense now. After removing the ReplicatedUsing property tag, the server doesn't replicate to the client...which make sense because the server is the simulated proxy on the client side; and testing with a dedicated server means neither players replicate to each other
Okay, OnRep is for simulated proxies...got it
And since I am using C++, I don't have to worry about SkipOwner, correct?
That doesn't even appear as a property tag in UPROPERTY anyways, so I would assume not
its in the DOREPLIFETIME
DOREPLIFETIME_COND(ASomeActor, SomeProperty, COND_SkipOwner);
Ah, thank you Kaos!
And we do skip owner because we don't need to "replicate" it to the owner since we already did that locally
correct?
yes
Learning has occurred! Thank you guys!
has anyone added steam API to there game before?
its built into the engine
Question
When you Change Variables In the Engine.ini file
Does it update on compile in the editor or will i need to Generate Visual Studio files and recompile it?
Got it working
Curious
for fast movement games in UE4 is it normal to have larger and 3.0 MAXPOSITIONERRORSQUARED values?
We use the default value atm
This is the error after which you get corrected
If that's bigger, the correction will also be bigger
And way more noticable
hmm a question within a question is what should I aim for that realistic error
based on the max speed of my movement? or acceleration?
I would suggest just playing your game on a simulated high ping
And then checking if that feels good
like with clumsy?
I tested with the netpkt lag console setting
defaultengine.ini
[PacketSimulationSettings]
PktLag=0
PktLagVariance=0
PktLoss=0
PktOrder=0
PktDup=0
Anyone here setup a Linux DedicatedServer via a Container? I only seem to find "Docker" for this and I'm surprised that Linux has no bare bones free version of this.
what do you mean? docker is free and what everyone uses to make containers
hey! any1 used Socket.io here for simple multiplayer purposes ?! I want to get some advices before digging it if there's any pitfalls or things to consider ?! Thanks
socket.io client plugin for Unreal Engine 4. Contribute to getnamo/socketio-client-ue4 development by creating an account on GitHub.
@young jacinth I guess most people here use the UE4 multiplayer
@fleet raven Yeah, I found the community part of it now. Google wasn't my friend.
Still no idea how to use it to get a Server Build onto it, but well, youtube tutorials it is
Hi, I'm trying to spawn some Pawns and possess them only locally at OnPostLogin or at a Seamless Travel. I don't want these pawns on any other client. I can't figure out how to do that, since the player controllers all belong to the Server, so "is local player controller" only returns true on the server.
How does one disable Steam for a Linux Server build? I have bUsesSteam = false in the Target file.
Do I have to actively change the ini before building?
Actually, I should probably fix the reason teh app id file can't be written.
Who knows what else can't be written
Perfect, nvm. Docker File was setup wrong
@past gate you can't do it in GameMode
BeginPlay of the PC -> if (IsLocalController()) <spawn and possess a local pawn>
note that NetRelevancy will cause problems there
as in, if you don't touch the settings, nothing over 15k from where PC was spawned will replicate, ever
would be much better to server spawn + possess a ReleventOwnerOnly replicated Pawns
It'll probably never work properly anyway since a player controllers' pawn and a pawns controller is replicated and it'll alter whatever you've done locally.
If you wanted to support multiple subsystems in the future, say for example Steam and EGS (and just for the sake of example, consoles too), would you generally have a giant GameInstance with different sections for different subsystems or instead have a plugin based approach or a separate GI per subsystem?
In theory you would just switch out the subsystem and the gamecode would seamlessly interface with it
If you're relying on platform-specific features that aren't available through the OSS system, I would either modify the OSS to expose stuff more "generally" or yeah, pre-processors to compile things out depending on platform.
I've done the former recently for HLL, since the Steam OSS has a crap implementation for Steam User/Server Stats
Just extended the interface so that it needs to provide a new FOnlineUserStatsPtr.
When packaging for a specific platform, it might be possible that if you have one giant GI, some stuff might break. Hence why the plugin based approach makes more sense + it would allow you do no package useless information for the platform
Thanks! So in theory if you were to keep all subsystems vanilla, you'd have any relevant communication for each in one GameInstance? For example steam lobbies vs whatever lobbies EGS has
@high current That makes sense! thanks
Apart from a few tiny exceptions, all of our game at least talks to online services via the OSS interface
You want to avoid doing things like this regularly because maintenence is just impossible:
#if PLATFORM_XBOXONE
// do something
#else
//etc...
So any calls via the GI would be generic?
And you'd branch within the functions there?
You wouldn't branch at all, you get the OSS interface and call the functions through that
Ah ok so basically it'd be like calling a generic CreateLobby function and depending on the device / subsystem being used you'll run the right code using the #if
Ah sorry missed the edit
I will have to look more into the OSS stuff, thanks!
Just trying to plan a bit ahead to not burrow into a corner and have to redo lots of stuff
if (UserStatsIFace.IsValid())
{
UserStatsIFace->RefreshUserStats(*PlayerID.Get());
return true;
}```
The idea is gamecode doesn't care what platform you're on
@winged badger Thanks! I'll settle for ticking Only Relevant to Owner ^^ For now the pawn I wanted only locally is a kind of spectator, but later I might have to add interactions, so I guess there isn't much of a point
thing is, if its just local
Kyle, are you beginning to implement OSS stuff? I'm in the process of doing that now and I am not having a fun time with it. 🙂
yeah yeah, i'll untick it later, I was just trying to save memory
@worthy perch @grizzled stirrup ShooterGame shows exactly how to do it
If you can recall, for ShooterGame, it's pretty much all in their implementation of AGameSession, right?
Yeah, the game only makes calls to AGameSession etc, which then passes whatever it needs on to the OSS interface
It has a few cases of preprocessor stuff, but it's only for things like this:
const FText ReturnReason = NSLOCTEXT( "NetworkFailures", "ServiceUnavailableXbox", "Connection to Xbox LIVE has been lost." );
#elif PLATFORM_PS4
const FText ReturnReason = NSLOCTEXT( "NetworkFailures", "ServiceUnavailablePS4", "Connection to \"PSN\" has been lost." );
#else```
Which is fair enough really, but hell you could wrap that in the OSS interface if you really wanted to
@worthy perch Yeah it's fine for Steam using existing examples but I'm very curious how it links in with more systems later down the road
@chrome bay Thank you will dive into ShooterGame again for that!
@grizzled stirrup
you can create GameInstance SubSystems now
in 4.22
which automatically get loaded in to the subsystem and creates convienient accessors in bp automaticcal
automatically
yus, got 2 of them in our project by now
One handling customizations, the other the backend connection
really handy
@meager spade Thats amazing thanks for sharing
i couldnt find a way to make a bp version of it tho
cause if you do it loads 2 copies
what is the purpose of USceneComponent::AttachChildren being replicated?
is AttachParent replicating and components attaching themselves to where they should be not enough?
it seems like all OnRep_AttachChildren does is try to fix the mess it just made by replicating it for no reason
plus, it makes it cry about objects not supported for networking when you attach non-replicated components on the server
@meager spade You could probably override the "ShouldCreateSubsystem" function and mark it to false for the parent.
Exact functionname could be different
if you make it abstract it won't instantiate it
but the problem is with the bps themselves
it uses GetDerivedClasses to locate all classes it should instantiate
which has two problems:
- it does not locate currently unloaded blueprints
- it locates a bunch of editor trash for loaded blueprints
things whose name starts with TRASHCLASS_, SKEL_, REINST_
it doesn't filter them out and tries to spawn those as subsystems
@fleet raven also, when it does replicate attachments, it causes any non net addressable attached component on clients to fall off
have not seen that happen yet
I did 😕
Not surprised, there is rarely any need to replicate a scene component or its subclass
If you have a fairly large struct of floats that define various upgrades that your character has that needs to be replicated to the owner after each seamless travel and potentially other players too, is it fine to have it as a standard OnRep struct? I ask because ~30 floats seems like a lot but they only ever change a few times a minute if even
And they'd never all change at once, always one at a time
If it makes a difference I could potentially use uint8's instead and convert to float after replication (using some kind of 4:1 conversion as the lowest I ever need is 0.25f)
yes it's fine
assuming they're individual properties it will only send changed ones
it's not changing every tick so 30 floats is like nothing
Great thanks!
Yeah only changing very rarely when a player levels up or finds a pickup
And only ever all being replicated at once at the start of a match after seamless travel
Hm, just noticed Linux - DevEditor compiles fine while Linux - DevServer reports:
1>ld.lld.exe : error : undefined symbol: Microsoft::Azure::Gaming::GSDK::logMessage(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
It does call the code to load the library and I don't see any errors.
Do DevServers anything different in terms of Build.cs etc?
Microsoft::Azure::Gaming::GSDK::logMessage as well as all the other functions of the library report this.
@grizzled stirrup they always get replicated all at once
you can try and force the issue @thin stratus , by adding a project reference to the library from VS manually
not sure if there will be any consequences of that tho
I kinda have the feeling there is some WITH_SERVER_CODE somewhere that kills something this library needs.
At least that's my vague idea
by adding a project reference to the library from VS manually
The "LibraryDirectories" in VC++ Directories?
no right click project, add > reference, browse, and select the library you need
(in solution explorer)
I can't browse with any of the AddReference
Only lists me Solution References to select from
@winged badger I thought structs have some clever way of only replicating changed properties within them?
Thought I saw that mentioned here recently
We looked into that and afaik they do indeed know what to replicate and what not
Same for Arrays
It doesn't use NetSerialize but NetDeltaSerialize
you can custom net serialize them
So it does in fact only replicate changed values in a struct?
i don't really
It'd make sense especially for larger structs
Yeah but not nested
So a Struct in a Struct probably will replicate fully
As well as an array in a struct or a struct in an array
that doesn't make sense
why would it NetDeltaSerialize itself but not call NetDelta on its members
Why does this get ignored? It doesnt get destroyed for anyone and does not stop on breakpoint
does it print?
It even sets the visibility
do you have anything red in the message log?
?
is your LookObjInfo valid?
its a replicated variable
so when a client picks it up
how does server know which object to destroy?
replication doesn't flow client->Server
so add the reference to it as an input to the RPC
along with that boolean
and try that
What do you mean?
and then connect destroy to that pin, not a variable
same way you added the fuse
add an actor reference
no need to put the fuse into RPC, presumably if ActorHasTag on client it does on the server as well, btw
so server can do its own tag check
Ok. Thank you so much!
I still have a lot to learn about replication and stuff, but I've been stuck at this for so long
Thanks again
exi's compendium, if you didn't read it
link is on pinned resources on the channel
Thanks. I will check it out now
btw, @steady aspen even if it was server sending an RPC to client and depending on replicated variable
it would still break 90% of the time
RPCs don't wait for the Actor to get to its scheduled update
replicated variables do
Ok. I will read the compendium. Thanks @winged badger
Would this be a bad way of doing it?
why is pickup a multicase?
Because it didnt work when running on server
and now it doesn't work when running on clients
multicast from a client is like you just called a normal function
Yes, I would like to have it run on server but the clients wont do anything if I do that
Finally fixed it! Thank you for all your help @winged badger Now I need to go read the compendium 🙂
If sending a player name to spectate from the server via a Client RPC, is it cheaper to send the character reference or a const FString& ?
The character reference could be used on the client to get the playerstate and then the name
I ask because I recall character pointers to have quite a small footprint since they are essentially an ID
a pointer is going to be four bytes because it's literally just a 32 bit int
It doesn't matter what "type" the pointer is, at it's core it is just a int
Great thanks I'll use the pointer then!
Is it possible to override a replication condition per actor?
For example in my health component, I want players to replicate health to all other players for UI use when spectating, however AI characters using the health component will also be replicating that health value and wasting bandwidth as it'll never be seen or used by the client
Your second sentence is hard to understand
replicate it COND_OwnerOnly
it'll only replicate to the owning connection
AI don't have one, so it wont replicate to anyone
oh
Right, AI aren't clients. They are driven by the server
Sorry it's late, my explaining isn't great 😄
Basically AI and human players share a generic health component
In order for human players to spectate other human players they need to know the value of the health float
However I don't want to waste bandwidth having potentially 20+ AI also replicating their health
As it won't be used anywhere
I had it COND_OwnerOnly which works fine for the owning client but as soon as you spectate another human player, you can't get his health
I've noticed some odd behaviour in a 3D widget I have in a VR game. I have a countdown when the game is about to start. The Gamemode handles the value, but sets it to the game state. The widget in the level goes to the game state and gets that value and displays it as text for the player to see. The widget also goes to the game state to get a variable to see if the text should be visible. It's not visible until countdown starts. In any multiplayer scenario (including PIE with dedicated server checked and only a single client) this text does not turn visible right away for the client. It seems to wait some random arbitrary amount of time before popping up. I've seen it pop up after 2 seconds have passed in the countdown and take as long as 17 seconds (it's a 20 second countdown). After setting that bool, it plays a sound. The client always hears the sound. So the code is definitely running.
This is the visibility check on the widget text
can there be some kind of delay on the replication of a variable, to the client, even in a PIE situation where there isn't any network lag?
maybe your net update frequency for gamestate is high
it will only replicate stuff as quick as netupdate frequency
@meager spade I haven't changed it from the default. I don't even know where to change it
Anyone know the best way to do floating name tags over players heads in multiplayer?
I am stumped on this but it seems like it would be pretty easy
Create a list of managed widgets locally, one for each player registered in the game state
Assign each widget a player
Every frame, update the widget position on screen to be above the players head
Some people use 3D widgets, personally I prefer doing it in 2D. Cheaper and easier.
I am using a 3d widget right now. So in order for this to work I need to keep a list. Which I am using the game state to do this
I do it in the HUD, since it's a convenient place to manage UI elements
Is there a way to get what client you are on the list?
Sure
just compare the player state the widget is assigned to, to your own player state
ez
Game State already has a list of Player States, which should contain all the info you need to get information about a player.
2D is better IMO. Depending on how many players you have, it's not all that cheap to have a bunch of extra scene components and render targets to move around
We are also using widget components in screen space
Yeah hmm so the only challenge is getting the widget to know what player state the player is?
You could just use IsLocalPlayerController().
Our pawns have healthcomponents which spawnt he widget ones
And handle their lifetime
Tis easy
every frame
Do the followiing (psuedo-code)
{
Widget[Index]->UpdateForPlayer(GameState.PlayerArray[Index];
}```
I am doing this with blueprint
Pseudo code is meant to be code that isn't actually code be still explains the idea
That can be used in bp or cpp or java etc
If you can't read cpp you should at least understand pseudo code:P
Yeah, I just need to know what nodes are to be used
yep seems right
In HLL I have an "indicator component", which you can drop onto an actor. It'll register itself in a central list somewhere and the HUD will create the desired indicator widget for it, and update it accordingly.
Cpp would be easier, you could just use the OnRep PlayerState in the pawn to create the healthbarwidget and pass the PlayerState
-_- why don't they expose it
Cpp isnt easier. You have to learn Cpp
Not as scary as it sounds trust me 🙂
The hardest part of CPP is figuring out what all the obscure compiler errors are when you're starting out tbh
but anyway I think I get it, I just need to figure out how to compare the character game state to compare to the game state list
? I believe you mean PlayerState.
ANything I try right now just return makes each player see their own name on every other player
Yeah player state list
sorry
So like this seems like most of the stuff I basically need. But all I get is every player seeing their own name on every other player
Each widget should be assigned one of the player states
Yep got that. hmm
And it pulls the info from that player state
that's the issue I am having then. How to assign that player state.
Since BP doesn't have any callbacks, the easiest thing to do IMO is on your HUD classes Tick, check the player state array from the game state
ok how
Create enough widgets (one for each player state)
what nodes tell me what player state a character has
I can't really explain that in anymore detail than I just did.
On each of those HUD ticks, call an 'Update' event in your custom widget and pass in a player state, it's just a big loop.
Yeah I get that, but this, does not give me that players player state.
It makes it so all players have the same name as the player
You're calling GetOwningPawn, that will just give you the 'Owner' of the widget which will always be the local player
Widgets are created locally, they are owned by the local player
ah! ok ..hmm
Hence you use the 'PlayerArray' from the game state, do a big loop through it, and tell each widget to update using a player from that array
Yeah I get that, but you cant iterate through the list if every player is marked as same person to every player
I need somethingto define, "This guy is number 3 on the list"
But they're not the same person?
Each PlayerState in the array is a different player, with a different name
Yep, all I need is a way for me to know what player state each player is. Otherwise a for each loop is pointless because I dont know who is who
See what I mean?
This would be super easy if know the way to know who is who
You can get the pawn from a player state IIRC
The alternative is a system I suggested, having a component on each pawn and updating it that way
Player controller I can get the pawn. I think you meant that right?
In MP the pawn may not exist right after the player spawns
@meager spade My gamestate is set to netupdate 10 min 2 so that shouldn't be the issue
There's APawn::GetPlayerState(), btw. Which surprisingly, I've never used.
hmm I think I might know what to do then. hmm
Calling owning player pawn to get the owning player state. Compare that variable to the game state list, if I get a match then make that the name that appears.
I don't think you would ever get anyone else's name, then.
what about get the player controller?
get owning player
I feel like the answer is so simple yet I am stuck on this crap....
Effectively the same. You would only get your playercontroller. And PlayerC's aren't replicated anyway.
there is an option to put the WidgetComponent on the PlayerState itself and just attach the PS to Pawn
it is an Actor after all
That's a pretty interesting approach.
Where are stored PlayerStates of players that recently left the game?
// GameMode.h
/** PlayerStates of players who have disconnected from the server (saved in case they reconnect) */
UPROPERTY()
TArray<class APlayerState*> InactivePlayerArray;
thanks
Is Rcon tool program only for torument servers or does it also work for dedicateds?
So after a bunch of work, I changed the inventory over to make sure that it's spawned by the server, and that when the code to attach the item to the inventory is run that it is run by the server only, and I'm slightly closer I guess? Again, this still works as the host. But as the client now, when the item is attached, it snaps to the slot, but then immediately falls to the floor. At least it's being located under the map anymore. Why would this attach work for the host but not the client, when this is being run "as server"?
This is the call to store it, as you can see, it's running on authority only.
I've attached other things as the server and they've always stayed put
If you know a replicated property will only have a value in the range of say 0 - 25, and you'd have many similar properties (such as a list of upgrades), would you then try and use uint8 instead of float to represent the current upgrade you are on?
Yep
You could go a step further and bitpack values too when it makes sense to do so. C++ only ofc
Thanks will switch to uint8 from float in that case
Is bitpacking like what they do in ShooterGame for bools?
So you get 8 bools for the price of 1?
Using 8 uint8s?
Sort of, UE4 automatically condenses bools to 1-bit anyway IIRC
Not even sure it does tbh
Oh for replication I mean
Is there a difference between uint8 and int8?
Just confused as there is no u in int32
int8 = - 127
Ah that explains a lot
Thanks
And I assumed uint16 is fine to use too?
yeah
for replication/reflection all the integer types are supported, just they can't all be exposed to BP
You can Intellisense to int16 (Platform.h) and all the types are defined there.
That's fine I'm doing almost everything in C++ where possible and BPs are data only.
Does it mean that you can't even have some types in the defaults window of a BP?
And should never be a UPROPERTY(EditDefaultsOnly) for example?
Just used internally in code?
It won't compile if you try to use a non-BP supported type anyway
Great thanks!
@worthy perch Many thanks for the platform.h tip, all the bytes specified there too!
Learning UE4 C++ first before the fundamentals is proving interesting 😄
Missing out on some essentials
Am I correct in saying that an int32 / uint32 is equal in size to a standard float ? (4 bytes)
How would I update a 3D widget's value for all connected players?
Instead of only changing to the client calling the function?
Should I call it to all PCs using the game mode?
Multicast is what I needed
@grizzled stirrup yes
Thanks!!
Certain objects like the player pawn, player state, player contoller can spawn in nearly random orders and its fairly unpredictable when it happens.
The client probably wouldn't know that it's missing the actors
Did anyone managed to get Steam overlay in the game without the steam networking?
I want to use the Null subsystem and get the steam overlay.
They say in the documentation that I need to setup the NetDriver class but never say how to do it and to what.
@velvet parcel I've also noticed this and with more clients it can be even more random
The solution I have found is to just have a pre game countdown before doing anything important
All networking spawning is completely random
You have pretty much no control over order of actor replication
Then all replicated channels will be open
Yogev, if you just want the overlay (and other Steam stuff), you can just manually load the Steam .dll's.
Yeah just to make sure because so much can work for 5 / 10 clients but not at all for the other 5
Waiting fixes all 🙂
@chrome bay Sorry for the tag, last question of the day I promise 😄 I saw this quote from you on the forums : It's never been supported. uint8 and int32 are the only numeric types you can expose to Blueprint Does this mean I can't use a uint16 to represent health instead of a float, as the value of health is set in Blueprint defaults / displayed on UI?
correcto
uint8, int32 and I believe uint64 as of 4.23 are support by Blueprint
And that's all yah get
Ok thanks I'll stay with floats then since damage is done with floats
No need to convert to int32 if there is no bandwidth reduction
The trick is to just not code stuff that is time-dependant
You have to workaround it, adding delays and the like is a quick way to get into trouble
Is there a "MyReplicationChannelsHaveFullyOpened" callback per client?
I'd love to not rely on the delay countdown but if I don't it's basically random which clients get initialized correctly
Sometimes all
Nope, nothing like that
Sometimes only the host and 1 client
you have zero idea when all objects are received
So basically a delay or polling is your friend?
Polling or using an event based-system
So an actor broadcasting a global delegate in BeginPlay() or something
Generally speaking though you shouldn't ever need either
generally speaking...
The case I ran into it was when spawning and initializing nametags for all other players- without at least a second of delay, a completely random amount of players got their nametags initialized
code the game as if objects can be created or destroyed at random and you'll be fine 😄
Yeah that's the kind of thing you just have to tick to make life easier
Our scoreboard in HLL for example just polls the PlayerArray constantly and adds/removes items as required
Thanks! In the initial nametag case would you say a delay isn't the end of the world since they only ever get initialized once and there is no join in progress? Also the countdown will happen anyway pre game
It's not the cheapest but it's far from a bottleneck either
I also generally prefer UI to poll the game for information rather than driving it via events where possible, as generally you expect the UI to represent what's truly going on in the game, and if it's not it can make it very hard to debug or find problems
Got it! I'm trying to do that too, but sometimes the initial bind misses (tries to bind to something in the GS / PS / A spawned actor but they aren't ready yet)
I find once the initial binds go off correctly (after the countdown when replication channels are fully open), it's all good
Events make sense in a some cases though, particularly if you need to create/remove widgets for things.
I really wish there was an option for a listen server host to instead load a local dedicated server and connect via that
Similar to how it works in non Single Process PIE
then there are no inconsistencies in smoothing and a few other things
Are multicast functions called to all clients if call the function from server?
Yeah.
all clients and server
ouch
server doesn't need to call ServerRPC
it can just call a normal event
multicast should also never call another multicast
already executes on everyone, what's the point? having the connected logic run twice?
also omg why
it is quite sufficient to just set the health on ClassDefaults, btw
well actually I want to update the 3d health for everyone
Okay, but just to understand, why won't the print string show from the client as well?
Server calls the multicast, so is this normal instead of showing to everyone?
What class are you doing this in?
It's a controller
😄
Which has an AI controller set up
So how would I call a function like that to everyone?
What I'm trying to do is to make the server set a health for the AI and then display it in its 3D health bar widget.
Could a solution be to connect the AIs with the server PC and call functions from there?
in a dedicated server, is overriding gamemode's PostLogin function the right place to do something to the client controller whenever a new client connects to the server?
with any server, yes
If I have a savegame object with something like "character customization" for like what hat / outfit the player selected. What's a good spot to store that and retrieve it on the server?
I was using gameinstance for local multi, but that only exists serverside right?
gameinstance is local to ALL
its created when game exe loads
and destroyed when game exe closes
it cant be accessed by anything but local
So I'd assume I would have to throw the variables into the controller (or some other object) to pass it to the server?
@unreal pine The way I do it (could be completely wrong) is each player saves their skin locally in the GI in the main menu and then when they load into the map they load it locally, then do a server RPC to set their skin on the server which also triggers an OnRep event for other clients so they see the correct skin too
For customizations how do you get them and are they like steam inventory items etc?
They will be, we're doing an alpha this weekend and I'm just gonna unlock 'em all
Thanks @grizzled stirrup! Sorry for getting you killed so many times when I was a teenager
this is being called in a client rpc, there's only gonna be one static camera in the game placed in the level, it isn't working tho any idea why?
How does one handle a Game Client with Steam and a DedicatedServer without Steam again?
@unreal pine I forgive you we got the job done in the end
Server is only known by IP
You could just ClientTravel to the IP address. If that's what you're asking.
Here the thing
The Client uses Steam and will 100% use Steam at this point.
The Server sits on a CloudServer.
Client receives the IP:Port of it.
There are two scenarios that both don't work:
If the Server implements the Steam Subsystem, connection via IP doesn't work anymore, cause the Steam NetDriver only works with Steam IDs.
The Server isn't and won't be registered to Steams MasterServer, so I will never get that.
The other scenario is that the Server DOES NOT implement Steam Subsystem, here PreLogin fails cause it checks if the Type of the UniqueNetId is the same.
I could skip that check but I doubt that's a good idea.
So I'm a tad lost
Well, in short, I think the UWorks plugin can handle connecting directly to a server by IP:port. So you can look how they do that. Which I've been meaning to do too.
void AGameModeBase::PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage)
{
// Login unique id must match server expected unique id type OR No unique id could mean game doesn't use them
const bool bUniqueIdCheckOk = (!UniqueId.IsValid() || (UniqueId.GetType() == UOnlineEngineInterface::Get()->GetDefaultOnlineSubsystemName()));
if (bUniqueIdCheckOk)
{
ErrorMessage = GameSession->ApproveLogin(Options);
}
else
{
ErrorMessage = TEXT("incompatible_unique_net_id");
}
FGameModeEvents::GameModePreLoginEvent.Broadcast(this, UniqueId, ErrorMessage);
}
But, the way I've been doing it prior to implementing the OSS stuff, was just by manually loading the Steam dlls. This apparently never did weird NetDriver stuff.
This shit is new in 4.21
Now I know why that worked a few months back
@fleet sluice Correct Vlad for UWorks?
Too many Vlads
that's the Vlad you're looking for
Now I wonder, if I remove that line again by overriding PreLogin
(it didn'T exist pre 4.21)
What does that break?
How important is it to have the same type
You can search the UWorks Discord for "Ip:port". That seems to be the go method for UWorks people. In fact, the UWorks subsystem was dropped anyway.
Yeah I think asking the dev directly helps more in this case
But my lucky evening he is probably out enjoying a friday night
So apparently that "new" check from 4.21 is to stop behavior that was never intended.
Epic doesn't want you to use two different subsystems at once
If you need that, you need to create your own Subsystem that interprets the ids from the various subsystem you are using
And I'm def not able to do that in one evening cause I need that running tomorrow
Cool
Well, it's not a traditional Steam DediServer
I won't register any Session with it
It just has Steam on it atm cause of this shit UniqueId mismatch
Can't I force the SteamNetDriver for now to accept IP connections?
if im not mistaken
they also broken something in 4.20
making it pretty difficult to roll your OSS
@chrome bay Found that out, yeah @winged badger
But if I have to modify the engine, that's also fine
i did steam connection once, and it was years ago, since then i always found a way to dodge that particular task
Using a custom build anyway
@woeful anvil Cloud
Service returns the client IP:Port
But when using Steam it just doesn't connect
And if Server doesn't use steam we get back to the Id Mismatch
I wouldn't even know how to implement my own Subsystem while still keeping 99% of the Steam features
After switching from 4.19 to 4.21 clients could not connect to dedicated server anymore.
I build UE4 from the source, rebuild dedicated server from the
This is basically the diff subsystem issue
And the Steam IP connection stuff is sadly generally known
He has a unique set up, HighGround.
why is your dedi without steam again, @thin stratus ?
Cause Steam brings the NetDriver that doesn't allow IP connections
100% not using SteamSessions
This is a cloudhosted Server
The service that handles starting and stopping these provides the Ip:port
so your using IPNetDriver?
@winged badger That was the idea first, but that doesn't work anymore since 4.21
why are your clients using steam OSS then?
Cause the game is on Steam
- the Backend Authentication goes through Steam
- we have ListenServer support too
you could gimmick some lobbies
steam lobbies
they are quite sufficient to share the IP/Port
and connection to a public IP is possible afterwards
I read you can get request the steam id of the server via ip:port via Steam
But without registering a session I doubt it has an id
Not sure how to add lobbies into the mix
can send anything through that
The Client only knows the IP:Port of the Server
And will also only ever know that
I have no control over the game server service to send more info
yeah, but you can get listen servers working via lobbies over IP/Port with IPNetDriver i believe
Hey
not sure how it will handle NAT, UWorks was a bit dodgy on the subject 2-3 years ago
I have a small question
instead of starting a steam session, you create a lobby other clients can find
I would rather not change listen servers
Is there a way o knowing when all pawn instances of a player controller ( counting the owning client and the others) are spawned?
you open a normal session, and transfer ip/port to them
yeah, your HandleStartingNewPlayer ran as many times as there are players
@astral fossil Not really, despite knowing upfront how many it should be an incrementing a value on beginplay of each pawn
HandleStartingNewPlayer is Server only though
i am assuming he was asking server only
would be kinda hit&miss to check that on clients 😄
Yop
I tried notifying each spawn but apparently theres no way of sending message from non-owning clients
and it calls RestartPlayer() by default which does exactly that
unless you changed it yourself
i have AIs of same class on some levels
case where that approach breaks
wait, I think I am kinda lost. I actually don't know if Im using the right terms
Only the server spawn pawns explicitly, the other clients just replicate that, right?
The thing is to know When this replication actually happens, because I don't know how the server would know that
you really don't want to be checking that on clients
so when it does that the number of times equal to GetNumPlayers
all of them are spawned
the GetNumPlayer return the number of clients right?
clients + listenserver if its the case*
yes!
there is no OnPossessed client side
hmm, but my problem is to know when the pawn that doesn't have a owningclient is spawned
nor anything else you can get to without c++
in my case, the problem is that the pawn controlled by the listen server is multicasting something, but the replicate is not spawned yet to receive the multicast
do not multicast
i can solve this with a delay, but its sketchy
use RepNoitfy instead
hmm
that can't break
right
if the variable is set in the same frame the actor is spawned in
it will be set, and its onrep will run before BeginPlay on clients
hmm
and no package loss or latency can interfere with that, as the variable arrives in the same bunch as instructions to spawn the actor in the first place
what causes the rotation?
maybe you can shove it thru the CMC
in any case, nothing RPCed on Tick should ever be reliable
whats the point? if a RPC doesn't arrive a more up to date one will land before its resent
not without having a CMC open in VS, sorry
the top pinned link on the channel
is a diagram of CMC calls
Hey zlo, that thing with rep notify worked great, thanks !
By default does a component inherit the NetUpdateFrequency of the actor it is attached to?
For example a health component on a character
Thanks!
Thanks! In this case I definitely want it to inherit
For example lower priority enemies should have lower update rates etc
So the health component would ideally update at the same rate
Thanks!
components replicate as subobjects via
{
check(Channel);
check(Bunch);
check(RepFlags);
bool WroteSomething = false;
for (UActorComponent* ActorComp : ReplicatedComponents)
{
if (ActorComp && ActorComp->GetIsReplicated())
{
WroteSomething |= ActorComp->ReplicateSubobjects(Channel, Bunch, RepFlags); // Lets the component add subobjects before replicating its own properties.
WroteSomething |= Channel->ReplicateSubobject(ActorComp, *Bunch, *RepFlags); // (this makes those subobjects 'supported', and from here on those objects may have reference replicated)
}
}
return WroteSomething;
}```
Has anyone got any info about the Epic Online Services? I'm having a hard time trying to figure out what exactly they provide.
Reading their website it sounds like right now it's just a ticketing system and a friend list, but doesn't look like it's an actual OnlineSubSystem or anything that could be listing out online sessions.
In general i'm trying to figure out what would be required for a game to be able to "find online sessions", as obviously the null subsystem only finds session on LAN.
Are the only options to use the OnlineSubSystem steam? Is that restricted to a game on steam or can it be on any store?
How are the current EpicGamesStore titles doing it? Do they have some kind of early access to the Epic Online Services?
PlayerControllers only exist for the Server and the Client that owns the PlayerController.
It does not exist on other Clients.
Therefore it cannot call BeginPlay.
Because it doesnt exist.
I mean the player controller that clients owns himself
So the BeginPlay isn't called locally?
Is this directly on start or when you SeamlessTravel?
Anyone know why some servers hosted by players playing my game through steam appear twice when fetching the current servers?
Am I doing something wrong here? I want to disable input for all players when a match ends. I dispatch the event through C++, and I wanted to implement what I'll do after the match ends here, but the DisableInput is not really doing anything. This is all implemented in the Game Mode blueprint.
input it Local
you need to client RPC it or multicast
you are only setting it on the server
The game mode itself is only instantiated on the server, though, isn't it?
yes
but you need to call that on the client
on all clients to disable the input
the disable input function
so either have a function on the PlayerController that ClientRPC's to disable input, or multicast it
@void nest Maybe because you don't clear the list before fetching servers again?
I do, the container widget is always cleared before it's filled with new servers.
it's only a very rare few servers that sometimes appear double
How do I get the Session Name from a FOnlineSessionSearchResult? The only way I can think of is to use FOnlineSessionSetting and that seems really bizarre for something so common.
To join a specific session and for displaying the name in a session/lobby browser.
Well you join the session by resolving the address via the Session Result
And for displaying you should just create a custom setting SERVERNAME
Alright, I'll look into resolving the address.
EDIT: Looks like I confused what GameSessionName/PartySessionName macros were for.
Yeah, I thought it would be for something like the friendly display name. Anyway, I'll use the custom settings approach. Thanks.
I'm using Load Level Instance (tried both by name and object reference) on the server side, however this doesn't seem to replicate to clients (while LoadStreamLevel doest, but can only be used for one static instance). Anyone has an idea how to fix this or work around it?
does anyone know if Find Sessions will find a dedicated server? if not, is there anyway to connect to a dedicated server other having a hard IP address that the client connects to when the game opens.
dedicated server ips are normally hidden
and handled via master server
which connects the clients to a chosen server
so theres no way to run something that just searches the internet for IP's that are running a server for the respective game?
sorry for the silly question, i'm handling killing pawns on the server and after a player dies I'm trying to create a widget to append to my HUD widget
the death is being handled on the server in the gamestate, from gamestate i'm calling an rpc in the pawn that is set to multicast but the hud is only being updated from whoever killed the player, other players huds aren't being updated.. 🤔
well i got it working, not sure if it was the best way but inside my ServerKillPlayer function on the gamestate i'm calling a custom event that is a multi cast which loops through game state's player array and inside the loop gets each players hud and calls the update killfeed function
Yo people
?
hey guys i have an AI
and i want change variable from thirdpersonbp
to my ai character bp
if i be server
its ok
but if i change my player to client
its cant be done
.
why?
its work now
how can I replicate a fps character's mesh2p? its child weapon does replicate but the hands mesh wont replicate
you dont normally replicate the first person mesh to other players
your normally have a TP mesh holding a fake gun
which acts like the fp gun
Please does anyone know how i can do the ik and ads for a first person shooter. With a third person mesh
Cus I want to make a first person multiplayer shooter but not replicate the change in bone location so every else sees you as normal
I mesh you see and the mesh others see are the same just that one has ik replicated and one does not
that works out of the box
as UAnimInstance is not replicated
nor are bone locations
you just need to run IK only on Pawn that IsLocallyControlled
probably by deriving from a UAnimInstance you run for other players, and extending it with IK, then just changing the UAnimInstance class on say BeginPlay if Pawn IsLocallyControlled
@thin stratus @worthy perch Taking this out of #cpp. I was wondering as well how I can get the SessionName from a SessionSearchResult, since many other methods in the OSS SessionInterface need the SessionName . For example JoinSession needs a player net id, a session name an a OnlineSessionSearchResult. Or one of the GetResolvedConnectString overloads needs a session name.
Or do I get purpose of SessionName completely wrong?
You usually know what you are joining
This is really just GameSession or PartySession
If you are just playing you use GameSession.
If you use beacons and shit for parties, you use party sessions (steam only allows one at a time)
See it like this: Your player wants to host a game -> GameSession.
Your Player invites another player to a Party -> PartySession
Your Player gets a list of Servers -> GameSession
Your Player clicks on a Server result -> GameSession
The only point where I would double check what exactly you are joining is if a Player gets an Invite through e..g the Steam Friends Interface
Then you'd need to know if it's a Party or game invite.
Ah, so SessionName is more like a "SessionType", which describes the type of the session with either being "open" (in the sense of not created beforehand, e.g. like Battlefield's game join) or "closed" (in the sense of created beforehand, e.g. like R6S)
It's just Party vs Game
