#multiplayer

1 messages ยท Page 250 of 1

nocturne quail
#

all my class mates

maiden flame
#

MACs may be globally unique, but what prevents someone from spoofing the initial packet when registering the player?

A secure authentication system is not easy to make. Not saying you shouldn't try though.

#

But if you really care about security it's too much hassle imo

nocturne quail
sinful tree
#

How are you going to be able to tell if spoofed?

dark edge
nocturne quail
#

it will not match with their IP and bann will execute

sinful tree
#

Like, sure, 0000-0000-0000-0000-0000 is easy to catch ๐Ÿ˜›

#

(or however many characters are in a MAC address... probably more...)

maiden flame
nocturne quail
#

so what if they use vpn, their ip will again not match and they even can't join

maiden flame
#

That's fair, but how do you register players then?

nocturne quail
#

if they registered an ip of their vpn, it will be rejected

nocturne quail
maiden flame
#

Yeah but it has to be whitelisted somehow right?

#

Like a form of authentication

nocturne quail
#

yeah

kindred widget
#

I feel like this personality coded ESO's guild trader UI's string search.

maiden flame
# nocturne quail yeah

But the whitelisting should be done before they can play, otherwise you'll have to continually ban the same person

#

If you're doing it manually it's fine, but yeah

sinful tree
#

I feel bad for multiple players that may use the same computer too but don't want to "share their account".

An actual Username and Password would be better than an IP and MAC address.
At least if you ban an account by username, you're not going to be preventing everyone else from playing just because they connect through some other connection.
If someone was persistent about cheating, in either case they could just buy a new copy, sign up again under new IP/MAC... You basically make it no harder for the cheaters but make life worse for your legit players.

maiden flame
#

That's a good point

dark edge
#

Hey guys i got a great anti-crime idea

#

anyone who gets accused of a crime just gets shot

#

all criminals will get shot

nocturne quail
#

like this is the basic data when someone wants to join

LogTemp: New Player Logged In DeviceID: DESKTOP-MYWIN11PC-XG92
LogTemp: New Player Logged In PlayerIP: 127.0.0.1
LogNet: Join succeeded: DESKTOP-MYWIN11PC-XG92

LogTemp: New Player Logged In DeviceID: DESKTOP-MYWIN11PC-A35B
LogTemp: New Player Logged In PlayerIP: 127.0.0.1
LogNet: Join succeeded: DESKTOP-MYWIN11PC-A35B
dark edge
#

Do you accept telegrams?

maiden flame
#

Adriel I think someone already had that idea

nocturne quail
#

lets say:
Mac = DESKTOP-MYWIN11PC-XG92
ip = 127.0.0.1

so server compare this join request with the text file , if it match allow else kick

dark edge
#

Anyways this is a whole lot of discussion for something that will obviously not work

maiden flame
nocturne quail
#

yeah its working, all day testing

#

๐Ÿ˜„

dark edge
nocturne quail
#

i'm happy no need to depend on steam

dark edge
#

also my ISP changed the IP

#

and I got a new motherboard

kindred widget
#

It's a whole lot of discussion for something that could be avoided by using the testing app ID on Steam or paying the $100.

nocturne quail
maiden flame
#

Of course its better to use Steam in the long run, or something else

dark edge
#

If you want to buy my game you gotta come find me personally and kiss the ring

#

also I only take wampum

nocturne quail
kindred widget
maiden flame
#

Yeah I saw lol

dark edge
#

Why did they reject it?

nocturne quail
maiden flame
# nocturne quail I like do things independently

Well if you plan to do this at scale and have it secure, you got a lot of research to do ๐Ÿ˜›
It will take away too much time from making the actual game is what people may be concerned about really

nocturne quail
#

i am confident in what i am doing :d

dark edge
maiden flame
#

Okay, good luck anyway

dark edge
#

why would anyone play your bootleg arma that they have to jump through gobs of hoops for?

nocturne quail
#

yeah, and my game name is also arma

kindred widget
#

It's not even about research. This goes back to the foundations of the MMO in BP as a single dev joke. It really has nothing to do with making the game, or even the backend. It's lacking the support staff and help to keep things moving.

maiden flame
#

I do understand the interest to make it yourself

nocturne quail
#

well, steam did a good thing to reject, it give me a chance to be independent ๐Ÿ˜„

#

and i did it

dark edge
#

Why not just come up with your own, independently?

nocturne quail
#

I started this project with this name, was just a learning project ๐Ÿ˜„

dark edge
#

Change the name, it's 2 clicks

kindred widget
#

Red Solstice 2's project name is Twinstick. ๐Ÿ˜‚ That's a terrible reason.

nocturne quail
#

its size is 80 gb and not two clicks

#

i could have done that already if it that easy

#

it has lots of linkers in and external anti cheat

kindred widget
#

You are aware that you don't need the public facing name to be the same as the project name, right? I mean ARK:SE still uses the ShooterGame.exe

nocturne quail
#

it would take minimum 30 days to change the name of it

nocturne quail
#

my project i mean

dark edge
#

and that tiny inconvenience is worth throwing the game right into the garbage?

sinful tree
#

30 days to change the name (probably an overestimate) but get appropriate DRM and session support vs. having to support players indefinitely forever whenever they decide to connect to a new network or get a new PC and manually handle a process that doesn't need to exist only to ensure that cheaters are temporarily inconvenienced. ๐Ÿคทโ€โ™‚๏ธ

dark edge
#

You actual thief, now we can't both play bootleg Arma!

kindred widget
#

Like.. how many places did you put the game name in public facing text? Is it like on every weapon name or something? Wtf? It's like three text blocks and a couple of images in most projects to change the public name.

nocturne quail
#

this even printed on the textures inside the game ๐Ÿ˜„

dark edge
#

Here's how things can go:

  1. Nobody buys it, nobody plays it, nothing happens
  2. Lots of people buy it and love it and play it, Bohemia Interactive sues you.
nocturne quail
#

lots of things needs to be changed ๐Ÿซ 

dark edge
#

better get cracking

kindred widget
#

Starting with the project manager.

nocturne quail
#

for now it works, and i am happy with it

#

on the way i learned a new thing to not depend on external services to have unique id's ๐Ÿ˜„

sinful tree
#

For some reason that last comment reminds me of a reddit thread I read a few days ago where someone was talking about making a website that can check if a GUID has been used by checking if someone else has already checked if it was used. ๐Ÿ˜›

tardy fossil
#

theres always that 1 programmer lmao

nocturne quail
#
string GenerateUniqueID() {

    string ip = GetUserIP();

    string mac = GetUserMAC();

    // Concatenate IP, MAC
    string combined = ip + mac;

    // Hashed combined string
    unsigned char hash[SHA256_DIGEST_LENGTH];

    SHA256((unsigned char*)combined.c_str(), combined.size(), hash);

    // hash to hex
    string uniqueId;

    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        char buffer[3];
        snprintf(buffer, sizeof(buffer), "%02x", hash[i]); // Convert to hex
        uniqueId += buffer;
    }
    return uniqueId;
}
formal turtle
#

so Im using textrender attachedd to character blueprint. then I spawn the character via server.

#

I am setting Name variable w/notify and in onrep function I am setting the textrender value with settext(PlayerState->GetPlayerName) but for some reason it keeps resetting visually to default value, im out of ideas

#

at the start when joining lobby it briefly changes to the correct playername but then defaults to whatever is inside the TextRender "Text" field, anyone has any idea why?

kindred widget
#

Sounds like your OnRep code is fine. But something else is setting it or resetting it later.

formal turtle
kindred widget
#

I haven't used textrenders a lot. But if you have C++ access I'd consider breakpointing it's set text code if it has any. Even an init function should probably be calling it which should get you some idea where the reset call is coming from.

fluid prawn
#

Quick simple question when you bind a UPROPERTY to an OnRep Function does this mean that when the Property is replicated this function is called?

quasi tide
#

Yes

fluid prawn
#

Ok follow up one

quasi tide
#

Woah woah woah

fluid prawn
#

its simple

quasi tide
#

You said quick simple question

fluid prawn
#

haha

quasi tide
#

Singular

fluid prawn
#

If I call this On_Rep explicity

#

like ->OnRep() w.e that is forcing it?

quasi tide
#

No

fluid prawn
#

lol

quasi tide
#

It's just calling a function like any ol' function.

#

You tell the reflection system what function to call with the onrep specifier

#

So UE's networking system calls the onrep for you

fluid prawn
#

So yes how is this function treated in the networking context when it's explicitly called and not called on rep?

quasi tide
#

Like if you called any other non-RPC function

#

It just executes on the local machine.

fluid prawn
#

ah so its local

quasi tide
#
  1. Variable changes on server
  2. UE replicates this down to clients
  3. UE calls the onrep on the client
fluid prawn
#

Ok so the OnRep in this case would be client only

quasi tide
#

Yes. In C++, the server has to call the onrep manually. In BP - it doesn't.

fluid prawn
#

I guess that is what I wanted to clarify if its replicated on client and on server if its not marked explicitly server or w.e

quasi tide
#

Properties are only ever replicated server -> client

fluid prawn
#

K

exotic wasp
#

have to rpc changes from client to server

formal turtle
#

can someone help with this

#

I have basically SpawnedLobbyCharacter variable inside PlayerState, andwhen switching teams I destroy the spawnedlobbycharacter hard pointer because i need to destroy the character

#

but it is telling me "pending kill or garbage collection" for some reason

#

even with isvalid added its giving me this error

#

and after setting the reference to nullptr

nova wasp
#

