#multiplayer
1 messages ยท Page 250 of 1
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
of they spoofed, they are inviting bann
How are you going to be able to tell if spoofed?
vibe check
it will not match with their IP and bann will execute
Like, sure, 0000-0000-0000-0000-0000 is easy to catch ๐
(or however many characters are in a MAC address... probably more...)
New spoofed MAC and they use a VPN
so what if they use vpn, their ip will again not match and they even can't join
That's fair, but how do you register players then?
if they registered an ip of their vpn, it will be rejected
original ip and their choosen mac
yeah
I feel like this personality coded ESO's guild trader UI's string search.
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
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.
That's a good point
Hey guys i got a great anti-crime idea
anyone who gets accused of a crime just gets shot
all criminals will get shot
they send me their ip and mac, and request to resister.
i created a text file for that person having the ip and mac, server will allow him to connect only if this text data matches with his login request
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
Do you accept telegrams?
Adriel I think someone already had that idea
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
Anyways this is a whole lot of discussion for something that will obviously not work
Okay, it may work for what you're doing
but I just reinstalled Windows and my DeviceID is different
i'm happy no need to depend on steam
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.
you can change it back with two clicks
Of course its better to use Steam in the long run, or something else
If you want to buy my game you gotta come find me personally and kiss the ring
also I only take wampum
I like do things independently
This conversation more or less started from here. #multiplayer message
Yeah I saw lol
Why did they reject it?
arma already exists in steam ๐
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
i'm researching it from like 2 years by now
i am confident in what i am doing :d
Well yeah, because Arma is a game that's owned by somebody else
Okay, good luck anyway
why would anyone play your bootleg arma that they have to jump through gobs of hoops for?
yeah, and my game name is also arma
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.
I do understand the interest to make it yourself
well, steam did a good thing to reject, it give me a chance to be independent ๐
and i did it
Why would you copy their name?
Why not just come up with your own, independently?
I started this project with this name, was just a learning project ๐
Change the name, it's 2 clicks
Red Solstice 2's project name is Twinstick. ๐ That's a terrible reason.
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
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
it would take minimum 30 days to change the name of it
yeah, but its using everywhere arma
my project i mean
and that tiny inconvenience is worth throwing the game right into the garbage?
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. ๐คทโโ๏ธ
You actual thief, now we can't both play bootleg Arma!
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.
this even printed on the textures inside the game ๐
Here's how things can go:
- Nobody buys it, nobody plays it, nothing happens
- Lots of people buy it and love it and play it, Bohemia Interactive sues you.
lots of things needs to be changed ๐ซ
better get cracking
Starting with the project manager.
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 ๐
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. ๐
theres always that 1 programmer lmao
I mean i'm generating unique ids using the user mac and ip/range that they will register for the game.
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;
}
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?
Sounds like your OnRep code is fine. But something else is setting it or resetting it later.
I have tried using print string to check if it runs only once. it does. I also checked the amount of spawned characters and it shows just 1.
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.
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?
Yes
Ok follow up one
Woah woah woah
its simple
You said quick simple question
haha
Singular
No
lol
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
So yes how is this function treated in the networking context when it's explicitly called and not called on rep?
ah so its local
- Variable changes on server
- UE replicates this down to clients
- UE calls the onrep on the client
Ok so the OnRep in this case would be client only
Yes. In C++, the server has to call the onrep manually. In BP - it doesn't.
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
Properties are only ever replicated server -> client
K
have to rpc changes from client to server
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
Why would it be valid when you destroy it?
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
Ah, separate ref variable
I find it hard to read when the nodes are behind things but I understand wanting to stay compact
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
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
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
You can update sessions though
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.
That's for a blueprint only system I want to sell on the marketplace, so I can only use the native ones unfortunately
They do though
Maybe cause you are testing with SubsystemNULL, where there is no backend :P
There is just this problem with the 0 players
could be, yea
As soon as someone plugs steam into that, it will probably not work.
So is there no way with the native nodes setup?
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?
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
AGameModeBase::Login -> AGameModeBase::InitNewPlayer -> AGameSession::RegisterPlayer -> APlayerState::RegisterPlayerWithSession -> IOnlineSession::RegisterPlayer.
Since you ServerTravel, you aren't calling Login again.
I am calling Event handle new player or whatever it was called
Cause that gets called
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.
So with the native nodes it's not exactly possible to create something like a party system
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.
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
I guess so
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.
Can i replicate the blueprintsessioninfo struct though?
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.
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
Not sure. The UniqueId of a Player can be replicated fwiw.
But this is all very much C++ area.
No worries, good luck
should I assume that replicated variables are reliable ?
they are reliable
That doesn't mean quick, though.
can someone confirm this is the proper way of removing player from the lobby system array. https://blueprintue.com/blueprint/gneuaynq/
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)
GameState is Server owned. You can't run Server/Client RPCs on it
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
GameMode isn't even accessible by clients. So whatever you mean is probably not that the client runs some function on the GameMode
RPCs would need to go into any client owner actor
PlayerState PlayerController possessed Pawn/Character
Whatever fits your needs
I have this running for when player wants to switch team.
it goes into gamemode and server does the new character selection
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
(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
That looks fine. What part of it doesn't work
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
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
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
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
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.
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
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 ?
A simple interaction like a light switch or door usually requires you to have the client send an RPC to the server with a reference to the actor they want to interact with on a replicated actor they already own (player controller/controlled pawn/playerstate or a replicated component of one of these) and then have the server replicate the results of the interaction with the desired actor.
ok, interesting idea ๐ค
if you mean like multiple players owning the same actor, it isn't trivial to mimic iirc
You do the rpc through a thing the player owns (pawn or player controller) then do whatever you want from there.
The server owns the thing, and the serverside version of the players pawns or player controllers give it commands.
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
No
Subsystems are local
It's as simple as a networked door
Pawn/PlayerController
Input -> rpc
Rpc -> tell Thing to do thing
PCs exsist on server right ?
Yes
oke ๐ค
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?
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
I'm having issues getting my Name tags to display the correct color it's currently only working with sever and client 1.
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?
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.
Sounds like you're probably using some kind of physics system for your vehicle in which case you're probably moving the scene components rather than the vehicle actor itself.
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
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.
Attachment has always been replicated. And there's no way around it without engine changes. This is why in cases like where you have a weapon, you'll have a FPS and TPS weapon mesh in the same actor that get attached to two different meshes on the character.
Could you give an update if you find a solution? I have the same problem.
Break in IsNetRelevantFor in your actor that should be relevant. If you make it all of the way to IsWithinNetRelevancyDistance, see why the view location is too far from the intended actor.
debugging using net.DebugDraw and it's defo looking weird
seems like the viewtarget/location isn't changing
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?
This is one of many cases where you find out the hard way that you need to refactor part of the game's code, since it doesn't have proper documentation.
update: it's using the camera manager's cached viewpoint which isn't updating for some reason
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
fixed on my end
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...
Does bReplicateMovement work in tandem with the new Predctive interpolation features?
I just made it set that bool to true if the player was in a moving vehicle, every tick.
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
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
Oh, ok I just need to pass it to a variable first, that makes sense, thanks!
Hi there i have trouble to destroy an actor on the server.
Steps:
- I show a widget for the item name
- 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.
Its Something with the owner ship. So it works but only with the beginoverlap method
Triggered runs every frame btw.
Use started to fire when the input is pressed.
Don't like the use of ownership there.
changing owner like that is usually always not the right thing to do IMO
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"
and is also probably causing his issue
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
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
when you use seamless servertravel, even if gamemodes are different, will their playercontrollers survive the transition given that both gamemodes use same playercontroller class?
Think so, yeah
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?
Input is always local so multiplayer doesn't really factor into it.
Multiplayer doesn't really change that? Just put it where it should be.
Ok Iโll keep it in pawn because itโs simpler that way
You should place it where it's context-wise used.
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.
Digged some more and to be able to copy properties there is a c++ function for it.
otherwise yeah it worked, also thanks for responding
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
);
}
}
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
Anyone else encountering issues with PostReplicatedChange not firing properly?
Yop, PlayerStates also have one, although they are always recreated iirc
There is a method that takes care of destroying the possessed pawn when the controller gets destroyed. You can just override that I guess
But you shouldn't delay destroying the controller
Can anyone help me understand why I get this movement jitter when a player stops moving? it's literally just the first person character, with 2 static meshes attached for the body + head
https://imgur.com/a/vDmnSy2
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?
Are you using character movement component?
This is due to movement extrapolation assuming this is a cmc
is this a cmc?
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:
-
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) -
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
PCGPartitionGridActorwhich is the parent actor of theInstancedStaticMeshComponentdoes not have anowning connectionto make RPCs. -
So far, this would handle runtime destruction of trees across clients. However, late-joining clients do not know of the destroyed instances, thus their
InstancedStaticMeshComponenthas all the trees. I am thinking of storingTransformsOfDestroyedTrees[]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.
-
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).
-
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.
I was not aware of the concept of IDs as I was under the impression instances of InstancedStaticMeshComponents could only be addressed via indices, I will research this a bit. Thanks for the help.
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
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.
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)
If all you're doing is wanting to move it when a player walks into it, then use the collision on the actor, check for authority, and then AddImpulse. No RPC required.
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.
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)
It's just that with bad ping, this can take some time for the server to get the message to apply the impulse.
So what would you expect to happen when two players with bad ping happen to collide with the object?
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.
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
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. ๐
endplay on pawn works fine in my case
i wanted to spawn a death box for the player when they leave, and that box contains all their inventory items so they don't leave with their inventory items ๐
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
Yes, I am using the Character Movement Component
Yes, I am. Is there any way I can disable, or lower the amount of extrapolation? This seems like a pretty visible issue
Shouldn't matter. Let them crash if they modify it :D
Ah it crashes the server itself.
Recompiling on the client shouldn't impact anything specifically on the server. Since a client wouldn't have authority the return is skipped which means it's likely something happening in the OnRep_CurrentHelmet function call that ends up calling something on the server if the server ends up crashing.
yeah this is why its an issue ๐
tested , its not an issue
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
I tested it and the server crash if i call server rpc by server
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
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.
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
Client change can't affect server. No matter how often you repeat that
let me make a cycle of the change they made to make it more clear what they did
Pawn->RequestHelmetChange();
RequestHelmetChange()
{
if(HasAuthority())
{
ServerRequestHelmetChange();
}
bApplyChangeToHelmetItem != bApplyChangeToHelmetItem ;
OnRep_CurrentHelmet();
}
OnRep_CurrentHelmet()
{
RequestHelmetChange(); // this call was added in here
//original method not changed
}
I even tracked the ip and pc name of him who did it
attaching a debugger, the server crashed in this line
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.
they are sending that rpc with new data
onrep is called by all client/server, and they are using the server method call the server on server
Missty :D this all makes no sense, sorry.
That's not how it works.
Clients can do whatever the fuck they want with their exe and code. This won't affect the Server
I block that guy and now the server is not crashing
The server has its own copy of this function and the On_Rep.
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
its mean they were doing some more dirty sh*** , blocking them server not crashing any more
i just kick them on post login
If your server crashes from that, then you have a bug :D
We're not doubting that someone may have messed up something...
This is tiring, Missty
But what it is they messed up has nothing to do with the code you've shown.
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
visual studio break point that rpc if statement i showed
on this if statement line
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);
}
}
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.
Testing now with using validate method, since its a reliable rpc, hope it will help to avoid it
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.
that's cool if it has it since i'm not using steamsubsystem
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.
Just out of curiosity... I remember discussing with you that you were using the IP address and computer name as a means of authentication, but what if this bad actor changes his IP & Computer name? Would there actually be anything that would stop them from being able to log in?
Like... Does the software have some kind of CD-Key or something that you keep on record too, or...?
they can join if they change that information, and will be banned again if they did something wrong
I have a packet logger script in wireshark which detects the server crash and a causing packet + the ip address of the sender
never thought of it, but a perfect idea for one more security layer
Hey guys, I managed to fix this buy doing 2 things:
- parenting the static meshes to be under the Character Skeletal Meshes
- Checking Network Skip Proxy Prediction on Net Update
Finally, no more jitters
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
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).
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 ๐
You have to override the function that causes the Pawn to be destroyed and then handle it how you need.
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();
}
}
}
}
Thank You very much, i was looking for it from like 3 hours
Its called by void APlayerController::Destroyed()
Ok got it
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();
}
The amount of wrongly tested UObjects will cause you crashes eventually.
if (!Driver) is not enough. This will crash if the Driver is pending kill.
Same with the ControlledPawn
Or the helmet pointer from yesterday.
i'm always checking uobjects using isvalidchecked(uitem)
and that function i guess is only checking for nullptr so doing if(!uitem) return; is ok?
and yes for driver i should do isvalid(driver) thanks
No, you should always use an IsValid test
oh, for uobjects also, i was thinking that only actors needs isvalid
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.
I mean, you aren't checking IsValid for a lot of things in that code.
ControlledPawn PossessedCharacter PossessedVehicle
Thank You so much for pointing these errors, its time to fix them ofcourse
I tried not to do that, but it didn't work either. There's still a lot of corrections
Shouldn't ApplyForce be called every tick? If I want to add a one-time force, shouldn't I use AddImpulse? I tried that (even though it's kinda the same as Launch Character), and it gives the same results โ many corrections
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.
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
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
@mystic estuary what did you end up using?
Also do you end up with prediction?
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
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.
I'm doing both
MovementComponent->bIgnoreClientMovementErrorChecksAndCorrection = true;
MovementComponent->bServerAcceptClientAuthoritativePosition = true;
not just the bIgnoreClientMovementErrorChecksAndCorrection
thanks, I will try that.
bServerAcceptClientAuthoritativePosition makes the client tell the server its position, which means that it overrides whatever server is thinking
Man, Iris is already pissing me off. So far I understand filtering like this:
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?
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.
I might be wrong, but I don't think so, It would be better if someone with more experience will confirm my answer
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
Awesome that confirms it well enough for me! Thanks a bunch
np
Update: I was a little bit wrong. Client doesn't seem to be able to predict movement of a simulated proxy in this context ๐ค
The LinearVelocity that is replicated is 0,0,0. SimProxies don't really predict. They just move according to what is replicated.
Would it make any sense to try to inject my knockback in there, or I would only get a lot of desyncs?
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.
Yes, I'm trying to do that on the hit instigator, not on the hit victim
You'll get a "correction" on HitInstigator for the SimProxy of HitVictim.
There's one note - this is supposed to be a co-op game where cheaters aren't a big concern
Cause that SimProxy works based on replicated information.
So it's at least VictimRTT/2 + InstigatorRTT/2 old.
Hmm, makes sense
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.
Yeah, in case they're actively moving that will be the case
Instigator will eventually see Victim get knocked back
Not only then. You get packages with the Character have 0 Velocity and standing still.
Which will override the knockback too.
Oh, true
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.
Yeah, doesn't sound good, alright, I'll see what Kaos has to say about it, but for now I'll leave it authoritative
Question, anyone know how to assure that an added audio component only plays locally?
Right now everyone connected can hear everyone's audio.
Only create it locally
Such as, is locally controlled condition check?
If it is supposed to be added to the player character - sure.
Yeah, I have the audio component being added upon begin play.
Then it should only be on the local client's pawn.
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
Show your code.
this is just running off of the begin play node
and there is no replication ticked to true on the audio component
Show more code. This doesn't show anything really.
Show the entire Begin Play
Show what that interface method is calling
BeginPlay is too early for IsLocallyControlled.
I was thinking that too
That calls on Server and ownign client.
That BeginPlay isn't even gated by an is local control check
That is what you would want typically, yes. But also - like Cedric said, Begin Play is too early for possession related behavior
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.
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?
Didn't even know there are two. Not convinced that they aren't both called on both.
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.
If you are spawning the Actor into the World, then the World would already keep the reference alive.
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.
You can increase how long it remembers the player state I believe. If that is the case, theoretically...you can make it forever enough ๐
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.
That's kinda what I am looking for. Server lifespan is 4 hours and I want the player to be able to resume.
That's usually provided by the backend/OSS.
Are you using any known OSS that provides a proper UniqueID? Like Steam, EGS, or so?
I am using Steam + PlayFab
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.
Exploring that now. Do PlayerStates persist by default, or do I need to set some flag?
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.
I actually can't find the OnControllerChanged event. But yeah, receive controller changed gets called on both.
Happens by default as long as you set the Inactive Lifetime of the PlayerStates in the GameMode defaults.
Strange.
Works like a charm! You saved me from creating a redundant system, thank you!
your actor must be getting destroy called on itself somewhere. as others have stated, the world holds a reference to actors spawned in it and shouldn't get garbage collected
You have to build it yourself
Movement corrections are generally handled already via the CMC
At least basic movement
Missed you a few days ago but yes. Currently debugging why Im not seeing PostReplicatedChange called with 0 ChangedIndices in our project. Seems odd since were calling MarkItemDirty with the change
It's difficult regardless
Actually my problem was that I was reassigning a new object on my previous one, and UE5 was treating it as an Add instead of Change, that was a stupid mistake
ah yeah thatll do it. This is definently a change, I suppose Im not sure how that aray of indices.....is its calculated based on UE detecting a replicated change or if its set because the entry was specifically marked as changing by the server
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
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?
I think the only way to do it for sure would be to use a RepNotify for the reference to the component, and in the OnRep function do whatever logic it is you want done when the object starts existing.
okay, i will try that.
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.
check the first pinned msg in this channel.
GetPlayerController 0 should return the local controller for listen server / client.
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
I mean what from context are you making the call, not what are you going to do with it.
Mmm mostly from actors and subsystems
Also there's no split screen to be worried about
APlayerController* UGameInstance::GetFirstLocalPlayerController(const UWorld* World) const
You can get the game instance from teh world, which you can get from your actor.
if your actor is a pawn you can also crawl up and get the controller
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
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.
yeah ofc
hmm, what does the actor need from the controller then? should it just be one way?
that sounds really cool though
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
yeah thanks โค๏ธ
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?
if the "dead" state is somehow replicated just have an OnRep and deselect locally no?
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?
probs I would still prefer the OnRep but you can probably switch anytime if it becomes a problem
okay
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? ๐ค
Why is that not just running locally? Do other clients even need to see it at all? The spawn box that is.
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.
I only enabled replication and replicate movement. its done locally
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.
i got drop packages set to 5%
It doesn't matter.
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
:<
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.
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.
is there node for this in ue4? Or I have manually compare owner PC and local PC ๐
GAs ๐ฎ
yolo
I don't think actors have a function for that. Unsure.
Pretty sure it is just - GetOwner
It should mostly just be GetOwner->CastToPlayerController->IsLocalController.
Assuming you set it to be owned by their controller.
works like charm
thanks
one question, is this node part of Unreal or this SDK im using?
I want to say not default. Specially if you're on ue4
Have you seen every node at some point in your life tho
Jk it isn't default
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.
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
I wouldn't think loading anything has anything specifically to do with multiplayer as loading things happen only to the local copy of the game.
run async is avalaible only in event graph and not function itself :/
Then don't have it as a function
If this is inside of an onrep - just call an event inside of that onrep
Async is only possible in the event graph
yeah like every other timed thingy
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?
From main menu, are you actually connecting to a server, or is this a listen server? The host of the game of a listen server would be the authority, and same if it is single player.
when i test, i use "client" settings, but now I'm not sure, maybe when session is created and client auto-join, it still counts as listen server?
ty, I'll check this tomorrow
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.
yes, i create a session and open level with "listen"
so, this lack of remote branch behavior should be fixed, if i create a dedicate server and connect properly?
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.
yes, its for dedicated server play only
looks like i need to rewrite some code here
thank you, its my work for tomorrow then
When player leaves game, does PC ref gets nullified? and owned actors gets destroyed? ๐ค
PC goes bye-bye and its controlled pawn is destroyed as well. There's a function in the PlayerController that you need to override if you want to keep their pawn in the game.
Does the thread of execution following a reliable RPC "wait" until the RPC completes over the network in order to continue execution?
nah, thats exactly what i want ๐
thanks
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.
Fair enough, here's an example
So the "Print String" would not execute until the reliable RPC returned correct?
No. That print happens immediately after Server Add Spirit is called.
RPCs have no "return".
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
Correct.
Beginner - need help. Thanks
It'd help if you showed some of your code
Iโm on my phone but my logic is this
Event begin play: sequence, first input stuff , then
If has authority spawn gun replicates on and attach to mesh. Then on my onRetNotify I attach to arms
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
C++ or BP onrep?
Bp
wdym rule
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
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?
race condition maybe?
do you set Rifle on begin play or after things are well established?
the attach gun?
the onrep
ok
also show what AttachGunToPlayer does
that fixed it lmao
should i keep it like this or lower it?
or is there a way to do it without the delay
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
with the sequence correct?
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
sure, doesn't matter
sequence is just syntactic sugar for a long chain of logic
with that delay i added, now the third person mesh is messed uyp
A -> B -> C -> D
and
A -> Sequence -> B
-> C
-> D
Is the exact same thing
Does the gun have replicate movement turned on?
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?
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
BeginPlay -> hook up input -> spawn gun -> set replicated MyGun var -> attach gun to mesh?
Onrep -> attach gun to arms
i feel like this is what i am doing exactly
whats the difference between mesh and arms?
the third person mesh
onrep i attatch to the first person arms
sorry i should have been more clear
what you should do is:
Attachment -> Are we locally controlled? -> yes -> 1st person
-> no -> 3rd person
doesn't the server have to attach to the third person body though
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
so i dont even need to check if have authority?
but if i attach the gun without authority isn't that just client sided
just make sure replicate movement is NOT on for the gun
that's local, nobody will know about where the gun is on your machine
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
the way i learned it is the server attaches the guns to the meshes and the client side does the first person arms
whether a gun is in 3rd or 1st depends only on if the pawn holding that gun is locally controlled
is that wrong
brah
but it seems kinda goofy
whats the commonly used pracitice
@dark edge still use the server to spawn in the gun though right?
yes
the server spawns the gun and says what MyGun is
but the server does NOT say where the gun is
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?
of course it's not, when would authority actually attach?
authority would only spawn
it doesn't but regardless the third person guns aren't staying on the character
just spawning in at that point
BeginPlay -> authority? -> yes -> spawn and set MyGun -> call attach code
OnRep_MyGun -> call attach code
Attach -> local? -> yes -> 1st person
-> no -> 3rd person
where's the onrep
showing now
Show
Beware with calling it too early.
If this gets run before possession happend for example.
Then your check will give "incorrect" result
race conditions all over the place
@cerulean barn have you go over the pinned msg? It's mandatory
validate rifle var
Do note that client only have their own controller.
in attachgun method?
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
That should at least not shit the bed when it can't get at the actual controller (which is the case most of the time)
a client only has their own controller, it does not have other ppls controllers
What's with that set owner
that's either doing nothing or clearing the owner on self
neither of which is what you want
that might be the rifle var being replicated before the rifle actor itself is
does a small delay in OnRepStuff fix it?
the errors?
yes
also don't duplicate code, this is basically a copy paste of onRepStuff so just call OnRepStuff here
is a rifle a replicated actor?
yea
You sure? Does 1 rifle show up on every screen for every pawn?
yep
everything works good
just the errors
click and show what bit of code it doesn't like
like double click an error?
i dont understand how these errors work
im new to all of this
you can click the underlined bits to jump to where it actually errored at
disconnect the false on has authority here
that's the path that's failing
?
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
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
oh right because the gun wasn't spawned yet
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?
just three instances
PIE settings, there's network emulation
network emulation?
ye
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
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
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
how do you set this
oh here?
time to get to work
show a clip
only when i changed the latency thing though?
is that a code fixeable issue
that means something is broken that will be broken in the real world
so you gotta fix it
something is working when you have zero lag but breaks when you have some
default first person template
show a clip of it messing up and I can tell you where to start looking maybe
the player like glitches back
make the capsule visible
turn off "Hidden in Game" on it
and make the lines thicker
what lines
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
is your anim BP doing anything funky?
could just be the character mesh interpolation stuff
i made a custom anim bp copying everything from ABP_MANNY
just with my skeleton
that prob might be bad
my third person mesh?
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
but is that what is causing the glitchiness
what does this do
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
im just trying to use all default stuff to fuck around what is the default general mode
so the end result is visually smoothed
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
anyone use iris?
ReplicationDisabled from client ConnectionId: any idea what this means
idk what to change?
whats like default good settings
shouldn't there be a generic thing
all depends on your movement settings really
its laggy with linear and network skip prediction
but its default first person template
what's good for snappy movement isn't good for realistic acceleration etc
open up another copy of the default template and see if it does it
make sure to also enable the same network emulation settings
the default template doesn't have third person in it
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?
these
test a default template with the same settings and see if you see the same rubberbanding
yea i did this
my actual character mesh is empty
i just realized
it should probably be the 3rd person mesh but not 100% sure
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)
when getting the mesh i just get TP body tho
the CMC doesn't know about your extra meshes
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
i can't tell if the capsule is lagigng on the firs tperson build
its hard to tell with just the capsule
try that
any other ideas?
figure out what's different between them and play with the smoothing factors
Issue:
@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.
No we use dedicated servers not tested on listen server
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
@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
I am updating the state of the door using onrep and according to the docs it should update the state on all clients/server
but currently the state only updates on server when client join back