[C#] UNET Client raycast not the same as Server raycast

I’m trying to fire a ray and then spawn an object at that location. It works perfectly fine on the server, but on any clients the placement is offset and I can’t figure out why for the life of me. Here’s a picture to describe what I mean in more detail.

And here’s my code:

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

public class Building_MP : NetworkBehaviour {

    [SerializeField]
    GameObject GhostGO;
    [SerializeField]
    LayerMask LM;

    bool snap = false;

    int ghostID;

	// Use this for initialization
	void Start () {
        ghostID = Random.Range(0, 10000);
    }
	
	// Update is called once per frame
	void Update () {
	
        if(Input.GetButtonDown("Fire2") && isLocalPlayer)
        {
            CmdSpawnGhostBrick();
        }

        if(isLocalPlayer)
        {
            //CmdMoveGhostBrick();

            if (Input.GetKeyDown(KeyCode.B))
            {
                snap = !snap;
            }
        }

	}

    [Command]
    void CmdSpawnGhostBrick()
    {
        RaycastHit hit;
        Ray ray = GetComponentInChildren<Camera>().ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit, 200.0f, LM))
        {
            GameObject ghostBrick = Instantiate(GhostGO, new Vector3(RoundToHalf(hit.point.x), RoundToHalf(hit.point.y), RoundToHalf(hit.point.z)), Quaternion.identity) as GameObject;
            ghostBrick.transform.name = "GhostBrick (" + ghostID + ")";
            ghostBrick.transform.tag = "Ghost";
            ghostBrick.layer = 10;
            NetworkServer.Spawn(ghostBrick);
            Debug.Log("Hit at " + hit.point.ToString());
            Debug.Log("BrickPos " + ghostBrick.transform.position);
        }
    }

    [Command]
    void CmdMoveGhostBrick()
    {
        GameObject ghostBrick = GameObject.Find("GhostBrick (" + ghostID + ")");
        if(ghostBrick != null)
        {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100.0f, LM))
            {
                if (!snap)
                {
                    ghostBrick.transform.position = new Vector3(RoundToHalf(hit.point.x), RoundToHalf(hit.point.y) + ghostBrick.GetComponent<Renderer>().bounds.size.y / 2, RoundToHalf(hit.point.z));
                }
                else
                {
                    ghostBrick.transform.position = new Vector3(hit.transform.position.x, hit.transform.position.y + ghostBrick.GetComponent<Renderer>().bounds.size.y, hit.transform.position.z);
                }
            }

            if(Input.GetButtonDown("Fire1"))
            {
                GameObject newBrick = Instantiate(GhostGO, ghostBrick.transform.position, ghostBrick.transform.rotation) as GameObject;
                NetworkServer.Spawn(newBrick);
            }
        }
    }

    [Command]
    void CmdDestroyGhost()
    {
        GameObject ghostBrick = GameObject.Find("GhostBrick (" + ghostID + ")");
        if(ghostBrick != null)
        {
            NetworkServer.Destroy(ghostBrick);
        }
    }

    public static float RoundToHalf(float f)
    {
        return f = Mathf.Round(f * 4f) * 0.25f;
    }
}

Thanks a ton in advance, I’m at my wit’s end right now.

I used this to destroy specific block, that was result of raycast on client. It is not 100% server-authoritative unfortunately, but it is okay for me. You can also send to server additional parameters as hit.point (vector3) or something like that.
Note there is network Identity component on that block also.

void DeleteOnMouseDown()
{
	//can only destroy components with myParent script attached to them
	if (Input.GetAxis("Fire3") > 0f)
	{
		ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if (Physics.Raycast(ray, out hit))
		{
			if (hit.collider != null)
			{
				nearbyColliderParentScript = GetBlockByColliderHit(hit).GetComponent<MyParent>();
				
				if (nearbyColliderParentScript != null)
				{
					blockToDestroy = nearbyColliderParentScript.myParent.gameObject;		
					if (blockToDestroy.GetComponent<MountPoints>().markedForDestroy == false)
					{
						CmdMarkBlockForDestruction(blockToDestroy);
						blockToDestroy.GetComponent<MountPoints>().markedForDestroy = true;
					}
				}
			}
		}
	}
}

[Command]
void CmdMarkBlockForDestruction(GameObject block)
{		
	GameObject shipRoot = block.GetComponent<MountPoints>().rootFragment.gameObject;
	shipRoot.GetComponent<ShipIntegrity>().AddBlockToDestroy(block);
}

Hi,
Following your discussion on Ray casting I have a related problem. Maybe it’s a question that @slimabob could answer: how did you pass the raycast hit collider position to the server as mentioned in your last answer? I’d really appreciate your help. Thank you.