Why would it be valid when you destroy it?

formal turtle
#

i am setting it in the macro at the end

#

basically i am spawning new character and assigning to it a new hard pointer value

#
    BP_Lobby_GM_C /Game/UTM/Maps/UEDPIE_0_LobbyMap.LobbyMap:PersistentLevel.BP_Lobby_GM_C_0
    Function /Game/UTM/Features/Lobby/BP_Lobby_GM.BP_Lobby_GM_C:ExecuteUbergraph_BP_Lobby_GM:23D9
PIE: Error: Blueprint Runtime Error: "Attempted to access BP_Lobby_Character_AgentCarter_C_3 via property SpawnedLobbyCharacter, but BP_Lobby_Character_AgentCarter_C_3 is not valid (pending kill or garbage)". Node:  Destroy Actor Graph:  CollapseGraph Function:  Execute Ubergraph BP Lobby GM Blueprint:  BP_Lobby_GM```
#

it doesnt make sense because i have isvalid checking if ref is valid before destroying it on server side in gamemode

nova wasp
#

Ah, separate ref variable

#

I find it hard to read when the nodes are behind things but I understand wanting to stay compact

formal turtle
#

maybe its because the nodes are like this but idk, something is missing...

#

wow

#

this is what you get for being so compact

#

i accidentally had 2 references plugged into destroyactor

#

one from the first node and the the other one from other variable

ruby lodge
#

I am having a weird problem where, when server travellin, The server that travelled kinda does not get recognized as a connected player and thus when the players try to join it says 0 players are in the session.

I have enabled seamless travel and assigned an empty transition map

thin stratus
ruby lodge
# thin stratus You shouldn't Destroy and Create the Session again. Why are you doing that?

This is being called in the main menu. I am trying to create somewhat of a party system where players can join you in the main menu but there is a possibility that you are alone in a session as no one has already joined. That's why I need to destroy the session to then create a new one with the public connections limit set to the amount required for a match and not for a party. If someone had already joined your party, then I still would need a new session with the new public connections value

thin stratus
#

Not with the native nodes, but with the AdvancedSessions plugin.

#

Fwiw, Parties are usually done with Beacons, but they require C++.

#

Destroying and Recreating the Session will most likely de-sync whatever other people you have in your Party

#

They won't magically move to the new Session.

ruby lodge
#

That's for a blueprint only system I want to sell on the marketplace, so I can only use the native ones unfortunately

ruby lodge
thin stratus
#

Maybe cause you are testing with SubsystemNULL, where there is no backend :P

ruby lodge
#

There is just this problem with the 0 players

thin stratus
#

As soon as someone plugs steam into that, it will probably not work.

ruby lodge
#

So is there no way with the native nodes setup?

thin stratus
#

The 0 player thing could be cause the Player is never re-registered with the Session.

#

The native nodes are only portion of what is actually used.

#

Are you using the same PlayerState and PlayerController in both levels?

ruby lodge
#

No, it's seperate ones

#

One is the main menu where they start, the other is the lobby menu where then others can join to prepare for a match

#

And then they all go to the game level with its own classes again

thin stratus
#

AGameModeBase::Login -> AGameModeBase::InitNewPlayer -> AGameSession::RegisterPlayer -> APlayerState::RegisterPlayerWithSession -> IOnlineSession::RegisterPlayer.

Since you ServerTravel, you aren't calling Login again.

ruby lodge
#

I am calling Event handle new player or whatever it was called

#

Cause that gets called

thin stratus
#

Doesn't matter. The code I posted above is what causes the Session to list the Player.

#

Without access to the C++ Subsystem code you won't be able to do that manually.

#

The Idea is that after you created the OnlineSession, it shares the "lifetime" with the GameSession.

#

ServerTraveling doesn't re-run things like registering the Player to the OnlineSession.

ruby lodge
#

So with the native nodes it's not exactly possible to create something like a party system

thin stratus
#

Probably not, no.

#

You are more or less forced to keep the OnlineSession alive until your Server actively stops hosting.

#

For the edge case that your Server is in the Party alone, you can maybe Destroy the Session, Create it, and then do an OpenLevel(LobbyLevel?listen) and see if that works. But since you are already a ListenServer, it might just not do that.

#

For the case where you want to update the Slots when you already have users connected to you, you are kinda out of luck.

ruby lodge
#

It foes work with the normal openlevel like you just said. Its just not as "smooth"

#

However, the more important part is how to travel with others in the party

thin stratus
#

The "proper" way to do all of this is:

  • Lightweight Beacons for the Party, so the Clients don't need to load the whole MainMenu level.
  • BeaconHost can then destroy the PartySession and create a GameSession when transitioning away from the MainMenu.
  • Clients will be disconnected from the BeaconHost, but can look for a Session with the same UniqueId of the BeaconHost, so they can re-find the actual GameSession once it's available.
ruby lodge
#

Can i replicate the blueprintsessioninfo struct though?

thin stratus
#

For a setup with DedicatedServers, ala Overwatch, Fortnite, etc., the Beacon part would stay the same, but the BeaconHost would usually tell the backend about the party and the backend then tells everyone the Server they should connect to invidually once a match is found, and the Beacon session is the destroyed before everyone travels to the server on their own to become clients.

ruby lodge
#

The thing is also, the server himself doesnt know the unique id of the session

#

There is no output on the creste session node and neither is there a node to get it I think

thin stratus
#

But this is all very much C++ area.

ruby lodge
#

Yea, I see

#

I appreciate the explanation, I will try some things out

#

Thank you

thin stratus
#

No worries, good luck

wanton sleet
#

should I assume that replicated variables are reliable ?

exotic wasp
#

they are reliable

latent heart
#

That doesn't mean quick, though.

formal turtle
#

I am running into issues specifically when client tries to run this function

#

it runs the gamemode RPC fine but this is kind of where it fails to remove, i think its the ==== player state name comparison that fails

#

unregisterplayer is set to run on server and playerstate ref is coming from gamemode (gamemode function rpc runs fine like i said)

thin stratus
#

GameState is Server owned. You can't run Server/Client RPCs on it

formal turtle
#

so where should i move this function then? gamemode is owned by server too

#

but gamemode function runs fine

#

for client

#

i mean it runs the server function

thin stratus
#

RPCs would need to go into any client owner actor

#

PlayerState PlayerController possessed Pawn/Character

#

Whatever fits your needs

formal turtle
#

I have this running for when player wants to switch team.

#

it goes into gamemode and server does the new character selection

thin stratus
#

Yeah but that's a server RPC in the PlayerController

#

Which is fine

#

The other one is a server RPC on the game state

#

Which is not fine

formal turtle
#

(forgive the mess) so i just make it normal function i guess since its replicated anyways

#

but my question still is why it cant find match or cant run this

thin stratus
#

That looks fine. What part of it doesn't work

formal turtle
#

server changes teams -> it runs fine, executes just fine. even when client is connected to the session
client changes teams -> it requests team switch from Gamemode, gamemode then does all of its logic (printed strings, it works just fine). but when gamemode finally reaches the part where it calls GameState -> Unregisterplayer -> it doesnt run it properly. it doesnt get to the remove part, because "Success/Not success" print strings wont run at all

#

I am printing out OnRep_TeamsArray values and for some reason it shows that the team array element is still present

#

so it kinda shows and tells me that remove failed for that player

#

but it did add player to the new array

#

so taht works

thin stratus
#

Are you maybe passing the array to something accidentally creating a local copy and modifying that?

#

Arrays of struts with nested arrays can be a bit annoying to work with in Blueprints

formal turtle
#

not sure

#

but the opposite works just fine

#

always

#

even for client

#

"registering"

#

thought might want to remove that rpc again lol

#

it works fine despite that tho

#

my only guess is that mayber playernames are faulty or empty

thin stratus
# formal turtle

That works cause you are setting the array element and giving it the local copy you created

#

The TeamMembers array in the screenshot is a copy of the one in the TeamArray. That's the nature of using for each loops and breaks like that in Blueprints

#

You'd need to show the removal code once more cause I can't see that properly on BlueprintUE on my phone

formal turtle
#

its a bit long so

#

separated into 2

#

multiplayer can be very confusing ngl

#

so my suspicions were right

#

it cant find match, now to figure out why exactly / why the names dont match, etc.

pseudo wagon
#

What possible cause this error:
The BP_Projectile_C_0 is set to DORM_DormantAll on server.


Script Stack (0 frames) :

Ensure condition failed: !SubObjectChannelRef->RegisteredOwners.Contains(NewRefOwner) [File:C:\UnrealEngine\Engine\Source\Runtime\Engine\Private\NetworkObjectList.cpp] [Line: 903] 
SwapReferencesForDormancy found new reference (0x000009A36B5A4000) IpConnection_2 was already registered to CueComponent (0x000009A357773700) owned by BP_Projectile_C_0
fallen fossil
#

how do you make actors that can be controlled by many players? ๐Ÿค” do I need to follow RPC standard or there is some simple way around ?

sinful tree
fallen fossil
#

ok, interesting idea ๐Ÿค”

exotic wasp
#

if you mean like multiple players owning the same actor, it isn't trivial to mimic iirc

dark edge
#

The server owns the thing, and the serverside version of the players pawns or player controllers give it commands.

fallen fossil
#

I am aware, but I wanted to do some cooperative stuff, so every player could manipulate anything they share ;d

#

so I guess subsystem for every player to send rpcs

dark edge
#

No

#

Subsystems are local

#

It's as simple as a networked door

#

Pawn/PlayerController
Input -> rpc
Rpc -> tell Thing to do thing

fallen fossil
#

PCs exsist on server right ?

dark edge
#

Yes

fallen fossil
#

oke ๐Ÿค”

dark edge
#

You can run a server rpc through your PC or pawn, that's typical

#

You can technically run it through anything you own, but those are the usual routes

#

Give an example, what is the shared thing and the mechanic around it?

fallen fossil
#

just broad idea about building city, build / interact or edit

#

but im fine with that answer

#

it helped

#

I was more curious if there are common patterns or some practices on making this: D

#

but PC seems ok

knotty frost
#

I'm having issues getting my Name tags to display the correct color it's currently only working with sever and client 1.

verbal ice
#

Got a bit of a problem in one of our systems. When a player is the driver of a vehicle, they possess said vehicle. However, there seems to be an issue with relevancy, as the player's "origin" for relevancy stays where they were when they entered the vehicle and possessed it. If they drive away far enough, nothing will become relevant for them anymore and they won't see other actors. How's the player's net origin determined for that?

sinful tree
# knotty frost I'm having issues getting my Name tags to display the correct color it's current...

You probably shouldn't be using RPCs for any of this. The initial collision that starts this process takes place on all instances of the game but then you are RPCing to the Owning Client, which means it would only occur on whoever happens to be controlling the character where the collision occurs. This means you may as well just put a check there initially to see if self is locally controlled and if so, call your "Check for Other Players" without having it set as an RPC.

UI stuff can usually be done entirely locally based on the replicated data of the target actors without having to replicate any more information. You can also run the line traces locally on clients without having to replicate the hit results.

For example, if you wanted to have different color names based on a character's team, you would normally store the team on the character or the playerstate, and that team value can be a replicated value. When you check the hit result, you can check if the local player's character's team is == to the team of the target character that you're checking against, and based on true/false, you can set the color.

Replication of properties can also only be done by the server, so marking all these variables as replicated does nothing for you when you're setting them within a Run On Owning Client event - only that client will ever have the value that you're setting since the server isn't setting it, and if the server happens to be the one in control of that actor, then those values will replicate out to clients, but only on their actor which probably doesn't do anything for you anyway.

sinful tree
verbal ice
#

No the actor itself is moving

#

Just seems like the controller isn't using it properly to determine current viewpoint, testing a fix that way atm

prisma merlin
#

Hello, the "Attach actor to a component" node event is being arbitrarily replicated to all clients when called by the server, how do I bypass this? I want the server and client to have their own component attachments individually, but it looks like the node is forcibly replicated.

This only started to happen with the UE5 version.

kindred widget
maiden flame
kindred widget
verbal ice
#

debugging using net.DebugDraw and it's defo looking weird

#

seems like the viewtarget/location isn't changing

verbal ice
#

Seems like the SrcLocation parameter of IsNetRelevantFor() never updates

#

while the player is in the vehicle, updates after leaving

#

Which is FNetViewer::ViewLocation

#

Is there a way to force update it, or what updates it in the first place?

prisma merlin
verbal ice
#

it's updating but the FNetDriver call to it has different data?

#

Or it's a different camera manager? wtf

#

ah im stupid, it's the client one

#

but the dedicated server doesn't get SetCameraCachePOV set

#

this isn't called in a vehicle

#

due to this, the vehicle doesn't use the pawn movement component

#

so bShouldSendClientSideCameraUpdate is never set to true

#

@maiden flame check if that's the case for you

verbal ice
#

fixed on my end

maiden flame
#

Huh, it seems to return true on my end, and I don't have the problem anymore ๐Ÿ˜‚

#

What did you have to do?

#

I had the exact same problem before, not really sure what changed it...

potent tundra
#

Does bReplicateMovement work in tandem with the new Predctive interpolation features?

verbal ice
verbal dust
#

I cant get a blueprint actor mesh component transforms to replicate.

#

this cone for debugging the camera direction, rotates on host side, wont rotate on client

#

im using listen server so im not sure if host/client terminolgy is correct

#

I also set is replicated in the construction script

#

transform is applied with Set World Rotation

dark parcel
#

You should check the source code. I'm pretty sure transform is not replicated out of the box.

#

Ticking component replicate will just allow variables marked as replicated to be able to replicate.

#

It will not magically replicate any non replicated property.

#

I know visible / hidden in game is replicated but that's about it? Rotation isn't replicated.

#

You would need to replicate it your self.

Or if it's a projectile then you can use projectile component.

#

Create your transform variable. Mark it as replicate with condition skip owner.

#

Event tick -> if isLocallyControlled -> server rpc set the transform.

#

Event tick if not locally controlled. Interp debug shape transform to the replicated transform variable.

#

@verbal dust

#

Make the server rpc unreliable too

#

Or for easier mode, there's already a replicated variable for the control rotation.

It's get base aim rotation

verbal dust
broken grail
#

Hi there i have trouble to destroy an actor on the server.

Steps:

  1. I show a widget for the item name
  2. When i press i trigger pickup item an this use run on server event to delete the actor

Its only working when i use the last event "beginoverlap" then the client picks and server deletes.
Without the overlap method the client picks up but server does not delete.

broken grail
dark parcel
#

Triggered runs every frame btw.

#

Use started to fire when the input is pressed.

#

Don't like the use of ownership there.

tardy fossil
#

changing owner like that is usually always not the right thing to do IMO

dark parcel
#

I feel that it is unnecessary.

#

Also letting the client to tell the server to destroy an actor, that's probably not what you want to do as well.

Client can request, then server check if the request is valid. If it is then proceed to destroy.

E.g other players not already "picking up the item"

tardy fossil
#

instead of doing the RPC and stuff in the actual item actor, where you need to change ownership for the RPC to work, you could pipe the RPC through the player controller or pawn with the item actor as a variable

broken grail
#

Thanks. No owner change now. Also using started as trigger. Moved the logic for now into the playercharacter - will be replaced by a inventory component thats also running on the playercharacter later

formal turtle
#

when you use seamless servertravel, even if gamemodes are different, will their playercontrollers survive the transition given that both gamemodes use same playercontroller class?

torpid crest
#

Hey guys ๐Ÿ‘‹

When it comes to multiplayer and enhanced input. Is better to have input in player controller or is it ok to have it in player pawn?

sinful tree
latent heart
#

Multiplayer doesn't really change that? Just put it where it should be.

torpid crest
#

Ok Iโ€™ll keep it in pawn because itโ€™s simpler that way

thin stratus
#

Not just where it feels easier.

#

If the Inputs are to control the Pawn, then they go into the Pawn.
If the Inputs are to control things that aren't Pawn-related, such as opening the Pause Menu, then they go into the PlayerController.
If the Inputs are to fire a Weapon, then they might as well go into the Weapon or something that is managing the Weapons.

#

That's the benefit of having InputActions and InputMappingContexts: You can place/add/remove them based on the context that they are used in.

formal turtle
#

otherwise yeah it worked, also thanks for responding

nocturne quail
#

when a player leaves the game, their AController::BeginDestroy() has been called? and can i override it?


void AArmaPlayerControllerBase::BeginDestroy()
{
    if (AArmaCharacterBase* PossessedCharacter = Cast<AArmaCharacterBase>(GetPawn()))
    {
        PossessedCharacter->HandleDeath(this);

        FTimerHandle TimerHandleBeginDestroy;
        GetWorld()->GetTimerManager().SetTimer(
            TimerHandleBeginDestroy,
            [this]()
            {
                UnregisterAllComponents();
                Super::BeginDestroy();
            },
            1.0f,
            false
        );
    }
}
nocturne quail
#

nah, this called when character logged in ๐Ÿ˜„

#

just confirmed it

#

is there any other virtual method that is called before destroying the disconnected character?

#

testing now endplay, not sure if this called before destroying the character

undone needle
#

Anyone else encountering issues with PostReplicatedChange not firing properly?

thin stratus
thin stratus
#

But you shouldn't delay destroying the controller

covert crow
covert crow
#

I am able to reproduce this on a brand new project as well, with the default first person characters. I have submitted a bug for it, perhaps it's an actual issue?

dark parcel
#

Are you using character movement component?

nova wasp
#

This is due to movement extrapolation assuming this is a cmc

jovial charm
#

Hi guys I am using PCG to spawn trees in the world (using the instanced StaticMeshSpawner) and want to add a "farming" mechanic so the player can cut down trees.

The idea:

  1. the player hits one of these tree instances, I use the index of that instance to remove it from the spawned InstancedStaticMeshComponent. (Got this working)

  2. Send an RPC containing the destroyed instance's tranform (because indexes do not match across clients) to the server to broadcast to other clients and remove the instance at that transform. (Can't get this to work, as the spawned PCGPartitionGridActor which is the parent actor of the InstancedStaticMeshComponent does not have an owning connection to make RPCs.

  3. So far, this would handle runtime destruction of trees across clients. However, late-joining clients do not know of the destroyed instances, thus their InstancedStaticMeshComponent has all the trees. I am thinking of storing TransformsOfDestroyedTrees[] and on the join replicate it to all clients to remove the trees at those transforms?

Any help with point 2 and 3 above would be very helpful.

sinful tree
# jovial charm Hi guys I am using PCG to spawn trees in the world (using the instanced `StaticM...
  1. RPCs to the server can only be sent on actors that are owned by the client. You basically need either the server to detect that they are harvesting say via an overlap of a tool of some kind, otherwise you'd have to rely on clients to tell the server they are harvesting a particular ID through one of their owned actors or replicated component of such (which could potentially be cheatable, if you're concerned about that).

  2. Using PCG means you should be able to generate the resources the exact same way on the client as on the server, and that includes IDs that can be used to reference them rather than transforms. If you're able to use the IDs, then you should be able to use a replicated array of IDs that have been harvested and on its OnRep you can then ensure the appropriate instances are removed on the clients.

