#multiplayer

1 messages · Page 274 of 1

shy gust
#

All 3 of you are kind of saying something different , which furthers my confusion on the topic.
But thats what I believe, they should be independent, but ive noticed in testing that if a game is running at 30 , less time passes compared to running at 60. unless im not understanding how timelines are meant to be used in this context. im using a very simple float timeline - time in seconds - print string.

halcyon ore
#

I just worded mine all goofy. 😛
but, same 1 second should pass, but of course at faster or smaller increments. (That’s why delta time exists)

You’ll need to provide code, or info, cuz your doing it wrong, or miss-understanding.

shy gust
#

understandable,this is the timer set up i use, and its just a time in seconds node to read in UI

magic helm
#

That's a timeline component, it is not framerate independent. It gets updated on the game thread

fossil spoke
#

@shy gust Just did a test for you

#
Cmd: t.maxfps 60
t.MaxFPS = "60"
Cmd: t.maxfps 0
t.MaxFPS = "0"
LogBlueprintUserMessages: [NewBlueprint_2] Server: Total Execution Time: 5.000018

Cmd: t.maxfps 30
t.MaxFPS = "30"
Cmd: t.maxfps 0
t.MaxFPS = "0"
LogBlueprintUserMessages: [NewBlueprint_2] Server: Total Execution Time: 5.00005
#

This is the difference

#

5 second timers

#

at 60 fps and 30 fps

#

Theres the BP for you as well

halcyon ore
shy gust
#

i guess i should be using set timer by event instead then

#

ive been told those timeline components were independent , so it makes me wonder what timelines people are actually referring too.

#

ive noticed that after a few minutes theyll be pretty inaccurate, not as noticeable in a few seconds. but there could be other issues in my implementation, but my timer logic really is just this

fossil spoke
#

Timelines are only good for doing weird interps. They shouldnt be used for complex things.

#

I certainly wouldnt use them for long periods

#

Running timelines for minutes just sounds like a bad idea.

quasi tide
shy gust
halcyon ore
#

Just use tick at that rate?

fossil spoke
shy gust
halcyon ore
#

?

quasi tide
#

Timers also tick on the game thread as an FYI

halcyon ore
#

Just add the delta time to your time value.

#

Or, use the base engine handled time, if you simply just need a second on some UI.
Unless it some clock.

shy gust
#

i see , I appreciate the insight, sorry I didnt mean to sideline the channel.

verbal ice
#

there's like, probably no scenario where you'd do IsValid(this)

#

since it doesn't protect against dangling pointers

#

should probably be

FCTween::Play(
    GetActorLocation(), GetActorLocation() + FVector(0, 0, 50),
    [WeakThis = MakeWeakPtr(this)](FVector t)
    {
        if (WeakThis.IsValid())
        {
            WeakThis->SetActorLocation(t);
        }
    },
    2.0f);
thin stratus
verbal ice
pseudo wagon
verbal ice
#

so it would defo crash

verbal ice
magic helm
# halcyon ore No joke. Timelines are dependent of FPS? I always thought they were super cursed...

Yes timelines are FPS dependent, they're just running tick internally the same as any actor component.
Timers also do this but the timer manager tries to account for the Fps as best as it can, but it's not true independence
Mover is currently trying to put in a solution for this by running on the game thread but ticking at a specific framerate causing it to be independent from regular game thread ticking

thin stratus
#

That's not Mover. That's NPP.

#

Mover is just using NPP.

#

And it's questionable how much effort Epic will put into supporting NPP.

mighty trout
#

i have a reload animation which is running on server and all clients but sometimes my server is not calling animnotifies for finished reloading during lag but my clients are calling it, is there anything i am missing overhere

nova wasp
nova wasp
#

what ticking option is set on the skeletal mesh components on the server?

mighty trout
#

i didn't get it

#

where should i check it

nova wasp
#

the skeletal mesh component of whatever plays the reload animation

mighty trout
#

always tick pose and refresh bones

nova wasp
#

one thing you have to be careful about is if it can be cancelled or change speed etc

#

the timer would need to have the same behaviour i guess but cancelling one is trivial

#

can try making it branching point too I guess but its still a ticking time bomb of issues

mighty trout
#

any better option as also my server calling animnotifes two times but my montage is playing one time

nova wasp
#

read the article

#

the answer is: don't rely on anim notifies and make some simple timer instead

void nest
#

Hello. Does anyone know why increasing the max player amount isn't working? I changed the max players from the default of 16 to 20 in the game engine's ini file but it doesn't work, the game still only allows up to 16 connections. What am I doing wrong?

mild prism
#

Hi everyone, I'm having trouble with the initial setup step to test my multiplayer game. I'm stuck in VS 2022. When I switch to the Development Server and then build, I see these messages in the Output Log. How can I fix this?

thin stratus
thin stratus
#

Also do you have a source engine build or did you download UE via the Launcher?

mild prism
# thin stratus You want to show the actual output log and not the error list.

This is what I see in VS 2022's Output Log.

Build started at 11:18...
1>------ Build started: Project: Sito_OASI, Configuration: Development_Server x64 ------
1>Using bundled DotNet SDK version: 6.0.302
1>Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" Sito_OASIServer Win64 Development -Project="C:\Users\Computer\Desktop\Sito_OASI\Sito_OASI.uproject" -WaitMutex -FromMsBuild -architecture=x64
1>Log file: C:\Users\Computer\AppData\Local\UnrealBuildTool\Log.txt
1>Creating makefile for Sito_OASIServer (no existing makefile)
1>Total execution time: 0.46 seconds
1>Server targets are not currently supported from this engine distribution.
1>C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.MakeFile.Targets(44,5): error MSB3073: The command ""C:\Program Files\Epic Games\UE_5.4\Engine\Build\BatchFiles\Build.bat" Sito_OASIServer Win64 Development -Project="C:\Users\Computer\Desktop\Sito_OASI\Sito_OASI.uproject" -WaitMutex -FromMsBuild -architecture=x64" exited with code 6.
1>Done building project "Sito_OASI.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 11 up-to-date, 0 skipped ==========
========== Build completed at 11:18 and took 01,157 seconds ==========
mild prism
lost inlet
#

see:

1>Server targets are not currently supported from this engine distribution.

mild prism
lost inlet
#

yes I know what goes into building a dedicated server. and again, you can't do this from the launcher engine

nova wasp
#

"I tried following a tutorial online" and a vague description of a c# file we can't see doesn't help us

lost inlet
#

I'm sure it'll mention a source build somewhere

nova wasp
#

its fair to look stuff up but in order to help we need to see what you did and not a description of why you did it I guess

mild prism
lost inlet
#

...

#

yeah, because you have to link your github account

#

this is source engine 101 stuff

#

and I'm really curious what tutorial you're following

mild prism
tardy fossil
#

did you accept the email invitation

mild prism
# lost inlet and I'm really curious what tutorial you're following
Epic Games Developer

Set up and run a dedicated server for your project.

Building Dedicated Servers with Unreal Engine 5

00:00 Intro
00:49 Create New Project
02:34 Create Main Menu
08:12 Level Blueprint
10:03 Project Settings
11:26 Server and Client Build Targets
14:37 Packaging builds
16:24 Launching and Connecting to Local Server

Links:
Setting Up Dedicated Servers
https://docs.unrealengine.com/5.2/en-US/setting-...

▶ Play video

In episode 17 of the UE5 game development series, we'll configure the project to build a dedicated server and standalone client. We'll show how to cook content for each of these configurations, as well as run them both in the debugger and from the command line. We'll then fix a bug that comes about when the client and server tick rates do not ma...

▶ Play video
lost inlet
#

so yeah it did say it

#

and you have to be also logged into the github account you linked

#

and it's been a while so I'm not sure if you have to accept an invite on the GH side

mild prism
#

Now I don't know why Gmail put it in Spam.... The mysteries of Gmail

#

Thanks anyway everyone for the help

marble arrow
#

Hi, i have a question; should I avoid using pointers in RPCs?

#

I’m still new to this, and it kind of scares me

lost inlet
#

why would it be scary?

#

it's not sent over the network as a memory address

#

you might want to show what you're doing/thinking

dark parcel
#

you really push through with incorrect method. Don't write code that don't work

lyric heart
#

works great

dark parcel
#

irrelevant

#

you don't want to multicast

lyric heart
#

well it works really well

#

exactly what i wanted, and there won't be alot of logon/offs

#

it's only meant for a group of people

dark parcel
#

Only use RPC for event based. I've said this dozens of times.
Many people new to networking use RPC for stateful things, ends with bugs on their end because RPC get dropped or players have yet join so obviously the RPC don't get run.

#

youtuber tend to do this and show that it "works"

#

until they don't

#

but I guess sometime, one has to actually experience the failure to accept that it's the wrong way to do it.

#

incrementing a replicated variable in a multicast don't make sense too.

lyric heart
#

what can fail with the rpc ?

dark parcel
#

RPC set Hp to 5 at the start of the game. Then player 2 join 2 minutes later. Obviously the RPC never run so the HP is not set to 5 for the late joiners.

#

well

lyric heart
dark parcel
#

I already paste a working example

lyric heart
#

i just need a event when they log off/on

#

nothing else, just log on/off

#

it's not really much of a state, because the cards are not premade

#

they are built each time

#

so i'm not toggling the state of a card

#

but rebuilding all the cards when someone logs on/off

dark parcel
#

Doesn't matters if they are pre-made or dynamically created

#

if the cards need to be retain the same values accross all machine

#

then that's a state.

#

Using Multicast = waiting for game to break.

#

and adding unncessary complication for something that surely just goonna fire back at you.

lyric heart
#

i don't see where it will break, but ig i'll find out lol

#

i'm used to finding out things like this, been programming since before the web was a real good informative source

#

but i understand your point

#

onrep > multicast

dark parcel
#

no, that's not my point

#

U use each of them where you need to use them.

#

One time event = RPC

#

stateful things = replicated variables

#

Broadcast hello world = RPC

#

ddealing cards = replicated variable

lyric heart
#

i mean it works so i'll use it untill it breaks

#

thanks for the information though

#

i'll keep this in mind

#

Honestly if it doesn't hurt performance i'm not concerned

#

unless it breaks, in which case i'll have to fix it lol

marble arrow
# lost inlet why would it be scary?

I was actually thinking the opposite of “it’s not sent over the network as a memory address,” which is why it sounded scary. If that’s not the case, that’s really good to know. But still, if this pointer points to an actor, wouldn’t that take up a lot of bandwidth?

lost inlet
marble arrow
lyric heart
#

i'm just used to trial and error

