Client gets disconnected when touching mesh

Hey,

I’m working with the GeneratedMeshComponent and at the moment I’m on implementing multiplayer functionality.
My basic design is as following: On the listen server upon login of the player I spawn an instance of ATerrain , which itselfs spawns multiple Chunks which all have a GMP. If another player logs in he himself spawns an instance of ATerrain with the corresponding Chunks clientside, so that I have one instance of ATerrain on the server and one on each of the connected clients. I chose that approach, because I thought that replicating the whole meshes over the network would be way too expensive, this way I only need to send the seed to the client and that’s it (in a simplified way).
This all works fine so far and I can also spawn my Characters without any problems, on the server I can even walk around with them. My problem occurs, as soon as a connected client’s character touches the terrain (I spawn them in the air and they fall down), then I get a bunch of errors and I get disconnected. This does not happen if I don’t spawn the Terrain client side (I tried that in order to find the error), but of course the player will then just keep on falling though the air, at least on the client, the listen server sees the clients character standing right next to him on the terrain.
From the errors I’d suppose that the engine is trying to replicate something of the terrain or anything similar but I don’t know what, as nothing there is set to replicate. Maybe because the Owner of the ATerrain instances is my PlayerController?

@mordentral(Btw, can I tag people here in the forum?): On page 4 of the procedural terrain generation thread you mentioned something that might help me out here, especially as one of the logs says that there was an overflow, maybe you could have a look at it?

Here the log:



LogNetPackageMap:Warning: FNetGUIDCache::SupportsObject: Chunk /Game/Maps/UEDPIE_1_Level_GameWorld.Level_GameWorld:PersistentLevel.Terrain.Chunk-1#-1#0 NOT Supported.
LogNetPackageMap:Warning: FNetGUIDCache::SupportsObject: Chunk /Game/Maps/UEDPIE_2_Level_GameWorld.Level_GameWorld:PersistentLevel.Terrain.Chunk272 NOT Supported.
LogNetSerialization:Error: FBitReader::SetOverflowed() called
LogNetSerialization:Error: FBitReader::SerializeBits: Pos + LengthBits > Num
LogNetPackageMap:Error: InternalLoadObject: Failed to load path name
LogNet:Error: ReceivedBunch: ReceivePropertiesForRPC - Bunch.IsError() == true: Function: ServerMoveDual, Object: CharacterMovementComponent /Game/Maps/UEDPIE_1_Level_GameWorld.Level_GameWorld:PersistentLevel.TGCharacter_Human_C_41.CharMoveComp
LogNet:Error: UActorChannel::ProcessBunch: Replicator.ReceivedBunch failed.  Closing connection. RepObj: CharacterMovementComponent /Game/Maps/UEDPIE_1_Level_GameWorld.Level_GameWorld:PersistentLevel.TGCharacter_Human_C_41.CharMoveComp, Channel: 10
LogNet: UNetConnection::Close: Name: IpConnection_75, Driver: GameNetDriver IpNetDriver_41, PC: GameWorldPlayerController_BP_C_17, Owner: GameWorldPlayerController_BP_C_17, Channels: 10, RemoteAddr: 127.0.0.1:64234, Time: 2015.05.07-18.40.52
LogNet: UChannel::Close: Sending CloseBunch. ChIndex == 0. Name: ControlChannel_41
LogNetTraffic:Error: UChannel::ReceivedRawBunch: Bunch.IsError() after ReceivedNextBunch 1
LogNetTraffic:Error: Received corrupted packet data from client 127.0.0.1.  Disconnecting.
LogNet: UChannel::ReceivedSequencedBunch: Bunch.bClose == true. ChIndex == 0. Calling ConditionalCleanUp.
LogNet: UChannel::CleanUp: [GameNetDriver] [GameWorldPlayerController_BP_C_18] [GameWorldPlayerController_BP_C_18]. ChIndex == 0. Closing connection.
LogNet: UNetConnection::Close: Name: IpConnection_74, Driver: GameNetDriver IpNetDriver_42, PC: GameWorldPlayerController_BP_C_18, Owner: GameWorldPlayerController_BP_C_18, Channels: 10, RemoteAddr: 127.0.0.1:1706, Time: 2015.05.07-18.40.52
LogNet: UChannel::Close: Sending CloseBunch. ChIndex == 0. Name: ControlChannel_40
LogNet:Warning: Network Failure: GameNetDriver[ConnectionLost]: Your connection to the host has been lost.
LogNet:Warning: Network Failure: GameNetDriver[ConnectionLost]: Your connection to the host has been lost.
LogNet: NetworkFailure: ConnectionLost, Error: 'Your connection to the host has been lost.'
LogNet:Warning: FObjectReplicator::UpdateUnmappedObjects: Connection->State == USOCK_Closed
LogNet:Warning: FObjectReplicator::UpdateUnmappedObjects: Connection->State == USOCK_Closed
LogPlayerController:Warning: Calling IsLocalController() while Player is NULL is undefined!
LogPlayerController:Warning: Calling IsLocalController() while Player is NULL is undefined!
LogNet: NotifyAcceptingConnection: Server Level_GameWorld accept
LogNet: Open Level_GameWorld 05/07/15 20:40:52 127.0.0.1
LogNet: Added client connection.  Remote address = 127.0.0.1:64234
LogNetTraffic:Warning: High single frame packet loss: 124
LogNetTraffic:Error: UNetConnection::ReceivedPacket: Received control channel close before open
LogNet: UNetConnection::Close: Name: IpConnection_76, Driver: GameNetDriver IpNetDriver_41, PC: NULL, Owner: NULL, Channels: 1, RemoteAddr: 127.0.0.1:64234, Time: 2015.05.07-18.40.52
LogNet: Browse: /Game/Maps/Level_MainMenu?closed
LogNet: Failed; returning to Entry
LogLoad: LoadMap: /Game/Maps/Level_MainMenu?closed
LogNet: World NetDriver shutdown IpNetDriver_42 [GameNetDriver]
LogNet: DestroyNamedNetDriver IpNetDriver_42 [GameNetDriver]
LogExit: GameNetDriver IpNetDriver_42 shut down


