#multiplayer

1 messages · Page 261 of 1

meager spade
#

hmm

brazen anvil
#

If I want to have multiple walking speeds, for example lets just say 10, is using a replicated variable to indicate which walking state is selected the best way? Or is this something that you would want in the saved move? The concern is having lots of corrections when switching walking speeds.

nocturne quail
#

using this method, you will get a very smooth transition between different speeds

meager spade
#

but ideally you would want to pack them into a saved move

brazen anvil
#

Is PredictedMovementSpeed just a replicated float? I was going to override GetMaxSpeed()

nocturne quail
#

not even a uproperty

brazen anvil
#

Ok

nocturne quail
# brazen anvil Ok

and you just update it using multicast simply by character

void AArmaCharacterBase::MulticastManageMovementSpeed_Implementation(const float NewPredictedMovementSpeed)
{
    if (IsValid(CustomMovementComponent))
    {
        CustomMovementComponent->SetPredictedMovementSpeed(NewPredictedMovementSpeed);
    }
}
#

phys walking will handle everything else

brazen anvil
#

Thanks I will keep this in mind. I am probably going to the saved move route as it fits better for my project.

nocturne quail
formal solar
#

That's a good way to be most of the time, sometimes it can be hard to get back up to speed on complex tasks if you swap them out for something else - in the context of programming at least.

meager spade
#

@candid star you know about the bits?

#
    AllowedObjects.ClearAllBits();

    if (bIsConnectionRelevant)
    {
        AllowedObjects.SetAllBits();
    }``` not sure i fully understand how these bits work or what im supposed to be setting
meager spade
#

Speed is a state

#

also multicast makes no sense

nova wasp
#

hold on

thin stratus
#

Also actively accessing objects in the filters etc is not gonna be a thing I would recommend

#

It's written like this to specifically avoid the cost of accessing random memory.

#

I assume your original function was in the IsNetRelevantFor function. It might be better if you just disallow the specific actor to the connection by hand.

#

Docs page should show you how that works

nova wasp
#

what you can do is make your own storage in the filter for your game data

#

instead of pointer chasing 4 times to the controller

thin stratus
#

Doesn't that need an engine mod then though?

#

I assume Kaos is sending an RPC to change the world generation state that he's checking. Might as well just set the actor allowed for a given connection in there.

#

Or if it's multiple actors , add them all to a group filter "Disallowed While Generating" and remove the connection from that group filter once they are done loading.

hollow swallow
#

I have an actor for each player that spawns projectiles. Then projectile checks collision then tells the server to do damage (co-op). How can I handle that? I want projectiles client side because theres going to be hundreds so don't want them replicated. But once it's hit I only want to tell the server to deal damage once

nova wasp
#

your filter can have whatever the hell you want in it

#

the fact iris just gives you IDs is intentional to make it fast

#

but if you only have a few things in it there's nothing wrong with just going the slow way to bounce around to the uobject owner

#

UNetObjectGridFilter::Filter for example

thin stratus
#

It's been a while since I looked at this, but aren't those filters restricted to one per actor?

hollow swallow
#

Can I use an is server? Because the host is technically the server so his version only will be the one to tell it to do damage

thin stratus
#

I would still suggest the other solutions given 90% of the time Kaos will be polling the state of the generation for no reason. The RPC he most likely has already offers a good entry point to stop the filtering manually.

thin stratus
#

Checking NetMode is probably a good way too.

#

But in Blueprints that's probably hidden behind IsServer anyway

hollow swallow
#

Sweet ty. Just trying to keep performance in mind as I go along. Could be 500+ projectiles at a time

#

Yeah i only use blueprints

nova wasp
#

but that's not really a big deal imo as you can just do whatever you want with a function

#

not sure

#

there's really nothing limiting in my mind about the network ref handle unless it's difficult to access the filter from outside (or when the object is created)

thin stratus
#

I only ever saw epic use the additionally cached transforms within the filters. No other data. If at all you'd cache your own data similarly (which is probably what you want to do?).

#

But since this whole thing here is super event driven, I don't even see the need for a complex filter as opposed to a simple exclusion group

nova wasp
#

and if that's annoying you can just resolve the network ref to the pointer and oh well

#

I have seen prioritizers more than filters

#

personally

#

I think the built in ones will probably cover a lot already though

thin stratus
#

I'm pretty sure we only have one of each per Actor. And the rest are group and connection filters.

#

The grid filter one and the first person prioritizer or whatever it is called.

nova wasp
#

that said I will not blame people for being confused by Iris stuff

#

because it's pretty much all new containers

thin stratus
#

Rest are exclusion groups for teams and what not

#

Yeah

#

The biggest confusion for me was the concept of the exclusion filters.

nova wasp
#

I say this once a week but oh my god, Iris serializers are just too much

#

let people make the scuffed overload for simple stuff imo

#

I like the idea of the serializer living in a distinct file from the type in some ways

#

but it's way too tryhard for most projects even though I enjoy that they are focused on the speediest setup possible

thin stratus
#

But they are actively improving it. So we shall see.

hollow swallow
#

when i play as host, why cant i see BP_ThirdpersonCharacter in the outliner at runtime? but if i play as client i can

nova wasp
#

you can click the gear in to top to change the world it's showing

hollow swallow
#

sweet thankyou

nova wasp
#

I'm not really sure which one it uses by default in all cases

hollow swallow
#

It was on auto and that was making it editor instead of server

#

just trying to work out how to test if my projectiles are working properly only client side now xD confusing tf out of me

#

was easy having them all on server side

#

i think its working properly, just dunno how to confirm it

#

Does that look kinda right? or is that making a double up?

#

i want each player to be spawning all the projectiles themself for visuals and less network bandwidth, but then the server is the only one that will actually deal damage when it hits

nova wasp
#

and by that I mean the output log not on screen

#

and visual logger

hollow swallow
#

even the print strings can confuse me with client / server at times xD

nova wasp
#

why?

#

if you get lost just clear the output window

#

and start again

hollow swallow
#

because the host is server too yeah?

nova wasp
#

you just said server twice

#

what else would the host be

hollow swallow
#

magician xD

nova wasp
#

Listen Server would be a playing+rendering instance with authority

hollow swallow
#

okay i think i have it right then how its setup

#

if the server spawns a projectile that isnt replicated, no one else will see it yeah?

nova wasp
#

yep, unless something else caused the client to do something similar (would still not be a replicated object but it could replicate just "play vfx here")

hollow swallow
#

okay sweet, i think im gucci then, thanks mate

nova wasp
#

the server sends data about replicated objects relevant to the client (new objects sometimes) and rpcs to already replicated objects

hollow swallow
#

ive never tried to make anything only client side before, so it was melting my brain a bit

nova wasp
#

just be aware the client can't replicate properties to others, only rpcs

#

so anything the client tells the server has to be in the form of an rpc

hollow swallow
#

Yep thats all good, its purly for visuals, i just didnt want 1000 projectiles being replicated bogging down the network

thin stratus
#

What's the smartest way to have an RPC enabled actor per connection, which doesn't need any of the existing game framework classes to spawn it? So basically no GameMode, PlayerController etc allowed.

nova wasp
#

you might underestimate how early the player controller appears

thin stratus
#

That counts as involving game framework classes.

nova wasp
#

is the reason to avoid a dependency or just because

thin stratus
#

I could spawn it runtime and add it to the PC but then I would need a callback for when the PC is there, which I then could use to just spawn the actor to begin with

thin stratus
nova wasp
#

as for that I think I guess I would say try mimicing how the player controller is replicated

thin stratus
#

It's a plugin and I need the actor to transfer debug data that only exists on server

nova wasp
#

I personally do not see the big value in dodging the player controller component here though

#

you could just have some interface in another module

#

it doesn't need to gaf about what a playercontroller is, it could be a replicated subobject of it though

thin stratus
#

I want to avoid any modifications to other modules because this is just debug related.

nova wasp
#

why would it modify other modules

#

I said component

#

or even a subobject

thin stratus
#

Cause I need any form of callback for when to spawn that actor

#

There is no global PlayerController spawned callback afaik

#

Maybe the NetDriver has some for connection created or so

nova wasp
#

global viewtarget delegate for the first viewtarget change could do it

thin stratus
#

That could work yeah

#

I assume they spawn the GameplayDebugger Actor through the PC or so.

#

But maybe not. I might check how that thing is spawned

nova wasp
#

it just ticks lol

#

when it sees a new playercontroller in the iterator it makes a new one

thin stratus
#

LOL

nova wasp
#

this is actually probably easier

thin stratus
#

It is

#

But that feels so nasty haha

nova wasp
#

because view target delegates can be treacherous

thin stratus
#

Actually I will start with that

#

Shitty loop over the PCs

nova wasp
#

view target delegates can trigger ANY time in the frame and even on other threads

thin stratus
#

Loops over a 100 PC sadly but well

nova wasp
#

why? because CheckViewTarget changes view targets

thin stratus
#

Hm yeah it would only be a hack

#

The view target one

#

I will def check the NetDriver

#

Just out of curiosity

#

Generic UObject or AActor created callback could also work. But also feels nasty

nova wasp
#

a tick would cost less than a universal cost to each new object

#

hell, you can even tick the new controller checking every half second

#

unless you have like 2000 controllers to iterate

thin stratus
#

Na. 100 max

#

Maybe I can use a bit array

#

To mark connections based on Iris or so.

#

To keep track of new ones.

#

Something something

nova wasp
#

I'm not sure if there's a new connection callback

#

I can look

#

that said iterating the iris connections will probably beat random pointers?

#

tbh I would not be too concerned with the cost of a debug replicating thing

#

unless it physically makes it harder to even test

#

I think you don't need to tryhard this for a first attempt

thin stratus
nova wasp
#
    friend UE::Net::Private::FReplicationSystemImpl;

    FConnectionAddedDelegate ConnectionAddedDelegate;

🤯

thin stratus
#

But all that improves is memory access, at which point you are right and it's a bit much for debug stuff

nova wasp
#

ReplicationSystem->GetDelegates()

#

TIL

thin stratus
#

Shall try

nova wasp
#

also no idea if this works as I assume

#

you might still need to gather existing ones if your registration is late

thin stratus
#

Yeah, it's a dedicated server that is usually fully spun up before connections come in, but it's still wise to have an initial loop. Even just for editor

thin stratus
#

Ah, nvm, they work anyway. Was using the wrong module in the build.cs

meager spade
#

@thin stratus you mention group filters per connection, but where do you even set this or call this? at what point in the flow? cause the doc's don't even say where you should call such function just shows code

sterile aurora
#

I am running a dedicated server and running into an error where players who are late joining end up triggering the other connected players to disconnect/reconnect

#

I am getting this "actor channel failed" kind of error, Lion from multiplayscape suggested it might be because of something we are doing on begin play of the player controller or post login of the player controller

#

[2025.07.03-18.43.58:514][323]LogNet: Actor channel failed: [UActorChannel] Actor: GameplayDebuggerCategoryReplicator /Game/Clonk/Maps/Hubs/LVL_ClonkHub_Island.LVL_ClonkHub_Island:PersistentLevel.GameplayDebuggerCategoryReplicator_2147482212, Role: 3, RemoteRole: 1 [UChannel] ChIndex: 14, Closing: 0 [UNetConnection] RemoteAddr: 31.94.4.55:54179, Name: IpConnection_2147482250, Driver: Name:GameNetDriver Def:GameNetDriver IpNetDriver_2147482459, IsServer: YES, PC: ClonkBR_Player_Controller_ARnBox_C_2147482233, Owner: ClonkBR_Player_Controller_ARnBox_C_2147482233, UniqueId: Null:localhost-7A7450F4113E48BABDCD52F45FB2502F

nova wasp
#

Different targets?

sterile aurora
#

On our postlogin event currently, we have been passing in a player session ID and attempting to do AcceptPlayerSession and also do a REST API call with VARest

#

I am wondering if these are not valid things to put in the post login flow and that ends up blocking the server or causing an issue, I'm building a development client build to try to see logs there of what happens for the disconnecting/reconnecting clients but if anyone has any other tips on how to diagnose this please let me know

meager spade
#

you blocking the gamethread for extended times?

#

also strange it says GameplayDebuggerCategoryReplicator

sterile aurora
#

when I searched I found one forum post that suggested I might want to fast spawn someone into a spectator pawn, then do the accept player session and then transfer them into the real game pawn if that works, so I don't block the post login flow.

But it's only an issue for the already connected clients that are getting disconnected/reconnected, not the new person coming in.

meager spade
#

that is odd

#

are they both the same builds

#

client and server?

#

and all clients

#

ie all using shipping?

#

or development?

#

we had a bug back in 4.27 where it would try to spawn it but some clients didnt have that actor

#

so they would get kicked out

#

which looks like what is happening here

thin stratus
meager spade
#

server would spawn the replicator, other clients would not have the replicator

dark parcel
#

Hmmm FastArrayyReplication order isn't guaranteed between server and client. So how are we suppose to use this for lets say inventory items?

meager spade
#

for example we have a struct of initializer stuff for map generation but client seems to have no data even though server 100% set

#

(lives on a component on the game state)

sterile aurora
#

we were running a shipping build for clients and development build for server, I am running a dev build for clients now to see if I can assess why they are getting disconnected

thin stratus
meager spade
#

i mean the current system the client and server should create a set of regioin points name stable (thats how it worked on the old system), on the old system the replicated property is working fine, client has the data and generates the point, on iris, client never has this data

#

so what would cause that struct to not send the data?

#
    GeneratedMapData.SetPoints(NewPoints, MapSize);
    MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, GeneratedMapData, this);
    GetOwner()->ForceNetUpdate();```