marble arrow
# lost inlet what do you think it would contain? UObject references are typically networked a...

Do you pass actors/pawns in RPCs?
I keep thinking in a dedicated server mindset :/
So I feel like I should only send primitive types.
I imagine the server just doing calculations for other players.
That’s why I don’t want to put something like a skeletal mesh pointer in an RPC.
Plus, that stuff would take a lot of bandwidth.
Honestly, I don’t even know how I should be thinking about this 😕

lost inlet
#

?

marble arrow
#

sorry for bad english :((

lost inlet
#

a USkeletalMesh reference will be sent down as a path to the asset

#

by default, it'll do a sync load if not already loaded by the client

#

there's a cvar to make it async

marble arrow
lyric heart
#

i use multicast

silent valley
#

If you don't care about history, RPC is good for chat

lyric heart
#

right because the onrep fires when then the player joins

#

i'm not concerned about history at all

#

but i see if i wanted it to load when the player loads into level then onrep

dark parcel
#

also what about the chat box specifically?

lyric heart
dark parcel
#

this is broad, what part of the chat box specifically.

#

if you don't need to store chat history, then you can just RPC the msg.

lyric heart
#

ya thats what was mentioned

dark parcel
#

to create the widget, just create them locally at begin play.

lyric heart
#

ya thats what i did, it works fine

torn hull
#

Hey, do you think this approach is “scalable enough for a prototype”? I’m going to dive deep into C++, but for now I just want to make a prototype that’ll let me test different variations/mechanics with my friends while doing the C++ course, I want to do it as painless as possible.
I’m using GameMode to track all the important variables/logic and handle match phase changes. Then I’m using blueprints with inputs that are sending these variables to GameState, and with a switch on an enum that afires multicast, or rep notifies, to call event dispatchers (like in the first screenshot, inside those rep notifies, there’s just a dispatcher call).
On my playercontroller or in widgets, I’m binding custom events to those dispatchers like in the second screen.

silent valley
#

Just be sure to read up a bit, what ColdSummer was talking about re: RPC vs onrep.
For any persistent state (i.e. most gamestate) you should usually use a replicated var and onrep.
For one shot events, RPC is usually best.

errant charm
#

im not following, how will the elapsed time be known to late joiners?

silent valley
#

ElapsedTime = GetServerWorldTimeSeconds() - GameStartTime

thin stratus
torn hull
dark edge
#

almost anything you'd want to know on a client is state or can be derived from state

mystic estuary
#

Hello, I have a character component which has an OnRep which accesses the player state of the said character to do stuff. It works fine, but if there's a hot joiner, the character with the component might get replicated before PS which makes it access none inside the OnRep. I thought about listening for PS replication from that component to do what I wanted to do inside the OnRep, but it's annoying. How do you guys usually go about this?

lyric heart
#

if it's a guaranteed to be valid thing it works

#

i just usually put a print string in there so i can see if it's infinite

torn hull
lyric heart
mystic estuary
#

The only issue is that there might be multiple OnReps in the same component that want to do something that toggles it back and forth. It might happen that it wants to toggle, let's say, a bool to true, but PS is invalid, so it would set up a delay, but while the delay is ticking, it would receive an OnRep which wants to set it to false, and PS might be already replicated, so it'll set the bool to false, and then the delay would be over, and it would set it to true, effectively ruining the state.

One can obviously replicate the variable altogether, but some times there might be things that are more than just a variable

quasi tide
lyric heart
mystic estuary
sage lance
#

recursive reference resolver

#

rrr

lyric heart
#

its how i got everything to sync while testing

#

so when all four windows pop up

#

i synced everything so the order doesn't matter

#

lots of try

#

but i do that on what i believe is "guaranteed"

thin stratus
#

Imagine you have states like this:

0: StartCountdown -> Shows UI
1: EndCountdown -> Hides UI
2: StartMatch

And the client now gets stats 0, and the next one it gets due to network conditions is state 2.

At that point state 1 would be skipped, and the UI would remain visible.

#

If you have "PreviousState", you can detect the gap and go from 0 to 1 to 2 instead of from 0 directly to 2.

#

That is if you use an OnRep for this. An RPC isn't a good idea as the GamePhase property is the very definition of a "state" and should use a replicated variable + OnRep if you need a callback for the property having changed.

#

Imagine you are already at state 2 and someone gets a disconnect and reconnects. Or connects late. They will never get the StartMatch event again.

coarse cave
#

I typically do something like "UpdateCountdownDisplay()" and inside you just switch the current state and do what needs doing... if the state is 1 or 2 (in the example above) you hide the UI.

thin stratus
#

But with the OnRep, the client will call the OnRep_State with state 2 again, where previous state is probably an invalid one (might want to use enum value 0 for "invalid").

thin stratus
coarse cave
#

It doesn't break when you write it in a way that makes no assumptions about prior data or passing through previous states

#

(it's a pattern I've used on multiple shipped titles, in multiple engines)

#

The only requirement is that the Update function is run whenever a dependency is changed... e.g. player state is replicated, CountdownEndTime changes, etc... which is generally pretty simple to do via delegates when necessary. If you're doing long running things like animated transitions it's a bit trickier.

halcyon ore
torn hull
coarse cave
#

That's roughly the idea. It might not be applicable in this case, but I'm not sure what the BP starts to look like if you add more dependencies though; for each one you'd need to trigger the same dispatcher.

#

Imagine you have another GameState or PlayerState variable "FooBar" that you need to reference when deciding to update visibility; ask yourself what it looks like to implement that into your BP, how easy is it to maintain, how easy is it to add more dependencies, etc...

#

In the case of a PlayerState dependency, you need to call your update function both when the existence of PlayerState changes and when the value being accessed on PlayerState changes.

#

In the case above, you've called the event "ChangePhase..."; you might be better off thinking of the event as "what does this event do" rather than "how was this event triggered". That way multiple places can trigger the same event without it feeling strange

#

So you might call your event "UpdateTimerVisibility()" instead, which currently only triggers when the Phase changes, but may also need to trigger in the future when something else changes

pliant cypress
#

How would the quest/mission system work?

Like I've a level, linear mission but level is open to explore such as military base.
Currently, all player has an object/mission to fix generator and generator shows that there's a part missing to start/run it. To find it, players will search around the base.

Now the thing is, when player goes to evacuate at last. A player out of other will have to stay or etc based on mission and that objective will be shown to that player or like that and once he stayed, other escaped. A Cutscene trigger/objective updates and mission end.

#

IMO/POV, I'll make

MissionDataAsset which will have array objectives (ObjectiveClass containing logic for each objective such as fix generator, gather the intel etc).

Each MissionDataAsset is associated with gamemode (per level) and Mission Manager will be inside GameState that'll handle the mission progression and mission related stuff

marble arrow
#

Hi, I have replication functions that trigger on outfit change. Since I’m using GetPawn there, everyone only sees the change on their own character. I’m confused - how could I make this more flexible?

void ACoopPlayerState::OnRep_HeadOutfitId()
{
    ChangeOutfitPart(EOutfitType::HEAD, HeadOutfitId);
}

void ACoopPlayerState::OnRep_BodyOutfitId()
{
    ChangeOutfitPart(EOutfitType::BODY, BodyOutfitId);
}

void ACoopPlayerState::ChangeOutfitPart(EOutfitType Type, int32 Id)
{
    ACoopCharacter* CoopCharacter = Cast<ACoopCharacter>(GetPawn());
    if (IsValid(CoopCharacter))
    {
        CoopCharacter->OnChangedOutfitPart(Type, Id);
    }
}
nova wasp
marble arrow
nova wasp
#

the question is if ChangeOutfitPart is called all on different objects or not

#

not sure how else to describe this

#

need to see who calls SetOutfitPart

marble arrow
nova wasp
#

I cannot tell what "Owner Character" actually is from a screenshot

#

you need to prove this is being called on distinct characters with logging or a debug watch window

marble arrow
nova wasp
#

there is only 1 owning player

marble arrow
nova wasp
#

a widget ONLY exists on the local player

#

the owning player is the LOCAL player

#

can you try just logging what calls Set Outfit Part with a simple print string and showing which sides log which objects?

nova wasp
#

I think I wanted to see the log of playing, not 200kb of the entire log

marble arrow
#

I only marked [CLIENT] and [SERVER], the relevant ones

nova wasp
#

that is a 205kb text file, I don't know what you "marked"

#

I can see them though

#

looks like it's being called twice for each player

#

but that seems intentional

#

you did not specify how many players there are either, I have to figure this out without much context

#

it looks like OnRep_BodyOutfitId is being called on 2 different playerstates, which seems like what you would want?

marble arrow
#

with 1 listener player and 1 client player tested

nova wasp
#

also notice the
GetOutfitData - NOT found for Type: 1, Id: 2 (Cache has 0 items)

marble arrow
#

I just said I guessed the issue might be because of using GetPawn

nova wasp
#

and you don't ensure or log if GetPawn is invalid

#

which could be another issue

#

my advice would be to use the callbacks for when the playerstate sets the pawn or add some if you don't have any

#

so you can listen for when the pawn is set

marble arrow
nova wasp
#

is CacheOutfitDataTable called on all clients? do you log if it isn't cached? why isn't it called? what should call it?

#

for starters do not silently early out in functions like this. these failing should at least log an error

#

or cause an ensure

#

if they are supposed to work

#

if you have logs, you can see for yourself what failed

#

which is helpful in situations like this

marble arrow
nova wasp
#

Only the local player has a controller for themselves (on a client)

#

the server has all of the controllers

#

make sure you check out the resources in the pins, they help with learning about this stuff

marble arrow
#

Alright, I’ll try to find the issue using these logs. Thanks for taking the time 🙏

nova wasp
#

you should probably just move CacheOutfitDataTable(); to outside of that if statement

#

why does it care about the player controller?

#

hopefully that helps

marble arrow
#

thank you :))

marble arrow
sage lance
#

getOwner->getController is better for pawns

lost inlet
#

the owner is the controller?

#

so not sure how it would be

sage lance
#

for like an actor component

#

or for ui like this

lost inlet
#

I must've missed the context

#

since I thought it was the conversation immediately above, which was on a character

sage lance
#

im using this for my character

#

but its lyra specific

mystic estuary
#

Hello, is it possible to have multiple relevancy origins for a player? I need to make a CCTV that translates what it sees to other part of the map where the player is, but things around the CCTV which is pretty far away will be irrelevant to the player looking at the monitor

sage lance
#

tony i would increase this value by alot

#

i think the default is 15000cm

#

(15000^2)

#

