Search Unity

How does the Client tell the Server to NetworkServer.Destroy()?

Discussion in 'Multiplayer' started by CarterG81, Jun 21, 2015.

  1. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    In game, whenever a character "picks up" an "item" (gameobject), I use NetworkServer.Destroy() to remove it from the game.

    This works on the Server/Host, but does nothing when the client does the same thing. (The host correctly tells everyone the itemGameObject is destroyed when the host's character 'picks up' an item. All clients are updated correctly by the server. However, when the Client's character picks up an item, it only destroys it on the Client but NOT the server- so it is not updated/synced.)

    I had this same problem with Instantiating gameobjects (in game, characters "dropping items") and the solution was to make instantiation in a command.

    Code (csharp):
    1.  
    2. [SyncVar]
    3. string ItemName;
    4.  
    5. [Command]
    6.   public void CmdDropItem(string ItemName)
    7.   {
    8.   GameObject spawnNetworkGOB = (GameObject)Instantiate(Resources.Load<GameObject>("Prefabs/Items/Item_" + ItemName), this.transform.position, this.transform.rotation);
    9.  
    10.   NetworkServer.Spawn(spawnNetworkGOB);
    11.   }
    However, from what I read in the documentation I cannot use a GameObject as a parameter in a [Command].

    So how does the Client tell the Server to destroy an item, if NetworkServer.Destroy() does not work?
     
    hickna likes this.
  2. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Shouldn't calling NetworkServer.Destroy(gameObject) on a client, tell the server to destroy it / update for everyone? (The server is also the first player, while the client is the second player. No need for authoritative/standalone server).

    The documentation for this new Unet is seriously lacking, I've spent so much time in futility >_<
     
  3. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    505
    In an authoritative server situation, like with unity networking, the client should not be able to destroy an object. Instead, it can request the server to do so, but the server must ultimately be the one to do it.

    If you want the client to decide to destroy something, it can put in a request via a command. You can identify a networked object using its NetworkInstanceId. Something like this might suit.
    Code (csharp):
    1. [Command]
    2. public void CmdDoThing(NetworkInstanceId netID)
    3. {
    4.     GameObject theObject = NetworkServer.FindLocalObject(netID);
    5.     ...
    6. }
    7.  
    8. // Call the above from a client. netId is accessible via NetworkBehaviour
    9. CmdDoThing(netId);
    I don't know how NetworkServer.FindLocalObject is implemented. I would love to know if it is efficient to use or not. I'm hoping it's based on a dictionary or something similar.
     
    CarterG81 likes this.
  4. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I tried something like this already and to no avail. Perhaps you can help me figure out where I went wrong? I forgot how I did it, but I just tried again and am getting an error.

    Code (csharp):
    1.  
    2.   Debug.Log(networkIdentity.netId);
    3.   Cmd_DestroyThis(networkIdentity.netId);
    4.  
    Log outputs the correct 'netID' (ex. "4").
    Then Cmd_DestroyThis(networkIdentity.netID) results in the following error:

    "There is no NetworkIdentity on this object. Please add one."

    Code (csharp):
    1.  
    2.   public NetworkIdentity networkIdentity; //linked in the Inspector, since I kept getting a null reference. Tried this with GetComponent<NetworkIdentity> as well.
    3.  
    4.   [Command]
    5.   void Cmd_DestroyThis(NetworkInstanceId netID)
    6.   {
    7.   GameObject theObject = NetworkServer.FindLocalObject(netID);
    8.  
    9.   NetworkServer.Destroy(theObject);
    10.   }
    11.  

    I honestly don't care HOW I do it. If it's easier to simply request the server to do so. However, I don't seem to be able to accomplish this either.

    4 hours and 30 minutes trying to figure out how to destroy an object with Unet. Urgh...
     
    Last edited: Jun 21, 2015
  5. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Ah I see. I was doing a lot of this using a parent's NetworkIdentity while the gameobject with this script did not have its own NetworkIdentity. Easy fix.

    Can also explain why so many of my attempts did not at all work as they "should have".

    Anyway, when I send the [Command] on the Client, it still doesn't destroy the gameobject. In game, this means I can pick up an infinite amount of the item (on the client).

    Code (csharp):
    1.  
    2.   [Command]
    3.   void Cmd_DestroyThis(NetworkInstanceId netID)
    4.   {
    5.   GameObject theObject = NetworkServer.FindLocalObject(netID);
    6.   NetworkServer.Destroy(theObject);
    7.   }
    8.  


    Warning:

    Code (csharp):
    1.  
    2. Trying to send command for non-local player.
    3. UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter, Int32, String)
    4. NetworkDestroyBool:CallCmd_DestroyThis(NetworkInstanceId)
    5.  
     
  6. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I'm going to close this and re-ask the question in a better context. I clearly have no idea what I'm doing despite my attempts at understanding the documentation & sample projects. (I don't need the client to delete objects. I can simply request the server to delete them.)
     
    Last edited: Jun 21, 2015
  7. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I was unaware that all [Commands] have to be on the Player object.

    Problem Solved.
     
  8. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    505
    Took a while for me to get back to the forum, but I'm glad you solved it in the end!
    All of your conclusions are correct :).
     
  9. Jordy-Rutjens

    Jordy-Rutjens

    Joined:
    Nov 18, 2015
    Posts:
    1
    Yeah, the client can't remove objects but the host can... was there an easy fix to this? I've tried alot of things but I just cant think of any other ideas to fix this myself.

    with my last good 'fix' I now have all the commands and such on the player, but now the client get an "Object reference not set to an instance of an object" error while the player tries to interact with it ingame. ( and it still doesnt destroy the object )
     
    Last edited: Apr 29, 2017
  10. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I honestly do not know. I don't use UNET, I use Forge Remastered.

    Perhaps if you pasted your code, someone more experienced with UNET could help? I understand network logic, but don't really know of UNET specific nuances.
     
  11. Kj756

    Kj756

    Joined:
    Jan 22, 2017
    Posts:
    7
    I'm having the same problem you had. In my case I have my script on the game object being picked up. I have no commands anywhere because I don't know where to place them. The server/host gets the pickup just fine but like in your situation when done on the client it seems outta sync? Any thoughts on how to fix it?
     
  12. Kj756

    Kj756

    Joined:
    Jan 22, 2017
    Posts:
    7
    You think you could post your final code? I'm just having trouble getting the command function to work.
     
  13. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    What's not working? It's really simple command:
    Code (CSharp):
    1.  
    2. [Command]
    3. private void CmdDestroyObject(){
    4.      NetworkServer.Destroy(#yourSpawnedGameObject#);
    5. }
    6.  
    Make sure your object is actually spawned, and the commands passed have authority.
     
  14. Kj756

    Kj756

    Joined:
    Jan 22, 2017
    Posts:
    7
    Make sure your object is actually spawned, and the commands passed have authority.[/QUOTE]
    Thanks the object is now destroying on the server and client, however i ran into a problem. When the player overlaps the other player the client disappears.
     

    Attached Files:

  15. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    It isn't a network problem, just a logic one. Or rather lack of it. Make sure you're not destroying what you're not supposed to.
     
  16. petroslouca

    petroslouca

    Joined:
    May 17, 2018
    Posts:
    14
    I have gone through your past conversation and I have followed the recommended steps. I still have problem with client to server sync/update.

    In a MatchMaker multiplayer game (Unity version 2018.1.0f2), when the GO is destroyed on the host, that GO is also destroyed on the client(s) but the other way round cannot be accomplished, here is my script code below, attached to the GO that is needed to be destroyed (the GO has "Server Only" and "Local Player Authority" options unticked and Network Transform Send Rate to 9):

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;

    public class GameObjectDestroyScript : NetworkBehaviour
    {
    [SerializeField]
    GameObject GOobject;

    private void OnMouseDown()
    {
    Destroy(GOobject);
    }
    }