Hope somebody can help me.

Thanks in advance,
Taces

/e I now also opened an AnswereHub question here: Client gets disconnected when touching mesh - Multiplayer & Networking - Unreal Engine Forums

I now tried to add normal Box to the map to test if I can walk on top of that without getting disconnected and indeed I can, therefore my error seems to be related to the GeneratedMeshComponent.
At first I thought that there is something wrong with the ownership as I’m using this to spawn my Character:



FActorSpawnParameters Params;
Params.Owner = this;
ATGHumanCharacter* NewPawn = GetWorld()->SpawnActor<ATGHumanCharacter>(HumanCharacterBP, LastPawnLocation, FRotator(0, 0, 0), Params);
Possess(NewPawn);


But then it should fail to walk on the box as well, I believe.

I can walk on top of the box, but as soon as I step onto my terrain, I get disconnected:
800d2cd101ffe26630bd5731a085fdad6ce9ac31.jpeg

Still my errors are coming from the CharacterMovementComponent, but now from a different function:



LogNetSerialization:Error: FBitReader::SetOverflowed() called
LogNetSerialization:Error: FBitReader::SerializeBits: Pos + LengthBits > Num
LogNetPackageMap:Error: InternalLoadObject: Failed to load path name
LogNet:Error: ReceivedBunch: ReceivePropertiesForRPC - Bunch.IsError() == true: Function: ServerMove, Object: CharacterMovementComponent /Game/Maps/UEDPIE_1_Level_GameWorld.Level_GameWorld:PersistentLevel.TGCharacter_Human_C_22.CharMoveComp
LogNet:Error: UActorChannel::ProcessBunch: Replicator.ReceivedBunch failed.  Closing connection. RepObj: CharacterMovementComponent /Game/Maps/UEDPIE_1_Level_GameWorld.Level_GameWorld:PersistentLevel.TGCharacter_Human_C_22.CharMoveComp, Channel: 10
LogNet: UNetConnection::Close: Name: IpConnection_45, Driver: GameNetDriver IpNetDriver_21, PC: GameWorldPlayerController_BP_C_19, Owner: GameWorldPlayerController_BP_C_19, Channels: 10, RemoteAddr: 127.0.0.1:54155, Time: 2015.05.08-13.37.07
LogNet: UChannel::Close: Sending CloseBunch. ChIndex == 0. Name: ControlChannel_23
LogNetTraffic:Error: UChannel::ReceivedRawBunch: Bunch.IsError() after ReceivedNextBunch 1
LogNetTraffic:Error: Received corrupted packet data from client 127.0.0.1.  Disconnecting.