jovial charm
dim trail
#

Running into a very odd issue where any first player that resides in a first map instance does not have their post process applied to the map. Any subsequent players however do have the post process applied.
Im not sure if this could be because somehow the camera is being created before the actual post processing is applied on the level?

#

This is on a dedicated server

waxen socket
#

Hello, I'm looking for advice on using AddImpulse on a client. ๐Ÿ‘‹

I have a physics object that is replicating well even with a bad ping. Now, I'd like to allow clients to push this object by running into it. When I call AddImpulse on the client however, the server immediately corrects it and it doesn't move.

I wonder if it's possible to facilitate this interaction without relying on an RPC? I'm not at all concerned about cheating.

Any advice would be appreciated. ๐Ÿ™‚

Cheers.

sinful tree
#

AActor default behavior is to make the actor no longer relevant when hidden & collision disabled

bool AActor::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const
{
    if (bAlwaysRelevant || IsOwnedBy(ViewTarget) || IsOwnedBy(RealViewer) || this == ViewTarget || ViewTarget == GetInstigator())
    {
        return true;
    }
// Truncated for brevity....
    else if(IsHidden() && (!RootComponent || !RootComponent->IsCollisionEnabled()))
    {
        return false;
    }

You can override IsNetRelevantFor in C++ or you can mark the actor as always relevant (not great if you have a lot of them in your world or your game takes place over large areas)

sinful tree
waxen socket
#

Hey, thanks for the response. I don't have authority on the client where I'd like to add the impulse. Does that mean it's not possible?

#

To be clear, when the player touches the object, I'd like to apply an impulse to the object to send it flying away. I'd like this to happen as immediately as possible on contact so if I could apply the impulse on the client and have the server respect that, that would be ideal.

sinful tree
#

If it's a replicated actor, then the collision detection will also execute on the server. Checking for authority when that happens means you're wanting the server to perform the action (which then properly replicates it to everyone else)

waxen socket
sinful tree
#

So what would you expect to happen when two players with bad ping happen to collide with the object?

waxen socket
#

Well... ๐Ÿค”

#

It's a four-player coop experience. That is a good point you raise.

#

I'm trying hard to cater to bad ping as much as I can but maybe impulse is something that can't be reconciled.

sinful tree
#

Bad ping is generally something you can't completely account for - you'd never have a perfect experience and typically players with bad ping know this.
You could go half way with this - you could still use the collision and just add impulse from there without any further checks - that would make all clients and server that detect the collision to start moving the actor, but then the server's position would take over. I imagine it may be a bit jumpy though

waxen socket
#

I've tried that and the server correction makes it look like it has a false start, resets, and then flies. ๐Ÿ˜• It might be what I go for as I think it's a bit better than waiting while nothing seems to happen but yeah... I could try faking it by moving the mesh on the client and then resetting it when the server replies but... Maybe the bad pingers will just have to suffer this little detail.

#

You've helped me out a couple times on here Datura. I'm grateful for your time. ๐Ÿ™‚

nocturne quail
#

I got another critical issue where people managed to modify game code and calling rpc by rpc, and it crash dedicatedserver.

I have this originally:

void APawn::RequestRemoveHelmet(UGearItem* CurrentHelmet)
{
    if(!CurrentHelmet)return;
    if (!HasAuthority())
    {
        ServerRequestRemoveHelmet(CurrentHelmet);
        return;
    }
       
       bApplyChangeToHelmetItem != bApplyChangeToHelmetItem ;
       OnRep_CurrentHelmet();
}

they changed it like:

void APawn::RequestRemoveHelmet(UGearItem* CurrentHelmet)
{
    if(!CurrentHelmet)return;
    if (HasAuthority())
    {
        ServerRequestRemoveHelmet(CurrentHelmet);
        return;
    }
       
       bApplyChangeToHelmetItem != bApplyChangeToHelmetItem ;
       OnRep_CurrentHelmet();
}
#

they changed the if (!HasAuthority())to if (HasAuthority()) in somekind of tool like IDA or ghidra and recompiled the .exe

covert crow
covert crow
thin stratus
#

Ah it crashes the server itself.

sinful tree
nocturne quail
thin stratus
#

Yeah, Client recompiling would only mean they get past the ServerRPC. I don't see how this can crash the Server atm

#

It's simple enough to test if that's the error .Change the condition and play in the editor.

#

You'll crash there too and will see what it crashes on

nocturne quail
#

that method is called directly by client, this is guaranteed they don't have authority.

client is calling it and then it calls the server rpc, and server rpc calls that function back and then it fails on if(!HasAutiority()) and called the onrep function

thin stratus
#

You do understand that a Client modifying their gamecode can't affect the Server, right?

#

If the Client modifies the method like you showed, then all that will happen is that they will not call the ServerRPC and just call the bApply = and the OnRep

#

This shouldn't affect the Server.

nocturne quail
#

they call that function with modified if statement and then on server it repeatedly called and server crashed itself.
i builded client and server with a change to just test if they changed it and it crashes the server

thin stratus
#

Client change can't affect server. No matter how often you repeat that

nocturne quail
nocturne quail
#

I even tracked the ip and pc name of him who did it

#

attaching a debugger, the server crashed in this line

sinful tree
#

A client modifying their .exe doesn't mean the server is now using that .exe.
If the server is crashing, the only thing that a client could potentially do is send something unexpected to the server and then the server may behave in a way that is unexpected and crash.

#

In this case, there isn't anything unexpected being sent to the server.

nocturne quail
#

they are sending that rpc with new data

sinful tree
#

They aren't sending any RPC.

#

HasAuthority() would return false on a client.

nocturne quail
#

onrep is called by all client/server, and they are using the server method call the server on server

thin stratus
#

Missty :D this all makes no sense, sorry.

sinful tree
#

That's not how it works.

thin stratus
#

Clients can do whatever the fuck they want with their exe and code. This won't affect the Server

nocturne quail
#

I block that guy and now the server is not crashing

sinful tree
#

The server has its own copy of this function and the On_Rep.

thin stratus
#

The Server will call the code you compiled

#

Not the one the person compiled

#

Only their local game will do that

#

And that will nto affect the server

nocturne quail
#

its mean they were doing some more dirty sh*** , blocking them server not crashing any more

#

i just kick them on post login

thin stratus
#

If your server crashes from that, then you have a bug :D

nocturne quail
#

now the game is up for like 1.5hr and no crash

#

16 players are in the game

sinful tree
#

We're not doubting that someone may have messed up something...

thin stratus
#

This is tiring, Missty

sinful tree
#

But what it is they messed up has nothing to do with the code you've shown.

thin stratus
#

You post some random stuff, not listening when we tell you that it doesn't work that way

#

You aren't sharing what exact thing it crashes on

#

If your Server crashes, then cause you are doing something wrong in your game code

nocturne quail
nocturne quail
#

and it does only when that guy was connected

#

when i click continue, server just exit

#

I am very stressed right now ๐Ÿ˜„

#

and not sure what to debug, since no crashed after blocking him

#

they tried like +10 joins, everytime he kicked

#

this is my onrep method, i don't see anything wrong or bad practice.

void APawn::OnRep_CurrentHelmet()
{
    if (!DynamicHelmetObject) { return; }

    switch (DynamicHelmetObject->HelmetSlot)
    {
    case EHelmetSlot::E_Lv1: UpdateLv1(nullptr); break;
    case EHelmetSlot::E_Lv2: UpdateLv2(nullptr); break;
    case EHelmetSlot::E_Lv3: UpdateLv3(nullptr); break;
    case EHelmetSlot::E_Lv4: UpdateLv4(nullptr); break;
    case EHelmetSlot::E_Lv5: UpdateLv5(nullptr); break;
    default:
        break;
    }

    DynamicHelmetObject->SetEquipped(false);
    if (DynamicHelmetObject)
    {
        DynamicHelmetObject->ConditionalBeginDestroy();
    }

    if (IsLocallyControlled())
    {
        bool bCheckValid = DynamicHelmetObject ? 1 : 0;
        OnHelmetChanged.Broadcast(this, !bCheckValid, DynamicHelmetObject, DynamicHelmetObject->HelmetSlot);
    }
}
sinful tree
#

It's probably RPC buffer overflow or something then.... If they're modifying the OnRep to call the RequestHelmetChange() function, then they could be making their client spam the RPCs.

#

That could be flooding the server, which results in the server not properly being able to handle RPCs and something important ends up failing.

nocturne quail
sinful tree
#

But still.. the issue doesn't specifically lie here... It's what is happening afterwards as RPC spamming is basically a DDoS but I would imagine that Unreal has some built in protection for something like that.

nocturne quail
sinful tree
#

Theoretically, I wouldn't even need to use a game client to spam the RPCs. So long as I have a connection to the game server, I could send through whatever packets I want to it, so if I made the packets resemble RPC calls.... Boom.

sinful tree
#

Like... Does the software have some kind of CD-Key or something that you keep on record too, or...?

nocturne quail
nocturne quail
covert crow
mystic estuary
#

Hello, how do people handle knocking back players on hit? What I mean is that when a player is hit with, let's say a word, I want them to get pushed back.

So far I tried to do Character::Launch(), but it doesn't work, there's a ton of correction with 100 ping. I tried to not do that server-side only, to send a multicast, to predictively apply that (e.g. simulate sword swing sweeps client-side), but everything gave me the same results - a ton of corrections on the owning client

dark parcel
#

I don't think you should predict knock back.

#

at least that's the advice given to me, so I end up just applying knockback after damage (which is server side execution).

#

im using motion warp for the knockback but you can probably use ApplyForce which happend on server if you don't want to use montage (maybe).

nocturne quail
#

if a player controller is possessing a vehicle and they press alt+f4, is there a way to switch possession back to player before they leave?

#

the issue is they destroyed the vehicle when they press alt+f4 when driving ๐Ÿ˜„

fossil spoke
#

You have to override the function that causes the Pawn to be destroyed and then handle it how you need.

nocturne quail
nocturne quail
# nocturne quail I tested with BeginDestroyed and EndPlay, this doesn't work in my case
void AArmaVehicleBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    if (!IsValid(Driver))
    {
        Super::EndPlay(EndPlayReason);

        VehicleInteractionComponent->OnInteract.RemoveDynamic(this, &AArmaVehicleBase::OnInteract);

        GetMesh()->OnComponentHit.RemoveDynamic(this, &AArmaVehicleBase::OnBodyHit);
    }
    else
    {
        if (Driver)
        {

            HandleDetachment(Driver, SeatOneExit);
            GetController()->Possess(Driver);
            Driver->SetIsDead(true);
            Driver->HandleEndplayDeath();

            /*Vehicle Stop Logic*/
            bool bWasMoving = FMath::Abs(GetVehicleMovementComponent()->GetForwardSpeed()) > 500.0f;

            if (bWasMoving && IsEngineStarted)
            {
                SmoothDecellerate();
            }
            else if (bWasMoving && !IsEngineStarted)
            {
                //Put vehicle in neutral for 5 seconds and then SmoothDecellerate() // TODO
            }
            else
            {
                ResetVehicleState();
            }
        }
    }
}
fossil spoke
#

