Gonna move to server authority

This commit is contained in:
2022-01-31 17:27:38 +05:30
parent f3d21f4ec6
commit 7368968176
1354 changed files with 107808 additions and 80043 deletions

View File

@@ -1,146 +1,146 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[AddComponentMenu("")]
public class MultiSceneNetManager : NetworkManager
{
[Header("Spawner Setup")]
[Tooltip("Reward Prefab for the Spawner")]
public GameObject rewardPrefab;
[Header("MultiScene Setup")]
public int instances = 3;
[Scene]
public string gameScene;
// This is set true after server loads all subscene instances
bool subscenesLoaded;
// subscenes are added to this list as they're loaded
readonly List<Scene> subScenes = new List<Scene>();
// Sequential index used in round-robin deployment of players into instances and score positioning
int clientIndex;
#region Server System Callbacks
/// <summary>
/// Called on the server when a client adds a new player with NetworkClient.AddPlayer.
/// <para>The default implementation for this function creates a new player object from the playerPrefab.</para>
/// </summary>
/// <param name="conn">Connection from client.</param>
public override void OnServerAddPlayer(NetworkConnection conn)
{
StartCoroutine(OnServerAddPlayerDelayed(conn));
}
// This delay is mostly for the host player that loads too fast for the
// server to have subscenes async loaded from OnStartServer ahead of it.
IEnumerator OnServerAddPlayerDelayed(NetworkConnection conn)
{
// wait for server to async load all subscenes for game instances
while (!subscenesLoaded)
yield return null;
// Send Scene message to client to additively load the game scene
conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive });
// Wait for end of frame before adding the player to ensure Scene Message goes first
yield return new WaitForEndOfFrame();
base.OnServerAddPlayer(conn);
PlayerScore playerScore = conn.identity.GetComponent<PlayerScore>();
playerScore.playerNumber = clientIndex;
playerScore.scoreIndex = clientIndex / subScenes.Count;
playerScore.matchIndex = clientIndex % subScenes.Count;
clientIndex++;
// Do this only on server, not on clients
// This is what allows the NetworkSceneChecker on player and scene objects
// to isolate matches per scene instance on server.
if (subScenes.Count > 0)
SceneManager.MoveGameObjectToScene(conn.identity.gameObject, subScenes[clientIndex % subScenes.Count]);
}
#endregion
#region Start & Stop Callbacks
/// <summary>
/// This is invoked when a server is started - including when a host is started.
/// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
/// </summary>
public override void OnStartServer()
{
StartCoroutine(ServerLoadSubScenes());
}
// We're additively loading scenes, so GetSceneAt(0) will return the main "container" scene,
// therefore we start the index at one and loop through instances value inclusively.
// If instances is zero, the loop is bypassed entirely.
IEnumerator ServerLoadSubScenes()
{
for (int index = 1; index <= instances; index++)
{
yield return SceneManager.LoadSceneAsync(gameScene, new LoadSceneParameters { loadSceneMode = LoadSceneMode.Additive, localPhysicsMode = LocalPhysicsMode.Physics3D });
Scene newScene = SceneManager.GetSceneAt(index);
subScenes.Add(newScene);
Spawner.InitialSpawn(newScene);
}
subscenesLoaded = true;
}
/// <summary>
/// This is called when a server is stopped - including when a host is stopped.
/// </summary>
public override void OnStopServer()
{
NetworkServer.SendToAll(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.UnloadAdditive });
StartCoroutine(ServerUnloadSubScenes());
clientIndex = 0;
}
// Unload the subScenes and unused assets and clear the subScenes list.
IEnumerator ServerUnloadSubScenes()
{
for (int index = 0; index < subScenes.Count; index++)
yield return SceneManager.UnloadSceneAsync(subScenes[index]);
subScenes.Clear();
subscenesLoaded = false;
yield return Resources.UnloadUnusedAssets();
}
/// <summary>
/// This is called when a client is stopped.
/// </summary>
public override void OnStopClient()
{
// make sure we're not in host mode
if (mode == NetworkManagerMode.ClientOnly)
StartCoroutine(ClientUnloadSubScenes());
}
// Unload all but the active scene, which is the "container" scene
IEnumerator ClientUnloadSubScenes()
{
for (int index = 0; index < SceneManager.sceneCount; index++)
{
if (SceneManager.GetSceneAt(index) != SceneManager.GetActiveScene())
yield return SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(index));
}
}
#endregion
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[AddComponentMenu("")]
public class MultiSceneNetManager : NetworkManager
{
[Header("Spawner Setup")]
[Tooltip("Reward Prefab for the Spawner")]
public GameObject rewardPrefab;
[Header("MultiScene Setup")]
public int instances = 3;
[Scene]
public string gameScene;
// This is set true after server loads all subscene instances
bool subscenesLoaded;
// subscenes are added to this list as they're loaded
readonly List<Scene> subScenes = new List<Scene>();
// Sequential index used in round-robin deployment of players into instances and score positioning
int clientIndex;
#region Server System Callbacks
/// <summary>
/// Called on the server when a client adds a new player with NetworkClient.AddPlayer.
/// <para>The default implementation for this function creates a new player object from the playerPrefab.</para>
/// </summary>
/// <param name="conn">Connection from client.</param>
public override void OnServerAddPlayer(NetworkConnection conn)
{
StartCoroutine(OnServerAddPlayerDelayed(conn));
}
// This delay is mostly for the host player that loads too fast for the
// server to have subscenes async loaded from OnStartServer ahead of it.
IEnumerator OnServerAddPlayerDelayed(NetworkConnection conn)
{
// wait for server to async load all subscenes for game instances
while (!subscenesLoaded)
yield return null;
// Send Scene message to client to additively load the game scene
conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive });
// Wait for end of frame before adding the player to ensure Scene Message goes first
yield return new WaitForEndOfFrame();
base.OnServerAddPlayer(conn);
PlayerScore playerScore = conn.identity.GetComponent<PlayerScore>();
playerScore.playerNumber = clientIndex;
playerScore.scoreIndex = clientIndex / subScenes.Count;
playerScore.matchIndex = clientIndex % subScenes.Count;
clientIndex++;
// Do this only on server, not on clients
// This is what allows the NetworkSceneChecker on player and scene objects
// to isolate matches per scene instance on server.
if (subScenes.Count > 0)
SceneManager.MoveGameObjectToScene(conn.identity.gameObject, subScenes[clientIndex % subScenes.Count]);
}
#endregion
#region Start & Stop Callbacks
/// <summary>
/// This is invoked when a server is started - including when a host is started.
/// <para>StartServer has multiple signatures, but they all cause this hook to be called.</para>
/// </summary>
public override void OnStartServer()
{
StartCoroutine(ServerLoadSubScenes());
}
// We're additively loading scenes, so GetSceneAt(0) will return the main "container" scene,
// therefore we start the index at one and loop through instances value inclusively.
// If instances is zero, the loop is bypassed entirely.
IEnumerator ServerLoadSubScenes()
{
for (int index = 1; index <= instances; index++)
{
yield return SceneManager.LoadSceneAsync(gameScene, new LoadSceneParameters { loadSceneMode = LoadSceneMode.Additive, localPhysicsMode = LocalPhysicsMode.Physics3D });
Scene newScene = SceneManager.GetSceneAt(index);
subScenes.Add(newScene);
Spawner.InitialSpawn(newScene);
}
subscenesLoaded = true;
}
/// <summary>
/// This is called when a server is stopped - including when a host is stopped.
/// </summary>
public override void OnStopServer()
{
NetworkServer.SendToAll(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.UnloadAdditive });
StartCoroutine(ServerUnloadSubScenes());
clientIndex = 0;
}
// Unload the subScenes and unused assets and clear the subScenes list.
IEnumerator ServerUnloadSubScenes()
{
for (int index = 0; index < subScenes.Count; index++)
yield return SceneManager.UnloadSceneAsync(subScenes[index]);
subScenes.Clear();
subscenesLoaded = false;
yield return Resources.UnloadUnusedAssets();
}
/// <summary>
/// This is called when a client is stopped.
/// </summary>
public override void OnStopClient()
{
// make sure we're not in host mode
if (mode == NetworkManagerMode.ClientOnly)
StartCoroutine(ClientUnloadSubScenes());
}
// Unload all but the active scene, which is the "container" scene
IEnumerator ClientUnloadSubScenes()
{
for (int index = 0; index < SceneManager.sceneCount; index++)
{
if (SceneManager.GetSceneAt(index) != SceneManager.GetActiveScene())
yield return SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(index));
}
}
#endregion
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: b982a1fd37427e64e8310a863d03d2c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: b982a1fd37427e64e8310a863d03d2c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,44 +1,44 @@
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(Rigidbody))]
public class PhysicsCollision : NetworkBehaviour
{
[Tooltip("how forcefully to push this object")]
public float force = 12;
public Rigidbody rigidbody3D;
void OnValidate()
{
if (rigidbody3D == null)
rigidbody3D = GetComponent<Rigidbody>();
}
void Start()
{
rigidbody3D.isKinematic = !isServer;
}
[ServerCallback]
void OnCollisionStay(Collision other)
{
if (other.gameObject.CompareTag("Player"))
{
// get direction from which player is contacting object
Vector3 direction = other.contacts[0].normal;
// zero the y and normalize so we don't shove this through the floor or launch this over the wall
direction.y = 0;
direction = direction.normalized;
// push this away from player...a bit less force for host player
if (other.gameObject.GetComponent<NetworkIdentity>().connectionToClient.connectionId == NetworkConnection.LocalConnectionId)
rigidbody3D.AddForce(direction * force * .5f);
else
rigidbody3D.AddForce(direction * force);
}
}
}
}
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(Rigidbody))]
public class PhysicsCollision : NetworkBehaviour
{
[Tooltip("how forcefully to push this object")]
public float force = 12;
public Rigidbody rigidbody3D;
void OnValidate()
{
if (rigidbody3D == null)
rigidbody3D = GetComponent<Rigidbody>();
}
void Start()
{
rigidbody3D.isKinematic = !isServer;
}
[ServerCallback]
void OnCollisionStay(Collision other)
{
if (other.gameObject.CompareTag("Player"))
{
// get direction from which player is contacting object
Vector3 direction = other.contacts[0].normal;
// zero the y and normalize so we don't shove this through the floor or launch this over the wall
direction.y = 0;
direction = direction.normalized;
// push this away from player...a bit less force for host player
if (other.gameObject.GetComponent<NetworkIdentity>().connectionToClient.connectionId == NetworkConnection.LocalConnectionId)
rigidbody3D.AddForce(direction * force * .5f);
else
rigidbody3D.AddForce(direction * force);
}
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: c709489168fec9348b7f8290ee2e8466
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: c709489168fec9348b7f8290ee2e8466
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,40 +1,40 @@
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class PhysicsSimulator : MonoBehaviour
{
PhysicsScene physicsScene;
PhysicsScene2D physicsScene2D;
bool simulatePhysicsScene;
bool simulatePhysicsScene2D;
void Awake()
{
if (NetworkServer.active)
{
physicsScene = gameObject.scene.GetPhysicsScene();
simulatePhysicsScene = physicsScene.IsValid() && physicsScene != Physics.defaultPhysicsScene;
physicsScene2D = gameObject.scene.GetPhysicsScene2D();
simulatePhysicsScene2D = physicsScene2D.IsValid() && physicsScene2D != Physics2D.defaultPhysicsScene;
}
else
{
enabled = false;
}
}
void FixedUpdate()
{
if (!NetworkServer.active) return;
if (simulatePhysicsScene)
physicsScene.Simulate(Time.fixedDeltaTime);
if (simulatePhysicsScene2D)
physicsScene2D.Simulate(Time.fixedDeltaTime);
}
}
}
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class PhysicsSimulator : MonoBehaviour
{
PhysicsScene physicsScene;
PhysicsScene2D physicsScene2D;
bool simulatePhysicsScene;
bool simulatePhysicsScene2D;
void Awake()
{
if (NetworkServer.active)
{
physicsScene = gameObject.scene.GetPhysicsScene();
simulatePhysicsScene = physicsScene.IsValid() && physicsScene != Physics.defaultPhysicsScene;
physicsScene2D = gameObject.scene.GetPhysicsScene2D();
simulatePhysicsScene2D = physicsScene2D.IsValid() && physicsScene2D != Physics2D.defaultPhysicsScene;
}
else
{
enabled = false;
}
}
void FixedUpdate()
{
if (!NetworkServer.active) return;
if (simulatePhysicsScene)
physicsScene.Simulate(Time.fixedDeltaTime);
if (simulatePhysicsScene2D)
physicsScene2D.Simulate(Time.fixedDeltaTime);
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: 78e3051d2c03f27429276d8a55a6d15c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 78e3051d2c03f27429276d8a55a6d15c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,112 +1,112 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(NetworkTransform))]
[RequireComponent(typeof(Rigidbody))]
public class PlayerController : NetworkBehaviour
{
public CharacterController characterController;
void OnValidate()
{
if (characterController == null)
characterController = GetComponent<CharacterController>();
}
void Start()
{
characterController.enabled = isLocalPlayer;
}
public override void OnStartLocalPlayer()
{
Camera.main.orthographic = false;
Camera.main.transform.SetParent(transform);
Camera.main.transform.localPosition = new Vector3(0f, 3f, -8f);
Camera.main.transform.localEulerAngles = new Vector3(10f, 0f, 0f);
}
void OnDisable()
{
if (isLocalPlayer && Camera.main != null)
{
Camera.main.orthographic = true;
Camera.main.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(Camera.main.gameObject, SceneManager.GetActiveScene());
Camera.main.transform.localPosition = new Vector3(0f, 70f, 0f);
Camera.main.transform.localEulerAngles = new Vector3(90f, 0f, 0f);
}
}
[Header("Movement Settings")]
public float moveSpeed = 8f;
public float turnSensitivity = 5f;
public float maxTurnSpeed = 150f;
[Header("Diagnostics")]
public float horizontal;
public float vertical;
public float turn;
public float jumpSpeed;
public bool isGrounded = true;
public bool isFalling;
public Vector3 velocity;
void Update()
{
if (!isLocalPlayer || !characterController.enabled)
return;
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
// Q and E cancel each other out, reducing the turn to zero
if (Input.GetKey(KeyCode.Q))
turn = Mathf.MoveTowards(turn, -maxTurnSpeed, turnSensitivity);
if (Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, maxTurnSpeed, turnSensitivity);
if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, 0, turnSensitivity);
if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, 0, turnSensitivity);
if (isGrounded)
isFalling = false;
if ((isGrounded || !isFalling) && jumpSpeed < 1f && Input.GetKey(KeyCode.Space))
{
jumpSpeed = Mathf.Lerp(jumpSpeed, 1f, 0.5f);
}
else if (!isGrounded)
{
isFalling = true;
jumpSpeed = 0;
}
}
void FixedUpdate()
{
if (!isLocalPlayer || characterController == null)
return;
transform.Rotate(0f, turn * Time.fixedDeltaTime, 0f);
Vector3 direction = new Vector3(horizontal, jumpSpeed, vertical);
direction = Vector3.ClampMagnitude(direction, 1f);
direction = transform.TransformDirection(direction);
direction *= moveSpeed;
if (jumpSpeed > 0)
characterController.Move(direction * Time.fixedDeltaTime);
else
characterController.SimpleMove(direction);
isGrounded = characterController.isGrounded;
velocity = characterController.velocity;
}
}
}
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(NetworkTransform))]
[RequireComponent(typeof(Rigidbody))]
public class PlayerController : NetworkBehaviour
{
public CharacterController characterController;
void OnValidate()
{
if (characterController == null)
characterController = GetComponent<CharacterController>();
}
void Start()
{
characterController.enabled = isLocalPlayer;
}
public override void OnStartLocalPlayer()
{
Camera.main.orthographic = false;
Camera.main.transform.SetParent(transform);
Camera.main.transform.localPosition = new Vector3(0f, 3f, -8f);
Camera.main.transform.localEulerAngles = new Vector3(10f, 0f, 0f);
}
void OnDisable()
{
if (isLocalPlayer && Camera.main != null)
{
Camera.main.orthographic = true;
Camera.main.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(Camera.main.gameObject, SceneManager.GetActiveScene());
Camera.main.transform.localPosition = new Vector3(0f, 70f, 0f);
Camera.main.transform.localEulerAngles = new Vector3(90f, 0f, 0f);
}
}
[Header("Movement Settings")]
public float moveSpeed = 8f;
public float turnSensitivity = 5f;
public float maxTurnSpeed = 150f;
[Header("Diagnostics")]
public float horizontal;
public float vertical;
public float turn;
public float jumpSpeed;
public bool isGrounded = true;
public bool isFalling;
public Vector3 velocity;
void Update()
{
if (!isLocalPlayer || !characterController.enabled)
return;
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
// Q and E cancel each other out, reducing the turn to zero
if (Input.GetKey(KeyCode.Q))
turn = Mathf.MoveTowards(turn, -maxTurnSpeed, turnSensitivity);
if (Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, maxTurnSpeed, turnSensitivity);
if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, 0, turnSensitivity);
if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E))
turn = Mathf.MoveTowards(turn, 0, turnSensitivity);
if (isGrounded)
isFalling = false;
if ((isGrounded || !isFalling) && jumpSpeed < 1f && Input.GetKey(KeyCode.Space))
{
jumpSpeed = Mathf.Lerp(jumpSpeed, 1f, 0.5f);
}
else if (!isGrounded)
{
isFalling = true;
jumpSpeed = 0;
}
}
void FixedUpdate()
{
if (!isLocalPlayer || characterController == null)
return;
transform.Rotate(0f, turn * Time.fixedDeltaTime, 0f);
Vector3 direction = new Vector3(horizontal, jumpSpeed, vertical);
direction = Vector3.ClampMagnitude(direction, 1f);
direction = transform.TransformDirection(direction);
direction *= moveSpeed;
if (jumpSpeed > 0)
characterController.Move(direction * Time.fixedDeltaTime);
else
characterController.SimpleMove(direction);
isGrounded = characterController.isGrounded;
velocity = characterController.velocity;
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: 479a5196564ede84791870b414a13645
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 479a5196564ede84791870b414a13645
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,30 +1,30 @@
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class PlayerScore : NetworkBehaviour
{
[SyncVar]
public int playerNumber;
[SyncVar]
public int scoreIndex;
[SyncVar]
public int matchIndex;
[SyncVar]
public uint score;
public int clientMatchIndex = -1;
void OnGUI()
{
if (!isServerOnly && !isLocalPlayer && clientMatchIndex < 0)
clientMatchIndex = NetworkClient.connection.identity.GetComponent<PlayerScore>().matchIndex;
if (isLocalPlayer || matchIndex == clientMatchIndex)
GUI.Box(new Rect(10f + (scoreIndex * 110), 10f, 100f, 25f), $"P{playerNumber}: {score}");
}
}
}
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class PlayerScore : NetworkBehaviour
{
[SyncVar]
public int playerNumber;
[SyncVar]
public int scoreIndex;
[SyncVar]
public int matchIndex;
[SyncVar]
public uint score;
public int clientMatchIndex = -1;
void OnGUI()
{
if (!isServerOnly && !isLocalPlayer && clientMatchIndex < 0)
clientMatchIndex = NetworkClient.connection.identity.GetComponent<PlayerScore>().matchIndex;
if (isLocalPlayer || matchIndex == clientMatchIndex)
GUI.Box(new Rect(10f + (scoreIndex * 110), 10f, 100f, 25f), $"P{playerNumber}: {score}");
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: 8be750efa9df50f47b65ae156053d149
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 8be750efa9df50f47b65ae156053d149
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,32 +1,32 @@
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class RandomColor : NetworkBehaviour
{
public override void OnStartServer()
{
base.OnStartServer();
color = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
}
// Color32 packs to 4 bytes
[SyncVar(hook = nameof(SetColor))]
public Color32 color = Color.black;
// Unity clones the material when GetComponent<Renderer>().material is called
// Cache it here and destroy it in OnDestroy to prevent a memory leak
Material cachedMaterial;
void SetColor(Color32 _, Color32 newColor)
{
if (cachedMaterial == null) cachedMaterial = GetComponentInChildren<Renderer>().material;
cachedMaterial.color = newColor;
}
void OnDestroy()
{
Destroy(cachedMaterial);
}
}
}
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
public class RandomColor : NetworkBehaviour
{
public override void OnStartServer()
{
base.OnStartServer();
color = Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
}
// Color32 packs to 4 bytes
[SyncVar(hook = nameof(SetColor))]
public Color32 color = Color.black;
// Unity clones the material when GetComponent<Renderer>().material is called
// Cache it here and destroy it in OnDestroy to prevent a memory leak
Material cachedMaterial;
void SetColor(Color32 _, Color32 newColor)
{
if (cachedMaterial == null) cachedMaterial = GetComponentInChildren<Renderer>().material;
cachedMaterial.color = newColor;
}
void OnDestroy()
{
Destroy(cachedMaterial);
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: 218520098fbe58b4b8f0963ef41953f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 218520098fbe58b4b8f0963ef41953f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,52 +1,52 @@
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(RandomColor))]
public class Reward : NetworkBehaviour
{
public bool available = true;
public RandomColor randomColor;
void OnValidate()
{
if (randomColor == null)
randomColor = GetComponent<RandomColor>();
}
[ServerCallback]
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
ClaimPrize(other.gameObject);
}
// This is called from PlayerController.CmdClaimPrize which is invoked by PlayerController.OnControllerColliderHit
// This only runs on the server
public void ClaimPrize(GameObject player)
{
if (available)
{
// This is a fast switch to prevent two players claiming the prize in a bang-bang close contest for it.
// First hit turns it off, pending the object being destroyed a few frames later.
available = false;
Color32 color = randomColor.color;
// calculate the points from the color ... lighter scores higher as the average approaches 255
// UnityEngine.Color RGB values are float fractions of 255
uint points = (uint)(((color.r) + (color.g) + (color.b)) / 3);
// Debug.LogFormat(LogType.Log, "Scored {0} points R:{1} G:{2} B:{3}", points, color.r, color.g, color.b);
// award the points via SyncVar on the PlayerController
player.GetComponent<PlayerScore>().score += points;
// spawn a replacement
Spawner.SpawnReward(gameObject.scene);
// destroy this one
NetworkServer.Destroy(gameObject);
}
}
}
}
using UnityEngine;
namespace Mirror.Examples.MultipleAdditiveScenes
{
[RequireComponent(typeof(RandomColor))]
public class Reward : NetworkBehaviour
{
public bool available = true;
public RandomColor randomColor;
void OnValidate()
{
if (randomColor == null)
randomColor = GetComponent<RandomColor>();
}
[ServerCallback]
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
ClaimPrize(other.gameObject);
}
// This is called from PlayerController.CmdClaimPrize which is invoked by PlayerController.OnControllerColliderHit
// This only runs on the server
public void ClaimPrize(GameObject player)
{
if (available)
{
// This is a fast switch to prevent two players claiming the prize in a bang-bang close contest for it.
// First hit turns it off, pending the object being destroyed a few frames later.
available = false;
Color32 color = randomColor.color;
// calculate the points from the color ... lighter scores higher as the average approaches 255
// UnityEngine.Color RGB values are float fractions of 255
uint points = (uint)(((color.r) + (color.g) + (color.b)) / 3);
// Debug.LogFormat(LogType.Log, "Scored {0} points R:{1} G:{2} B:{3}", points, color.r, color.g, color.b);
// award the points via SyncVar on the PlayerController
player.GetComponent<PlayerScore>().score += points;
// spawn a replacement
Spawner.SpawnReward(gameObject.scene);
// destroy this one
NetworkServer.Destroy(gameObject);
}
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: 10da7fdf8caa1eb4697658bf129457fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 10da7fdf8caa1eb4697658bf129457fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''

View File

@@ -1,26 +1,26 @@
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
internal class Spawner
{
internal static void InitialSpawn(Scene scene)
{
if (!NetworkServer.active) return;
for (int i = 0; i < 10; i++)
SpawnReward(scene);
}
internal static void SpawnReward(Scene scene)
{
if (!NetworkServer.active) return;
Vector3 spawnPosition = new Vector3(Random.Range(-19, 20), 1, Random.Range(-19, 20));
GameObject reward = Object.Instantiate(((MultiSceneNetManager)NetworkManager.singleton).rewardPrefab, spawnPosition, Quaternion.identity);
SceneManager.MoveGameObjectToScene(reward, scene);
NetworkServer.Spawn(reward);
}
}
}
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.MultipleAdditiveScenes
{
internal class Spawner
{
internal static void InitialSpawn(Scene scene)
{
if (!NetworkServer.active) return;
for (int i = 0; i < 10; i++)
SpawnReward(scene);
}
internal static void SpawnReward(Scene scene)
{
if (!NetworkServer.active) return;
Vector3 spawnPosition = new Vector3(Random.Range(-19, 20), 1, Random.Range(-19, 20));
GameObject reward = Object.Instantiate(((MultiSceneNetManager)NetworkManager.singleton).rewardPrefab, spawnPosition, Quaternion.identity);
SceneManager.MoveGameObjectToScene(reward, scene);
NetworkServer.Spawn(reward);
}
}
}

View File

@@ -1,11 +1,11 @@
fileFormatVersion: 2
guid: f522bf510b49da44caa9f3ca0ac17f3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: f522bf510b49da44caa9f3ca0ac17f3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''