if you are replicating stuff and its not appearing on the client unless you get close this helps

mystic estuary
#

I don't want to replicate everything else on the map though, only what's around the cctv and the player

sage lance
#

is the map dynamic or fixed?

mystic estuary
#

It's fixed

#

Looking at the IsNetRelevantFor callstack, it looks like I could make use of this

    /** valid only during replication - information about the player(s) being replicated to
     * (there could be more than one in the case of a splitscreen client)
     */
    UPROPERTY()
    TArray<struct FNetViewer> ReplicationViewers;

the NetDriver uses to call IsNetRelevantFor

sage lance
#

if its fixed you shouldnt need to replicate anything should just be able to load it on the client and everything should be there

mystic estuary
#

When player is far away from, let's say, a door, they won't see the door replicating anything, e.g. it opening or closing, as it's irrelevant. The door will be there, yes, but the player won't see it opening/closing

sage lance
#

you might need to replicate your doors then

mystic estuary
#

They are replicated, they aren't relevant to players that are far away

sage lance
#

so make the doors always relevant with the increased distance

mystic estuary
#

What's the purpose of relevancy then...?

sage lance
#

to be able to adjust the network communication. you could use it to determine what is more important or how to efficiently communicate about networked game objects. really you need to adjust it so that your game works with the least bandwidth.

#

In the case of replicating all your doors its definitely okay

mystic estuary
#

It's more than just doors. It was just an example. It might be other players, players dropping things on the floor, players interacting with other objects like doors. It would mean replicating the entire map to the player watching one single area through the CCTV

sage lance
#

replicating everything dynamic

#

anything interactable

#

heres the thing if its out of range, and say you add a new player as your cctv that can be possessed, when you possess a new camera the objects will all take a second to load, which might kill immersion.

#

rather if you ensure everything is loaded (from the start) then theres a more seamless experience

mystic estuary
# mystic estuary Hello, is it possible to have multiple relevancy origins for a player? I need to...

I couldn't find any proper entry point for non-local players viewers, so had to hack it a little bit. Since it clears AWorldSettings::ReplicationViewers every frame before checking the IsNetRelevantFor, I had to take any virtual function which is called in-between the clear and checks. I went with APlayerController::SendClientAdjustment. This works, at least in the editor

void AMESS_PlayerController::SendClientAdjustment()
{
    Super::SendClientAdjustment();

    AWorldSettings* WorldSettings = GetWorldSettings();
    for (TObjectPtr<AActor> AdditionalNetViewer : AdditionalNetViewers)
    {
        if (IsValid(AdditionalNetViewer))
        {
            FNetViewer NetViewer;
            NetViewer.InViewer = AdditionalNetViewer;
            WorldSettings->ReplicationViewers.Add(NetViewer);
        }
    }
}
coarse cave
#

Or set force net relevant for objects near/in view of your CCTVs via overlap, etc...

mystic estuary
coarse cave
#

True, but that seems worth it to me. I generally have a custom base actor for everything anyway

mystic estuary
coarse cave
meager spade
#

wouldnt you just se the viewtarget

#

to the camera your looking through

coarse cave
#

The CCTVs are monitors in the world based on the original description

mystic estuary
#

Yes, they're a monitor. Originally I was changing the entire view, but now I want it to be on a monitor

formal turtle
#

I've a question, why if it's Client1 instance, then it is considered also server aka standalone? even when there is client1 and client2?

#

like if I run this node then it tells me Server: client1
Client: client1 (or whatever I have connected to standalone & client exec pins

halcyon ore
#

Not sure I understand your miss-understanding?
Your saying playing in a server is also triggering standalone, or that your confused why standalone says server?

formal turtle
#

like, if i am running client1 in pie editor then client pin will never run at all

coarse cave
#

What mode are you running PIE in?

halcyon ore
formal turtle
#

i thought this would be client only and server would be in the bg

halcyon ore
#

Hmm, ok.
What about where is that graph at?
Does it even get ran at all?
(aka, put a print before that switch, does it even get ran?)

formal turtle
#

yea it does, its from lyra blueprint utilities or smth like that

#

but its inside GameplayAbility

#

if i connect standalone then it works in client but idk why its like that

#

shouldnt it be client only

halcyon ore
#

I'm not too aware of how gameplay ability stuff is setup.
It may not have valid world context, so it can't correctly check network mode?

(thats just a guess, someone more aware of gameplay abilities would know)

#

I would say double check on some basic begin play on a spawned actor.

#

Like the player pawn

#

If that has the issue, then something else is weird

formal turtle
#

tested on a character rn, beginplay executes the client pin twice and says Client 1: Hello
standalone doesnt get triggered at all

#

thats really weird

#

that x2 might be bc of the way pawn is setup to call beginplay but it works just fine in the pawn

halcyon ore
#

Why would standalone get triggered in client mode?

formal turtle
#

so idk why it does this in the ga

formal turtle
halcyon ore
#

Yeah, GA may lack world context, thus can't correctly get network stuff.
Given the difference of behavior.

#

Or, perhaps how that specific one is used, lacks world context.
Since, can't GA's spawn actors, so they need world context sometimes

lusty timber
#

Anybody have tutorial on how to make multiplayer match timer in blueprint ~~ not match countdown~~

exotic wasp
#

clients can calculate the time since start themselves as long as they know when it began

olive orchid
#

I've been banging my head on my desk for an hour now...

What determines whether a variable will be replicated JIP?

I have 2 Actors:

ADoor and ALightSwitch

Both have a boolean, which uses push model to replicate. They're completely identical in code.

Changing the boolean on door will be reflected instantly on clients joining late, however doing the same on the light switch does not.

Any idea why?

UFUNCTION(BlueprintSetter, Category = "Light Switch")
    void SetLightsOn(const bool LightsOn)
    {
        bLightsOn = LightsOn;
        MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, bLightsOn, this);
    }
exotic wasp
olive orchid
#

Changing it after the client has joined works, it's just JIP not replicating properly.

#

Adding a log to the OnRep_XXX() will:

  • Print on the door if you open it before someone joins
  • Not print on the light switch if you toggle it before someone joins

I've taken screenshots of the replication properties on each BP just to make sure and everything matches.

exotic wasp
#

it could be dormant for some reason

olive orchid
#

Is that the bAlwaysRelevant?

exotic wasp
#

no, relevancy controls whether or not an actor replicates at all to a client

#

dormancy controls whether or not property updates are sent to clients

olive orchid
#

Tried changing it but no matter what I set it to, the issue persists.

#

It seems to be due to the instance being set to true, and it being false by default in the class.

Is there a recommended approach to remedy this? I tried marking it as dirty in the BeginPlay but that didn't seem to do much.

exotic wasp
#

so, the class default is false, and in the instance placed in your level its marked as true?

#

is it placed in your level in the editor or spawned at runtime?

#

if its already in the level i dont believe theres any replication occuring

olive orchid
#

Admittedly my brain is exhausted 😅

exotic wasp
#

with it already being true in the level, are you trying to replicate a false state? or that initial true?

olive orchid
exotic wasp
#

next to no info on this online lol

#

im wondering if push model disables replicating the state of that property to clients during the initial bunch? that would be incredibly dumb if true

coarse cave
#

You said the class default is false, but the instance is true? I wonder if it's just that when a client connects networking is seeing "bLightsOn == false == default, so don't send over network"

olive orchid
coarse cave
#

The door instance is also different from the default state?

olive orchid
#

Hmm, I need to double-check tomorrow actually. You could be right.

My brain is fried right now after staring at this for so long.

#

Thank you!

exotic wasp
#

that would be such a silly bug if true

olive orchid
#

I'll give it a go in a few minutes actually, I know I can't sleep without trying.

coarse cave
#

All PushModel really does is say “don’t compare this property until I say so”. It’s really more of a server-side optimisations to avoid expensive property comparisons - the savings are minimal at best.

Worth noting though that all parameters are initially considered “dirty”, so it will send at least once (if it differs from the CDO’s default value)
If that's correct, that would mean since your instance value differs from the CDO by default, turning it "off" makes it match the default when the player connects, meaning it won't replicate I guess

olive orchid
#

CDO?

exotic wasp
#

class default object

olive orchid
#

Cheers.

#

Yeah, then it does sound logical. I'll have to figure out a way around it at a later stage, I guess.

exotic wasp
#

every time you make a c++ or bp class in unreal engine theres a constant version of it that acts as a template for instances to copy from

olive orchid
#

the savings are minimal at best.
Is that really true?

exotic wasp
#

depends on use case

coarse cave
#

Objectively, no, since what plinyvic said applies

exotic wasp
#

but no, every benchmark i've seen shows pretty decent performance improvements

coarse cave
#

If you have 10k replicated actors it's probably pretty good savings... if you have 10 replicated actors, less so

exotic wasp
#

not as significant as some other networking optimization techniques, but push model basically requires 0 change to how you normally design classes

olive orchid
#

Programmatically it makes more sense to me to force values to update rather than letting the engine check so often.

However, I've apparently hit one of the limitations with it as well. I assume this is not an issue without PushModel.

exotic wasp
#

well, you could always disable it and see if it still occurs

#

would help narrow down the issue

olive orchid
#

I'll give it a try, I guess. Gimme 2

olive orchid
#

I wonder how I'll work my way around this 😅

halcyon ore
#

Just call on rep on begin play.
Its what I do.

olive orchid
exotic wasp
#

on rep wont change the fact the client has the wrong value

halcyon ore
#

Did I miss-understand the issue?
I thought it was that default is false.
Current is false
On rep doesn't occur, so false isn't applied

olive orchid
#

Default is false

Set to true on instance

Disable it while running
Player joins late with JIP, doesn't see the new value

exotic wasp
#

OnRep is just a callback when the new value replicates down

olive orchid
#

Spaghetti

halcyon ore
#

Yeah, disable.
Which means false.
Which matches the default.
So, justy call on rep, to apply the false?

#

Or, do I just whole miss-understand?

olive orchid
#

Because it assumes it's now the CDO of false, so shouldn't rep I guess?

halcyon ore
#

I'm not sure if I'm lost, or who.

So, default is false
Its set to true.
Then, what is "disable it while running"
Does that mean setting it to false?

halcyon ore
#

So, how is that a value issue?

Default is false, and current is false

#

Done

olive orchid
#

Imagine this:

CDO = false
BeginPlay: Set to true on server
While running: Disable it (set to false)

Client 2 joins: It is still on

#

Should it not be false for the joining client?

halcyon ore
#

Did you turn off that client loads or whatever bool, so the clients version is 100% replication.
Rather then half replication, half map actor?