void APlayerController::PawnLeavingGame()

#

Its literally this function

nocturne quail
fossil spoke
#

Its called by void APlayerController::Destroyed()

nocturne quail
#

Ok got it

nocturne quail
#

Finally managed to write the system, testing now

void AArmaPlayerControllerBase::PawnLeavingGame()
{
    APawn* ControlledPawn = GetPawn();
    if (!ControlledPawn) return;

    AArmaCharacterBase* PossessedCharacter = Cast<AArmaCharacterBase>(ControlledPawn);
    PossessedCharacter ? Super::PawnLeavingGame() : (AArmaVehicleBase* PossessedVehicle = Cast<AArmaVehicleBase>(ControlledPawn)) ? PossessedVehicle->EndPlayDriver() : void();
}

void AArmaVehicleBase::EndPlayDriver()
{
    if (!Driver) return;

    HandleDetachment(Driver, SeatOneExit);
    GetController()->Possess(Driver);
    Driver->HandleEndplayDeath();

    float ForwardSpeed = GetVehicleMovementComponent()->GetForwardSpeed();
    bool bWasMoving = FMath::Abs(ForwardSpeed) > 500.0f;

    bWasMoving ? (IsEngineStarted ? SmoothDecellerate() : EnterNeutralState()) : ResetVehicleState();
}
thin stratus
#