#

just odd

#

the OnRep doesnt even trigger

meager spade
#

@thin stratus ok i solved those issues, but basically we have a bunch of actors called region point, the client and server both create locally, and they should be mapped (theres 100s of these). i need to not send any replciation to these if client has not generated its local side yet

#

i couldnt work out how to default them to a group, cause i can tell the server hey im ready for them, but how do i initially block them?

hollow raven
#

Hello, does it make a huge difference if I send the damage as a float or as an enum?

#

Because in my game, I handle damage by 5 stages

#

Not by numbers

meager spade
#

enum ist a uint8

#

so it doesnt matter

hollow raven
latent heart
#

uint8 is 8 bits, 1 byte.

hollow raven
modest crater
#

You save 4 - 1 bytes.

hollow raven
#

Assuming every second there are like 700 shots fired

modest crater
#

You would save 3 * 700 bytes

hollow raven
meager spade
#

which is nothing

#

we send quite a bit of data per shot

#

no issues

sterile aurora
#

our reconnection issue ended up being something simpler we were able to find on our client logs

meager spade
#

not sure why your worrying about it, i would worry if your sending a huge struct with tons of stuff thats not relevent

sterile aurora
#

we are using a web socket system to initiate matchmaking and the web socket was left open, so when the second client went to join the server, the original client was getting web socket messages coming in telling it to also join the server

meager spade
#

oof

hollow raven
#

2.1 kB is 2.1 kB I guess

hollow raven
modest crater
# hollow raven Thank you

It's all contextual is my point, optimize when you can and just be aware in context, no point having a custom network serialized struct to optimize something that gets sent once upon the start of the game and that's it vs something actually worth optimizing that is sent every few ms (like firing a weapon or movement etc)

thin stratus
thin stratus
#

Usually the best approach is to have a CMC child class and to have a list of overlapping black holes (or something more generic that the black holes use that you can reuse for something else in the future). And in the CMC child you can then calculate the velocity of the player based on whatever the super call gives you from the input of the player and then on top of that a velocity calculated from the overlapping black holes.

#

Doesn't even need to be further networked as running into and out of the black holes will already happen in sync for the predicting client and the server. It would be enough if server and client handle the list of overlaps each on their own.

#

Fwiw, if you can't use C++ (which would be quite bad if you are working on a multiplayer project), you can try to set the Velocity variable of the CMC on tick in your character. That would replace having a child CMC class and overriding the calc velocity function. Keeping track of what you overlap would remain the same

#

Would want to limit that tick stuff to auto proxy and authority though I believe

pseudo wagon
#

My implementation is just add movement delta to CMC.

nocturne quail
#

Undefined property BlueprintAuthorityOnly ?

UPROPERTY (BlueprintAuthorityOnly, Event, Private, BlueprintEvent)
meager spade
#

@thin stratus it works great

#

Tjabks

#

Thanks

thin stratus
#

Glad I could help :P

meager spade
#

Had to fix a few structs and stuff with net serializers

#

But got iris working

thin stratus
#

Nice. Don't look at how expensive it is in the traces :D

meager spade
#

Actually our game time was reduced by 2ms

#

With 6 clients

thin stratus
#

Ah yeah, guess depends on the game.

meager spade
#

On the server

thin stratus
#

100 players with a shit ton of stuff going on vs 6 player game.

meager spade
#

Yeah

#

I mean fortnite run iris now

#

So I assume it must be able to handle it

thin stratus
#

Yeah, but their fixes and improvements only slowly get to us.

meager spade
#

That's coreect

#

And a lot for stuff they do never gets to us haha

thin stratus
#

I wonder if they ever multi thread part of Iris.

meager spade
#

Oh we fixed this in fortnite by doing x and y

thin stratus
#

There are some good candidates for work thread stuff

meager spade
#

Well fix the underlying system ?

#

Yeah

#

I think like you said performance gains is based on what you do

nocturne quail
meager spade
#

If you don't use dormancy and stuff it will just still eat into your costs

thin stratus
thin stratus
#

On top of some silly things they did for tagging what needs to be considered.

meager spade
#

Hmm

thin stratus
#

E.g. you know what PushBased does in Iris?

#

It just marks the whole Actor to be checked

meager spade
#

I assume it sets a dirty flag

#

Or a bit

#

Eek

#

Not just that single property б

#

But the entire actor which I assume makes sense

thin stratus
#

And when you mark a SubObject dirty, guess what it will do?

meager spade
#

Yeah nark the owning actor dirty

thin stratus
#

Mark the Owner Dirty and the Owner will cause all Subobjects to be checked.

meager spade
#

Oof

thin stratus
#

Yeah. I think that part they improved by now.

meager spade
#

I didn't know that but then again

#

Isn't that how the old system works ÑŽ

#

?

thin stratus
#

But there are some really lovely things in there. If you check this channel for Nick Darnell's and mine conversation, you should see what I mean.

meager spade
#

I keep switching to Cyrillic keyboard lol. Joys of living in bulgaria haha. Still learning bulgarian

thin stratus
meager spade
#

Yeah it does seem to be better for us but I will need to do more profiles

thin stratus
meager spade
#

Ah we are lucky we don't spawn many replicated actors during gameplay

#

Probably in entire game about 200 in an hour

thin stratus
#

There were also some fun bugs in the prioritizer, which they fixed nowadays, but a 2 versions or so ago, they had a bug in the prioritizer where it calculates the distance between 2 points but only used the Direction * Distance for one of them forgetting to add the Origin to it :D

#

Which means everything was prioritized around ~0,0,0

meager spade
#

Oof

#

I'm looking at the player state prioritizer

#

Thinking I could make something for us to prioritise certain actors in our world

thin stratus
#

Yeah we only noticed cause my wife added some debugging to list all the priorities and they made 0 sense. So we combed through the code (which is quite annoying to read, cause they handle 4 objects/locations/etc. at once) and suddenly found that math error.

meager spade
#

Basically we have a bunch of worldmapactors that are active but don't always need to update unless they are dirty

#

Can't use dormancy cause that kinda breaks a few things atm

thin stratus
#

Keep mind, afaik, each Actor Class can only have one Prioritizer at a time.

meager spade
#

But we don't want to them to all go the same net frame if not needed

#

Or whatever

#

I see playerstate one has a round Robin thing

twin kite
#

Howdy, what does the SessionName FName that you need to provide to a lot of the OnlineSubsystem functions really mean? Does it need to be unique on the online backend, or can it be a hardcoded name that's the same on every client?

#

I figured that you use it to lookup and modify the session instance locally, of course. But I'm wondering if there will be a problem if two clients are hosting their game via Steam, and use the same FName SessionName internally

thin stratus
#

There are only two options in theory.

#
REGISTER_NAME(287,GameSession)
REGISTER_NAME(288,PartySession)
#

