I’m trying to combine these tutorials: http://www.palladiumgames.net/tutorials/unity-networking-tutorial/
and https://www.3dbuzz.com/training/view/3rd-person-character-system
My goal is to use the 3rd person character system in an authoritative server environment, where the server dictates movement to the client according to inputs it receives from the client.
I have not yet tried to include the camera from the 3rd person character system as I’m trying to get movement working and I’m doing this one step at a time
The playerhandler script is attached to the playerprefab, and the error(s) is/are in there somewhere
The Problem:
What is happening is that when the players spawns, their prefab drops slowly until it hits the ground where it stops, if i give it inputs, it stops falling midair but does not move.
I’m going to keep trying to make this work, but I’m honestly not sure what direction to go with this. any help where someone could explain to me whats going on here would be greatly appreciated. I want to understand this.
from googling for a while, it seems that not many people have tried to make the character system from 3dbuzz into multiplayer, and the few that have, have not gone with authoritative structures which is what i need and their movement is still dictated by the client and just synced between clients, so that doesn’t really help me much
The output.log from the server:
Initialize engine version: 4.3.4f1 (e444f76e01cd)
GfxDevice: creating device client; threaded=1
Direct3D:
Version: Direct3D 9.0c [nvd3dum.dll 9.18.13.3165]
Renderer: NVIDIA GeForce 8400 GS
Vendor: NVIDIA
VRAM: 1898 MB (via DXGI)
Caps: Shader=30 DepthRT=1 NativeDepth=1 NativeShadow=1 DF16=0 INTZ=1 RAWZ=0 NULL=1 RESZ=0 SlowINTZ=0
Begin MonoManager ReloadAssembly
Platform assembly: C:\GAMEDIR2\SRV\Server_Data\Managed\UnityEngine.dll (this message is harmless)
Loading C:\GAMEDIR2\SRV\Server_Data\Managed\UnityEngine.dll into Unity Child Domain
Platform assembly: C:\GAMEDIR2\SRV\Server_Data\Managed\Assembly-CSharp.dll (this message is harmless)
Loading C:\GAMEDIR2\SRV\Server_Data\Managed\Assembly-CSharp.dll into Unity Child Domain
- Completed reload, in 0.066 seconds
<RI> Initializing input.
<RI> Input initialized.
desktop: 1024x768 70Hz; virtual: 1024x768 at 0,0
Running as server. Player ID is 0.
(Filename: Line: 2479)
New connection established (127.0.0.1:63872)
(Filename: Line: 2479)
Network protocol version 0 connected
(Filename: Line: 2489)
New scope index 0 is now in scope for AllocatedID: 0
(Filename: Line: 2479)
New scope index 0 is now in scope for SceneID: 1 Level Prefix: 0
(Filename: Line: 2479)
Allocated 2 batches of size 50 for player 1
(Filename: Line: 2489)
Sent initalization to player 1
(Filename: Line: 2479)
Sending generic initial state update, broadcast on, view ID 'SceneID: 1 Level Prefix: 0'
(Filename: Line: 2489)
Received RPC 'AccountCreate'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: AccountCreate - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Platform assembly: C:\GAMEDIR2\SRV\Server_Data\Managed\System.Xml.dll (this message is harmless)
Platform assembly: C:\GAMEDIR2\SRV\Server_Data\Managed\System.dll (this message is harmless)
Received RPC 'AccountLogin'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: AccountLogin - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Received RPC 'RequestSpawn'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: RequestSpawn - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Allocating view ID AllocatedID: 1.
(Filename: Line: 2479)
Sent RPC call '__RPCNetworkInstantiate' to all connected clients
(Filename: Line: 2479)
Added RPC '__RPCNetworkInstantiate' to buffer.
(Filename: Line: 2479)
Assigning a view ID: old view ID 'AllocatedID: 0', new view ID 'AllocatedID: 1'
(Filename: Line: 2489)
Sent RPC call 'SetPlayer' to all connected clients
(Filename: Line: 2479)
Added RPC 'SetPlayer' to buffer.
(Filename: Line: 2479)
Sending generic initial state update, broadcast on, view ID 'AllocatedID: 1'
(Filename: Line: 2489)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
(Filename: Line: 2489)
Sending generic state update, broadcast on, view ID 'AllocatedID: 1'
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
NullReferenceException: Object reference not set to an instance of an object
at PlayerHandler.SnapAlignCharacterWithCamera (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.UpdateMotor (UnityEngine.Transform targetLookAtTransform) [0x00000] in <filename unknown>:0
at PlayerHandler.Update () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Received RPC 'SendMovementInput'- mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
Relay RPC - name: SendMovementInput - mode 0 - sender 127.0.0.1:63872
(Filename: Line: 2489)
using UnityEngine;
using System.Collections;
public class PlayerHandler : MonoBehaviour
{
public static CharacterController CharacterController;
public static PlayerHandler Instance;
Vector3 MoveVector { get ; set; }
float VerticalVelocity {get ; set; }
float ForwardSpeed = 5f;
float BackwardSpeed = 2f;
float StrafingSpeed = 3f;
float SlideSpeed = 7f;
float JumpSpeed = 10f;
float Gravity = 21f;
float TerminalVelocity = 20f;
float SlideThreshold = 0.8f;
float MaxControllableSlideMagnitude = 0.4f;
Vector3 slideDirection;
Vector3 lastMoveVector { get ; set; }
Vector3 currentMoveVector { get ; set; }
public NetworkPlayer theOwner;
//float lastClientHInput = 0f;
//float lastClientVInput = 0f;
//float serverCurrentHInput = 0f;
//float serverCurrentVInput = 0f;
void Awake()
{
if (Network.isClient)
{
enabled = false;
}
CharacterController = GetComponent("CharacterController") as CharacterController;
}
[RPC]
void SetPlayer(NetworkPlayer player)
{
theOwner = player;
if (player == Network.player)
enabled = true;
}
void Update()
{
if (theOwner != null Network.player == theOwner)
{
Instance = this;
Transform targetLookAtTransform = transform.FindChild ("targetLookAt");
GetLocomotionInput(targetLookAtTransform);
HandleActionInput(targetLookAtTransform);
//float HInput = Input.GetAxis("Horizontal");
// float VInput = Input.GetAxis("Vertical");
if (lastMoveVector != MoveVector)
{
lastMoveVector = MoveVector;
}
if (Network.isServer)
{
SendMovementInput(MoveVector);
}
else if (Network.isClient)
{
networkView.RPC("SendMovementInput", RPCMode.Server, MoveVector);
}
}
if(Network.isServer)
{
Instance = this;
Transform targetLookAtTransform = transform.FindChild ("targetLookAt");
//if(Camera.main == null)
// return;
UpdateMotor(targetLookAtTransform);
/*
Vector3 moveDirection = new Vector3(serverCurrentHInput, 0, serverCurrentVInput);
float speed = 5;
transform.Translate(speed * moveDirection * Time.deltaTime);
*/
}
}
[RPC]
void SendMovementInput(Vector3 MoveVector)
{
currentMoveVector = MoveVector;
// serverCurrentHInput = HInput;
// serverCurrentVInput = VInput;
}
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
if (stream.isWriting)
{
Vector3 pos = transform.position;
stream.Serialize(ref pos);
}
else
{
Vector3 posReceive = Vector3.zero;
stream.Serialize(ref posReceive);
transform.position = posReceive;
}
}
public void UpdateMotor(Transform targetLookAtTransform)
{
SnapAlignCharacterWithCamera(targetLookAtTransform);
ProcessMotion();
}
void GetLocomotionInput(Transform targetLookAtTransform)
{
var deadZone = 0.1f;
VerticalVelocity = MoveVector.y;
MoveVector = Vector3.zero;
if(Input.GetAxis("Vertical") > deadZone || Input.GetAxis("Vertical") < -deadZone)
MoveVector += new Vector3 (0,0,Input.GetAxis("Vertical"));
if(Input.GetAxis("Horizontal") > deadZone || Input.GetAxis("Horizontal") < -deadZone)
MoveVector += new Vector3 (Input.GetAxis("Horizontal"),0,0);
DetermineCurrentMoveDirection();
}
void HandleActionInput(Transform targetLookAtTransform)
{
if(Input.GetButton("Jump"))
Jump();
}
void ProcessMotion()
{
/*
Vector3 moveDirection = new Vector3(serverCurrentHInput, 0, serverCurrentVInput);
float speed = 5;
transform.Translate(speed * moveDirection * Time.deltaTime);
*/
MoveVector = transform.TransformDirection(MoveVector);
if (MoveVector.magnitude > 1) MoveVector = Vector3.Normalize(MoveVector);
ApplySlide();
MoveVector *= MoveSpeed();
MoveVector = new Vector3(currentMoveVector.x, VerticalVelocity, currentMoveVector.z);
ApplyGravity();
CharacterController.Move(MoveVector * Time.deltaTime);
}
void ApplyGravity()
{
if(MoveVector.y > -TerminalVelocity)
MoveVector = new Vector3(MoveVector.x, MoveVector.y - Gravity * Time.deltaTime, MoveVector.z);
if(CharacterController.isGrounded MoveVector.y < -1)
MoveVector = new Vector3(MoveVector.x, -1, MoveVector.z);
}
void ApplySlide()
{
if(!CharacterController.isGrounded)
return;
slideDirection = Vector3.zero;
RaycastHit hitInfo;
if(Physics.Raycast(transform.position + Vector3.up, Vector3.down, out hitInfo))
{
if(hitInfo.normal.y < SlideThreshold)
slideDirection = new Vector3(hitInfo.normal.x, -hitInfo.normal.y, hitInfo.normal.z);
}
if(slideDirection.magnitude < MaxControllableSlideMagnitude)
MoveVector += slideDirection;
else
{
MoveVector = slideDirection;
}
}
void Jump()
{
if(CharacterController.isGrounded)
VerticalVelocity = JumpSpeed;
}
void SnapAlignCharacterWithCamera(Transform targetLookAtTransform)
{
if(MoveVector.x != 0 || MoveVector.z !=0)
{
transform.rotation = Quaternion.Euler(transform.eulerAngles.x,Camera.main.transform.eulerAngles.y,transform.eulerAngles.z);
}
}
float MoveSpeed()
{
var moveSpeed = 0f;
switch (MoveDirection)
{
case Direction.Stationary:
moveSpeed = 0;
break;
case Direction.Forward:
moveSpeed = ForwardSpeed;
break;
case Direction.Backward:
moveSpeed = BackwardSpeed;
break;
case Direction.Left:
moveSpeed = StrafingSpeed;
break;
case Direction.Right:
moveSpeed = StrafingSpeed;
break;
case Direction.LeftForward:
moveSpeed = ForwardSpeed;
break;
case Direction.RightForward:
moveSpeed = ForwardSpeed;
break;
case Direction.LeftBackward:
moveSpeed = BackwardSpeed;
break;
case Direction.RightBackward:
moveSpeed = BackwardSpeed;
break;
}
if(slideDirection.magnitude > 0)
moveSpeed = SlideSpeed;
return moveSpeed;
}
public enum Direction
{
Stationary, Forward, Backward, Left, Right,
LeftForward, RightForward, LeftBackward, RightBackward
}
public Direction MoveDirection {get; set;}
public void DetermineCurrentMoveDirection()
{
bool forward = false;
bool backward = false;
bool left = false;
bool right = false;
if(MoveVector.z > 0)
forward = true;
if(MoveVector.z < 0)
backward = true;
if(MoveVector.x > 0)
right = true;
if(MoveVector.x < 0)
left = true;
if(forward)
{
if(left)
MoveDirection = Direction.LeftForward;
else if(right)
MoveDirection = Direction.RightForward;
else
MoveDirection = Direction.Forward;
}
else if(backward)
{
if(left)
MoveDirection = Direction.LeftBackward;
else if(right)
MoveDirection = Direction.RightBackward;
else
MoveDirection = Direction.Backward;
}
else if(left)
MoveDirection = Direction.Left;
else if(right)
MoveDirection = Direction.Right;
else
MoveDirection = Direction.Stationary;
}
}