if (!Driver) is not enough. This will crash if the Driver is pending kill.

#

Same with the ControlledPawn

#

Or the helmet pointer from yesterday.

nocturne quail
#

and yes for driver i should do isvalid(driver) thanks

thin stratus
#

No, you should always use an IsValid test

nocturne quail
#

oh, for uobjects also, i was thinking that only actors needs isvalid

thin stratus
#

UObjects are invalid if they are PendingKill. That won't clear the pointer.

#

Only once they are garbage collected they will be nullptrs.

#

In between that time, you will crash if you access them.

thin stratus
#

ControlledPawn PossessedCharacter PossessedVehicle

nocturne quail
#

Thank You so much for pointing these errors, its time to fix them ofcourse

mystic estuary
mystic estuary
thin stratus
#

Anyone here touched Iris and its ObjectFiltering a bit?

Kinda confused what one should use for a more dynamic approach if the Object might move between Groups often. DynamicFilters sound correct but at the same time, Objects can only be part of one DynamicFilter (based on the docs) and this is not a filter that should be the main and only DynamicFilter for this Object.

mystic estuary
# mystic estuary Shouldn't ApplyForce be called every tick? If I want to add a one-time force, sh...

I ended up dropping Launch as it caused issues because it tried to transition to Falling even though in my case it's a horizontal knockback. First half of the video is with launch, the other half is my thing
https://pastebin.com/1DS4y9cv

dark parcel
#

@mystic estuary what did you end up using?
Also do you end up with prediction?

mystic estuary
# dark parcel <@322346506571218967> what did you end up using? Also do you end up with predict...

I linked the pastebin with related cmc and knockback code. I do the prediction on the hit instigator side. The hit actor doesn't predict it, it gets an authoritative replication of the knockback impulse, and it follows that instead, and the hit target has the authority over the movement for a second~ (depends on ping and knockback strength, e.g. the more knockback, the more time for the authoritative move)

#

I have to test that in real world, but at least it's not giving me any issues in the editor, unlike launch

#

Launch was always giving me weird results even on listen server, the character was not actually sliding along the floor as I would expect

dark parcel
#

my issue with toggling client authorative movement was the moment it's switched back on, the character get corrected.
Doesn't seems like it's doing that on your end.

mystic estuary
#

I'm doing both

MovementComponent->bIgnoreClientMovementErrorChecksAndCorrection = true;
MovementComponent->bServerAcceptClientAuthoritativePosition = true;

not just the bIgnoreClientMovementErrorChecksAndCorrection

dark parcel
#

thanks, I will try that.

mystic estuary
#

bServerAcceptClientAuthoritativePosition makes the client tell the server its position, which means that it overrides whatever server is thinking

thin stratus
maiden abyss
#

With the push model enabled, if I have an actor component that contains a variable and I change the variable and mark it dirty, do I also have to mark the actor component reference in the actor as dirty?

bright summit
maiden abyss
# bright summit why? Did the reference changed? No

Thanks thats what I figured, but I just wasn't certain how it works under the hood as I remember reading something about replicating through the parent actor channels, but that might have been specifically for dealing with custom UObject replication and something totally different and unrelated to this lol.

bright summit
#

but I am working with actor components and the push model and I am not marking the component reference as dirty after change in component and I don't see any issues

maiden abyss
#

Awesome that confirms it well enough for me! Thanks a bunch

bright summit
#

np

mystic estuary
thin stratus
mystic estuary
thin stratus
#

You want to predict the knockback locally so it is somewhat responsive?

#

I'm pretty sure @meager spade has words of wisdom about predicting knockbacks.

#

Summary is usually: Don't.

mystic estuary
#

Yes, I'm trying to do that on the hit instigator, not on the hit victim

thin stratus
#

You'll get a "correction" on HitInstigator for the SimProxy of HitVictim.

mystic estuary
thin stratus
#

Cause that SimProxy works based on replicated information.
So it's at least VictimRTT/2 + InstigatorRTT/2 old.

mystic estuary
#

Hmm, makes sense

thin stratus
#

And when you forward predict it locally on Instigator, it will get "corrected", cause the old data of Victim will just override whatever you are forward predicting.

mystic estuary
#

Yeah, in case they're actively moving that will be the case

thin stratus
#

Instigator will eventually see Victim get knocked back

thin stratus
#

Which will override the knockback too.

mystic estuary
#

Oh, true

thin stratus
#

A MOBA I worked on opted for predicting the Knockback on the Victim instead, as that made sure that it felt butter smooth for them.
But that also means that the whole thing felt even worse on the Instigator.
Cause now you have InstigatorRTT + VictimRTT as time delay.

#

As it has to first go to the Server from Instigator, then down to the Victim, there it gets predicted, then back to Server from Victim and back to Instigator for SimProxy movement.

#

Which means, your best bet remains: Don't predict it.

mystic estuary
#

Yeah, doesn't sound good, alright, I'll see what Kaos has to say about it, but for now I'll leave it authoritative

livid gale
#

Question, anyone know how to assure that an added audio component only plays locally?
Right now everyone connected can hear everyone's audio.

quasi tide
#

Only create it locally

livid gale
#

Such as, is locally controlled condition check?

quasi tide
#

If it is supposed to be added to the player character - sure.

livid gale
#

Yeah, I have the audio component being added upon begin play.

quasi tide
#

Then it should only be on the local client's pawn.

livid gale
#

That's what I thought, as I haven't replicated anything to do with it. Yet, in testing on steam everyone can hear everyone else's audio which should only play for the local player, such as breathing.

#

Hence why I'm a bit confused

quasi tide
#

Show your code.

livid gale
#

this is just running off of the begin play node

#

and there is no replication ticked to true on the audio component

quasi tide
#

Show more code. This doesn't show anything really.

#

Show the entire Begin Play

#

Show what that interface method is calling

thin stratus
#

BeginPlay is too early for IsLocallyControlled.

quasi tide
#

I was thinking that too

thin stratus
#

Use the Controlled Changed Event or whatever it is called

#

And do it there.

livid gale
thin stratus
#

That calls on Server and ownign client.

quasi tide
#

That BeginPlay isn't even gated by an is local control check

livid gale
#

somthing like this then?

quasi tide
#

That is what you would want typically, yes. But also - like Cedric said, Begin Play is too early for possession related behavior