Either you pass in NAME_GameSession, which you'll 99% of a time, or you pass NAME_PartySession, which is very specific to some of the Subsystems.

#

If you use Beacons with Steam to do a lobby in the mainmenu (to queue up for games or so) you'd for example use the Party one.

#

But that's a lot more advanced in theory.

twin kite
#

Ah huh, interesting. I've been just passing my own name all the time. But that's easy, I can switch to NAME_GameSession

thin stratus
#

Na, this isn't meant to be used for custom names.

twin kite
#

Why isn't it an enum then? 🤔

thin stratus
#

Cause it can potentially be something totally different based on your Subsystem.

#

You can also code your own, which might need more than 2 options.

#

It's used by the backend to know what kind of Session you want to host.

twin kite
#

Oh yea, that makes a lot of sense!

#

Alright cool, thanks!

thin stratus
#

If you want to give your Session a name and display that in a list of Sessions, you'd usually use the additional Server Settings you can pass along.

thin stratus
#

How much do FastArrays dislike being altered very often?

nova wasp
#

if it's somthing that changes every frame you aren't saving many bits from them sending the changed indices

#

but if only some of a large set change it will still beat the entire thing sending?

meager spade
#

So I heard fast arrays are great for things that don't often and ofc you get the benefit of easier callbacks for changes om the client side. If it's something updating super often like once a frame or it can be more overhead over a normal array. But again this is also dependent on how much data actually changes and how big the array is. You won't see benefits till your array is a big enough size. If your talking the replication size then if the data the array not sure that matter cause I'm pretty sure the normal array serializing doesn't send everything? Might be wrong. Ut I thought it can reduce the size by know what was changed but probably not cause you might want to just change the order in the array.

lament flax
#

iirc when you edit a normal array, EVERYTHING past the modified index gets sent

#

so if you have 500 entries and edited at 110, everything from 110 to 500 will be sent

#

and oc on the other side you have to iterate the 500 entries to check if anything changed

#

so i guess it depends on how MANY entries you think you will have, as well as how big EACH entry will be

#

(for the update to much thing i dont remember)

verbal ice
#

I just like fast arrays for the added/modified/removed callbacks

#

they're cool

nova wasp
jagged kernel
#

How can I decrease the jitter on clients when using the CMC's Add Force?

nova wasp
#

either turn off corrections or make the force done in a way that is part of the cmc moves instead of externally

lean oak
#

How can I make my mouse work with my player controller on both my server and client while testing in-engine with a listening server? When I run the "Get mouse position" node on the server (using controller 0) it returns true, meaning it detects the mouse. But when I run the "Get mouse position" node on the client (still using controller 0 since locally it refers to its own controller) it returns false.

#

Here are the nodes (Also for added context in case it's useful, the player is in Game & UI mode when this is fired):

dark parcel
#

@lean oak the mouse must be on focus on the window.

#

if you are focusing on one machine, the other one will just return false.

#

also I don't see a point using the index here at all

#

where is the blueprint of the cropped picture at?

lean oak
# dark parcel <@867595610438107136> the mouse must be on focus on the window.

When I was running the code, I had been clicking on the client's window and controlling the character's movement and all that, so I had just assumed it was focused. If that's not the case how should I go about focusing the mouse onto the client window?
The blueprint is in a basic custom actor, not the player character, controller, or any of those. The mouse is being used to drag around a static mesh that's attached to the actor.

formal solar
#

I thought of adding a vote kick feature in my p2p game and then realised it's pointless unless I have a rehosting mechanism, which is too complicated for me to introduce at this stage

dark parcel
#

When you dont focus on the window then there seems to be no valid mouse device.

#

You can probably replicate mouse x and y as variable instead getting it directly from the controller function.

#

If theres valid device, continue to set the replicated x and y

#

Otherwise dont set it.

dark parcel
#

That requires you to build from the ground up.

formal solar
#

huh

#

just by using steam and host/join setup?

dark parcel
#

There's no p2p if you use what unreal provide

#

Epic use server client model not p2p

#

It is architecturally very different.

formal solar
#

oh idk, i heard different people call stuff different things

dark parcel
#

There is no server with p2p

formal solar
#

like 'listen server' is not understood in some circles

dark parcel
#

Everyone connects with each other.

formal solar
#

orite well its listen server then that was irrelevant to the point but ty

dark parcel
formal solar
#

well its both a client and a server

dark parcel
#

Listen server and dedicated = server client model.

#

P2p will be like old diablo game

#

Where if someone disconnect, game may continue

#

Because theres no server

formal solar
#

my game happens to be setup in such a way that if a client disconnects other people can still carry on playing

#

but if host disconnects everyone is booted

dark parcel
formal solar
#

yea sure

dark parcel
#

Client doesn't talk to other client directlt ever

formal solar
#

but anyway it is funny trying to think about anti cheat when 1 player is just the server anyway lol

dark parcel
#

Thats only in p2p

formal solar
#

its a casual game not hyper competitive

dark parcel
#

If you are using server client model and you are the server

#

Then you can freely do w.e you want and have that change reflected on others.

#

Afterall you are the authority

formal solar
#

well yea if ur a nerd enough to want to hack it, i think there is some protections u can put in place

dark parcel
#

So preventing cheat when you give the ability for others to host is pointless imo

formal solar
#

maybe i shoulda made it coop but i aint undoing 6 years work lol

#

but i knew from day one i wouldnt have leaderboard anything like that u need secure game for that to be meaningful

dark parcel
#

Why do you need rehosting mechanic for a vote kcik to happend?

#

You can have player rejoin the game

#

And kick anyone

#

Except the host

formal solar
#

what

#

I was thinking along the lines of one player initiates vote kick -> all other players except vote kicked player see yes/no

#

and if everyone says yes then the voted kicked gets kicked

#

but its 2-4 players so i wouldnt have it in 2 player mode in case everyone just vote kick when they losing because butthurt

#

I dont allow rejoin once session is formed

dark parcel
#

Your game your rule

formal solar
lean oak
# dark parcel If theres valid device, continue to set the replicated x and y

Well that node that saves the mouse position is old code, at some point earlier in the project it resolved an issue somehow and I kept it there, it doesn't actually mean anything. The problem is that I have an item that moves in the world under the mouse, I click this item in order to begin moving, at which point it should snap to my cursor, but instead it goes off to world origin because it can't find the screen position of the mouse, because it can't detect the mouse (despite detecting the mouse's click). So it sounds like I just need to figure out how to focus on one window or another, which I'm not entirely sure how to do beyond just clicking on it, but I'll look into it, thanks for your help

cold cipher
#

how to make a platform (interp movement) with fully client authoritive movement?
like it is spawned at server and replicated, and then the movement is completely smooth on client side (no need to be synced)

nova wasp
cold cipher
#

shared accurate server time?

verbal ice
#

@pallid mesa hey! Just wanted to let you know your article ^ has a broken link to Jambax's network event subsystem

#

The file is still there on this discord but Discord's new temporary links to attachments suck

#

^

cold cipher
#

edit: I did that with exposed on spawn replicated variables

nova wasp
#

could be done with bp I think

dark parcel
#

isn't there something you can use from the player state

#

GetServerTime()

#

it's "good enough" for general purpose

nova wasp
#

yeah that would be a decent start

fossil veldt
nova wasp
#

Are quat4f serializers reduced quality or are they just packed really well?

quaint roost
#

hello! Im running into a weird issue where if a player disconnects (and the players pawn gets unpossessed), on the simulated proxies the player pawn is like moving very slightly

#

does anyone know of an issue like that?

#

the pawn looks like it's sliding

thin stratus
#

The only exception being that the data originally didn't need those bits.

nova wasp
#

given a known range you can reduce a lot of waste

thin stratus
#

Yeah that's what I meant with the second sentence.

nova wasp
#

your average normal value is only using a small subset of possible numbers

thin stratus
#

If your Quat needed the whole 32 bits of each component, (for whatever reason), then you probably lost some precesion.

#

But quats are also not using very high floats numbers iirc.

nova wasp
#

the frustrating thing here is that since it's not just some floats (it must be a perfect normalized amount) things get weird

#

and lower float numbers actually use more bits given how much more precision there is at the end of the exponent etc

thin stratus
#

Hm. I can't even find the code for that thing

#

Only same macro driven implementations

#

Ah nvm

#

I'm not awake enough yet

#

Right, Iris serializer code.

#

Who doesn't love reading that

nova wasp
#

I made my own 1000th decimal serializer for floats as meters

thin stratus
#

They are quite straight forward after you've written one

#

Just a lot of boilerplate code

nova wasp
#

(some partial llm sludge to do the boilerplate stuff) but oh my god the static config is frustrating

#

if you mix up the order of boilerplate stuff it actually can never see the property

thin stratus
#

So. One thing they seem to do is to expect a Unit Quat

#

So they can ditch one component

nova wasp
#

yes the W is derived

#

which is interesting

#

I'm kind of doing something similar to Mover where I manually bodge all values to a simple representation

#

which is nothing new I guess but to me it is

thin stratus
#
    if constexpr (sizeof(FloatType) == 4U)
    {
        if (Value.Flags & EQuantizedFlags::XIsNotZero)
        {
            Writer->WriteBits(Value.X, SignificandBitCount);
        }
        if (Value.Flags & EQuantizedFlags::YIsNotZero)
        {
            Writer->WriteBits(Value.Y, SignificandBitCount);
        }
        if (Value.Flags & EQuantizedFlags::ZIsNotZero)
        {
            Writer->WriteBits(Value.Z, SignificandBitCount);
        }
    }
#

static constexpr uint32 SignificandBitCount = (sizeof(FloatType) == 4U ? 23U : 52U);

nova wasp
#

that's to make it change if it's a float or double

thin stratus
#

Yeah I know, just sharing what it writes out

nova wasp
#

I wonder how bad it would be to just make these Euler angles

thin stratus
#

Hm. Well most peeps serialize Rotators to shorts or similar

#

Which def cuts precision

nova wasp
#

a short for rotation is plenty for lossy trasmition

#

for something that doesn't have a long arm

