I currently have this basic multiplayer system where I can either create a server, join as a host, or join as a client. I can do all but when i join as a client, the client cannot move and the camera vibrates violently and I do not know what is going on.
Here is my script for handling the multiplayer connections:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Unity.Netcode;
public class mainMenuHandler : MonoBehaviour
{
[SerializeField] private Button serverBtn;
[SerializeField] private Button hostBtn;
[SerializeField] private Button clientBtn;
[SerializeField] private GameObject dStroy;
private void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
{
// The client identifier to be authenticated
var clientId = request.ClientNetworkId;
// Additional connection data defined by user code
var connectionData = request.Payload;
// Your approval logic determines the following values
response.Approved = true;
response.CreatePlayerObject = true;
// The Prefab hash value of the NetworkPrefab, if null the default NetworkManager player Prefab is used
response.PlayerPrefabHash = null;
// Position to spawn the player object (if null it uses default of Vector3.zero)
response.Position = Vector3.zero;
// Rotation to spawn the player object (if null it uses the default of Quaternion.identity)
response.Rotation = Quaternion.identity;
// If response.Approved is false, you can provide a message that explains the reason why via ConnectionApprovalResponse.Reason
// On the client-side, NetworkManager.DisconnectReason will be populated with this message via DisconnectReasonMessage
response.Reason = "Some reason for not approving the client";
// If additional approval steps are needed, set this to true until the additional steps are complete
// once it transitions from true to false the connection approval response will be processed.
response.Pending = false;
}
private void Awake() {
serverBtn.onClick.AddListener(() => {
NetworkManager.Singleton.StartServer();
Destroy(dStroy);
});
hostBtn.onClick.AddListener(() => {
NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck;
NetworkManager.Singleton.StartHost();
Destroy(dStroy);
});
clientBtn.onClick.AddListener(() => {
if (NetworkManager.Singleton.StartClient()) {
Debug.Log("Client started successfully!");
}
else {
Debug.Log("Client failed to start.");
}
Destroy(dStroy);
});
}
}
This is my movement / player input handler (sorry about the messy code)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using System;
using UnityEditor;
using Unity.Mathematics;
//using UnityEditor.Experimental.GraphView;
using UnityEngine.TextCore.Text;
using Unity.Netcode;
using Unity.Netcode.Components;
using Unity.VisualScripting;
//using UnityEditor.ShaderGraph.Internal;
using Unity.Burst.Intrinsics;
//using UnityEditor.Animations;
using UnityEngine.Animations;
using System.Net.Http.Headers;
public class PlayerInputHandler : NetworkBehaviour
{
//**VARIABLES**//
//private//
//grabs the bound inputsystem class into this script
private InputSystem inputSystem;
[Header("PlayerContoller")]
public CharacterController cController;
//Object for moving in direction of camera
[Header("Direction of movement")]
public Transform orientation;
//public Transform other_orientatino;
//Coefficients
[Header("Speed Gravity and RunMultiplier")]
public float groundDistance;
public float vVelocity;
public float gravity;
public float speed;
public float runMultiplier;
private bool isGrounded = true; //Chekcs whether the player is touching the ground or not
public bool touchGround;
public LayerMask layermask;
private Vector3 yVelocity;
//Animators in both rigs//
[Header("Animators")]
public GameObject FP_rigAnimator;
public GameObject GUN_rigAnimator;
private Animator fpAnimator;
private Animator gunAnimator;
private bool isReloading = false;
// Start is called before the first frame update
void Awake()
{
//ReturnReloadFinishedScript = GUN_rigAnimator.GetComponent<ReturnReloadFinishedEvent>();
//grabs the animator objects when the game runs.
fpAnimator = FP_rigAnimator.GetComponent<Animator>();
gunAnimator = GUN_rigAnimator.GetComponent<Animator>();
//Initialize input system
inputSystem = new InputSystem();
inputSystem.PlayerInputs.Enable();
//Find Bool var
}
//Fixed update should be used with physics stuff. Fixed udpate runs in step with fixed update
void FixedUpdate()
{
//checks to see if the player object is the owner or not. if it isn't then it won't move other players
if (!IsOwner) {
return;
}
//Ground Check
isGrounded = Physics.Raycast(transform.position, Vector3.down, groundDistance, layermask);
if (!isGrounded && yVelocity.y > 0) {
yVelocity.y = gravity;
}
//***PLAYER MOVEMENT + ANIMATIONS***//
//Get Player Inputs
float r = inputSystem.PlayerInputs.R.ReadValue<float>();
float w = inputSystem.PlayerInputs.W.ReadValue<float>();
float a = inputSystem.PlayerInputs.A.ReadValue<float>();
float s = inputSystem.PlayerInputs.S.ReadValue<float>();
float d = inputSystem.PlayerInputs.D.ReadValue<float>();
float shift = inputSystem.PlayerInputs.Shift.ReadValue<float>();
float mouseClick = inputSystem.PlayerInputs.mouseClick.ReadValue<float>();
float spacebar = inputSystem.PlayerInputs.Space.ReadValue<float>();
if (mouseClick > 0.0f && !fpAnimator.GetBool("Fire")) {
fpAnimator.SetBool("Fire", true);
gunAnimator.SetBool("Fire", true);
}
else if (mouseClick == 0.0f && fpAnimator.GetBool("Fire")) {
fpAnimator.SetBool("Fire", false);
gunAnimator.SetBool("Fire", false);
}
if (r > 0.0f && !fpAnimator.GetCurrentAnimatorStateInfo(0).IsName("FP_RELOAD")) {
print("looping?");
switchReloadStatus();
fpAnimator.SetBool("Reload", true);
gunAnimator.SetBool("Reload", true);
}
else {
fpAnimator.SetBool("Reload", false);
gunAnimator.SetBool("Reload", false);
}
if (!isReloading && (w > 0.0f || a > 0.0f || s > 0.0f || d > 0.0f) && shift == 0.0f && !fpAnimator.GetBool("isWalking")) {
fpAnimator.SetBool("isWalking", true);
fpAnimator.SetBool("isRunning", false);
gunAnimator.SetBool("isWalking", true);
gunAnimator.SetBool("isRunning", false);
//gunAnimator.SetBool("isWalking", true);
}
else if (!isReloading && (w > 0.0f || a > 0.0f || s > 0.0f || d > 0.0f) && shift > 0.0f && !fpAnimator.GetBool("isRunning")) {
//print("running");
fpAnimator.SetBool("isWalking", false);
fpAnimator.SetBool("isRunning", true);
gunAnimator.SetBool("isWalking", false);
gunAnimator.SetBool("isRunning", true);
}
else if (w == 0.0f && a == 0.0f && s == 0.0f && d == 0.0f){
fpAnimator.SetBool("isWalking", false);
fpAnimator.SetBool("isRunning", false);
gunAnimator.SetBool("isWalking", false);
gunAnimator.SetBool("isRunning", false);
}
print("Running: (FP ANIMATOR)" + fpAnimator.GetBool("isRunning") + ", (GUN ANIMATOR) " + gunAnimator.GetBool("isRunning") + '\n' + "Walking: (FP ANIMATOR)" + fpAnimator.GetBool("isWalking") + ", (GUN ANIMATOR) " + gunAnimator.GetBool("isWalking"));
//Gravity
touchGround = Physics.Raycast(transform.position, Vector3.down, 1.2f, layermask);
if (spacebar > 0.0f && (touchGround)) {
yVelocity.y = vVelocity-gravity*Time.deltaTime;
}
shift = shift * runMultiplier;
//Set up movement direction
float xAccel = d - a;
float zAccel = w - s;
//Vector Normalization
float length = (float)Math.Sqrt(xAccel * xAccel + zAccel * zAccel);
//Set direction to orientation direction, sets up Vector3
Vector3 forward = orientation.forward * zAccel / length * speed;
Vector3 right = orientation.right * xAccel / length * speed;
//Debug.Log("Forward Values: " + forward + "\n" + "rightLeft Values: " + right);
if (shift > 0.0f) {
forward *= shift;
right *= shift;
}
//print(yVelocity.y);
//Debug.Log(forward + right + yVelocity);
if (length > 1.0e-6f) {
movePlayerOnServerSideServerRpc(forward, right, yVelocity, true);
}
else if (spacebar == 0.0f) {
movePlayerOnServerSideServerRpc(forward, right, yVelocity, false);
}
transform.rotation = Quaternion.Euler(orientation.forward);
}
public void switchReloadStatus() {
isReloading = !isReloading;
}
[ServerRpc]
private void movePlayerOnServerSideServerRpc(Vector3 forward, Vector3 leftRight, Vector3 yVelocity, bool isJump) {
if (isJump) {
cController.Move(forward + leftRight + yVelocity * Time.deltaTime);
}
else {
cController.Move(yVelocity * Time.deltaTime);
}
}
}
/*
//Sprint speed multiplied by runMultiplier
shift = inputSystem.PlayerInputs.Shift.ReadValue<float>() * runMultiplier;
//Set up movement direction
float xAccel = d - a;
float zAccel = w - s;
//Vector Normalization
float length = (float)Math.Sqrt(xAccel * xAccel + zAccel * zAccel);
//Set direction to orientation direction, sets up Vector3
Vector3 forward = orientation.forward * zAccel / length * speed;
Vector3 right = orientation.right * xAccel / length * speed;
//Check is shift down
if (shift != 0.0f) {
forward *= shift;
right *= shift;
}
//if length isnt 0 then move player by forward and right
if (length > 1.0e-6f) {
rb.AddForce(forward + right, ForceMode.Impulse);
}
/*
else {
rb.velocity
}
*/
This piece of code makes sure to disable any scripts that the player who joined / created the server doesn’t own
using UnityEngine;
using Unity.Netcode;
public class OwnerComponentManager : NetworkBehaviour
{
[SerializeField] private GameObject objectus;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
objectus.SetActive(IsOwner); // only enable PLAYER'S CAPSULE, all others will stay disabled
}
}
Please let me know if you need more information!