livid gale
#

one of these two I am assuming>

quasi tide
#

Which this boils down to because the Is Locally Controlled method will be checking the player controller

#

The Receive Controller Changed should get called on the client. OnControllerChanged is server only I believe.

livid gale
#

okay, I'll give that a go

#

thank you

torpid lantern
#

Can somebody please validate my understanding of garbage collection?

I want my server to maintain player states after logout. I am creating a "Persistent Player Entity" actor and spawning it into my game world, I am then putting a ref to that actor in the game state array and also on the player controller.

But this actor is being garbage collected almost immediately. I thought that if a reference is maintained, then the GC won't remove the actor. What am I doing wrong?

thin stratus
quasi tide
#

I'm pretty sure one was added after the other because the pawn's controller being changed would only ever be called on the server.

thin stratus
#

fyi, UE already has logic to retain the PlayerState and re-instantiate it. Not sure if that supports being alive "forever" though.

#

Should be some setting in the GameMode class

#

And PlayerStates have an "OverrideWith" function to move the data.

quasi tide
#

You can increase how long it remembers the player state I believe. If that is the case, theoretically...you can make it forever enough ๐Ÿ˜…

thin stratus
#

Yeah, given the Server has to be restarted eventually, you won't get around saving the data somewhere permanent anyway.

#

Might as well start with that :D

#

The inactive PlayerState stuff that is builtin is usually used for like a player that had a short disconnect and wants their info from the current session back. Like a player that had an issue with their internet in Unreal Tournament who doesn't want to lose their Kill/Death stats.

#

The stuff you do works too, as long as you can identify the player based on some unique ID.

torpid lantern
#

That's kinda what I am looking for. Server lifespan is 4 hours and I want the player to be able to resume.

thin stratus
#

That's usually provided by the backend/OSS.

#

Are you using any known OSS that provides a proper UniqueID? Like Steam, EGS, or so?

torpid lantern
#

I am using Steam + PlayFab

thin stratus
#

Then the PlayerState should h old the SteamID and the player that reconnects would get a chance to get their data from the inactive PlayerState found via the UniqueID.

#

Which then would call OverrideWith in the PlayerState.

torpid lantern
#

Exploring that now. Do PlayerStates persist by default, or do I need to set some flag?

thin stratus
#

The original question though: The Actor shouldn't get destroyed if you spawn it into the World. Doesn't matter that you ref it in some other actor.

#

Logout will destroy the PlayerController though, so that ref isn't much worth.

quasi tide
thin stratus
torpid lantern
#

Works like a charm! You saved me from creating a redundant system, thank you!

exotic wasp
quasi tide
#

You have to build it yourself

#

Movement corrections are generally handled already via the CMC

#

At least basic movement

west basalt
quasi tide
#

It's difficult regardless

undone needle
west basalt
exotic wasp
#

networking prediction is just difficult

#

the character movement component does prediction and is fine for like 90% of cases

#

there is a network prediction plugin in unreal but i honestly know nothing about it and it has really limited support afaik

#

the new movement component, mover 2 uses it, but it is also not easy to get into using

#

mixed opinions on it here in terms of use readiness

wanton sleet
#
            USplineMeshComponent* SplineMeshComponent = Cast<USplineMeshComponent>(AddComponentByClass(USplineMeshComponent::StaticClass(), false, IndexTransform, false));
            SplineMeshComponent->SetMobility(EComponentMobility::Type::Movable);
            
            SplineMeshComponent->SetIsReplicated(true);

            // SplineMeshComponent->SetCollisionEnabled(ECollisionEnabled::Type::QueryAndPhysics);
            SetSplineComponentCollision(SplineMeshComponent);

SetSplineComponentCollision is MultiCast function. SplineMeshComponent is nullptr on client-side. I think I should wait for a time to construct the object on client side. Is there a event that I could listen to call the function to work properly?

sinful tree
prisma snow
#

This question has probably been asked like hundreds of times, but what's the recommended way to get the player controller for a multiplayer game, if we want to get the controller that represents the actual player (handling input, UI etc)?
In both Clients and Listen Server.

latent heart
#

Depends โ„ข๏ธ

#

What's the context?

dark parcel
#

GetPlayerController 0 should return the local controller for listen server / client.

prisma snow
# latent heart What's the context?

Basically, retriveing the local player controller so that I can do UI/input logic - show/hide a widget, or route data into one, handle input (mouse clicks, keyboard presses etc).
It wouldn't be used for server logic

latent heart
#

I mean what from context are you making the call, not what are you going to do with it.

prisma snow
#

Mmm mostly from actors and subsystems

#

Also there's no split screen to be worried about

dark parcel
#
APlayerController* UGameInstance::GetFirstLocalPlayerController(const UWorld* World) const
latent heart
#

You can get the game instance from teh world, which you can get from your actor.

prisma snow
#

yeah exactly

#

perfect then

#

thanks both!!!

exotic wasp
#

if your actor is a pawn you can also crawl up and get the controller

prisma snow
#

yeah but I am precisely avoiding that (which is the current setup) because we'll have a slightly different "control" flow. We're doing an RTS and I want to support something like the "Archaon" mode in SC2, with multiple players controlling the same "player" if that makes sense

latent heart
#

Or anything actually owned by the player itself.

#

Never do the "get first local player controller" or whatever if you actually have a locally controlled pawn or widget or whatever to get the reference from.

exotic wasp
#

that sounds really cool though

prisma snow
# exotic wasp hmm, what does the actor need from the controller then? should it just be one wa...

mostly nothing, there are very few instances. But for example, PlayerController has an array of selected entities. If you are selecting a builder and order it to construct a building, it gets automatically "deselected" just for player convenience.
So currently we get the PC owner, but that won't work if we want units to be controllable by more than one player. So getting the local player controller makes sense in that scenario since that player is the only that cares about his own selection

prisma snow
dark parcel
#

My deselect is a MC event :D, feels wrong but I guess that's how it should be?
A.I dead in server -> MC Deselect on LocalPlayer Targeting component.

#

any input?

prisma snow
#

if the "dead" state is somehow replicated just have an OnRep and deselect locally no?

dark parcel
#

hmm gonna check my code again

#
void AAGEnemyCharacter::Death()
{
    Super::Death();
    // This function only called on server.
    GetCharacterMovement()->bRunPhysicsWithNoController = true;
    GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);

    // Turn off avoidance.
    GetCharacterMovement()->SetAvoidanceEnabled(false);

    CurrentState = EState::Dead;
    Mobility = EAGMobility::IgnorePawn;

    // Remove this character from targeting.
    TargetingComponent->RemoveFromSelectedActorTargetData();
    
    // Call client logic here.
    MC_Death(this);

    
    // AI death, stop logic and UnPossess.
    AAGEnemyAIController* AIController = Cast<AAGEnemyAIController>(GetController());
    if (AIController)
    {
        AIController->UnPossess();
        GetCharacterMovement()->StopMovementImmediately();
    }
    
    FTimerDelegate TimerCallback;
    TimerCallback.BindWeakLambda(this, [=]()->void
    {
        // Remove collision with other pawn after a short while.
        Mobility = EAGMobility::NotMoveAble;
        GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
    });

    FTimerHandle Handle;
    GetWorld()->GetTimerManager().SetTimer(Handle, TimerCallback, FMath::RandRange(0.75f,2.f), false);
}

void AAGEnemyCharacter::MC_Death_Implementation(AAGCharacterBase* UnitToDeselect)
{
    
    // Deselect this character from locally controlled player that is targeting this character.
    UTargetingComponent* l_TargetComponent = TargetingComponent->LocalTargetingComponent();
    l_TargetComponent->DeselectUnitFromThisTargetingComponent(UnitToDeselect);
}

Hmm yeah, why the f i didn;'t have OnRep here.
I think from what I remember, I am hoping GAS took care of the visual (dead anim) for late joiners.

#

haven't test though.

#

and I think something like deselect is a one off event.

#

so I think MC is okay?

prisma snow
silk kayak
#

okay

fallen fossil
#

I increased lag emulation, and my spawner twitsted in weird way. Can I make it somehow relevant so it updates only from OwnerClient to Server? and not back? ๐Ÿค”

quasi tide
#

Why is that not just running locally? Do other clients even need to see it at all? The spawn box that is.

kindred widget
#

Even if they do need to see it. This is client authoritive stuff. Placing client should be moving this locally like Duro said and then telling server where it's moving it. Final placement can of course be server auth.

#

Very similar to how your look input is done.

fallen fossil
#

I only enabled replication and replicate movement. its done locally

kindred widget
#

It's not done locally if it's lagging.

#

Or it is and you're getting server corrections. Either way it needs to be owned by the client placing it. Then your replication placement can skip owner but on rep for everyone else while owning client gets a nice smooth placement update each frame.

fallen fossil
#

i got drop packages set to 5%

kindred widget
#

It doesn't matter.

fallen fossil
#

LogBlueprintUserMessages: [A_HeliBoxSpawner_C_0] Server: SpawnerBox: seting rotation: P=7.279199 Y=-48.471649 R=-18.822554
LogBlueprintUserMessages: [A_HeliBoxSpawner_C_0] Client 1: SpawnerBox: seting rotation: P=0.000016 Y=-43.395786 R=0.000017
LogBlueprintUserMessages: [A_HeliBoxSpawner_C_0] Server: SpawnerBox: seting rotation: P=7.279199 Y=-48.471649 R=-18.822554
LogBlueprintUserMessages: [A_HeliBoxSpawner_C_0] Client 1: SpawnerBox: seting rotation: P=0.000016 Y=-42.695873 R=-0.000000