thin stratus
#
    else
    {
        // All transmitted quaternions must be unit quaternions, in which case we can deduce the value of W.
        if (!TempSource.IsNormalized())
        {
            TempSource.Normalize();
        }

        TempSource.X = FMath::Clamp(TempSource.X, -FloatType(1), FloatType(1));
        TempSource.Y = FMath::Clamp(TempSource.Y, -FloatType(1), FloatType(1));
        TempSource.Z = FMath::Clamp(TempSource.Z, -FloatType(1), FloatType(1));
    }
    
    TempValue.Flags |= EQuantizedFlags::XIsNegative*(FloatAsUint(TempSource.X) >> SignBitShiftAmount);
    TempValue.Flags |= EQuantizedFlags::YIsNegative*(FloatAsUint(TempSource.Y) >> SignBitShiftAmount);
    TempValue.Flags |= EQuantizedFlags::ZIsNegative*(FloatAsUint(TempSource.Z) >> SignBitShiftAmount);
    TempValue.Flags |= EQuantizedFlags::WIsNegative*(FloatAsUint(TempSource.W) >> SignBitShiftAmount);

    // Rebase the X, Y and Z components to end up in the range [1.0, 2.0], which allows us to not replicate the exponent
    // except for a bit to differentiate between 1.0 and 2.0.
    TempSource.X = FGenericPlatformMath::Abs(TempSource.X) + FloatType(1);
    TempSource.Y = FGenericPlatformMath::Abs(TempSource.Y) + FloatType(1);
    TempSource.Z = FGenericPlatformMath::Abs(TempSource.Z) + FloatType(1);

    // If the value is 1.0 after rebasing then we denote that to avoid replicating the significand.
    TempValue.Flags |= EQuantizedFlags::XIsNotZero*(FloatAsUint(TempSource.X) != FloatOneAsUint);
    TempValue.Flags |= EQuantizedFlags::YIsNotZero*(FloatAsUint(TempSource.Y) != FloatOneAsUint);
    TempValue.Flags |= EQuantizedFlags::ZIsNotZero*(FloatAsUint(TempSource.Z) != FloatOneAsUint);

    TempValue.X = FloatAsUint(TempSource.X);
    TempValue.Y = FloatAsUint(TempSource.Y);
    TempValue.Z = FloatAsUint(TempSource.Z);
#

I think the middle part is what saves a lot of bits.

#

Exponent is like 8 bits per float or so?

#

1 is the sign and 23 for the mantisse or however you write that

#

I'm struggling with something else currently.

#

I have data that is being collected 30 times per second, but only on the Server.
And it has to be only on the Server, because it needs to be Transforms and Shapes of Actors on the Server.

Now I would love to be able to visualize those Transforms and Shapes more or less live on the Client, BUT, not only in the Editor.
Which means I can't just use things like VLogger or Rewind Debugger, as those either won't work at all outside the Editor or they can't be viewed outside the Editor.

I tried replicating the data outside of shipping, but the Actor the data is replicated through is throttled I guess.

#

I would love to have a standalone VLogger Window >.>

nova wasp
#

override send limits

#

FScopedBandwidthLimitBypass

thin stratus
#

You want me to commit the same crimes NPP does?

nova wasp
#

network prediction uses this to cheese sending more things by gaslighting the net driver

#

tbh the default bandwidth limits are kinda low anyways

thin stratus
#

The data itself is probably not even too much, but the update rate is super low.
I assume it's potentially just throttled by Iris naturally.

#

Like, it's currently an Array of 30 entries. And it doesn't grow or shrink. All I do is write the next index and loop back to 0 when I reach 30.

nova wasp
#

enable delta serialation for the class

thin stratus
#

I had this wrapped into a FastArray with DeltaSerialization. Didn't change a thing.

#

That's why I think it's the update rate that is throttled

nova wasp
#

I'm honestly not even sure how to measure when throttling is happening

#

just raise the defaults

#

it's kind of crazy how there's basically no inidication throttling is happening

thin stratus
#

SetNetUpdateFrequency(60.f); That's how often per second it should update or not?

#

That's what the tooltip says at least.

#

I went through so many iterations (theoretical ones) by now. I even have a Replicator setup per Client by now (based on what we looked at yesterday), but that doesn't help with data that changes so damn often. I can use that for data that changes once in a while and then request it via RPCs.

#

I would love to have a Standalone Rewind Debugger + VLogger, but well.

verbal ice
#

Or well, will be considered for replication

thin stratus
#

Yeah, will check if the PollFrequency of Iris is the problem.

verbal ice
#

God I need to get started on Iris for work and everything I'm reading makes me anxious

#

I'll probably get the hang of it but it seems like a steep climb to get there

thin stratus
#

Yeah, still not updating often enough. I guess I drop the idea of replicating this for now..

verbal ice
#

Have you tried increasing the MinNetUpdateFrequency

thin stratus
#

Yop

verbal ice
#

odd then

thin stratus
#

Takes 2 to 3 seconds for each update to arrive.

#

Or rather

#

Not each update. It also only represents the current set of 30 entries 2-3 seconds later.

nova wasp
#

are they being sent as full sized doubles?

#

honestly that seems insanely low given it's a single element

thin stratus
#

tbh, we replicate more data at once through Mover than this.

nova wasp
#

I would be curious if it's just not marked dirty

thin stratus
#

I removed pushbased from it for now

#

Cause that made no difference either

#

I will replicate a float now and see if that updates more often (and stop replicating the array)

#

Sanity check..

verbal ice
#

How much data are you trying to send

thin stratus
#

Well if we assume the DeltaSerialization and FastArray setup that I originally had worked, which had the same update rate problem, then a set of 20 FKAggregateGeom atm.

#

Which each a single Elem in it fwiw.

#

Some have a BoxElem, others a Capsule (Sphyl...) Elem

#

That's kinda it.

verbal ice
#

Might be big yeah

thin stratus
#

It's like, at max 20 vectors, 10 rotators and 60 floats. That's a lot, I get it, but the cycle at which I get the updates is just too "in rhythm" to be related to that.

verbal ice
#

What's holding the fast array

thin stratus
#

Just an Actor

#

Yeah no, it's not the array. I'm setting an int now during the same call where I update the array and I removed the DOREPLIFETIME of amd the array dispaly the int and it updates similarly slow.

verbal ice
#

server tickrate?

thin stratus
#

30 Hz, since I tied it to NPP TickRate.

nova wasp
#

try with netquantize vectors

thin stratus
#

I can't without writing my own type atm

#

And a simple int has the same issue

#

Yeah it must be replication rate related. I will have to solve this differently I guess and forget about allowing visualization of the looping buffer for now.

#

Replicating a set of data that changes 30 times per second is just not viable. I will fall back to the limit of recording things via VLogger and users will have to open it in the Editor if they want to analyze it.

#

GameplayDebugger Replicator does a lot of extra work to manually delta serialize the data and also keep track of Acknowledge packages etc.

#

I could try and replicate it through NPP itself, by turning this stuff into a NPP Component, but I would rather not.

#
  • that also doesn't replicate every frame for SimProxy stuff anyway.
nova wasp
#

you could probably help split the work up by having multiple net objects for broad things

#

but separate properties should have changemasks fine

#

did you enable delta serialization?

thin stratus
#

Yeah, already tried that within the FastArray

nova wasp
#

no

#

that is not delta serialization in iris (even though it does send deltas for a fast array)

thin stratus
#

Again, the Integer alone is already not replicating often enough

#

It updates more often, but I can never be sure to get every frame.

nova wasp
#

also like I said raise the bandwidth limits

#
default engine

[/Script/IrisCore.ObjectReplicationBridgeConfig]
; Classes for which deltacompression is enabled
+DeltaCompressionConfigs=(ClassName=/Script/MyModule.MyClass))
[/Script/Engine.Player]
; These numbers should match TotalNetBandwidth
ConfiguredInternetSpeed=200000000
ConfiguredLanSpeed=200000000


default game
[/Script/Engine.GameNetworkManager]
; Increase from the base bandwidth, numbers need to match ConfiguredInternetSpeed in DefaultEngine
TotalNetBandwidth=200000000
MaxDynamicBandwidth=200000000
MinDynamicBandwidth=200000
modest crater
#

Anyone know how I can save my layout for PIE windows? I am over every... single... time... I have a few pie windows needing to drag them all into the optimal spot, make them larger etc

thin stratus
#

Can't you just use the Save Layout stuff under Window?

#

Or does that only apply to the Editor itself?

modest crater
#

That has never worked for me like it should, almost always resets or re-organizes tabs, I dont think that works for pie stuff

thin stratus
#

Hm ok

#

We do have an internal change that allows PIE to play in the additional Viewports you can open.

#

As opposed to opening a new window for Client 2, 3 and 4.

#

But might not be what you want and needs an engine change.

modest crater
#

ooh that sounds nice, so it just splits the main window?

thin stratus
#

A small one fwiw

modest crater
thin stratus
#

Well you can enable more Viewports under "Window" -> "Viewports". Up to 4 in total.
UE will use only Viewport 1 by default and open new PIE Windows for Clients 2 to 4 anyway.

#

But you can have it use the other Viewports too.

#

I just can't share the exact code. I can only give you tips where to change things.

#

Cause client code base.

modest crater
#

Tips would be appreciated, whatever you can share within reason (if youre not too busy)

#

That sounds like a massive QOL

thin stratus
#

Inside of UEditorEngine::CreateInnerProcessPIEGameInstance there is a point where it checks if (InParams.DestinationSlateViewport.Get(nullptr).IsValid()). That is valid if you select "Play In Viewport" (as opposed to New Window).

#

In there, it usually does this:

SlatePlayInEditorSession.DestinationSlateViewport = InParams.DestinationSlateViewport.GetValue();

// Only one PIE Instance can live in a given viewport, so we'll null it out so that we create
// windows instead for the remaining clients.
InParams.DestinationSlateViewport = nullptr;
#

Which causes Clients 2 to 4 to get new Windows.

#

What you would need to do is to get the LevelEditor Module, and the ForegroundTabViewports of that.

#

And then you can map the InPIEInstanceIndex that you get from the CreateInnerProcessPIEGameInstance function to that array and use the given viewport for the SlatePlayInEditorSession.DestinationSlateViewport.

modest crater
#

Appreciated greatly

thin stratus
#

Just need to make sure the index is valid, cause it will only use viewports you also have visibly added.

#