olive orchid
halcyon ore
#

Yeah

olive orchid
#

Changing it had no affect, tried on and off

#

My assumption was that regardless of default or not, the client would always receive the latest replicated state on JIP

halcyon ore
#

Weird.
I had expected that would fix it. 😛
Did you change that bool in the defaults, or the instance?
I'm not sure which "works", or if both work.
I always just edit the defaults

exotic wasp
coarse cave
#

Are you setting it to true in BeginPlay? That's not quite the same as setting the instance value

coarse cave
#

Gotcha

olive orchid
#

Originally it was on the instance, when I posted.

#

For clarity.

olive orchid
coarse cave
#

I mean, what you're dealing with is pretty indicitive of my UE experience over the last 5 years... /sigh

olive orchid
#

Sorry, long day and it's almost midnight so it's getting harder to express myself.

halcyon ore
#

Sounds like the cursed fix should be.
Have a special bool for per instance
And, it just sets the actual bool on begin play.

#

No weird replication on the actual bool, and still an instance value

olive orchid
exotic wasp
#

sorry, are you positive the value isnt changing to whats intended and its not just the OnRep not getting called?

halcyon ore
#

Yeah.
Its only used on begin play server side, so normal bool works like normal

olive orchid
exotic wasp
#

ok im fairly sure now that setting NetLoadOnClient to false should fix this

halcyon ore
#

Yeah, I'm pretty sure of that to.
But, they said they tried that, so. 😛

#

I guess we'll see what cursed 2nd bool does.
If still has issues, then that narrows it downm

olive orchid
halcyon ore
#

Yeah.

olive orchid
#

Because that did not work... :(

#

Nor did unticking this

halcyon ore
#

That suggests its something unrelated to replication then.

#

Put a log on every set of that lights var.
Cuz, I do something similar to what you just tried, and never had issues.
(I rarely ever use instance defaults)

olive orchid
#

And that's from BeginPlay()

halcyon ore
#

Just to see.
Flip it.
Default true
Instance false

Issue flipped, or?

#

Cuz, yeah.
This ain't making any sense even more.

olive orchid
#

Flipping them works diosmios

exotic wasp
#

a this point just send code

olive orchid
#

I don't even

olive orchid
exotic wasp
#

constructor?

olive orchid
#
void ALightSwitch::BeginPlay()
{
    Super::BeginPlay();
    if (Lights.IsEmpty())
    {
        UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
    }

    if (HasAuthority())
    {
        SetLightsOn(bDefaultLightsOn);
    }
}
UFUNCTION()
    void SetLightsOn(const bool LightsOn)
    {
        LOG_NETROLE(__FUNCTION__, this)
        bLightsOn = LightsOn;
        MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, bLightsOn, this);

        // run on server as well
        OnRep_LightsOn();
    }
ALightSwitch::ALightSwitch()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = false;
    bReplicates = true;
}
UPROPERTY(ReplicatedUsing = OnRep_LightsOn, VisibleInstanceOnly, Category = "Light Switch")
    bool bLightsOn = true;

    UPROPERTY(EditInstanceOnly, Category = "Light Switch")
    bool bDefaultLightsOn;
#

So... I can't reproduce the problem if I flip the booleans.

#

I guess I'll keep it like this for now, with the dirty fix. Thank you 😄

tardy fossil
#

maybe Params.RepNotifyCondition = ELifetimeRepNotifyCondition::REPNOTIFY_Always; might help

olive orchid
thin stratus
#

@olive orchid Default value of the boolean is true. You are setting it to true. That won't trigger the OnRep. Change the RepNotifyCondition to "always" like Omnicide suggested and it will work. Or change the default value of bLightsOn to false.

olive orchid
#

I will try the Always route, thank you.

thin stratus
#

You basically have a variable bLightsOn, which can have a default value set already. The existence of bDefaultLightsOn is redundant.

olive orchid
thin stratus
#

RIght okay.

#

I would suggest you simply remove bDefaultLightsOn and you replace this:

void ALightSwitch::BeginPlay()
{
    Super::BeginPlay();
    if (Lights.IsEmpty())
    {
        UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
    }

    if (HasAuthority())
    {
        SetLightsOn(bDefaultLightsOn);
    }
}

with this:

void ALightSwitch::BeginPlay()
{
    Super::BeginPlay();
    if (Lights.IsEmpty())
    {
        UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
    }

    // Handles initial bLightsOn value to be applied.
    OnRep_LightsOn();
}
olive orchid
thin stratus
#

It does Rep

olive orchid
thin stratus
#

But the Client doesn't call the Notify if the value is the same already.

#

There is a path for prediction in multiplayer after all

#

And if the client predict the value, there is no need to call the OnRep again.

thin stratus
olive orchid
#

I thought so too.

thin stratus
#

You#d need to change bLightsOn to be editable in Blueprints of course.

olive orchid
#

I think the simplest would be the Always for me in this scenario. I am going to give it a try in a bit.

thin stratus
#

And you might want to put a HasBegunPlay() check into its OnRep.

thin stratus
#

I usually have a setup like this:

// Header
UFUNCTION()
void OnRep_SomeVariable(const int32 PrevValue);

UPROPERTY(ReplicatedUsing = OnRep_SomeVariable, EditDefaultsOnly, Category = "Settings")
int32 SomeVariable = INDEX_NONE;
// Cpp
void ASomeClass::BeginPlay()
{
  Super::BeginPlay();

  // Initial setup on BeginPlay. Also covers default value.
  OnRep_SomeVariable(INDEX_NONE);
}

void ASomeClass::OnRep_SomeVariable(const int32 PrevValue)
{
  // Called too early by replication.
  if (!HasActorBegunPlay())
  {
    return;
  }

  // Handle new SomeVariable value.
}
#

At least when I actively need this kind of setup.

#

There is an actual bug in the Engine if you have a scenario like this:

// Header
UPROPERTY(..., EditAnywhere, ...)
bool bSomeVariable = true;
// Cpp
void ASomeClass::BeginPlay()
{
  Super::BeginPlay();

  if (HasAuthority())
  {
    bSomeVariable = true;
  }
}
  1. Place an instance of ASomeClass into your level. (It might be that this needs a Blueprint child class of ASomeClass to be created and placed into the level.)
  2. Set bSomeVariable to false on the instance.
  3. Press play.

Expected Result: OnRep_SomeVariable calls, because the Server sets the value to 'true' while the default value on the instance is 'false'.

Actual Result: OnRep_SomeVariable won't call, even though the default value on the instance is 'false' and BeginPlay sets it to 'true'. For whatever reason, UE compares the value initially against the "archetype" of the instance, where the value is 'true' by definition.

olive orchid
thin stratus
#

Yeah I saw that years ago here on the server where someone had the issue with a BP for one of those car blocking poles that come out of the floor.

olive orchid
thin stratus
#

The boolean controlled if the pole was up or not and when they set the default to false but the class had it true, only to then set it back to true on BeginPlay, it wasn't going up for the Client.

thin stratus
#

E.g. void OnRep_CurrentState(const ESomeState OldState);

olive orchid
#

5 tutorials and no one mentioned this peepoGawd

thin stratus
#

I might actually be guilty here too. Lemme check.

#

Did I have to spot a typo in my compendium.......

#

Yeah I'm also not mentioning it. I should add that.

#

Man I really need to set up the automatic publish sh*t for this page. Docusaurus is great but not being able to edit it live on the spot is sh*te.

olive orchid
#

So... is this the correct approach?

void ALightSwitch::BeginPlay()
{
    Super::BeginPlay();
    if (Lights.IsEmpty())
    {
        UE_LOG(LogTemp, Warning, TEXT("%s does not have any lights assigned!"), *GetName());
    }

    OnRep_LightsOn(bLightsOn);
}
void ALightSwitch::OnRep_LightsOn(bool OldValue)
{
    if (!HasActorBegunPlay())
    {
        return;
    }

    // logic...
}
UPROPERTY(ReplicatedUsing = OnRep_LightsOn, VisibleInstanceOnly, Category = "Light Switch")
    bool bLightsOn;

UFUNCTION()
    void OnRep_LightsOn(bool OldValue);
#

Yeah I butchered that somehow

#

Gotta change the VisibleInstanceOnly around

thin stratus
#

Yeah, was just gonna say that. Not specifying the default of bLightsOn doesn't actually make it "nothing", so you can just set it to false at that point in C++.

#

But yeah, that should be fine.

olive orchid
#

So, if I wanted to change this to true on an instance in the editor, would I not need EditInstance?

thin stratus
#

Yes you do.

#

The idea behind the HasBegunPlay part is that BeginPlay isn't really a fixed point in an Actors lifecycle, yet some things rely on the Actor having begun play. The initial "bunch" that replicates with the Actor can, however, trigger OnReps before BeginPlay calls. By calling it by hand on BeginPlay and by early returning if the Actor hasn't begun play yet, you also capture that problem as an added bonus.

#

I wouldn't be able to list you what stuff fails if you are trying it before BeginPlay, however, as Epic made sure this just silently fails and f*cks up your day.

olive orchid
#

Maybe I'm being obtuse but this doesn't resolve the problem.