These two answere hub posts seem to be very related to my problem, which leads me to the suggestion that there might be something wrong in CharacterMovementComponent, as the three of us have pretty similar problems while independently working on similar things.

By digging deeper into the engines (networking)code and seeing things I never wanted to see, it seems to me that I can’t spawn a collidable mesh only on the client, without the server knowing. Something I stumbled across multiple times was the BaseComp, most probably the primitive component the character is standing on at the moment. My suggestion is, that the characters stands on the clientside mesh and as the server doesn’t know about it he thinks that it is some kind of hack and disconnects him, can somebody confirm that or has similar experiences?

Furthermore that would mean that I had to replicate all of the meshes (512 meshes * ~4500Tris per mesh) from server to the clients, I suppose that would be less than ideal?

I am having trouble duplicating your issue, I have a test project with a generated voxel terrain and working multiplayer and just loaded it up with no problems when colliding. Are you replicating the actor and is the collision location the same on the client as the server?

I tested with sending compressed chunks across the network to generate on the client as well as having the client directly extract everything without information from the server and both worked fine under 4.7.6. The only time I have had crashing errors with terrain collision was when I had a bug that was generating incorrect collision indices and the collision system crashed every time I touched the terrain.

Also regarding your PM to me, since it has something to do with this topic i’ll answer it in here:

For multiplayer I RLE encode all of the chunks, split them into multiple arrays (there is a maximum packet size for RPC’s) and then pass them to the archived base to ZIP before sending them to the client with an RPC. Once the entire chunk is received I then queue up a thread to extract it to a mesh while the next one in queue gets sent. Any section that has no solid voxels in it is ignored during this to save bandwidth and time.

I tried RLE with saving the position of solid strings of voxels and skipping empty sections but it ended up using more bytes that just RLE encoding the entire thing since I have all voxel information in a single INT right now. If I had a larger Voxel format it would have ended up as more efficient.

For large worlds as you appear to be doing it would probably be better to generate the world off of the same seed on server and client and only send voxels that have been changed / removed to the client so that you use less bandwidth.

Sending the mesh itself is a bad idea in most cases as the client doesn’t have a good map of the volume data then and can’t quickly re-mesh when changes happen or do cool things like handle fracturing and specific voxel traces.

First, thanks for your answer.

No, I am not replicating the actor, but the collision position is the same. There is an actor on the server with the same collision mesh as the one on the client but in fact they do not know about each other, which is probably the problem, therefore I’m trying around a bit with replicating actor and seed but generating the mesh per running instance (Client/Server), similar to what you are describing.

That seems like a pretty good way to do it, but as you said it’s probably not suitable for what I’m doing.

Still it’s great to hear that it should work to replicate just the actor and then generate the mesh itself on the client based on the seed. I’ll reply if I get it to work :smiley:

Apart from that, do you know if it’s possible to just replicate some components and not all or better is there a similar function like AActor::IsNetRelevantFor just for components? In my earlier - obiously not so succesfull - approach all the Chunks were components that had been managed by a single actor, the “problem” now is that I can’t use that design as the components are using their actors cull distance or network relevancy and therefore either alle the chunks or no chunk at all is replicated down to the clients instead of just those who are nearby the player. I now changed all the chunks to being actors which solves that problem but I don’t like the idea of having (at maximum) 512 active actors per player in the servers level. So far that haven’t been a problem but I haven’t gotten too far in testing either.

Do you have Server_Validate function that doesn’t just use ‘Return true;’?

Regarding the actual mesh generating there aren’t any RPCs involved, all the other _Validate functions are just “return true;”

Ok, great I got it working!

For anyone who comes to this thread with similiar problems, this is how I’m doing it now (This just works and it is likely that there is a better way, but it suits my needs so far with decent 60-80FPS).

On the server the gamemode spawns actor which manages the whole Terrain, which is replicated to the clients (In the basic design it doesn’t do anything at all clientside, but If you go on and extend functionality further you will need it there as well). This “Manager” then spawns the chunks on the server which are actors and as well replicated. Those chunks have a subobject (the mesh), which replicates as well ( without the subobject replication it worked as well but I got spammed with warnings a la “Unable to resolve default guid from client:” and “could not resolve the new relative movement base actor, ignoring server correction!”). And that’s the magic, the server just has to know that the actors and components exists. The mesh is then created clientside and serverside individually; clientside with the seed I’m sending over with an RPC.

Thanks mordentral and TheJamsh for the help!