Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impossible to move non player local authoritative objects #273

Closed
Lagunovas opened this issue Jan 10, 2019 · 6 comments

Comments

@Lagunovas
Copy link
Contributor

commented Jan 10, 2019

Describe the bug

ISSUE 1:
As the title says, it is not possible to move non-player local authoritative objects. According to some members of the discord, this was working just fine but stopped working. This bug/issue? was introduced when the new NetworkTransform was implemented.

if (!isServer && hasAuthority && connectionToServer != null)
{
// check only each 'syncInterval'
if (Time.time - lastClientSendTime >= syncInterval)
{
if (HasMovedOrRotated())
{
// serialize
NetworkWriter writer = new NetworkWriter();
SerializeIntoWriter(writer, targetComponent.transform.position, targetComponent.transform.rotation, compressRotation);
// send message to server
TransformMessage message = new TransformMessage();
message.netId = netId;
message.componentIndex = componentIndex;
message.payload = writer.ToArray();
connectionToServer.Send((short)MsgType.LocalPlayerTransform, message);
}
lastClientSendTime = Time.time;
}
}

As you can see in the code above, there is an if statement which will check if connectionToServer != null, but if this is a non-player local authoritative object for which you have the authority, then this statement will fail and no updates will be sent to the server.

In the previous version of the NetworkTransform, as well as in the UNET itself, ClientScene.readyConnection was used for the very same check, therefore changing it as well as the send call in the if statement, will fix this problem, however, not sure if this affects anything else.

Fix?

if (!isServer && hasAuthority && ClientScene.readyConnection != null)
{
	// check only each 'syncInterval'
	if (Time.time - lastClientSendTime >= syncInterval)
	{
		if (HasMovedOrRotated())
		{
			// serialize
			NetworkWriter writer = new NetworkWriter();
			SerializeIntoWriter(writer, targetComponent.transform.position, targetComponent.transform.rotation, compressRotation);


			// send message to server
			TransformMessage message = new TransformMessage();
			message.netId = netId;
			message.componentIndex = componentIndex;
			message.payload = writer.ToArray();
			ClientScene.readyConnection.Send((short)MsgType.LocalPlayerTransform, message);
		}
		lastClientSendTime = Time.time;
	}
}

ISSUE 1.1:

The non-player local authoritative objects don't even move on the client side, and this is the line of code that is causing it.

if (!(isLocalPlayer && hasAuthority))

In this case:
isLocalPlayer == false
hasAuthority == true

(isLocalPlayer && hasAuthority) == false
(!(isLocalPlayer && hasAuthority)) == true

Therefore, this object will be teleported or interpolated back to the old position if you try to move it.

FIX (Disclaimer: Same as before, not sure how this affects LAN Hosts (server & client) because I'm not using it, therefore it needs to be tested.)

if (!hasAuthority)

To Reproduce
Steps to reproduce the behaviour:

  1. Create a prefab with NetworkIdentity & NetworkTransform components.
  2. In the NetworkIdentity component select "Local player authority".
  3. Place the prefab in the game, so the server can spawn it.
  4. Connect to the server.
  5. Assign client authority of the object created to this client.
  6. Client: Try to move the object.

Hope didn't forget to mention anything, thanks for reading.
Ed

@vis2k

This comment has been minimized.

Copy link
Owner

commented Jan 11, 2019

what do you mean by non player local authoritative object?
what's the use case? I was under the impression that local authority is only for players. if you use it for a monster then every player could use the monster, which is kinda weird.

@Lagunovas

This comment has been minimized.

Copy link
Contributor Author

commented Jan 11, 2019

Well, in my case I have vehicles which can be controlled by players. Server spawns the vehicles, and if any of the players wishes to control one of the vehicles they must send a request to the server so the server can assign the authority. This way only one player at a time can control any of the vehicles.

@liamdeez

This comment has been minimized.

Copy link

commented Jan 11, 2019

I too am having this issue. I created a project to demonstrate it.

https://drive.google.com/open?id=1DvpNbv33OZIIikVbn0dbNXwVdHS7AUS4

Build and run external instance. Host on external instance. Connect client inside unity editor. Press Q on the host to pass the black cube authority to the client. Move the client in the editor and you'll see on the host that it doesn't update the cube's location.

The above example demonstrates the issue, but my use case isn't represented with it. Mine would be for VR when a player would pick up an object. The player client has to be able to take over the authority of an object in order for other players to see him carry it around so to speak.

I made the following changes to NetworkTransformBase in the same location Ed had posted above. This may not be an adequate fix, but it got my VR app back on track.


if (hasAuthority && ClientScene.readyConnection != null)
{
    // check only each syncInterval
    if (Time.time - lastClientSendTime >= syncInterval)
    {
        if (HasMovedOrRotated())
        {
            // serialize
            NetworkWriter writer = new NetworkWriter();
            SerializeIntoWriter(writer, targetComponent.transform.position, targetComponent.transform.rotation, compressRotation);

            // send message to server
            TransformMessage message = new TransformMessage();
            message.netId = netId;
            message.componentIndex = componentIndex;
            message.payload = writer.ToArray();
            ClientScene.readyConnection.Send((short)MsgType.LocalPlayerTransform, message);
        }
        lastClientSendTime = Time.time;
    }
}

// apply interpolation on client for all players
// except for local player if he has authority and handles it himself
else if (!(isLocalPlayer && hasAuthority))
{

@paulpach paulpach added the bug label Jan 13, 2019

@vis2k

This comment has been minimized.

Copy link
Owner

commented Jan 18, 2019

Well, in my case I have vehicles which can be controlled by players. Server spawns the vehicles, and if any of the players wishes to control one of the vehicles they must send a request to the server so the server can assign the authority. This way only one player at a time can control any of the vehicles.

I didn't know UNET can do that.
will look into it

@vis2k vis2k closed this in 12f0ba6 Jan 18, 2019

@Lagunovas

This comment has been minimized.

Copy link
Contributor Author

commented Jan 19, 2019

While this fixes the movement on the client, it still won't send updates to the server because of the (connectionToServer != null) check. This will be null as mentioned in the first post.

@vis2k

This comment has been minimized.

Copy link
Owner

commented Mar 19, 2019

🎉 This issue has been resolved in version 1.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@vis2k vis2k added the released label Mar 19, 2019

tomkrikorian pushed a commit to tomkrikorian/Mirror that referenced this issue Jun 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.