I set it to true in the editor now, join as host. Turn off the lights (it's now false)

Join as client, lights are still on BUT the OnRep ran and logged:

ALightSwitch::OnRep_LightsOn called on Client

thin stratus
#

Can you print the value inside the OnRep?

olive orchid
#

Sure

thin stratus
#

In theory, if the Client joined after bLightsOn got set to false, that value should be part of the initial data that is replicated. The only thing I can imagine is that having NetLoadOnClient active on the LightSwitch causes the Client to load it in with the wrong value.

olive orchid
#

3rd arrow is client joining

thin stratus
#

Yeah, can you disable NetLoadOnClient for that LightSwitch please.

olive orchid
#

Wizard pepe_content

thin stratus
#

NetLoadOnClient means the Client loads the Actor from Disc when the map is loaded. That will load true initially. Beats me why the false never makes it to the Client.

nova wasp
#

GetDebugStringForWorld is useful for stuff like this

thin stratus
#

Disabling it will treat the LightSwitch as a runtime spawned Actor that replicates down to the Client and spawns then.

#

I had that issue with looted chests in The Ascent.

nova wasp
#

I mean it being loaded from disk is fine, it's still stably named and can replicate things
they would just need to call the onrep manually, right?

thin stratus
#

They are.

olive orchid
#

Yeah, I am.

#

Not loading it on the client seems to have done it.

nova wasp
#

ah, that is in the beginplay

#

I am showing up in the middle here, my bad

olive orchid
#

Should I've tried the override for the "NetReady" or whatever it is

thin stratus
#

Yeah, not sure if this is maybe just a PIE thing, cause it joins in the middle of everything.

olive orchid
#

PIE?

nova wasp
#

play in editor

thin stratus
#

Play in Editor

olive orchid
#

Ah

thin stratus
#

You could try the late join feature to see if that also happens in a more natural flow.

olive orchid
#

I am doing JIP right now, if that's what you mean?

I add the client later, manually with this. Is that not the same?

thin stratus
#

Yeah it is, then nevermind.

#

I thought you start with 2 players already set.

nova wasp
#

this is referred to as "join in progress" in some circles edit: time for bed, they literally said JIP in the message lol

olive orchid
#

Ok, good. Sorry, trying to learn and it's a lot to take in pepe_fall

thin stratus
olive orchid
#

Yeah, I am used to the old ARMA term "JIP"

thin stratus
#

HOT JOIN

nova wasp
#

we call it JIP, RIP and DIP

#

r being rejoining if you support a persistent state from the first join

olive orchid
#

Well, I've gotten some insight in the problem now. Fortunately not a lot of the actors are static on the map... I've just got to figure out how I want to deal with this architecturally.

#

I appreciate your time and effort, a lot.

thin stratus
#

I would probably be able to figure out why it doesn't just work with net loaded actors, but I don't really have the time atm.

olive orchid
#

I need a break for a day or two pepe_smh

thin stratus
#

And I wouldn't be able to fix it either, so yeah.

nova wasp
#

yeah I admit 99% of the time I deal with runtime created actors

#

I cannot recall the last time I have dealt with replicated data in a stable named level actor

#

besides just like, pointing to it

#

it makes sense to have stuff like a button you can push or that light just kinda there... I'm susprised this is so wacky to do out of the box

nova wasp
#

probably my longest-standing issue with unreal netcode: how can we tell when objects were omitted from a broadcast due to bandwidth reasons?

#

I'm getting close to the point where I might start adding events to the engine network tracing or something because it's insane to me how you have no way of telling wtf is going on

#

Basically you just kind of... visually look to see if things are moving oddly

#

there isn't really like a strong indicator of "we are capping on bandwidth!! omg!!" I am aware of

#

of course capping on bandwidth is not an ERROR per se, the idea is you have a rate and you hit it

#

but to me if an object starts to get skipped from a send in a way that goes to like sub 50% of their net update rate it seems like I would want to see when that occurs

#

you can measure each packet in extreme detail, but you can't really see WHY a packet was the last one or what was skipped!

olive orchid
#

Well, that's a lot of good info. Thank you!

pseudo wagon
#

Apply root motion source from GAS sometime cause net correction. Any idea to solve it. crying

thin stratus
# pseudo wagon Apply root motion source from GAS sometime cause net correction. Any idea to sol...
  • Ensure Client has a valid Prediction Window.
    • Any Latent Node breaks the Prediction Window and needs a new NetWaitSync call.
    • This also needs Server Moves to be flushed once more, which GAS does by itself for the initial Activate Ability call, but needs to be re-done if you delay the RMS by some latent node.
  • Ensure Client and Server 100% agree on the same values that are passed into the RMS. Differences in starting location etc. can cause differences in end location.
exotic wasp
#

there should at least be a toggle to make the actor server only

#

I thought that's what NetLoadOnClient does but I legitimately couldn't tell you what that does now

chrome bay
#

IIRC, if you set bNetLoadOnClient = false on an actor in the map, and it's replicated, the client will "spawn" it from replication as if you'd spawned it manually.

exotic wasp
#

fuck

#

sorry

olive orchid
#

Lol no worries. It's good info noted

quasi tide
#

I use bNetLoadOnClient all the time for server-only actors

#

Mainly trigger boxes.

exotic wasp
#

if it's not replicated yeah it's server only

#

if it's replicated and false it should basically spawn the actor on clients like any other runtime actor

tight spoke
#

Is there a recommended way that someone would have to make it so an AI controller takes over a character when a player isn't controlling the character?

#

This is our current multiplayer set up

#

How could I go about setting up an AI player to go along with this set up? Would it be best to create an Identical but separate AI player to spawn in only if there isn't a controller connected? Or can I just add the AI controls to the player character as is?

fallow mango
#

anyone know why an animation would not be applying root motion on the client only?

torn hull
#

Hey I’m making a spectator mode using Set View Target. It works for left/right, but not up/down. I’m using the first-person template, any idea why that might be? When Im printing Pitch from "GetControlRotation" it looks good

thin stratus
#

Are you saying the spectated player looking up/down isn't visible to the spectator?

marble lodge
#

is it safe to using SetTimerForNextTick() to show the character information in the hud such as health? it is hard to know which time fully initalised the character, character stat infromation which is attacted to the character and HUD in both server and client.

nova wasp
#

"character stat infromation"??

#

is is a separate object in the actor? a property? another actor?

marble lodge
#

Character stat is separated as the UObject, but attached to the component the character has.

nova wasp
#

how about an if statement

#

each of the different things calls CheckInitialization

#

which just... checks for those things being present

#

this is how init states work in modular gameplay

#

I don't see why the stat can't just report itself showing up to the owner or something

#

delaying it by 1 frame would only be meaningful if you already knew the object was 100% doing something already but just needs 1 tick to start

#

delaying just because you THINK it will show up soon is a bad practice... but might work if you don't care about it breaking occasionally

#

"HUD in both server and client" is also not meaningful for multiplayer

#

the HUD is a local thing... you are not replicating the hud object

#

unless you just mean that it's FOR the hud

marble lodge
#

ah you right in the hud

#

cause I miss out Hud isn't replicated, but it means HUD in the client player and server player (it runs in the listen server, still HUD is remain in the local though)

nova wasp
#

there might be some cursed thing that can replicate properties on a hud for all I know but that would definitely be unorthodox

chrome bay
#

hud actors are spawned locally, so yeah no replication

marble lodge
#

wdym about cursed thing?

chrome bay
#

they are also extremely legacy things, but honestly still useful especially for widget management

nova wasp
#

also from my experience I would say my ideal for the player being "ready" is a lot more than just "it is here" unless you want

  • character and player state present
  • playerstate is ACTUALLY AWARE and has the current playerstate set as its "get playerstate" and vice-versa

Just beacuse the playerstate and pawn are present does not mean they are mutually set on each one. They should also be AWARE of one anotyher unless you want subtle issues where GetPawn randomly doesn't do anything despite both having begun play

Beginplay != set in places you would expect to obtain the object

#

which in this case generally occurs right after they begin play which is actually a situation where a 1 frame delay would help if you can observe in the engine code it's going to assign it soon (better to just have some delegate that fires after each one I guess)

#

I'm sure someone is thinking "maybe you shouldn't rely on GetPawn from the playerstate"... hmm yeah let me just fix the 200 places that do that lol

chrome bay
#

Gets annoying writing the same event-binding boilerplate in every widget class you create

nova wasp
#

it's nice to have a sort of boilerplate BindOrCall thing

#

where you either call immediately if X thing is already present or it calls the delegate later once it appears

chrome bay
#

yeah

#

pattern i use a lot now tbh, even for non-ui stuff

nova wasp
#

yeah it's kinda universally useful especially when you can't control object init order

#

I tried to templatize it recently but I can't really think of a nice setup that would not just make it more confusing for users

#

I have one hellish function that is like 6 chained delegates together to make damn sure that ~4 objects are present before doing anything

hollow sapphire
#

has anyone tried using AnimNotifyState in multiplayer where, at Notify Begin/End, you send a gameplay event to the actor? The idea is that a gameplay ability is waiting on that event, and when it receives the tag, it executes its logic.

My problem is that I put a debug print on Event Received and noticed that on the client it prints multiple times, as if the event is being triggered too many times. I even made my own AnimNotifyState class and routed the gameplay event through a server RPC so the event is only sent from the server, but the client still prints multiple times.

Is AnimNotifyState just not reliable for multiplayer? Because when I do the same thing with a regular AnimNotify, everything works fine: the client receives the tag, and the debug prints only once per notify.

torn hull
thin stratus
torn hull
#

Yeah, thats what I thought, but I have no clue how to fix this. Do you have any idea, that wouldnt require messing with replication system in c++?

tardy fossil
#

if you use APawn's GetBaseAimRotation() function, it should take RemoteViewPitch into account when being called on a client

#

though i dont remember if theres extra steps to make the server replicate RemoteViewPitch

dapper kraken
#

Hi all, I'm building a project on top of GAS, one of the conceptual problems I find myself running into again and again is how to provide instantaneous feedback on client for actions that are ultimately server-authoritative. So for example, dealing damage to an enemy and instantly seeing their health bar go down and a flinch reaction play without having to wait for network delay both ways.

#

I was wondering if Unreal has anything ootb to help with this kind of scenario since I'd imagine it comes up a lot in multiplayer game dev.

halcyon ore
#

While not knowing much about GAS.
Isn't this the entire idea of client prediction?
Client legit just does it too, and when server does it, any variables are replicated to there correct value (aka health in this case)

dapper kraken
#

right, just wondering if GAS has an implementation of client prediction for its gameplay effects/cues systems.
maybe I'll ask in GAS channel

halcyon ore
#

As far as I understand it does come with client prediction (GAS)
But, yeah GAS channel is probably gonna be better

quasi tide
#

You shouldn't do damage for client prediction

#

Because players will feel cheated when the see the health drop and then go back up because the server corrected it.

halcyon ore
#

Players feel cheated, even with the client prediction of blood splatter and stuff. lmao
I see rage about it like every day

dapper kraken
#

how often are client predictions actually wrong though? my gut sense was that it's pretty rare for a correction like that to actually happen

halcyon ore
#

Could be wrong, or just different.

dapper kraken
#

my intuition says better to be immediately responsive and get it wrong 1% of the time rather than wait for network delay 100% of the time?

#

but idk I'm not a networking engineer, idk what the industry standard solution for something like this is

lament flax
#

FX are mostly predicted

#

important stuff like headshot hitmarker can be server authoritative

exotic wasp
#

when the client asks to run it, it starts on the client, and the server also runs it in parallel

#

clients get instant feedback and the server runs it to validate it

#

typically things like damage you don't want to predict

#

predictions can be wrong a lot depending on what triggers them

#

if you're raytracing a bullet on both client and server, good chance it doesn't perfectly line up

#

imagine getting a headshot in counterstrike on your client but missed in the server

dapper kraken
#

I'm surprised it's not normal to predict damage... running my almost brand-new project with network emulation on and net settings set to average, the delay between hitting an enemy and getting the hit reaction is very palpable and it feels terrible

halcyon ore
#

Its normal to predict the effects of damage.
But not the "damage"

dapper kraken
#

oh I see... interesting.

halcyon ore
#

You see blood fly out, and some do predict the flinch animation.
But, never seen any predit the stat going down

dapper kraken
#

interesting

halcyon ore
#

Especially since, some code (I know base UE, and MAYBE GAS?)
Gate damage behind authority, so you need to go through extra/ special hoops to actually affect the HP.
Just so many factors, especially with a complex game.
Does client even know of some of the metrics that affects the damage, or what if the damage is random?

dapper kraken
#

I think that the client would probably have a pretty good sense of all the metrics that would determine the damage dealt, but if it's weird to predict damage then I probably won't go down that route

#

what I'm wondering if I can do is predict the health bar changes at all, maybe making use of the inherent delay in layered health bars to make wrong predictions / corrections a little less jarring

halcyon ore
dapper kraken
#

interesting

#

my gut tells me that all the different vectors of immediate visceral feedback for dealing damage are some of the most important things to be instantaneously responsive when you hit an enemy to make the game feel good, and I felt like seeing the health bar start to chunk down or highlight the portion of it that's about to deplete was part of that

#

but if that's not the industry standard then I'm probably not gonna try to invent some new networking system to make it work that way

#

I appreciate the insight! angel

#

one other question I had - all my character classes get a ranged attack, and for the petmaster character their ranged attack is basically to send their pet to dash at the target and damage them, essentially like a living projectile. similarly to the previous question, I want the pet to leap immediately so that it feels responsive, like firing a gun

#

I'm wondering if it makes more sense for this pet to be a server-controlled AI, or be an autonomous proxy more like the player character that can predict its movement on client side

halcyon ore
#

To me.
Since this sounds like a unique case.
I might spend a bit of extra time.
and, have the attack make the actual pet invisible, then spawn a predicted projectile that looks like the pet and all that jaz.
Shares code with the other characters, and the pet doesn't need weird projectile type collision or something.

dapper kraken
#

yeah that general approach makes sense... I had been looking into something like it but wasn't sure if it was too hacky. I think the biggest headache I had was trying to align the positions when switching between the client and server version

halcyon ore
#

I do a similar very cursed thing, when I wanted to implement casting magic spells.
My weapons just shoot a like 10,000 speed projectile.
No reason to re-make the weapon, just to be a line trace.

Sure, spawning a whole projectile that then gets destroyed in like 1 frame might be a bit much to some people.
But, it works, and doesn't have issues. 😛

exotic wasp
exotic wasp
halcyon ore
#

Well, it works well enough thankfully. 😛

exotic wasp
#

and thats all that matters

dapper kraken
#

like if a boss is in a rage mode that negates hit reactions or something

exotic wasp
#

the boss's ability component would need to be relevant to the client

#

thats probably the case unless you've meddled with it

#

client and server should calculate identical values

#

at least good enough for cosmetics

dapper kraken
#

hmm... if hit reactions can knock back an enemy and interrupt their current state though, i'm not even sure they can be thought of as cosmetic...

exotic wasp
#

imo just wait for server

#

a normal amount of latency wont be all that noticeable

dapper kraken
#

that's what I have right now and it literally looks terrible with average net settings, I struggle to believe that this is standard for multiplayer games

dark edge
#

Shooters nowadays are typically "favor the shooter" in matters of latency, and I wouldn't be surprised if many of them just used clientside hit detection with server sanity checks

dapper kraken
dapper kraken
exotic wasp
#

you could predictively move the model of the enemy on the client

halcyon ore
#

and, they don't have very sane server checks. 😛

dark edge
#

reconciling what happened when you have 3+ different versions of reality is very very difficult

exotic wasp
#

siege also has irredeemable net code

dark edge
#

At a given time, all clients and the server see different things. And it's not just that the clients see the same things later, the game gets into different states on different machines if you have prediction. That's the core of the problem.

#

So it's a tradeoff. You need to decide if you want to allow shooting a thing on your screen and nothing happening, or being shot on your screen when you're sure you were around a corner. Can't have it both ways.

dapper kraken
#

our game is PvE so I'm definitely happy to be on the side of favor the client

#

just trying to figure out how to make that GAS compliant

dapper kraken
coarse cave
#

reconciling what happened when you have 3+ different versions of reality is very very difficult
More so in Unreal than say, Source engine. The lack of fixed tick and snapshot based networking massively increases the difficulty

halcyon ore
#

Maybe UE emulation is going super crazy with it?

I play ARK, with it doing like a billion million things, on like 100 ping, and you barely see issues.
That be damage, items, moving, etc

#

Takes like 200 ping to start to feel it.

exotic wasp
#

they also definitely predict a lot

halcyon ore
#

Not saying they don't predict

#

Is this no prediction at all?
Or, does it have the hit anim prediction?

dapper kraken
#

no prediction at all. the little temp hit fx happens immediately cause it's a cue

coarse cave
#

That looks like no prediction except for the little gold stars VFX on the hit location

dapper kraken
#

is this the sort of thing that we could use prediction for? cause it's an entire state change, it's not just cosmetic

exotic wasp
#

seperate the change of state and the cosmetic so that the client can safely apply the cosmetic

dapper kraken
#

but like if the enemy is mid-attack and I flinch them out of it, how am I supposed to only play the cosmetic half of that?

halcyon ore
#

Just play the anim?

exotic wasp
#

^

dapper kraken
#

right but that would interrupt the attack and potentially spare the player from getting hit

coarse cave
#

Different parts are easier/harder. For the health bar, it's pretty typical to draw the damage you just did (which would be predicted) in white/yellow, and then have it disappear after a short delay. The actual knockback might be hard to predict and could end up popping, though you could split that into an additive flinch on the client and leave the knockback on the server

exotic wasp
#

the attack is still occuring on the server

#

though ideally the player's attack goes through, changes the state on the server, and it lines up exactly with the client

dapper kraken
#

oh, I see what you mean

verbal ice
#

because you're pretty much adding 240ms of latency here (RTT)

#

takes 120 ms to go from server to client, and vice versa

dapper kraken
#

ah, I figured I might be doing something wrong for emulation

#

what should I be using instead?

#

/ I'm still a little concerned about this problem regardless

exotic wasp
#

simulating just client lag is probably a fair test

#

or just half the values currently in there

#

regardless some cosmetic prediction on the client will help

#

GAS is pretty much designed around that

dark edge
#

If you have clientside prediction you by definition have different views of the world on all clients. The hard part is hiding that

coarse cave
#

Oh I'm aware... the last game I was on added fixed tick to our engine (UE 4.27) for just that purpose, but it was a huge undertaking. It's just that snapshots make it MUCH easier, and fixed tick makes snapshots much easier. I'm surprised they're not really there in UE at all, outside of something like Snapnet.

exotic wasp
#

i believe it used a fixed tick kinda thing

verbal ice
#

rest in peace NPP

coarse cave
#

deprecated?

verbal ice
#

ehhhh more like, never finished

#

don't remember if they're still working on it but it wasn't looking good last I checked

coarse cave
#

Yeah, I see it here in the 5.6 docs

exotic wasp
#

i believe the main dev working on it left the company

verbal ice
#

F

halcyon ore
#

EPIC

#

Clearly we just gotta set a timer for/ on tick, to 0.01 seconds.
Fixed tick done. 😛

coarse cave
#

Note that during rollback, all fixed rate instances are rolled back and resimulated as a global operation.
Well that could get expensive..

exotic wasp
#

indeed!

#

but basically required if you want accurate resim

coarse cave
#

I mean yeah, but some predictions matter less than others. Like, if your weapon recoil vector mispredicts but doesn't have any side effects/dependencies on movement (and visa versa), it's pretty painful and expensive to resimulate all of the movement code

exotic wasp
#

if movement state isnt dependent on recoil it wouldnt resim

coarse cave
#

It sounds like it would from the documents... unless "all" doesn't mean all in the quote above

#

Yeah, definitely sounds like all:

A RollbackFrame is identified depending on
whichever was the earliest frame among all instances that requested a rollback, and then ALL fixed rate
simulation instances are rolled back to that frame, and stepped forward in the correct
ENetworkPredictionSortPriority until we are back to the predicted timeline.

verbal ice
#

However you can do it in "AncillaryTick" which is after movement updates and isn't affected by those

#

I like it since you pretty much sync up movement and shooting on client prediction & server validation

#

You can do it with the CMC but it's a lot harder IMO

coarse cave
#

Ouch.. $599 for that component?

#

Seems cool, but maybe a bit steep for a hobby project 🙂

dark edge
coarse cave
#

True

dark edge
#

My game project uses a tilemap plugin I'm developing, and It'd take me like $5k worth of time to redo this, even knowing exactly what I want to do.
I'm not going to bother selling it, I'll just slap it on Github.

exotic wasp
fossil spoke
#

I think a big detriment of marketplaces like Fab and the Unity store, is they create the perception in regular peoples minds that writing code is meant to be cheap.

#

When in reality, its extremely expensive.

#

Especially good code.

#

You could probably just generalize that more and say "systems" instead of just code.

#

Its complex, time consuming and expensive to develop good systems.

coarse cave
#

For me it's a combo of things; 1) Overkill; I don't doubt that GMC is worth every penny, it's just more than I need (not doing competitive/PvP), but I still like to work with solid, future-proof systems. 2) No evaluations; many plugins are of unknown quality until you download them and look under the hood, so the more expensive the plugin the bigger the risk. I've seen a few plugins that were quite expensive ($350+) that have demos, and the demo instantly convinced me that it was NOT well made... but it's still $350 with a 4.8+ rating.

verbal ice
#

Yeah not saying to jump onboard the GMC ship

#

But it's an example of how you could do it

plush mauve
#

I have a large array that I need to replicate to clients when they join. I'm going to batch it and call a run-on-owning-client rpc with a delay in between to slowly replicate it out to that client, but I'm unsure how to call the roc rpc on the specific client that connects? I only have access to blueprints.

dark parcel
coarse cave
#

A large array of what data type?

dark parcel
#

normally large array are handled with FastArray

#

it should be good enough for things like inventories

plush mauve
#

It's a struct array of collated data from actors in the world. About 30k entries.

verbal ice
#

Any reason why said actors can't replicate data down themselves?

#

But yeah what ColdSummer said, use PostLogin, it's available to blueprints

plush mauve
verbal ice
#

Why not let them send their data when they load on the client?

plush mauve
spiral ravine
#

Hi I followed this tutorial (and many others) but they never work. Are the tutorials wrong? The issue i'm having is that newly joining clients aren't seeing the other player's info (only their own), but the server/host correctly sees everything properly https://www.youtube.com/watch?v=DQziq6oA6qA

🛖 Check out my advanced Building System:
🪚 https://www.fab.com/listings/e4d59e7c-cb75-408f-86c0-c69f72357c83

How a player can determine an own player name and how to replicate name tags so they load up correctly when players are joinig a server.

🔷💬Join my Discord Server: https://discord.com/invite/eX3p5q6

Basic Advanced Session (...

▶ Play video
thin stratus
#

I think they also used an FText for the player name...

spiral ravine
#

Damn, figured. Checked comments to no avail. Every video tutorial i've found on the subject is all the same, i run into the same problem everytime.

#

I personally run logic off of OnPostLogin so i ignored that BeginPlay part

dark parcel
#

you best reading the pinned material over and over again. Then practice your self until you understand how replication work.

spiral ravine
#

I've gotten many things working i'm just having a mental block with this particular thing i've been at it for a few days, constantly trying new things, researching new info, reading forums wikis, the refferundem thingy getting nowhere

#

I'm failing to comprehend it frankly

dark parcel
#

do you have access to C++?

spiral ravine
#

I need to see it working once then work backwards I think

spiral ravine
dark parcel
#

in anycase, if the data (the name for example) is on client side.

#

OnAcknowledgePossession-> Send Server RPC with the player's name.
OnRep (Name) -> Set Widget text to the Name.

spiral ravine
spiral ravine
dark parcel
#

either way, all you have to do is send the data from client to the server

#

then server replicate that variable down to all clients

#

where client react to the new value with OnRep

spiral ravine
#

What if that value is already set before they join? Because I feel like i'm doing this already

dark parcel
#

Have you went through the pinned materials?

#

how would the server know the name of the clients

spiral ravine
#

One sec

dark parcel
#

Like you set the name in your computer, then you join my game where I am the host.

#

Ok you have that set in your own G.I or where ever, but how would my computer knows that value?

#

You will have to send the data to me (the name), only then I can use that information to replicate the name to all other clients.

spiral ravine
#

Okay so OnPostLogin (from gamemode) I fire an event down to the client to PlayerController
Here I get the Username from the computer then after Pawn is posessed, I fire an event on the server on the pawn to set the replicated variable with the username
Then on the Pawn on the RepNotfiy function, I update the widget info

#

But this has the issue

#

I think its because clients arent allowed to RPC to server from PlayerController maybe?

dark parcel
#

They can

spiral ravine
#

Only the actual server host can?

#

Oh

#

Well i have no idea then lol

dark parcel
#

Clients can call RPC on objects they owned. By default it would be the possesed character and their controller.

spiral ravine
#

Do you see an immediate problem with my logic

dark parcel
#

I don't know, hard to see without looking at the code.

#

This is my setup

spiral ravine
#

let me rewrite my message

#

As GameMode
Event OnPostLogin > Cast to PlayerController > PlayerController Event "Very Epic" (Owning Client)

As PlayerController
Event "Very Epic" > Set Username (from Computer Info) > Wait Until Pawn Posession > Cast to Pawn > Pawn Event "SetUsername" (Server)

As Pawn
Function OnRepNotify > Get Widget from Widget > Cast to Widget Class > Set Widget Info

dark parcel
#

"Wait until Pawn posession" how exactly are you doing this?

spiral ravine
#

I confirmed this works

#

With other events

dark parcel
#

so why not just use AcknowledgePossession? That's run on client and the pawn is guaranteed to be valid at that point.

spiral ravine
#

Oh I will switch to it but i wasnt aware of it until you've told me here

dark parcel
#

So where is the replicated name are kept?

spiral ravine
#

But yeah this has the problem of, newly joining clients not seeing other's usernames. Whereas the server client player host whatever you wanna call bro, can see everyone's names perfectly

dark parcel
spiral ravine
dark parcel
#

show the codes

#

not by writing what you think you do.

#

just paste it here, bp or cpp.

spiral ravine
#

Actually I lied, the replicated variable and function is on the player controller, in the onrep function it gets the pawn then calls a function to update the widget. Sorry ive been messing around with it so much i forgot i changed things

spiral ravine
dark parcel
#

I think your task today is just to look at the pinned material. It really saves you time from guessing.

#

Client only know their own controller.

#

While server have everyone controller.

#

so if you have the name in the PC.

#

there's no way that Client 1 can know about Client 2 name or properties.

#

because Client 2 controller doesn't exist in Client 1.

spiral ravine
#

Okay. I have read through a lot like a lot but i just seem to fail comprehension on this specific thing, like i said ive been at this for days trial and error, research, tutorials

#

I will keep going though

dark parcel
#

Yeah, personally take me like dozens of re-reading, practice, fail, until it click.

#

So now, you have to move the name else where. Either in player state or the pawn.

#

I would just have it on the player state since name normally doesn't interchange while pawn may be switched around (who knows what game you are making)

spiral ravine
# dark parcel

Lmao i saw this ages ago and I guess ive misremembered. In my mind the pawn was furthest away from server lol because i started thinking of it hierachy wise like GameMode > GameState > Controller > Player State > Pawn. Ok let me cook

dark parcel
#

Game mode only exist on server.
Game state is replicated, everyone has a copy.
Server has everyone's controller. Client only have their own local controller.
Player state is replicated, everyone has a copy.
Pawn is replicated, everyone has a copy.

spiral ravine
#

Multiplayer cooking my brain

#

Ok hold up

#

is AcknowledgePossession exclusive to C++?

dark parcel
#

not bp exposed

#

ask epic

spiral ravine
#

ok ill expose it to bp

dark parcel
#

just run Blueprint impelmentable event

#

don't want to touch engine's code

#

Override in your custom controller, call super then call BIE

spiral ravine
#

Holy McMoly it's all working

#

Okay so I actually DID understand it the entire time I just forgor about the controller vs pawn thing lmao

#

Thanks for your help big time

lime leaf
#

I have a problem: Wanted to use the AdvancedSteamSessions plugin in my c++ UE5.6 project, but I have my own custom c++ GameInstance with a lot of variables defined in c++ which I need in the GameInstance in my RTS game. Hmm. Can I in c++ inherit from the plugin version AdvancedFriendsGameInstance some way, in c++/project?

#

Or should I go the heavy route of learing steam c++ stuff and make my own solution.. IDK. I've been procrastinating the Steam multiplayer stuff, I got multiplayer listen server working for my game though, so a lot of multiplayer stuff "working" locally in PIE.

thin stratus
#

@dark parcel If the user has access to C++, there is no need to send an RPC with the Player Name.

lime leaf
#

Managed to derrive my custom c++ gameinstance from the advancedsessionsfriendgameinstance, nevermind 🙂

thin stratus
#

@spiral ravine @dark parcel

When connecting to a Server, the Client will use a URL, which can have options provided via ?Key=Value.
By default, you should already see that one of those is ?Name=.... This is what's being used by UE to assign the PlayerName on the PlayerState.
You can see that in the log, e.g., LogNet: Browse: /Game/Maps/SomeMap?Name=Player.

Where does the name option get applied to the URL?

This is done within UPendingNetGame::NotifyControlMessage, where it calls ULocalPlayer::GetNickname and adds the option to the URL.
After that it sends a Login message to the Server, which ultimately ends up calling all the AGameModeBase::PreLogin/Login/PostLogin stuff.
ULocalPlayer::GetNickname first tries to grab a name for the specific platform and if that fails it will fall back to grabbing a name via the online backend.
So that results in your PC name by default, or in your Steam name if you are using that (or any other OSS).

ULocalPlayer::GetNickname is virtual, so you can inherit from ULocalPlayer and override the method, passing in whatever you want.
You could grab the UGameInstance here and take a name you stored there, or your Widgets where players can type in a name can already just set a custom property on your own ULocalPlayer class and you return that.

Bonus info: You can also override ULocalPlayer::GetGameLoginOptions to pass even more info to the Server.

#

Where does the Server grab the name option from the URL?

The Name keyword is being grabbed inside AGameModeBase::InitNewPlayer:

// Init player's name
FString InName = UGameplayStatics::ParseOption(Options, TEXT("Name")).Left(20);
if (InName.IsEmpty())
{
    InName = FString::Printf(TEXT("%s%i"), *DefaultPlayerName.ToString(), NewPlayerController->PlayerState->GetPlayerId());
}

ChangeName(NewPlayerController, InName, false);

AGameModeBase::ChangeName will ultimately set the name on the APlayerState, where it's replicated.
This also offers APlayerState::OnRep_PlayerName, which you can override, as well as APlayerState::HandleWelcomeMessage.

--

This ensures that:

  • The whole name/nickname/playername stuff stays within UEs framework.
  • You don't need to create any new replicated properties.
  • You don't need to send any additional RPCs.
dark parcel
#

Awesome, good to know.

pliant cypress
#

Can someone explain me how does loadout work and persist across server and map?

lyric heart
#

If I load something on begin play, that's one for each player on the server and clients ?

#

So it would load four times ?

#

Begin play of the player

#

Would this be a good time for is locally controlled ?

dark parcel
dark parcel
#

maybe more helpful to say, where you obtain the data.

#

e.g RPG game where the data is stored in online data base will have different mean to obtain it with games that let user save locally and let them send that value to the game they joined

thin stratus
pliant cypress
# dark parcel depends on your game?

Soldier game, fps.

You have one loadout which can be configured by you, not 10 loadout like COD. Then you go into your selected map (host/join) then select the character (soldier character), and play the game with that loadout + equipment which are prefix for the level.
Such as NightVision and Flashlights are given basis on level, can be set inside loadout

pliant cypress
tardy fossil
#

could use a save game object and just load it and then RPC the data when successfully connected

pliant cypress
#

But the game is listenserver so it's more likely locally saved and no authorative database

tardy fossil
#

you could have the server RPC verify the loadout and if its invalid, send an RPC back to the client in which the client would update its save object.. even if its a listen server host, send the save object through the RPC function and verify it just as if its a client.. RPC functions will work as expected, they're just treated as local calls if its dealing with a local player

halcyon ore
lyric heart
#

if i use index 0 it won't load on everyone right ? but will it load multiple for every player ?

thin stratus
exotic wasp
#

Is it worth just making the swap to iris and learning that instead of going forward with the "legacy" replication system?

quasi tide
#

Depends on how far along into your project you are

#

Early and plan on working on it for a few years? Probably

#

Late and plan to release soon? Nah

exotic wasp
#

Still in development

#

Iris is mostly backwards compatible right?

quasi tide
#

Should be, yeah

#

Iris just went into beta mode in 5.7

exotic wasp
#

Oh

lament flax
#

It reps a changed entry, added entry, removed entry. Doesnt matter any other stuff

#

You get a per-entry callback so you know what changed/got added/removed

#

You save up bandwith for arrays larger than hundreds

halcyon ore
lament flax
#

Yeah

#

Anything that has to be sent is chunked if to big

#

Thats how bunches works

halcyon ore
#

I know that.
I just wasn’t sure if FAs do that by default automatically.

#

I couldn’t find anything that said that, and GPT was un-helpful

lament flax
lament flax
halcyon ore
#

Yeah.
I was just curious if it could find any info.

I got the answer I wanted/ needed from you thankfully.
But don’t think I am/ was asking correctly.

lament flax
#

Np

#

Also whatch out that replicated objects inside the entries might replicate after the OnAdd event

#

It will trigger the OnChange event

halcyon ore
#

The more I think about this.
The more it confuses me. 😛

cuz you guys suggest this type makes sense for inventories, and items.
But how does that work with replication?
Cuz, the clients would 24/7 know of all nearby items when not needed.
Since in the past I have asked about per player replication of a var and got told it’s not possible.
Or is FA special?

lament flax
#

Do you want clients to not know whats in the nearby chest until its opened ? For example

halcyon ore
#

Correct.
I don’t.

lament flax
#

Mh

#

Then you can have a rep condition

#

A custom one

#

And only rep to nearby actors

#

Never done it but its possible

halcyon ore
#

I thought conditions were global?
For all players.

lament flax
#

Thats probably still the case, iris wants to change that buts its beta in5.7

#

But each player has an unique actor channel

#

So maybe you can do it per player

#

You will have to get an answer from some more experienced networking devs

halcyon ore
#

Yeah, no worries.

#

Cuz I have a working method.
But this talk of FA and apparently it already being used for inventories sounds a ton better

lament flax
#

If you ever find the way to do this im interested

halcyon ore
#

Yeah if I had some free time, I’d “TRY” to mess with it. lol

lyric heart
#

if i get index o and set a value

#

each one will just have there own seperate value right ?

#

and it won't replicate unless i specify that

lament flax
#

I would never go near beginplay events if i need controller or pawns

sick holly
#

Hi everyone,
I decided to create a multiplayer 1v1 card game in UE5.
Basically there will be 8 active slots (like in inscryption) and rest of the cards will be in player's deck.
So the issue is that physically player's are on the same position in the world, so they see the same image and logically I want every player to see his own cards on the bottom line and enemy's cards on the top and I don't really know how to make this game logic. I have 8 physical slots on the table where cards can be placed, I have the card data structure that contains all the data, I already have a working multiplayer lobby you can join, but I don't know how to display cards differently for each client and still be able work with them and add some features in the future.
Any suggestions how to implement this logic into my game? Many thanks!

lyric heart
sick holly
# lyric heart so are the cards in the world ? or as a ui ?

In the world as I want to make complex logic with them later. Maybe I should spawn them only on the clients and have all the data inside a GM, but it sounds like a huge pain in the butt, so will be glad to see how others would create this logic

dark edge
#

just make sure the location of the pawn is NOT a replicated property and it'll just work.

#

The pawn should be replicated, but its movement should not be. The movement (position rather) is a function of whether or not they are the local player's pawn on a given machine.

sick holly
#

Srry, but I don't get you. I don't care about the players pawn positions, they are just cameras, that are looking at the table from the same perspective. I care about card actors on the table and their positions should be different on the clients

dark edge
#

that transform is effectively their place at the table

#

on my screen, I'm at 0 facing X and you're at 100 facing -X
on your screen, I'm at 100 facing -X and you're at 0 facing X

#

On all screens, the local player is at 0 and the other guy is at 100 facing the opposite way

thin stratus
#

There is no need for it.

#

Just use an Event that ensures the pawn has a valid Controller.

halcyon ore
# lament flax If you ever find the way to do this im interested

Some more in-depth googling suggests a "replication graph", which as far as I know is very complex, and like source engine stuff.
and, my only experience with a "replication graph" in any capacity, is that it makes ARK modding very buggy at times. 😛
But, its at least a starting point.
We'll see if anyone sees this perhaps.

#

But, now that I think of it more.
Seems like everything is goofy?
Sure, we fixed the FA.
But, what about the replicated UObject?
Wouldn't those still replicate to everyone (I guess maybe the replication graph could also handle those?)

dark parcel
#

What is it you want to do? Have a chest that gives loot independently to each client?

halcyon ore
#

No

#

Clients only know of items they access.

No reason to know of the like 1,000 stone in each box, when you only wanna access 1 box

#

But, default replication has no form of per client sending, just all or none (apart from the special owner case)

dark parcel
#

If the goal is to hide information per player basis then you can just use the controller class

#

e.g card games where client doesn't have the information of other client cards

#

so even if they hack the camera, they still won't know the cards other player hold.

halcyon ore
#

How would that work, in a case like this.

In the context of a card game, that makes sense, cuz you only ever have 1 deck of cards, not 5,000 decks of cards.

dark parcel
#

In the context of MMO game, bunch of programmers will come with custom solution.
No MMORPG I know built with unreal usses unreal replication system as far as I know.

halcyon ore
#

Ok.
Thats what it was seeming like.
But, just see peole being like yeah, just use FA's for inventories, and profit

dark parcel
#

you are not making mmo though?

#

most of us don't either

#

also people handle sending large data by batching.

#

you don't have to send 5000 entiries in a single frame

halcyon ore
#

No, not an MMO.
But, the items are still an issue in this case.

I already have a working custom solution, but without any I guess "cool" UE5 tech. 😛

dark parcel
#

with FA only the delta got send

halcyon ore
#

Essentially an MMO amount of items I guess is a good way to put it.
It'll probably be the most complex part of the game.

Being able to place like 50 boxes down, and each box has like 300 items in it.
So, without blocking FA, or item reps, that'd be 15,000 items just from standing near it.
Even like 10 boxes, thats still 3,000

dark parcel
#

I don't like reaching but if that's a requirement on my end, I would probably just ask for the data when I opened the box / chest.

#

and if a chest has 300 items, that sounds like a game design issue.

#

no one has the time of day to browse thousands of items.

halcyon ore
#

Correct, and that is my current setup.
Ask for data on open.

But, just the talk of FA's, and replicated sub-objects made me wonder if/ how I can switch to those.
But, the idea of custom handling those, seems like it adds even more I guess "base" complexity to that method.
Meanwhile my current method is probably a similar amount of complexity, but spread out.

crisp shard
#

when making replicated doors that update to new players, doing 1 door , 2-3 even, is easy enough, have repnotify bool for the doors, but what if i have like 15-20 or maybe more , how would you go about keeping track of that many doors in 1 actor? i'd say a bool array, but then im looping through the all the doors to change the 1 door that was interacted with. i've thought of a custom struct array, but i still would see the same problem with it being that i'd be having to loop through all the door when updating just 1 door. is there a better approach or another method that might suit me here? i basically have a building where there's a lot of interior doors throughout it

verbal ice
#

you're gonna have to loop regardless i think

#

it's hardly an issue though

#

that or you do something like a bitfield, and find out which bit changed, using that as an index

#

but then again you're also having to loop through the bitfield, probably

dark parcel
exotic wasp
#

a door should almost definitely be an actor instead of a component

thin stratus
#

There is a world in which replicating a lot of state in the form of a NetBitArray is a really good idea. But I agree, that the doors should probably be their own actors.

nova wasp
#

unlesss these were changing EVERY frame

#

like if it's just 20 things flipping on and off occasionally them sending directly to the network object will be far cheaper than sending all of them to 1 thing with 19 extra bits of information

#

definitely situations where a bitarray makes sense but the order of 20 things we don't know the rate of change of seems overkill

#

I don't really understand "having to loop through all the door when updating just 1 door"
Why would you have to loop through all the doors ever here (except for like late joiners)? do they not declare when they are changed somehow?

verbal ice
#

Would have to loop through an array of bools to figure out which changed ig

nova wasp
#

ah they did mention that

nova wasp
#

the change should just say "hey manager thing, I changed to open"

verbal ice
#

Going with their original message which seemed like they wanted to replicate an array of bools

#

You'll still have to loop through the old/new values with that

nova wasp
#

ah I guess it would not be clear which ones were actually different

verbal ice
#

you'd kinda have to use the rep notify's previous state

nova wasp
#

a fast array would help alleviate that I guess

#

but I assume this is a bp only thing

verbal ice
#

pretty sure the change event is an array of indices, so still looping. In the end I doubt there's a solution that doesn't involve looping (seems like it's what they're trying to achieve) except just having one actor per door

nova wasp
#

making "network managers" or just "manager of thing" in general is a good idea imo but this seems unneeded for this scale

verbal ice
#

yeah

nova wasp
#

notice how the text here says "all the door"

#

this means more than just the changed elements

verbal ice
#

yeah a little better (not like looping for this is going to break the performance budget anyway)

nova wasp
#

and yeah I agree it would be trivial at the order of 20 things

#

either way

verbal ice
#

and if you have one building actor that contains hundreds of doors, you're gonna have other problems to handle than just loops heh

thin stratus
#

I assume their houses are made of mesh components and the doors are individual meshes.

nova wasp
#

once you get to that scale then I think going fancy might start to eclipse the cost of each one being a distinct network object

thin stratus
#

So the house actor keeps track of all door states

nova wasp
#

another thing with network objects is that they are kinda more overehead of they must be polled, which ironically is looping over them and bonking their properties

thin stratus
#

And this might even be a blueprint and no c++

nova wasp
#

can you not address the sub components? I forget

verbal ice
#

you can

thin stratus
#

Yeah they are stable

verbal ice
#

as long as they're stably named which default subobjects are anyway (or replicated, but considering this is a building blueprint it's probably the former)

nova wasp
#

of course if they are replicated you can but I wonder if a replicated actor with a defaultsubobject can be stable sent over

thin stratus
#

Yes

verbal ice
#

yea

nova wasp
#

where you target x subobject on x actor

thin stratus
#

They resolve via the house actor

verbal ice
#

you can even send over non replicated actors & their subobjects as long as they're stably named and exist on both sides

nova wasp
#

yeah of course, I guess my question is if the root actor describes the shape of the default components on both sides

#

which of course it does but idk if unreal Just Works ™ for that

thin stratus
#

Yeah aka almost every pre placed actor in levels