#

:<

kindred widget
#

You should be able to have 0.5s latency and still be able to smoothly place that locally. There should be zero networking in the placement for the local user outside of the local user telling the server where it should be placed.

fallen fossil
#

i think i need switch in tick

#

this is for player?

kindred widget
#

Not quite. It needs to be owned by the local player, and it's ownership needs checked. Similar to Pawn's IsLocallyControlled. Server is still the "Authority" networking wise.

fallen fossil
#

is there node for this in ue4? Or I have manually compare owner PC and local PC ๐Ÿ˜„

#

GAs ๐Ÿ˜ฎ

#

yolo

kindred widget
#

I don't think actors have a function for that. Unsure.

quasi tide
#

Pretty sure it is just - GetOwner

kindred widget
#

It should mostly just be GetOwner->CastToPlayerController->IsLocalController.

#

Assuming you set it to be owned by their controller.

fallen fossil
#

works like charm

#

thanks

#

one question, is this node part of Unreal or this SDK im using?

kindred widget
#

I want to say not default. Specially if you're on ue4

quasi tide
#

Can confirm - that's not default

#

Never seen that node before in my life.

grand kestrel
#

Have you seen every node at some point in your life tho
Jk it isn't default

torpid crest
#

Hey guys! ๐Ÿ‘‹

Iโ€™ve been using data tables with object references in my project, but I just realized that my player pawn has a size map of 1.2 GB in memory.
Itโ€™s loading all the meshes and textures for every object in the data tables.

My plan is to convert everything to soft references, but that involves running a blocking LoadAsset function. Iโ€™m not sure if thatโ€™s viable for multiplayer.

quasi tide
#

So don't run the blocking version

#

Run the async

#

And it is absolutely viable

#

Pretty much every big game does it

#

I'm sure small games do as well

#

But depending on the size - they may not

sinful tree
torpid crest
quasi tide
#

Then don't have it as a function

#

If this is inside of an onrep - just call an event inside of that onrep

torpid crest
#

hate things in event graph ๐Ÿ˜„ but if it's necessary

#

so be it

quasi tide
#

Async is only possible in the event graph

torpid crest
#

yeah like every other timed thingy

frail barn
#

i have 2 game modes, "battle mode" and "main menu mode"
when i test battle mode, spawned and possessed character works fine, but, when i start from the main menu mode, spawned character dont run "remote" branch at all, and i dont have idea why its happened
any hints?

sinful tree
frail barn
sinful tree
#

If you are creating a session through your main menu, then that usually means you're creating a listen server session.
Usually after creating a session it's followed by opening the level with the ?listen option to make it so that instance starts as a listen server.
Dedicated servers can be made to also create sessions, but they usually would do this automatically on their startup, and you would join it from a client, but you wouldn't have the client create the session for the dedicated server.

frail barn
sinful tree
# frail barn yes, i create a session and open level with "listen" so, this lack of remote bra...

No.
The issue is in what Authority means.
If you're running the game single player, Has Authority would always return Authority.
If you're running a Listen Server, the host would always return Authority. Clients would only return Authority if it's an actor locally spawned on the client.
If you're running a Dedicated Server, the server would always return Authority. Clients would only return Authority if it's an actor locally spawned on the client.

#

So if your intention is to only allow dedicated server play, sure, changing your game entirely to only use dedicated servers would mean that only people actually playing the game would normally go through the "Remote" path on replicated actors.

#

But, that's not really a fix if you're intending on clients being able to create sessions and host listen servers.

cerulean barn
#

why is this happening lmao

frail barn
fallen fossil
#

When player leaves game, does PC ref gets nullified? and owned actors gets destroyed? ๐Ÿค”

sinful tree
cunning orbit
#

Does the thread of execution following a reliable RPC "wait" until the RPC completes over the network in order to continue execution?

fallen fossil
#

thanks

sinful tree
# cunning orbit Does the thread of execution following a reliable RPC "wait" until the RPC compl...

What you're asking isn't exactly clear, but at face level, the answer would be no. Reliable RPCs send their RPC and wait for a response back from the other side to indicate they've received it, and if not within a certain amount of time it'll attempt to resend the RPC and again wait for that confirmation, repeat ad nauseum untli a response is received. It's not really waiting for it to be executed on the other side, just that the other side has received the RPC and a confirmation has been sent back indicating that it was received.

#

An RPC acts just like a function, and any further functions you are callling after it will still be executed on the sending side. The receiving side will execute whatever you've defined in the RPC 's implementation when that RPC is received.

cunning orbit
#

Fair enough, here's an example

#

So the "Print String" would not execute until the reliable RPC returned correct?

sinful tree
#

No. That print happens immediately after Server Add Spirit is called.

#

RPCs have no "return".

cunning orbit
#

Ok, so that's what I'm attempting to articulate. The thread of execution does not "wait" until the reliable RPC gets a "response back"

#

Awesome, thanks for the clarification

sinful tree
#

Correct.

cerulean barn
dark edge
cerulean barn
#

The problem is if it has authority and is locally controlled it wonโ€™t attach to arms because thatโ€™s done in the onrep function

cerulean barn
#

Bp

dark edge
#

bp onrep should fire on server

#

what is the rule for attaching to arms?

cerulean barn
#

wdym rule

dark edge
#

are you attaching to different skelmeshes or at a different socket depending on if locally controlled or not or is there just 1 attachment point for all machines and all pawns?

#

Is it just:
OnRep_MyGun -> attach MyGun to Skelmesh at socket Arms

cerulean barn
#

so yeah it does run on the server i checked

#

why is it applying the gun on the arms differently on the server-client then a regular client?

dark edge
#

do you set Rifle on begin play or after things are well established?

dark edge
#

like 1s later

cerulean barn
#

the attach gun?

dark edge
#

the onrep

cerulean barn
#

ok

dark edge
#

also show what AttachGunToPlayer does

cerulean barn
#

that fixed it lmao

#

should i keep it like this or lower it?

#

or is there a way to do it without the delay

dark edge
# cerulean barn

i mean manually call the same code the onrep is, just a bit later. Don't put a delay in the onrep

#

Curious if there's some sort of race condition. There shouldn't be, but just checking

#

The onrep is probably being called before the controller is ready

#

BeginPlay -> hook up input -> spawn gun -> set replicated MyGun var -> attach gun to arms
Onrep -> attach gun to arms

#

that should cover it

cerulean barn
dark edge
#

I bet that Onrep is happening before begin play, maybe see if there's a way around that, maybe disable tick before begin play but idk if onreps require tick

dark edge
#

sequence is just syntactic sugar for a long chain of logic

cerulean barn
#

with that delay i added, now the third person mesh is messed uyp

dark edge
#

A -> B -> C -> D
and
A -> Sequence -> B
-> C
-> D
Is the exact same thing

cerulean barn
dark edge
#

Does the gun have replicate movement turned on?

cerulean barn
#

yes

#

replicate movenemtn

#

idk actually

#

if i put this at the end it doesn't work

#

im guessing because add mapping context is a local controller only?

dark edge
#

yes

#

This would be identical, as you can see the sequence makes it a bit cleaner

#

the failure paths would still lead to the gun spawning

cerulean barn
#

ill just leave the seuqnce

#

sequence

#

is that bad practice?

cerulean barn
cerulean barn
#

i feel like this is what i am doing exactly

dark edge
#

whats the difference between mesh and arms?

cerulean barn
#

the third person mesh

#

onrep i attatch to the first person arms

#

sorry i should have been more clear

dark edge
#

what you should do is:

Attachment -> Are we locally controlled? -> yes -> 1st person
-> no -> 3rd person

cerulean barn
#

doesn't the server have to attach to the third person body though

dark edge
#

no, that rule applies everywhere

#

the gun is attached to the 3rd person body except in the case that the pawn is locally controlled, it's then attached to the 1st person arms or whatever

cerulean barn
#

so i dont even need to check if have authority?

#

but if i attach the gun without authority isn't that just client sided

dark edge
#

just make sure replicate movement is NOT on for the gun

dark edge
#

where the gun is depends on the machine, the machines local pawn has their gun in 1st person, all other pawns on that machine have the gun in 3rd person

cerulean barn
#

the way i learned it is the server attaches the guns to the meshes and the client side does the first person arms

dark edge
#

whether a gun is in 3rd or 1st depends only on if the pawn holding that gun is locally controlled

cerulean barn
#

is that wrong

dark edge
#

sounds pretty wrong to me

#

I mean you could probably make it work

cerulean barn
#

brah

dark edge
#

but it seems kinda goofy

cerulean barn
#

whats the commonly used pracitice

#

@dark edge still use the server to spawn in the gun though right?

dark edge
#

the server spawns the gun and says what MyGun is

#

but the server does NOT say where the gun is

cerulean barn
#

okay

#

let me fix that up then one sec.

humble plume
#

Issue:
Data copies for Clients correctly but ListenServer's local player state fails on level transidtion

Relevant information:
Listen Server
Using Seemless Travel from a Lobby to gameplay level
Using override on CopyProperties in playerstate to preserve some data
Breakpoints are failing on this override for the server's playerstate as well
Engine Version 5.5
For screenshots I have reduced the player count to JUST the server but I can demonstrate that the function correctly works for clients.