If you only have 1 viewport, it still needs to create windows for the others.

#

It's like 5 lines of code if we don't count {}

#

Maybe a few more if you want to wrap that behind a boolean you may add to UEditorExperimentalSettings to be able to turn it on/off

#

You will need to expose the ForegroundTabViewports from within the LevelEditor.h

#

That's potentially the bigger part of the change, but I'm sure you can figure out how to return an array of TSharedPtr<IAssetViewport> from there, by grabbing the LevelEditorInstancePtr and collecting all Viewports that are ForegroundTabs.

#

And that's kinda it. Overall something Epic could easily support.

modest crater
#

Yeah it sounds simple enough, I'll make some food an get started on it, appreciate the tips

thin stratus
#

@modest crater fwiw, there is code that should make the Windows not reposition constantly.

#

UEditorEngine::GetWindowSizeAndPositionForInstanceIndex

#
// Now we can position the window. If it is the first window, we can respect the center window flag.
if (InWorldContext.bIsPrimaryPIEInstance)
{
    // Center window if CenterNewWindow checked or if NewWindowPosition is FIntPoint::NoneValue (-1,-1)
    if (InEditorPlaySettings.CenterNewWindow || InEditorPlaySettings.NewWindowPosition == FIntPoint::NoneValue)
    {
        // We don't store the last window position in this case, because we want additional windows
        // to open starting at the top left of the monitor.
        OutPosition.X = FMath::RoundToInt((DisplaySize.X / 2.f) - (OutSize.X / 2));
        OutPosition.Y = FMath::RoundToInt((DisplaySize.Y / 2.f) - (OutSize.Y / 2));
    }
    else
    {
        OutPosition = InEditorPlaySettings.NewWindowPosition;
    }
}
else
#
else
{
    if (InViewportIndex < PlayInEditorSessionInfo->CachedWindowInfo.Num())
    {
        OutPosition = PlayInEditorSessionInfo->CachedWindowInfo[InViewportIndex].Position;
        FitWindowPositionToWorkArea(OutPosition, OutSize, WindowBorderSize);
    }
    // Add a new entry.
    else
    {
        // We bump the position to go to the right, and the clamp will auto-wrap it for us if it falls off screen.
        OutPosition = PlayInEditorSessionInfo->LastOpenedWindowInfo.Position + FIntPoint(PlayInEditorSessionInfo->LastOpenedWindowInfo.Size.X, 0);
        // We're opening multiple windows. We're going to calculate a new position (opening them
        FitWindowPositionToWorkArea(OutPosition, OutSize, WindowBorderSize);

        // Store this position as the 'last opened' position. This means additional windows will start to
        // the right of this, unless they run out of room at which point they'll start over on the next row
        PlayInEditorSessionInfo->LastOpenedWindowInfo.Size = OutSize;
        PlayInEditorSessionInfo->LastOpenedWindowInfo.Position = OutPosition;
    }
}
#

There is supposedly CachedWindowInfo.

#

That code fails a lot though. I even have Windows opening on top of each other..

#

They should honestly just expose the NewWindowPosition stuff for the other windows too.

#

What is a "creep"? Like the MOBA term for those things you last hit to gain currency?

#

What class are they?

#

Yeah, cause you throw away all the smoothing the CMC gives you.

#

Are you able to use C++?

#

Honestly, I would suggest you write your own, simplified, UCreepMovementComponent, inherting from UPawnMovementComponent and handle Interpolation/Smoothing there by hand.

#

Just enabling Replicate Movement will do nothing good for you, as that just replicates the Location and Rotation and applies it, without any smoothing applied.

#

UE only has a handful of things that have smoothing built in.

#

The CMC, The PMC (Projectile Movement Component) and, if you want to count it, NPP/Mover.

#

You could opt into using NPP and Mover for just the Creeps fwiw.

#

But, I usually suggest to stay away from NPP and Mover for a few more months, as it's still being developed and Epic is pushing harded for Chaos Mover than NPP Mover.

#

At least for Multiplayer.

#

I would suggest using the CMC for now then.

#

If you, in the future, notice that the CMC costs you dearly, you can still refactor it to make it cheaper.

#

I wouldn't get held up on that for now.

thin stratus
#

When you are probably the only one working on the project and Horde gives you 15 agents with over 500 cores to compile your 3.5k modules in a few seconds.

verbal ice
#

3.5k modules?

#

dang

thin stratus
#

Yeah I modified PlayLevel.cpp and LevelEditorPlaySettings.h

#

Added that my new PIE windows just spawn in a grid.

verbal ice
#

ahhh fair

#

How's Horde?

#

Been using Jetbrains TeamCity for builds

thin stratus
#

Useful

#

There is more to horde than just that fwiw

#

But most of horde is tied to P4.

#

The UBA stuff is, however, funtional without P4, so everyone can set that up if they have Agents to help compiling.

verbal ice
#

So guessing it doesn't work with Git?

#

outside of the compiling part

thin stratus
#

No, the automated build stuff where you can kick off preflights etc. wouldn't work.

#

This is a customer's setup. Internally we just use UBA and for the rest I use the CICD stuff that comes with GitLab.

verbal ice
#

I see

verbal ice
#

For my own stuff I just rent a server and slapped Gitea on it

#

So far so good

#

I don't like having to pay for licenses on my own projects heh

thin stratus
#

Yeah GitLab is free so same here

verbal ice
thin stratus
verbal ice
#

Did that change or was I crazy a few years ago

#

I had a self hosted Gitlab CE instance and I'm pretty sure the limit applied? Could be wrong

thin stratus
#

Not to my knowledge.

verbal ice
#

rip

torpid crest
#

Is it a good idea to limit input triggering on the client until the current action is complete? Right now, the player can spam the mouse button.
If I implement this, something would need to be sent back to the client once the action is finished. However, I'm concerned that desynchronization could block the response entirely.

thin stratus
pallid mesa
#

should now be fixed thanks a lot @verbal ice

jagged kernel
#

Is it normal to have huge amount of movement correction on client when the server window is on background in standalone game while using CMC's Add Force?

golden merlin
#

need help with steam sessions for UE 4.27

my game isn't always able to find steam sessions, only works about 10% of the time.
It works randomly when I relaunch the game, but works only once - if I rehost the lobby, can't find sessions again :(

incredibly frustrating, it would be awesome if I could get some help on this!

dark parcel
#

it sounds like you never destroy previously created session.

#

for a bandaid, you may just want to call destroy session before you host, before you search, and when you quit a game.

#

@golden merlin

golden merlin
#

I already do that actually

#

It works randomly sometimes when I relaunch the game, that's the issue

#

It's not like it always fails

grizzled stirrup
#

relaunching the game will destroy the session. are you sure you are destroying it cleanly?

#

are you logging what is happening when finding sessions

#

as in do you find a session and if so at which point does the join fail?

#

you have to destroy session on both client and server btw

proven pagoda
jagged kernel
proven pagoda
#

I have no idea. On my dedicated server games I don't have a way to put the server in the background so I've never run into this issue

somber mortar
#

Hi, I'm making a 3D third-person online (LAN) dueling game, and I'm having an issue with Xbox controller handling. If I launch the game with the controller already connected, it bugs out: the camera moves on its own, some buttons don't work or trigger the wrong actions, and the character constantly moves downward. This only happens when the controller is already connected when I join or host the session. If I wait to connect the controller after I'm already in the game, everything works perfectly. Have you ever seen something like this before?

thin stratus
#

Also what is Online LAN? LAN is by definition Local 😅

somber mortar
somber mortar
errant charm
#

Hello! I can't figure this one out for some reason so going to ask here. I’ve got this replicated actor BP_PizzaStation, and I’m trying to do a client side camera/input setup when the player interacts with it. I don’t want to move all that logic into the PlayerController, because that just turns into a dumping ground for stuff from random actors.
I know it doesn't have to be replicated, but these are called by the server as all interactions are processed on the server. Maybe a multicast? Or maybe I could make the client the owner?

Any help would be great CF_CatEpic

nova wasp
#

It can still have rpcs and replication

errant charm
errant charm
#

Would just setting the client as the new owner of the actor not be suitable?

dark parcel
#

If input is processed on server, it can take a reference to the client that press the input.

#

If you want the client to get an answer from the server you can just do client rpc.

But it must be routed to actor that the client pressing input own.

#

So i would add component to the PC like megafunk suggest.

#

Setting ownership may work but there can only be one owner.

#

If multiple people required to interact with your pizza station then the game breaks.

hasty tendon
#

hi folks, I need a bit of help. SetActorLocation isn't really working for the client. here's the setup:

exotic wasp
#

is the position replicated?

hasty tendon
#

yep, a replicated trace

hasty tendon
nocturne quail
boreal wadi
#

I just found a huge issue with Mover 2.0 & Anim BP's. I'm wondering if anyone has already ran into this.

TL:DR Essentially, any logic that uses the last frame's data and compares it with the current frame's data will have really unexpected results.

For example Lyra's animation state machine uses "Displacement Speed" which is calculated by getting the distance between the last updated position and the current one.

