485 lines
16 KiB
C#
485 lines
16 KiB
C#
using DamageNumbersPro;
|
|
using Photon.Pun;
|
|
using Photon.Realtime;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Animations.Rigging;
|
|
using static UnityEngine.EventSystems.EventTrigger;
|
|
|
|
public class PlayerNetwork : MonoBehaviourPunCallbacks, IPunObservable
|
|
{
|
|
public string username;
|
|
public string partyname;
|
|
public string partyId;
|
|
public Rig weaponRig;
|
|
public Rig aimRig;
|
|
|
|
public Animator anim;
|
|
public RuntimeAnimatorController defaultAnim;
|
|
public Transform lookAtTarget;
|
|
public List<PlayerWeaponEntry> weapons;
|
|
public List<LootObjectEntry> nades;
|
|
public int selectedWeaponIndex = -1;
|
|
public int selectedNadeIndex=-1;
|
|
|
|
[Range(0,100f)]
|
|
public float health = 100;
|
|
[Range(0,100f)]
|
|
public float shield = 100;
|
|
|
|
public int kills;
|
|
public int deaths;
|
|
public int assists;
|
|
|
|
PlayerFX playerFX;
|
|
public AnimationCurve DistanceDamageCurve;
|
|
public float BulletEffectiveRange;
|
|
List<HitBox> hitboxes = new List<HitBox>();
|
|
public void RegisterHitbox(HitBox hitBox){
|
|
if(hitboxes == null){hitboxes = new List<HitBox>();}
|
|
|
|
hitboxes.Add(hitBox);
|
|
}
|
|
void Awake()
|
|
{
|
|
playerController = GetComponent<PlayerController>();
|
|
playerFX = GetComponent<PlayerFX>();
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
if (photonView.IsMine)
|
|
{
|
|
photonView.RPC("RpcSyncName", RpcTarget.AllBuffered ,string.IsNullOrEmpty(LoginManager.username) ? "Dev0" : LoginManager.username);
|
|
|
|
UIManager.SetHealth(health,shield);
|
|
UIManager.SetUsername( username);
|
|
|
|
|
|
//
|
|
partyId = GameManager.partyId;
|
|
List<string> availablePartyNames = Helpers.battleTeamNames.ToList<string>();
|
|
string partyName = Helpers.RandomTeamName;
|
|
PlayerNetwork[] players = FindObjectsOfType<PlayerNetwork>();
|
|
bool foundMyParty = false;
|
|
foreach(PlayerNetwork player in players){
|
|
if(player == this){continue;}
|
|
if(player.partyId == partyId){
|
|
//Found my party!
|
|
partyName = player.partyname;
|
|
foundMyParty = true;
|
|
Debug.Log("Found my party! Its called " + player.partyname);
|
|
break;
|
|
}else{
|
|
if(availablePartyNames.Contains(player.partyname)){
|
|
availablePartyNames.Remove(player.partyname);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!foundMyParty){
|
|
partyName = availablePartyNames[UnityEngine.Random.Range(0, availablePartyNames.Count)];
|
|
Debug.Log("Got a new party name! : " + partyName);
|
|
}
|
|
|
|
partyname = partyName;
|
|
}
|
|
|
|
GetComponent<CharacterController>().detectCollisions=false;
|
|
}
|
|
|
|
public void SetActiveWeapon(LootItemScriptableObject data)
|
|
{
|
|
int _selectedIndex = -1;
|
|
int _selectedNadeIndex =-1;
|
|
|
|
if(data == null){
|
|
selectedNadeIndex = _selectedNadeIndex;
|
|
selectedWeaponIndex = _selectedIndex;
|
|
return;
|
|
}
|
|
|
|
if(data.isThrowable){
|
|
_selectedIndex=-1;
|
|
|
|
for(int i=0;i < nades.Count; i++){
|
|
if(nades[i].data == data){
|
|
_selectedNadeIndex=i;
|
|
break;
|
|
}
|
|
}
|
|
}else{
|
|
_selectedNadeIndex=-1;
|
|
for(int i=0; i < weapons.Count; i++)
|
|
{
|
|
if (weapons[i].data == data)
|
|
{
|
|
_selectedIndex = i;
|
|
UpdatePlayerFX(weapons[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
selectedNadeIndex =_selectedNadeIndex;
|
|
selectedWeaponIndex = _selectedIndex;
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcSyncName(string name)
|
|
{
|
|
username = name;
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcSyncPartyName(string name,string id){
|
|
partyname = name;
|
|
partyId = id;
|
|
}
|
|
|
|
|
|
void IPunObservable.OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
|
|
{
|
|
if (stream.IsWriting)
|
|
{
|
|
stream.SendNext(lookAtTarget.position);
|
|
stream.SendNext(weaponRig.weight);
|
|
stream.SendNext(aimRig.weight);
|
|
stream.SendNext(weaponRig.weight);
|
|
stream.SendNext(selectedWeaponIndex);
|
|
stream.SendNext(selectedNadeIndex);
|
|
stream.SendNext(health);
|
|
stream.SendNext(shield);
|
|
stream.SendNext(kills);
|
|
stream.SendNext(deaths);
|
|
stream.SendNext(assists);
|
|
stream.SendNext(partyId);
|
|
stream.SendNext(partyname);
|
|
}
|
|
else
|
|
{
|
|
lookAtTarget.position = Vector3.Lerp(lookAtTarget.position, (Vector3)stream.ReceiveNext(),0.5f);
|
|
weaponRig.weight = (float)stream.ReceiveNext();
|
|
aimRig.weight= (float)stream.ReceiveNext();
|
|
weaponRig.weight= (float)stream.ReceiveNext();
|
|
selectedWeaponIndex =((int)stream.ReceiveNext());
|
|
selectedNadeIndex = ((int)stream.ReceiveNext());
|
|
health = (float)stream.ReceiveNext();
|
|
shield = (float)stream.ReceiveNext();
|
|
kills = (int)stream.ReceiveNext();
|
|
deaths = (int)stream.ReceiveNext();
|
|
assists = (int)stream.ReceiveNext();
|
|
partyId = (string)stream.ReceiveNext();
|
|
partyname = (string)stream.ReceiveNext();
|
|
|
|
|
|
if(prevActiveWeapon != selectedWeaponIndex || prevActiveNade != selectedNadeIndex){
|
|
UpdateActiveWeapon();
|
|
}
|
|
|
|
prevActiveWeapon = selectedWeaponIndex;
|
|
prevActiveNade = selectedNadeIndex;
|
|
}
|
|
}
|
|
float prevActiveWeapon =0;
|
|
float prevActiveNade=0;
|
|
void UpdateActiveWeapon()
|
|
{
|
|
for(int i=0; i < weapons.Count; i++)
|
|
{
|
|
weapons[i].obj.SetActive(i == selectedWeaponIndex);
|
|
weapons[i].muzzleFlash.SetActive(false);
|
|
|
|
if(selectedWeaponIndex == i)
|
|
{
|
|
UpdatePlayerFX(weapons[i]);
|
|
}
|
|
}
|
|
|
|
for(int i=0; i < nades.Count; i++){
|
|
nades[i].obj.SetActive(i==selectedNadeIndex);
|
|
}
|
|
}
|
|
public LootItemScriptableObject CurrentWeaponData;
|
|
void UpdatePlayerFX(PlayerWeaponEntry data)
|
|
{
|
|
playerFX.MuzzleFlash = data.muzzleFlash;
|
|
playerFX.FireSFXs = data.FireSFX;
|
|
|
|
// playerFX.fireSFX = data.FireSFX;
|
|
|
|
if(!photonView.IsMine){
|
|
if(data.data.overrideController == null){
|
|
anim.runtimeAnimatorController = defaultAnim;
|
|
}else{
|
|
anim.runtimeAnimatorController = data.data.overrideController;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnNadeThrow(){
|
|
photonView.RPC("RpcOnNadeThrow", RpcTarget.All);
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcOnNadeThrow(){
|
|
if(!photonView.IsMine){
|
|
anim.SetTrigger("Throw");
|
|
}
|
|
}
|
|
|
|
PlayerController playerController;
|
|
public void OnHit(int id, HitBoxType type, Vector3 point, float dist)
|
|
{
|
|
float damage = PlayerControllerHelper.GetDamageForHitboxType(type) *GetDamageMultiplier(dist);
|
|
photonView.RPC("RpcOnHit", RpcTarget.All, id, damage,point);
|
|
}
|
|
|
|
public void OnHit(int id, float damage,Vector3 point,float dist)
|
|
{
|
|
photonView.RPC("RpcOnHit", RpcTarget.All, id, damage * GetDamageMultiplier(dist), point);
|
|
}
|
|
|
|
public float GetDamageMultiplier(float dist){
|
|
if(!GameManager.isInit){return 0;}
|
|
return DistanceDamageCurve.Evaluate(Mathf.Clamp01(dist/BulletEffectiveRange));
|
|
}
|
|
|
|
|
|
[PunRPC]
|
|
void RpcOnHit(int id, float damage, Vector3 point)
|
|
{
|
|
Debug.Log($"{username} ({photonView.ViewID}) Got hit by user ID {id})");
|
|
|
|
float newShield = shield;
|
|
float newHealth = health;
|
|
|
|
if(shield > 0){
|
|
newShield = Mathf.Clamp(shield - damage,0,100);
|
|
}else{
|
|
newHealth = health-damage;
|
|
}
|
|
|
|
if (photonView.IsMine)
|
|
{
|
|
playerController.OnHit(damage);
|
|
|
|
UIManager.instance.OnScreenDamageFx.color = new Color(1, 1, 1, UIManager.instance.OnScreenDamageFx.color.a + (damage / 100f));
|
|
GameObject enemy = PhotonView.Find(id).gameObject;
|
|
|
|
if(newHealth <= 0 && health >0)
|
|
{
|
|
//Death
|
|
bool shouldSpawnLoot = GameManager.desiredGameMode != GameModes.Deathmatch.ToString();
|
|
//Spawn loots
|
|
if(shouldSpawnLoot){
|
|
float a= 0;
|
|
foreach(KeyValuePair<LootItemScriptableObject,int> item in InventoryManager.instance.Stock){
|
|
a += Mathf.PI * 0.2f;
|
|
float x = Mathf.Sin(a);
|
|
float y = Mathf.Cos(a);
|
|
GameManager.instance.SpawnPickup(item.Key.spawnableName, transform.position + new Vector3(x,0,y), count: item.Value);
|
|
}
|
|
|
|
if(InventoryManager.instance.FirstWeapon != null){
|
|
a += Mathf.PI * 0.2f;
|
|
float x = Mathf.Sin(a);
|
|
float y = Mathf.Cos(a);
|
|
GameManager.instance.SpawnPickup(InventoryManager.instance.FirstWeapon.spawnableName,point: transform.position + new Vector3(x,0,y));
|
|
}
|
|
if(InventoryManager.instance.SecondWeapon != null){
|
|
a += Mathf.PI * 0.2f;
|
|
float x = Mathf.Sin(a);
|
|
float y = Mathf.Cos(a);
|
|
GameManager.instance.SpawnPickup(InventoryManager.instance.SecondWeapon.spawnableName,point: transform.position + new Vector3(x,0,y));
|
|
}
|
|
if(InventoryManager.instance.PrimaryWeapon != null){
|
|
a += Mathf.PI * 0.2f;
|
|
float x = Mathf.Sin(a);
|
|
float y = Mathf.Cos(a);
|
|
GameManager.instance.SpawnPickup(InventoryManager.instance.PrimaryWeapon.spawnableName,point: transform.position + new Vector3(x,0,y));
|
|
}
|
|
}
|
|
InventoryManager.ResetStocks();
|
|
CameraFollow.Pause();
|
|
enemy.GetComponent<PlayerNetwork>().GainedKill();
|
|
|
|
//Destroy(GetComponent<PlayerController>());
|
|
playerController.OnDeath();
|
|
UIManager.OnDeath();
|
|
|
|
deaths++;
|
|
|
|
if(GameManager.desiredGameMode == GameModes.Deathmatch.ToString()){
|
|
StartCoroutine(CoroutineRespawner());
|
|
}
|
|
UserDataManager.instance.AddDeath();
|
|
|
|
// PhotonNetwork.Destroy(gameObject);
|
|
}
|
|
|
|
UIManager.SetHealth(newHealth,newShield);
|
|
|
|
|
|
Vector3 toPosition = (enemy.transform.position - Camera.main.transform.position).normalized;
|
|
float angle = Vector3.SignedAngle(Camera.main.transform.forward, toPosition, Vector3.up);
|
|
|
|
UIManager.SetDamageDirection(angle);
|
|
}else{
|
|
|
|
}
|
|
|
|
|
|
if(newHealth <=0){
|
|
//Dead general
|
|
anim.SetBool("dead",true);
|
|
}
|
|
health=newHealth;
|
|
shield= newShield;
|
|
|
|
if(GameManager.localPlayer.photonView.ViewID == id && health >0)
|
|
{
|
|
Debug.Log("Show damage number");
|
|
//I HIT THIS GUY!
|
|
playerFX.ShowDamageNumber(point, damage);
|
|
|
|
}
|
|
}
|
|
|
|
IEnumerator CoroutineRespawner(){
|
|
int seconds = 0;
|
|
while(seconds < 4){
|
|
yield return new WaitForSeconds(1);
|
|
seconds++;
|
|
|
|
//TODO: Update timer text here
|
|
}
|
|
|
|
Respawn();
|
|
}
|
|
|
|
public void Respawn(){
|
|
if(photonView.IsMine){
|
|
respawn();
|
|
}else{
|
|
photonView.RPC("RpcRespawn",RpcTarget.All);
|
|
}
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcRespawn(){
|
|
respawn();
|
|
}
|
|
|
|
void respawn(){
|
|
Transform newSpawnPoint = GameManager.instance.GetRandomSpawnPoint();
|
|
transform.position = newSpawnPoint.position;
|
|
anim.SetBool("dead",false);
|
|
health = 100;
|
|
shield= 100;
|
|
UIManager.SetHealth(health,shield);
|
|
CameraFollow.Resume();
|
|
playerController.isActive=true;
|
|
UIManager.OnRespawn();
|
|
if(GameManager.desiredGameMode == GameModes.Deathmatch.ToString()){
|
|
InventoryManager.instance.GiveDefaultLoots(GameManager.instance.DeathmatchDefaultInventory);
|
|
}
|
|
UIManager.UpdateInventory(InventoryManager.instance);
|
|
}
|
|
|
|
public void GainedKill(){
|
|
if(photonView.IsMine){
|
|
gainedKill();
|
|
}else{
|
|
photonView.RPC("RpcGainKill", RpcTarget.All);
|
|
}
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcGainKill(){
|
|
if(photonView.IsMine){ gainedKill();}
|
|
}
|
|
|
|
void gainedKill(){
|
|
Debug.Log("Got a new kill");
|
|
UserDataManager.instance.AddKill();
|
|
kills++;
|
|
}
|
|
|
|
public void StartBomb(int pid, GameObject nade, LootItemScriptableObject data)
|
|
{
|
|
StartCoroutine(TickBomb(pid,nade, data));
|
|
}
|
|
|
|
IEnumerator TickBomb(int pid, GameObject nade, LootItemScriptableObject data)
|
|
{
|
|
yield return new WaitForSeconds(data.throwableTimer);
|
|
|
|
photonView.RPC("RpcBlastEffect", RpcTarget.All, photonView.ViewID, nade.transform.position, data.spawnableName);
|
|
//Handle Nade damage
|
|
PlayerNetwork[] players = FindObjectsOfType<PlayerNetwork>();
|
|
foreach(PlayerNetwork player in players){
|
|
player.photonView.RPC("RpcHandleNadeDamage", RpcTarget.All, nade.transform.position, photonView.ViewID, data.throwableDamage, data.throwableDamageRange);
|
|
}
|
|
PhotonNetwork.Destroy(nade);
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcBlastEffect(int thrower, Vector3 blastPosition, string lootSpawnableName){
|
|
LootItemScriptableObject data = GameManager.GetLootByName(lootSpawnableName);
|
|
|
|
ObjectsPool.instance.Spawn(data.throwableBlastEffect, blastPosition, Quaternion.identity, effect: true);
|
|
float distToBomb = Vector3.Distance(transform.position, blastPosition);
|
|
Debug.Log($"{username}({photonView.ViewID}) was {distToBomb} away from grenade thrown by {thrower}");
|
|
}
|
|
|
|
[PunRPC]
|
|
void RpcHandleNadeDamage(Vector3 blastPosition, int thrower, float damage, float range){
|
|
float distToBomb = Vector3.Distance(transform.position, blastPosition);
|
|
Debug.Log($"{username}({photonView.ViewID}) was {distToBomb} away from grenade thrown by {thrower}");
|
|
if(photonView.IsMine){
|
|
if(distToBomb < range){
|
|
float intensity = (range - distToBomb) * damage;
|
|
OnHit(thrower, intensity, transform.position,0);
|
|
CameraFollow.Shake(intensity * 0.01f);
|
|
}else{
|
|
Debug.Log($"Bomb was {distToBomb} far away");
|
|
}
|
|
}
|
|
}
|
|
//Testing Damage Direction
|
|
/* float a;
|
|
void Update()
|
|
{
|
|
a += Time.deltaTime;
|
|
|
|
float x = Mathf.Sin(a) * 100;
|
|
float y = Mathf.Cos(a) * 100;
|
|
|
|
Vector3 newPos = transform.position + new Vector3(x, 0, y);
|
|
Debug.DrawLine(transform.position, newPos);
|
|
Vector3 toPosition = (newPos - Camera.main.transform.position).normalized;
|
|
float angle = Vector3.SignedAngle(Camera.main.transform.forward, toPosition, Vector3.up);
|
|
Debug.Log(angle);
|
|
UIManager.SetDamageDirection(angle);
|
|
}*/
|
|
}
|
|
|
|
[Serializable]
|
|
public struct PlayerWeaponEntry
|
|
{
|
|
public LootItemScriptableObject data;
|
|
public GameObject obj;
|
|
public GameObject muzzleFlash;
|
|
public AudioClip[] FireSFX;
|
|
public Transform leftHandIk;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct LootObjectEntry{
|
|
public LootItemScriptableObject data;
|
|
public GameObject obj;
|
|
}
|