I am saving a team number and color data in a copyproperties override. I test with 2 clients and a the server and the clients work great. however the server's player fails. and debugging is proving difficult.
I have checked the data is being set correctly before server travel and the input data at the time of setting in the lobby is accurate however my print during travel fires and shows default values for the host unlike the client.
This all seems wierd as it confirms the event DOES fire for the server. but all the logic is failing? Strangely enough my breakpoints only fire for the client members and my output log displays: "Display: Encountered a blueprint breakpoint in /Game/Assets/GameModes/CarShooterPlayerState.CarShooterPlayerState without an associated node. The blueprint breakpoint has been removed"

Anyone have some insight on this?

cerulean barn
#

this isn't working

dark edge
#

authority would only spawn

cerulean barn
#

it doesn't but regardless the third person guns aren't staying on the character

#

just spawning in at that point

dark edge
#

BeginPlay -> authority? -> yes -> spawn and set MyGun -> call attach code
OnRep_MyGun -> call attach code
Attach -> local? -> yes -> 1st person
-> no -> 3rd person

cerulean barn
#

i forgot this branch

dark edge
cerulean barn
#

showing now

cerulean barn
dark edge
#

show the actual onrep for MyGun

cerulean barn
#

ye

#

it all works

dark parcel
#

Show

cerulean barn
dark parcel
#

Beware with calling it too early.

#

If this gets run before possession happend for example.

cerulean barn
#

not sure why i am getting all of this

dark parcel
#

Then your check will give "incorrect" result

dark edge
#

race conditions all over the place

cerulean barn
dark parcel
#

@cerulean barn have you go over the pinned msg? It's mandatory

dark edge
#

validate rifle var

dark parcel
#

Do note that client only have their own controller.

cerulean barn
dark edge
#

oh yeah that too

#

you want to check is locally controlled, not is local controller

#

i think that might be in pawn? Not sure

#

anyway the happy path is if you can get the controller at all and its local so if you can't get a controller it's remote

#

welcome to multiplayer

cerulean barn
#

use is locally controlled - self ?

#

without get controller?

dark edge
#

a client only has their own controller, it does not have other ppls controllers

cerulean barn
#

still getting all of these

dark edge
#

show current code

#

all of it

cerulean barn
dark edge
#

that's either doing nothing or clearing the owner on self

#

neither of which is what you want

cerulean barn
#

deleted

dark edge
# cerulean barn

that might be the rifle var being replicated before the rifle actor itself is

#

does a small delay in OnRepStuff fix it?

cerulean barn
#

the errors?

dark edge
#

yes

cerulean barn
#

how i had it before>

#

?

dark edge
#

test

#

put a small delay in OnRepStuff and check if errors disappear

cerulean barn
dark edge
# cerulean barn

also don't duplicate code, this is basically a copy paste of onRepStuff so just call OnRepStuff here

cerulean barn
#

yeah i realized that

#

cuz before i had more shit

dark edge
#

is a rifle a replicated actor?

cerulean barn
#

yea

dark edge
#

You sure? Does 1 rifle show up on every screen for every pawn?

cerulean barn
#

everything works good

#

just the errors

dark edge
#

click and show what bit of code it doesn't like

cerulean barn
#

i dont understand how these errors work

#

im new to all of this

dark edge
#

you can click the underlined bits to jump to where it actually errored at

cerulean barn
#

the gun probably wasn't attached yet im guesing?

dark edge
#

that's the path that's failing

cerulean barn
#

?

#

this

#

oh yeah that fixed it all

#

thanks man

#

im new to all of this visual scripting stuff

#

i know c++ but i feel like this is easier since im new to unreal engine

dark edge
#

What was happening is it was trying to attach something that wasn't spawned yet

#

it would have been ruled out by an IsValid check on RifleVar as well

#

which you should probably implement, RifleVar being not valid means you have no weapon

cerulean barn
#

oh right because the gun wasn't spawned yet

dark edge
#

or at least wasn't spawned on that machine yet

#

multiplayer gets crazy like that

#

maybe the ref is here, but the thing it refers to isn't yet, all sorts of race conditions like that

#

idk if the actor is guaranteed to be there before the ref is, that's worth checking

#

you testing with packet loss and latency?

cerulean barn
dark edge
cerulean barn
dark edge
#

Test with that on

#

advanced settings

cerulean barn
#

network emulation?

dark edge
#

ye

cerulean barn
#

what does that do

dark edge
#

what it says on the tin

#

emulates packet lag and loss

#

I'd do the average or bad profile and server and clients

#

you don't want a game that works great until you test with 2 computers, then it shits the bed

cerulean barn
#

im just trying to make a game for me and my friends

#

once i get the basics then i might worry about the other stuff

dark edge
#

just set it and forget it on at least average settings

#

that way you don't go to test with your friends and it doesn't get past the spawn screen

cerulean barn
#

oh here?

dark edge
cerulean barn
#

the characters r glitching around tho

dark edge
#

time to get to work

dark edge
cerulean barn
#

is that a code fixeable issue

dark edge
#

so you gotta fix it

#

something is working when you have zero lag but breaks when you have some

cerulean barn
#

default first person template

dark edge
#

show a clip of it messing up and I can tell you where to start looking maybe

dark edge
#

turn off "Hidden in Game" on it

#

and make the lines thicker

cerulean barn
dark edge
#

The capsule's lines

#

so you can see how its moving and rotating

#

to see if the capsule + mesh or just the mesh is snapping

dark edge
#

could just be the character mesh interpolation stuff

cerulean barn
#

just with my skeleton

#

that prob might be bad

dark edge
#

test it with no anim bp just with a static pose or animation

#

easy test

cerulean barn
#

my third person mesh?

dark edge
#

yeah

#

where you choose the anim bp, you can just have it play an animation

#

see if it does it then, that'll narrow it down between the mesh snapping or the animation

cerulean barn
#

nope i turned it to none in third person bp

#

it's still glitchy if not more

dark edge
#

Probably want to tune these

cerulean barn
#

but is that what is causing the glitchiness

dark edge
#

network smoothing

#

you're running, then you suddenly stop

#

smoothing overshoots a bit

cerulean barn
#

what should the mode be?

#

disabled?

dark edge
#

Dunno, will have to play around with it

#

probably not disabled no lol

cerulean barn
#

what does this do

dark edge
#

lots

#

the CMC is a giant bit of code

#

but basically the server isn't sending you positions at 240 hz, it might be at 30 or so

cerulean barn
#

im just trying to use all default stuff to fuck around what is the default general mode

dark edge
#

so the end result is visually smoothed

cerulean barn
#

for smoothness

#

yea its defintely capping the fps

dark edge
#

I'd probably start by messing with the distances and trying linear smoothing mode

#

and maybe try the skip proxy prediction

#

that might get rid of the overshoot completely

#

but it'll introduce a bit more lag. Nothing a player would feel but more lag between a player moving and others seeing it

meager spade
#

anyone use iris?

#

ReplicationDisabled from client ConnectionId: any idea what this means

cerulean barn
#

whats like default good settings

#

shouldn't there be a generic thing

dark edge
cerulean barn
#

its laggy with linear and network skip prediction

#

but its default first person template

dark edge
#

what's good for snappy movement isn't good for realistic acceleration etc

dark edge
#

make sure to also enable the same network emulation settings

cerulean barn
#

the default template doesn't have third person in it

dark edge
#

doesn't matter

#

what you're seeing is the character mesh overshooting due to smoothing/prediction when you suddenly stop

#

wait, which mesh is your characters mesh and which is additional, the 3rd person or the arms?

dark edge
#

test a default template with the same settings and see if you see the same rubberbanding

cerulean barn
#

my actual character mesh is empty

#

i just realized

dark edge
#

or at least attached to it

#

the characters Mesh is special, lots of code is involved with messing with it

#

it should probably be state driven just like the attachment

#

that is, you attach gun to mesh no matter what, but the mesh is 3rd person if not locally controlled and 1st person (arms) if locally controlled

#

so 1 mesh component instead of 3 (with the default one empty)

cerulean barn
#

when getting the mesh i just get TP body tho

dark edge
#

so all the smoothing stuff it does doesn't happen

#

at least attach body to the empty mesh so anything done to empty mesh happens to it as well

cerulean barn
#

i can't tell if the capsule is lagigng on the firs tperson build

#

its hard to tell with just the capsule

dark edge
#

instead of to the capsule

cerulean barn
#

like this?

dark edge
#

try that

cerulean barn
#

still glitching around

#

way more on my game then the template tho

cerulean barn
dark edge
#

figure out what's different between them and play with the smoothing factors

humble plume
#

Issue:

molten vine
#

@meager spade You said you had a working killcam prototype. Did you get the killcam to play on the Listen Server? It plays on the listen server for me, but after the replay ends, the client movement bugs out. Almost like there's an authority issue, even though the authority doesn't change.

meager spade
#

No we use dedicated servers not tested on listen server

nocturne quail
#

why the building door gets closed when client rejoins?

void ADoorBase::ToggleDoor()
{
    if (HasAuthority())
    {
        if (DoorTimeline->IsPlaying()){
            return;
        }
        IsDoorOpened = !IsDoorOpened;
        OnRep_ToggleDoor();
    }
}
#

for example, client joins the game, opened the door and leave, when they rejoin the door is closed on client

#

but on server it is still opened

#

doors are spawned by buildings at runtime and they are set replicated

dark parcel
#

@nocturne quail what about just playing the anim on the OnRep logic?

#

The cons is late joiners probably see door open/close when they first join.

Can probably address that though by adding more info.

Maybe onRep a struct

#

Can probably just replicate a float for the client to check where in the timeline the anim should be

nocturne quail
#

but currently the state only updates on server when client join back