Problem is when you have your fixed tick set too low (I've been testing on 15hz, 20hz, 30hz, 60hz) those updates don't happen as fast as the animation blueprint is checking for it. Meaning you will get displacement speed up somewhere in the high 2000's for a frame then every other frame that value will be 0 causing the animation to output to look really bad.

I've done some things to try and solve it. The only thing that even seems like it is working is only updating the values(like displacement speed etc) when the values they use in calculations change in the sync state but that opens up a whole new can of worms.

Any alternative solutions are extremely welcomed!

thin stratus
boreal wadi
#

I am!

thin stratus
#

SimulationenState only updates every SimTick. For visual stuff that's not often enough. PresentationState is updated every GameTick and gets set to the Interpolated values between last and current SimulationState, based on how much time has gone by.

nova wasp
#

does the PresentationState always use a pair of sim tick states?

#

or does it extrapolate

thin stratus
#

Would need to check again. It's also slightly different between local client and SimProxy

boreal wadi
#

I’ll spend some time in a bit swapping things over. Thanks

nocturne quail
#
USTRUCT()
struct FPlaneRoute
{
    GENERATED_BODY()
    FVector StartPoint;
    FVector EndPoint;
};

UPROPERTY(Replicated, BlueprintReadOnly, Category = "Plane")
TArray<FPlaneRoute> Routes;

error : Type 'TArray<FPlaneRoute>' is not supported by blueprint. Class: AArmaBoardingPlane Property: Routes 🤔

verbal ice
#

Missing BlueprintType on the struct

nocturne quail
dawn cargo
#

I use World->SeamlessTravel() while testing in UE5 PIE, and I get a crash on flags,
ServerTravel doesn't crash though

#

I tried following the execution and all I found was it is some sort of debug rendering doing it,
but IDK why rider, is not showing what the flags, or what is actually causing the exception

#

only happens for clients connecting to server

verbal ice
#

Means the object it's called on is invalid

dawn cargo
#

i can't figure out what object it is trying to call it on, the stacktrace is not helpful, I can't tell where it is causing this issue

#

I am using GAS if that means anything

nova wasp
#

Go further up the callstack

#

It's a local player debugger category canvas draw

thin stratus
#

Probably had the GAS GameplayDebugger window open?

boreal wadi
#

Okay I switched everything over and it seems to work fine. Values are more stable. I've tried it a couple ways. First I was just using the Presentation state as is and that gave me a similar issue to earlier where the values are coming out as 0 most of the time.

My current code looks like this

    FMoverSyncState PreviousPresentationState;
    GetCharacterMovementComponent()->GetBackendLiaisonComp()->ReadPresentationSyncState(CurrentPresentationState);
    GetCharacterMovementComponent()->GetBackendLiaisonComp()->ReadPrevPresentationSyncState(PreviousPresentationState);
    const FMoverDefaultSyncState* CurrentSyncState = CurrentPresentationState.SyncStateCollection.FindDataByType<FMoverDefaultSyncState>(); 
    const FMoverDefaultSyncState* PreviousSyncState = PreviousPresentationState.SyncStateCollection.FindDataByType<FMoverDefaultSyncState>(); 
    if (CurrentSyncState && PreviousSyncState)
    {
        DisplacementSinceLastUpdate = (CurrentSyncState->GetLocation_WorldSpace() - PreviousSyncState->GetLocation_WorldSpace()).Size2D();
    
        WorldLocation = CurrentSyncState->GetLocation_WorldSpace();
        
        DisplacementSpeed = UKismetMathLibrary::SafeDivide(DisplacementSinceLastUpdate, UNetworkPredictionWorldManager::ActiveInstance->GetDeltaTime());
    }```

I was using delta time from the anim instance before I decided to use the delta time from the prediction world manager and the values were coming out extremely high similar to earliier so thats why I switched. 

Values are really similar to what I was getting with my manual lerp but the animation looks odd. I probably messed something else up when trying to fix the problem earlier.
dawn cargo
#

cachedReplicated is null

thin stratus
#

Above that part it should be checking if the CachedReplicator is nullptr and early return.

dawn cargo
#
{
    // this change is required for multi-client PIE, since even though every client has its own UWorld this OnDebugDraw
    // gets called by a multicast-delegate - the same for all the clients. 
    CA_SUPPRESS(6011);
    const FSceneInterface* Scene = (Canvas && Canvas->Canvas) ? Canvas->Canvas->GetScene() : nullptr;
    if (Scene && Scene->GetWorld() != CachedReplicator->GetWorld())
    {
        return;
    }
    check(Canvas);
    
    if (CachedReplicator && CachedReplicator->IsEnabled() && bDebugDrawEnabled)
    {
        FGameplayDebuggerCanvasContext CanvasContext(Canvas, HUDFont);```
thin stratus
#

What Engine version is that?

#

@dawn cargo

dawn cargo
#

5.4

thin stratus
#

Welp, that's an Engine bug then.

#

They placed code that uses CachedReplicator above the part where they ensure it's valid.

#

This is not how that looks like in 5.5+ anymore.

#

@dawn cargo I would suggest not using SeamlessTravel in the Editor then. It's still somewhat experimental anyway.
Start the game standalone or package it to test SeamlessTravel flow.

#

Or update your project to a new Engine version, if that's an option for you.

thin stratus
#

Lemme check how native Mover looks like again.

#

You can't just read the states via the Backend Component. That is something you should generally avoid.

#

Right, man native Mover is ugly.

boreal wadi
#

that’s the only access to it as far as I could see.

thin stratus
#

But in UMoverComponent::FinalizeFrame it caches the Sync and Aux States.

#

FinalizeFrame is what SimProxies call from within the Interpolation/Smoothing services.

#

ReadPresentationSyncState and ReadPrevPresentationSyncState return to you the two states that it interpolates between.

#

It calls FinalizeFrame with the result of the interpolation.

#

So in theory you only have access to the properly interpolated value in there.

#

But they cache the state.

#

So just grab the Cached State and you are good.

boreal wadi
#

Ah so the cached sync state should already be interpolated for the sim proxy.

thin stratus
#

Yes

#

I don't know how their AutoProxy smoothing works again

#

We have have a FinalizeSmoothingFrame method for that one.

#

We also cache the Simulation and the Presentation States, not just one of them.

#

It's also an absolute mindf*ck to understand when a given state in the View is valid.

#

Like, if you call those Read methods, when does it point to the current and when the last state?

#

The stuff it gets that data from is the "View", which just contains pointers to the States in the Buffer.

#

When a SimTick happens, it updates those pointers to point to the OUT States, so the stuff that will be produced.

#

So if you grab those states during SimTick or after, it will have the new data, but if you grab it before the SimTick, it still has old data.

#

So the best is to avoid touching those backend functions.

#

Actually, during SimTick it will have just "sh*t" in it, cause nothing is produced yet.

#

But you get the idea.

#

Ah they do have UMoverComponent::FinalizeSmoothingFrame.

#

You will want to also cache the State there, so your AutoProxy (if you use FixedTick) can have smoothed values too.

boreal wadi
#

Yea that makes sense. That’s why my initial approach was just to use the simulation state since it’s cached. I didn’t know that finalize frame ran at regular frame rate for sim proxies

thin stratus
#

FinalizeFrame actually calls for everyone fwiw.

#

But SimProxies call it additionally when smoothing.

#

It's relatively important to understand NPP and its Services for this stuff.

#

So you know when what is being called and valid.

boreal wadi
#

True. I’m not a traditional engineer so that code is still cryptic to me. Especially with all of the templated functions. I’ll have to take more time with it.

thin stratus
#

Understandable. It took me a lot of time to get behind all of that.

#

It's relatively save to start in the UNetworkPredictionWorldManager, in its StartNewSimulationFrame function and then just going down the code to see what is called when.

#

The different Simulation Components, like UMoverNetworkPredictionLiaisonComponent, are basically plugged into arrays of Simulations. Mover is one Simulation, so when it calls stuff like this:

for (const TUniquePtr<ILocalTickService>& Ptr : Services.FixedTick.Array)
{
    Ptr->Tick(Step, ServiceStep);
}

All that actually does is call the Tick function on a ILocalTickService instance that was created for Mover.
So if you have another simulation, like some custom Ability System or what not, then that Array would have two entries.

But if you only have Mover, than that's just one. And if you then click on that ILocalTickService to follow it you usually end up in files called NetworkPredictionService_XYZ.inl (here XYZ would be Ticking). And while you will just end up at the interface class, you can scroll down to find the implementations, such as TLocalTickServiceBase.

That thing then uuuuusually has something called Instances (here InstancesToTick) which are the actual Components (so UMoverNetworkPredictionLiaisonComponent).

If you then scroll it a bit further in the Ticking one, you'll find Tick_Internal, where it loops over those InstancesToTick. It then accesses the overall DataStorage that holds basically everything regarding that Simulation (Mover). In this case it will grab the matching TInstanceData<ModelDef> and TInstanceFrameState<ModelDef> and call TTickUtil<ModelDef>::DoTick.

If you follow that, you'll find where they call View->UpdateView (which is what shifts the Pointers around that you get via those Read methods), and then ultimately will grab the Instance.Info.Simulation and call SimulationTick on that.

Instance.Info.Simulation in this case is the UMoverNetworkPredictionLiaisonComponent which got originally passed along when registering the UNetworkPredictionComponent.

#

Ultimately, the rest of NPP works the same.

  • Some Array of Service Interfaces, where each entry is a Service instance that takes care of one Simulation.
  • Each Service instance usually has an Array of Instances, so the UNetworkPredictionComponents of a given Simulation.
  • Each Service will then call some templated function on either the Simulation or the Driver.
    • For Mover that's both the same UMoverNetworkPredictionLiaisonComponent.
#

With that you can get through most of NPP when reading through the code without getting lost.

#

E.g. the code that ultimately calls the ProduceInput stuff.

Inside UNetworkPredictionWorldManager::BeginNewSimulationFrame_Internal:

// - Some Array of Service Interfaces.
for (const TUniquePtr<IInputService>& Ptr : Services.FixedInputLocal.Array)
{
    Ptr->ProduceInput(FixedTickState.FixedStepMS);
}

Actual implementation in the .inl file class TLocalInputService : public IInputService.

class TLocalInputService : public IInputService
{
    // [...]

    // - Array (in this case Map, I guess) of Instances of a given Simulation.
    TSortedMap<int32, FInstance, TInlineAllocator<1>> InstanceMap;

    // [...]
}
void ProduceInput(int32 DeltaTimeMS) final override
{
    for (auto& MapIt : InstanceMap)
    {
        FInstance& Instance = MapIt.Value;

        // [...]

        // Service calls templated function on Driver.
        FNetworkPredictionDriver<ModelDef>::ProduceInput(Instance.Driver, DeltaTimeMS, (InputType*)Instance.View->PendingInputCmd);

        // [...]
    }
}
#

@boreal wadi Hope that helps a bit getting started on learning this crap :D

meager spade
#

npp is in such a weird state

#

had good intentions but was done so weirdly

thin stratus
#

That's why we will most likely see Chaos Mover in the future as opposed to anything NPP related.

jagged kernel
#

Why does server handles lerp different from client and how do I fix this? I am doing lerp (rotator) to rotate my character mesh to the grappling point. It's supposed to look like more rotated like in the first screenshot. But others see like second screenshot.

#

When I don't use lerp it's completely same as what client sees

torpid crest
#

traveling from lobby to game level is retriggering listen option which leads to instant disconnect?

[2025.07.06-11.37.28:650][599]LogSteamSocketsAPI: Error: SteamSockets API: Error Cannot create listen socket. Already have a listen socket on P2P vport 7777
[2025.07.06-11.37.28:650][599]LogNet: Warning: SteamSockets: InitListen failed to start listening on the Steam Network.
[2025.07.06-11.37.28:650][599]LogNet: Error: UEngine::BroadcastNetworkFailure: FailureType = NetDriverListenFailure, ErrorString = , Driver = Name:GameNetDriver Def:GameNetDriver SteamSocketsNetDriver_2147481771
[2025.07.06-11.37.28:650][599]LogNet: Warning: Network Failure: GameNetDriver[NetDriverListenFailure]:

any idea?

jagged kernel
#

Did you enabled seamless travel?

torpid crest
#

listen shouldn't be there because it's already listen server in lobby

#

let me check seamless

meager spade
#

pretty sure we had to always pass listen just checking our code now

torpid crest
#

The log is complaining that I'm trying to reinitialize the same socket because the lobby is created as a listen server.

#

oh yeah seamless travel was off in game mode

#

gonna rebuild it and let see

#

ok map is loaded, but it doesn't assing player controller and pawn to player 😄 😄 😄 what the hell is that
camera stuck 0 0 0

#

seamless travel preserves PC's right? so I guess I need to manually reassign

jagged kernel
#

maybe it's because of you have one player start. I don't know if you have more but just saying

#

If you don't have, you can try adding another

meager spade
#

like LobbyCOntroller or GameController

#

iirc it recreates all of it

#

thats why playerstat has CopyProperties, etc

#

playerstate*

torpid crest
#

@meager spade it preserves them by default

#

https://dev.epicgames.com/documentation/en-us/unreal-engine/travelling-in-multiplayer-in-unreal-engine

Persisting Actors across Seamless Travel

When using seamless travel, it's possible to carry over (persist) actors from the current level to the new one. This is useful for certain actors, like inventory items, players, etc.

By default, these actors will persist automatically:

The GameMode actor (server only)
    Any actors further added via AGameModeBase::GetSeamlessTravelActorList
All Controllers that have a valid PlayerState (server only)
All PlayerControllers (server only)
All local PlayerControllers (server and client)
    Any actors further added via APlayerController::GetSeamlessTravelActorList called on local PlayerControllers
Epic Games Developer

An overview of how travelling works in multiplayer.

thin stratus
#

PlayerControllers are only recreated on SeamlessTravel if the class doesn't match.

#

Which is why a lot of peeps run into the issue that their BeginPlay on the PlayerController doesn't call anymore when they travel to the next gameplay map.

#

Also you don't need to pass ?listen along with the ServerTravel.

#

@torpid crest GameMode has OnSwapPlayerControllers, which allows you to move data from old to new PlayerController when it actually changes.

#

it's the equivelant of CopyProperties for PlayerStates.

#

I use that usually to move lobby data over, such as what character a player selected.

torpid crest
#

hmm it works fine in editor but it doesn't work in build
Lobby and game level are two different PC classes

thin stratus
#

PostLogin doesn't call for SeamlessTravel

torpid crest
#

[2025.07.06-14.22.42:410][475]LogGameMode: >> GameMode::HandleSeamlessTravelPlayer: BP_Lobby_PC_C_2147482166
[2025.07.06-14.22.42:410][475]LogGameMode: << GameMode::HandleSeamlessTravelPlayer: BP_Game_PC_C_2147481974

#

this is controller swap right?

thin stratus
#

The Client isn't logging in again.

#

Doesn't matter.

torpid crest
#

oh yeah

thin stratus
#

PostLogin only calls on the initial Login.

torpid crest
#

that makes sense

#

so on swap controllers

thin stratus
#

Well yes and no

#

Not for spawning.

#

Only for moving data over.

#

If you don't need any custom logic for the Pawn Class, just set it as the Default one in your Gameplay GameMode.

#

If you need a class per player, then use the overrides that the GameMode offers you.

#

There is one that is called something with Get Pawn Class for Player or so.

#

That gives you the PlayerController and lets you return a Pawn Class. So you can take whatever identifies your Pawn from the PlayerController (assuming you store it there and move it over with OnSwapPlayerControllers).

#

If you really need to spawn the Pawn by hand and possess it by hand, then PostLogin would be wrong, as that would only call if a Player joins while already being on the Gameplay level.

#

There is a function/event you can override that calls for both cases. Something with Generic Initialize Player or so.

torpid crest
thin stratus
#

You also don't need to package to test this btw.

#

Depending on the Engine version, you can try to enable the experimental Seamless Travel support in the Editor (console variable), or you just start the game as standalone (e.g. via the uproject file -> Right click -> Launch Game), as that supports Seamless Travel too.

#

Packaging to test this would otherwise take ages in terms of iteration time.

torpid crest
#

works fine!

#

thank you very much 🙂

jagged kernel
#

It's runnning on event tick

#

I did replication stuff before but it didn't work as I expected

stable aspen
#

Hey all, to achieve a very high max concurrent players (100 to 200), should i try to use Iris or stick with Replication Graph?
And if yes is iris plug and play or do i need to write custom code?

meager spade
#

use regpraph if you don't use iris

stable aspen
meager spade
#

well thats hard to say

#

iris is new and experimental

#

repgrah is old and more battle tested

#

what you choose depends

#

Iris has some issues still

stable aspen
#

I'm not a multiplayer expert, does Iris have documentation? And do you need to write a lot of custom code with it?

meager spade
#

only whats on the site

stable aspen
#

How much faster is it than rep graph?

#

Like how much more players can i handle on the same server compared to rep graph?

quasi tide
#

I'd say build something smaller than 100-200 player count first.

stable aspen
#

With Iris? With the normal multiplayer thing i got a little combat game thing working

quasi tide
#

Did you release it?

#

Do you have real networking conditions?

#

Do you have a playerbase?

stable aspen
#

Yeah im aware having a playerbase is the main issue

quasi tide
#

If your game needs to have 100 people in a game to be viable, you should also have plenty of budget for marketing

#

Even with iris - there are still going to be standard challenges with CMC

stable aspen
#

Yup i just want to support up to 100-200 players, it can work with 8 online

quasi tide
#

I would say, regardless, use Iris as that is where all the dev focus is going. So future proofing and all that.

stable aspen
#

Hmm smart
Is there an iris sample game the same way theres a mass sample game?

quasi tide
#

No

#

Hope you can read and understand C++ networking

brazen anvil
#

If I add a variable like uint8 MyVar : 4; to the saved moves, will it send a full byte or just 4 bits?

meager spade
#

it will be uint8

brazen anvil
#

Ok thanks. I will just use a full byte and split it then

#

I want the ability to have different crouching heights, which affect movement speed. And also be able to change the walking speed. So I can split a byte in half. Top 4 bits can be used for walking speed and last 4 bits can be crouch height. That gives me 16 walking speeds and 16 crouch heights if I needed.

thin stratus
#

Most UE games struggle to get 100 players going.

#

Performance of the Server will just go down the drain eventually.

#

Not even Iris helps there.

#

200 players is also not even replication-wise a problem. The GameThread will need to do too much for the Server to keep a stable 30+fps.

#

RepGraph and Iris help with that, but all the other stuff that can happen in a game is still gonna cost ms.

#

UE is just not really made for 200 players.

stable aspen
#

Would i have more luck with Unity or is 200 a wet dream?

thin stratus
#

Idk. I never really used Unity. I don't like their licensing model.

#

It can totally be that Unity's networking and overall Engine is cheaper and allows for more stuff to happen on the same server.
You can also look into replacements for UEs networking and use something that is meant to work for a lot more players.
How expensive your game is in the end is really depending on what you are even trying to do.

#

But going custom requires a lot of work and C++.

#

For most projects, 100 players is already a wet dream fwiw

nova wasp
#

Unity has like 5 different netcode solutions so... I have no idea lol

#

I think there are games that have gotten 100~ or so unreal players going, it's not unheard of

thin stratus
#

A lot of native systems also might need performance specific changes. Or have stuff that could make them more performant hidden behind cvars and experimental flags.

#

We've just been through optimizing a 100 player game, and it's really not that easy if the game uses a lot of stuff from UE and has a lot going on.

#

That's why I can hardly imagine 200 players.

acoustic inlet
thin stratus
acoustic inlet
#

okay thanks

brazen anvil
#

Is it better to replicate variables on the character versus making the CMC replicated?

fossil spoke
brazen anvil
meager spade
#

we tend to put it on the character

#

as it matches things like Crouch etc

brazen anvil
#

Thats what I was going to do

meager spade
#

keeps everything similar

#

i am really suprised theres no built in sprint

#

in cmc

#

i mean 90% of people put sprint in lol

teal heath
#

if i want to make an inventory array with three slots where should i put all the data when a player is picking up an item so others see it and its deleted for them as well?

exotic wasp
#

loaded question

#

either a component on their pawn or their playerstate I would think

teal heath
#

could you explain further? i don't get neither of these

grand kestrel
grand kestrel
#

Its like they didn't think a character would ever do more than walk

fossil spoke
#

Naming is hard

#

lol

grand kestrel
# fossil spoke Naming is hard

That is actually the real, bonafide, factual reason Epic never added sprinting
Because someone used the term walking they couldn't be bothered trying to resolve this or figure it out
||This is a complete lie||

grand kestrel
#

MaxWalkSpeedRunning VomitRainbow

#

Y'know...

#

I could have just done MaxRunSpeed and MaxSprintSpeed..

#

Naming IS hard

fossil spoke
#

Meh, we did MaxWalkSpeedSprinting

grand kestrel
#

Yep

fossil spoke
#

MaxWalkSpeedFloorSliding

#

We did that to

#

lol

grand kestrel
#

Looks like either someone had a stroke during naming or the naming is going to give someone a stroke, not sure which one

fossil spoke
#

Probably both

grand kestrel
#

Sounds about right

brazen anvil
jagged kernel
jagged kernel
#

yes

grand kestrel
#

There is no extrapolation for mesh smoothing on listen server
Epic never really completed listen server support for CMC

#

Read here

#

Reason: Fortnite doesn't use it

jagged kernel
#

thank you!

grand kestrel
nova wasp
#

Less distinct objects to poll for replication is slightly better

fossil spoke
#

Having an extra uint8 appended to the bunch isnt going to break the bank was what I was getting at. But you are right, there is a benefit.

#

A novice isnt going to notice the difference.

nova wasp
#

but it is probably not going to be that much more data

#

the bandwidth is kinda not the issue here I guess

#

my extra hot take for character sim proxy data is that it's generally better to keep it in 1 atomic replicated property

#

multiple properties can arrive at random times

#

so sometimes it's worthwhile to pack into one struct for atomicity

#

which is more of a thing for very fast paced games where missing it could move something

#

for example replicating the fact your are crouched but the location of where you end up when crouched is later

#

instant jitter on sim proxies

fossil spoke
#

I totally agree with you, I was giving my answer in context to the question the OP asked specifically. Deciding to have a single replicated property on the Actor or the Component is not going to have a material impact on performance.

nova wasp
#

if it was already replicated yeah... I guess I mean making something that wasn't replicated before replicating

fallen fossil
#

why RPC functions must be usually as const ref?

    UFUNCTION(Client, Reliable, BlueprintCallable, Category = "UI")
    void NotifyOwner_Client(const FText& message);

why can't be const? 🤔

nova wasp
fallen fossil
#

I don't, but I think I had some errors with copy of other types, actor ref maybe ? 🤔

nova wasp
#

those aren't sent as references

#

so I'm not sure what you are referring to

fallen fossil
#

its not that important.

Can I send text messages?

#

Like properly with const &, will it work on client ?

#

like, will it work properly and display translated messages on client? :d

    UFUNCTION(Client, Reliable, BlueprintCallable, Category = "UI")
    void NotifyOwner_Client(const FText& message);
    virtual void NotifyOwner_Client_Implementation(const FText& message);
nova wasp
#

I'm not really sure

#

this would rely on perfect identical keys on both sides

fallen fossil
#

I am pretty sure translation keys are deterministic

nova wasp
#

if they are then this seems like it should be okay

fallen fossil
#

fine, ill code the rest and check it, no ui yet or anything ;d

nova wasp
#

I would say you could just make your own dumb mapping of gameplay tags to messages

#

or fnames

#

if this doesn't work out

exotic wasp
exotic wasp
#

it's just faster to pass by ref

#

and if you don't plan on changing the value, make it const so you don't do something weird

nova wasp
#

I can't find an iris serializer for text

#

it appears to use a "last resort" byte buffer serializer

exotic wasp
#

text over network sounds ripe for weird errors

#

like what do you do if the text isn't on the client

nova wasp
#

yeah I'm questioning doing this vs just gameplay tags

#

for me it's sending 700 bits for like "asdasd" lol

exotic wasp
#

I just question sending text at all

#

it should probably already be known by the client

#

or if it's a runtime thing it needs to be a string anyway

fossil spoke
#

Is there even a legit reason to send Text in an RPC, or even across the network to begin with. I cant really think of a reason?

nova wasp
#

I mean if they want to show X locallized message

#

I would say some kind of key the the text kinda makes sense

#

I just don't see how these work with exports internally

fossil spoke
exotic wasp
#

I can't think of a reason the server should tell the client specifically what text to see

fossil spoke
#

What dynamic element would require Text be sent across the network.

nova wasp
#

yeah, text internally is a pointer to the text

fossil spoke
#

I dont think there is one

nova wasp
#

yeah I can't find anything obvious that says this is exported as a key

#

across the network

#

it would be better to send some id/name/tag

nova wasp
#

doesn't seem that weird but of course it makes more sense as a mapped id

fossil spoke
nova wasp
#

yeah

fossil spoke
#

Or at least, via some more efficient context

#

The only thing that might come close is Chat Messages, but even then, they should just be strings.

fossil spoke
#

🤷

#

Never tried

thin stratus
#

I mean, you can construct texts on the fly and put them into widgets that are not set up for localization.

#

But then you can just use an FString.

nocturne quail
#

Why this Actor can't move smoothly? it does lots of corrections!

AArmaBoardingPlane::AArmaBoardingPlane()
{
    bReplicates = true;
    SetReplicatingMovement(true);
    AirplaneMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("AirplaneMesh"));
    SetRootComponent(AirplaneMesh);
    PlaneSpeed = 1500.0f;
    ProjectileMovement = CreateDefaultSubobject<UProjectileProjectileMovement>(TEXT("FlightMovementComp"));
    ProjectileMovement->ProjectileGravityScale = 0.0f;
    ProjectileMovement->bSweepCollision = false;
    ProjectileMovement->InitialSpeed = PlaneSpeed;
    ProjectileMovement->MaxSpeed = PlaneSpeed;
}

