metahunt/Assets/Scripts/PlayerNetwork.cs
2024-02-15 00:15:22 +05:30

562 lines
18 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);
//
if(GameManager.desiredGameMode== GameModes.TeamDeathmatch.ToString()){ignoreFriendlyFire=true;}
}
GetComponent<CharacterController>().detectCollisions=false;
}
public void AutoAssignParty(){
StartCoroutine(AutoSwitchTeams());
}
void autoAssignParty(){
partyId = GameManager.partyId;
List<string> availablePartyNames = Helpers.battleTeamNames.ToList<string>();
Dictionary<string, int> parties = new Dictionary<string, int>();
PlayerNetwork[] players = FindObjectsOfType<PlayerNetwork>();
string myLobbyParty = "";
foreach(PlayerNetwork player in players){
if(player.partyname != ""){
//has a party
if(parties.ContainsKey(player.partyname)){
parties[player.partyname]++;
}else{
parties.Add(player.partyname, 1);
}
if(availablePartyNames.Contains(player.partyname)){availablePartyNames.Remove(player.partyname);}
if(partyId == player.partyId){
myLobbyParty = player.partyname;
}
}
}
Debug.Log($"Found {parties.Count} Parties");
if(myLobbyParty == ""){
//Didn't find a party of my own
if(parties.Count > 1){
foreach(KeyValuePair<string,int> party in parties){
if(party.Value < 4){
partyname = party.Key;
break;
}
}
}else{
partyname = availablePartyNames[UnityEngine.Random.Range(0, availablePartyNames.Count)];
}
}else{
if(parties[myLobbyParty] < 4){
partyname = myLobbyParty;
}else{
foreach(KeyValuePair<string,int> party in parties){
if(party.Value < 4){
partyname = party.Key;
break;
}
}
}
}
if(partyname == ""){
partyname = availablePartyNames[UnityEngine.Random.Range(0, availablePartyNames.Count)];
}
}
int autoTeamSwitchCount = 0;
IEnumerator AutoSwitchTeams(){
while(autoTeamSwitchCount < 4){
autoTeamSwitchCount++;
yield return new WaitForSeconds(UnityEngine.Random.Range(0.5f,1f));
autoAssignParty();
}
}
public Dictionary<string, int> GetPartySizes(){
Dictionary<string, int> parties = new Dictionary<string, int>();
foreach(PlayerNetwork player in FindObjectsOfType<PlayerNetwork>()){
if(player.partyname != ""){
//has a party
if(parties.ContainsKey(player.partyname)){
parties[player.partyname]++;
}else{
parties.Add(player.partyname, 1);
}
}
}
return parties;
}
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));
}
public bool ignoreFriendlyFire;
[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(ignoreFriendlyFire){
PlayerNetwork[] players = FindObjectsOfType<PlayerNetwork>();
foreach(PlayerNetwork p in players){
if(p.photonView.ViewID == id){
//This is the shooter
if(partyname == p.partyname){return;} //Friendly fire
}
}
}
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() || GameManager.desiredGameMode == GameModes.TeamDeathmatch.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;
}