void AArmaBoardingPlane::BeginPlay()
{
    Super::BeginPlay();
    if (HasAuthority())
    {
        InitializeRoutes();
        SelectRandomRoute();
    }
}

void AArmaBoardingPlane::InitializeRoutes()
{
    Routes.Add({ FVector(-346832.280026f, -300673.276454f, 200000.0f), FVector(963401.868591f, 1004940.795252f, 200000.0f) });
    Routes.Add({ FVector(963401.868591f, 1004940.795252f, 200000.0f), FVector(-346832.280026f, -300673.276454f, 200000.0f) });
}

void AArmaBoardingPlane::SelectRandomRoute()
{
    if (Routes.Num() == 0) return;

    if (ProjectileMovement)
    {
        const uint8 RandomIndex = FMath::RandRange(0, Routes.Num() - 1);
        CurrentStartPoint = Routes[RandomIndex].StartPoint;
        CurrentEndPoint = Routes[RandomIndex].EndPoint;

        SetActorLocation(CurrentStartPoint);
        SetActorRotation(FindLookAtRotation(CurrentStartPoint, CurrentEndPoint));

        FVector Direction = (CurrentEndPoint - CurrentStartPoint).GetSafeNormal();
        ProjectileMovement->Velocity = Direction * PlaneSpeed;
    }
}

FRotator AArmaBoardingPlane::FindLookAtRotation(FVector Start, FVector Target)
{
    FVector Direction = (Target - Start).GetSafeNormal();
    return FRotationMatrix::MakeFromX(Direction).Rotator();
}
#

but on server it moves fine smoothly

pseudo wagon
nocturne quail
pseudo wagon
queen ermine
#

Has anybody had problems calling ServerTravel?

Doesnt seem to work. It works in editor, but on a shippiing Build no joy

nocturne quail
#

let me try again

nocturne quail
#

seems like i just have to use other approach maybe a timeline

pseudo wagon
nocturne quail
#

i commented the line to enable movement replication

#

when i play as server everything is smooth

#

I can dig into source of unreal to find what is making this issue

#

but not worth it, so writed here maybe someone know the quick fix

pseudo wagon
#

Yeah, It won't work.
From your code to make it work, you need to run this code on client also:

        SetActorLocation(CurrentStartPoint);
        SetActorRotation(FindLookAtRotation(CurrentStartPoint, CurrentEndPoint));

        FVector Direction = (CurrentEndPoint - CurrentStartPoint).GetSafeNormal();
        ProjectileMovement->Velocity = Direction * PlaneSpeed;

Just replicate RandomIndex and setup based on it.

nocturne quail
nocturne quail
# pseudo wagon Yeah, It won't work. From your code to make it work, you need to run this code o...
void AArmaBoardingPlane::MultiStartFlightSimulation_Implementation(const FVector NewStartPoint, const FVector NewEndPoint)
{
    SetActorLocation(NewStartPoint);

    /** Set rotation towards the x Vector of the plane mesh*/
    FVector Direction = (NewStartPoint - NewEndPoint).GetSafeNormal();
    SetActorRotation(FRotationMatrix::MakeFromX(Direction).Rotator());

    MovementComponent->Velocity = Direction * PlaneSpeed;
}

no luck

formal solar
#

What exactly is 'consider actors time' and how can I improve it? This is costing me almost 4ms

#

From its name I wouldn't think it had anything to do with the actors' individual complexity/number of replicated properties and more to do with how many actors you have and whether the engine needs to calculate things like relevancy based on cull distance

#

But the bulk of replicated actors in my game are 'always relevant'

#

And that overrides cull distance right?

#

also cull distance is very high anyway

thin stratus
#

@nocturne quail You need to set up a bunch of stuff to make that smooth. The PMC has an Interpolated Component pointer for example. You are supposed to have a collision root component and a second non collision visual component, like a mesh. You then set the interpolated component on the PMC in post init components to the mesh.

#

There are also things like setting velocity of the PMC (iirc) via the virtual velocity replication function of your actor.

#

You might want to read through the PMC header file to get an idea.

#

There might also be the need to call something interpolation related on the PMC on tick

thin stratus
#

Why is so much stuff always relevant?

formal solar
#

its my rts units

thin stratus
#

Consider Actor Time is the time spent on checking if an Actor needs to replicate.

formal solar
#

some are contained in hives and stored as data until hive is entered

thin stratus
#

Make sure you use push model whenever possible in c++.

thin stratus
#

If you need their data, store a simple version of it in a fast array on a single manager actor.

formal solar
#

I guess they all get simulated on server anyway

thin stratus
#

You can't just make everything always relevant and then be surprised the consider time is high

quasi tide
#

But what's to consider? It is always relevant 🙃

formal solar
#

Yeah thats what I thought

nocturne quail
queen ermine
#

So, everybody else can do a server transfer?

hollow swallow
#

somehow my lobby that spawns players broke and i havent changed anything 😢

thin stratus
thin stratus
#

The two concepts aren't really the same

hollow swallow
#

anyone have a spare second to help me try trouble shoot something? 3 players works fine, 4 players i get an error and it only spawns 3

hollow swallow
#

4 platforms are there and 4 player controllers are there, but im getting these errors

Blueprint Runtime Error: "Accessed None trying to read (real) property CallFunc_Array_Get_Item_1 in not an UClass". Node:  Branch Graph:  IsValid Function:  Update Players on Platforms Blueprint:  GM_Lobby```
thin stratus
#

Just throw your info here, maybe into a 🧵

hollow swallow
#

confirmed the 2 arrays have the correct amount in them at the time it runs