UPF/Assets/Game/Scripts/Minigame/SpaceshipController.cs
2023-01-13 23:26:48 +05:30

1076 lines
33 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using Mirror;
using System.Linq;
using UnityEngine.UI;
using System.Collections;
using CustomExtensions;
using Debug = CustomLogger.Debug;
public class SpaceshipController : NetworkBehaviour
{
public LayerMask pickupsLayer;
[SyncVar]
public bool ready;
public SpriteRenderer playerImg;
public SkinsData skins;
[SyncVar(hook = nameof(OnSkinChanged))]
public string skinName = null;
[SyncVar(hook = nameof(OnPnameChanged))]
public string pname;
[SyncVar(hook = nameof(OnScoresChanged))]
public int Scores;
[SyncVar(hook = nameof(OnKillsChanged))]
public int Kills;
[SyncVar(hook = nameof(OnTrailTimeChanged))]
public float trailTime;
public float minTrailTime;
public float maxTrailTime;
[SyncVar]
public int moonsCollected;
public float trailIncrementRate = 0.5f;
[SyncVar]
public bool dead;
[SyncVar]
public float speed;
[SyncVar]
public float speedMultiplier;
[SyncVar]
public float boostConsumption;
[SyncVar]
public float energyGain;
public float _scaleMultiplier = 1;
public Text pnameTxt;
public Transform body;
public TrailMgr trailMgr;
public float movingSpeed = 0.1f;
public float turningSmoothFactor = 0.1f;
public Joystick joystick;
[SyncVar]
public bool boosting;
public bool boosting_local;
[Header("Client Prediction")]
private Vector2 input;
[SyncVar]
public Vector2 m_Input;
[SerializeField]private float rubberbandSmoothness = 0.3f;
private float timer;
private int currentTick;
private float minTimeBetweenTicks;
private const float SERVER_TICK_RATE = 30f;
private const int BUFFER_SIZE = 2048;
private const bool CUSTOM_NET_TRANSFORM = true;
private float ERROR_THRESHOLD =0.25f;
private int MIN_ERROR_COUNT = 10;
public bool showDebugHUD = false;
private double clientNetworkRTT;
public InputState[] clientInputBuffer;
public Queue<InputState> inputQueue;
public PlayerState[] stateBuffer;
public GameObject DeathEffect;
public GameObject debrisEffect;
// public GameObject boostStartEffect;
public ParticleSystem[] boostStartEffect;
public ParticleSystem[] boostEffects;
// public GameObject PickupEffect;
public float distanceFromCenter = 0;
RocketLevel rocketStats;
[Header("AudioFX")]
public AudioSource engineAudio;
public float normalPitch,boostedPitch;
public void SetReady(bool value)
{
if (isServer)
{
ready = value;
}
else
{
CmdSetReady(value);
}
}
[Command]
void CmdSetReady(bool value)
{
ready = value;
}
[Command]
void CmdSetPname(string value)
{
pname = value;
}
void OnPnameChanged(string oldName, string newName)
{
pnameTxt.text = newName;
Debug.Log(pname + " Joined the game");
}
[Command]
void CmdSetSkin(string newSkin)
{
skinName = newSkin;
}
[Command]
void CmdSetStats(float _speed, float _energy, float _boost)
{
speedMultiplier = _speed;
energyGain = _energy;
boostConsumption = _boost;
}
void OnSkinChanged(string oldSkin, string newSkin)
{
ChangeSkin(newSkin);
}
void ChangeSkin(string name)
{
Sprite newSprite = SkinManagerHelper.getSkinSprite(name, skins);
playerImg.sprite = newSprite;
}
void OnScoresChanged(int oldScores, int newScores)
{
Debug.Log($"Add scores {newScores - oldScores}, (total: {newScores})");
}
bool isBoostAvailable {get{ return trailTime > minTrailTime;}}
void OnTrailTimeChanged(float oldValue, float newValue)
{
trailMgr.trail.time = newValue;
if (isLocalPlayer)
{
// SceneData.holder.boostBtn.gameObject.SetActive(isBoostAvailable);
SceneData.holder.boostBtn.transform.GetChild(0).gameObject.SetActive(isBoostAvailable);
SceneData.holder.boostBtn.transform.GetChild(0).GetChild(0).gameObject.SetActive(trailTime > maxTrailTime/2f);
SceneData.holder.boostBtn.transform.GetChild(0).GetChild(1).gameObject.SetActive(trailTime > maxTrailTime* 0.8f);
SceneData.holder.boostBtn.transform.GetChild(0).GetChild(2).gameObject.SetActive(trailTime >= maxTrailTime);
SceneData.holder.boostBtn.transform.GetChild(0).Find("Slider").GetComponent<Image>().fillAmount = Mathf.Clamp(0.73f - ((trailTime /maxTrailTime)*0.73f),0f,0.73f);
if (!isBoostAvailable && boosting)
{
CmdSetBoosting(false);
}
}
}
void OnBoostDown()
{
if(!isBoostAvailable){return; }
if (isLocalPlayer)
{
boosting_local = true;
AudioManager.instnace.Boost();
if (isServer)
{
boosting = true;
}
else
{
CmdSetBoosting(true);
}
CameraFollower.instance.ShakeBoost();
Vibrate();
// GameObject fx = EffectPool.Spawn(boostStartEffect, transform.position);
foreach(ParticleSystem particle in boostStartEffect){
particle.Play();
}
}
}
void Vibrate(){
#if UNITY_ANDROID
if(ControlSettings.HapticEnabled){
Handheld.Vibrate();
}
#endif
}
void OnBoostUp()
{
if (isLocalPlayer)
{
boosting_local = false;
if (isServer)
{
boosting = false;
}
else
{
CmdSetBoosting(false);
}
}
}
[Command]
void CmdSetBoosting(bool value)
{
boosting = value;
}
[SyncVar]
public double startedTime = 0;
void ResetStats()
{
startedXp = DBmanager.Xp;
startedMetal = DBmanager.Metal;
}
void Start()
{
clientInputBuffer = new InputState[BUFFER_SIZE];
inputQueue = new Queue<InputState>();
stateBuffer = new PlayerState[BUFFER_SIZE];
minTimeBetweenTicks = 1f / SERVER_TICK_RATE;
string[] args = System.Environment.GetCommandLineArgs();
for (int i = 0; i < args.Length; i++)
{
// Debug.Log("ARG " + i + ": " + args[i]);
if (args[i] == "-et")
{
ERROR_THRESHOLD =float.Parse(args[i+1]);
}
if(args[i] == "-grace"){
MIN_ERROR_COUNT = int.Parse(args[i+1]);
}
}
if (isLocalPlayer)
{
ResetStats();
if (MinigameManager.instance.isRanked)
{
DBmanager.SetMetal(DBmanager.Metal + DBmanager.CurrentRank.energyReward);
DBmanager.SetMetal(DBmanager.Metal - DBmanager.CurrentRank.entryFee);
}
if (joystick == null) { joystick = FindObjectOfType<Joystick>(); }
FindObjectOfType<CameraFollower>().SetTarget(transform);
string myName = DBmanager.DisplayName;
SceneData.localPlayer = gameObject;
SceneData.OnBoostDown.AddListener(OnBoostDown);
SceneData.OnBoostUp.AddListener(OnBoostUp);
//Set username
if (isServer) { pname = myName; }
else
{
CmdSetPname(myName);
}
//Set Skin
if (DBmanager.GetSkinIdByName(SkinShopManager.GetEquipedSkin()) < 0)
{
//False skin purchase
}
else
{
string skin = SkinShopManager.GetEquipedSkin();
SkinType rarity = SkinShopManager.GetRarityFromName(skin);
PurchasedSkin purchasedSkin = DBmanager.GetSkinByName(skin);
float m_speed = SkinShopManager.GetStatsForRarity(rarity)[purchasedSkin.speedLevel].speedMultiplier;
float m_energy = SkinShopManager.GetStatsForRarity(rarity)[purchasedSkin.energyLevel].moonMultiplier;
float m_boost = SkinShopManager.GetStatsForRarity(rarity)[purchasedSkin.boostLevel].boostConsumption;
if (isServer)
{
skinName = skin;
speedMultiplier = m_speed;
energyGain = m_energy;
boostConsumption = m_boost;
}
else
{
CmdSetSkin(skin);
CmdSetStats(m_speed, m_energy, m_boost);
}
}
pnameTxt.text = myName;
pnameTxt.gameObject.SetActive(false);
}
if (isServer)
{
startedTime = NetworkTime.time;
trailTime = 0;
DecreaseTrail(0);
}else{
if(AudioManager.SFX_enabled){
engineAudio.volume = 1;
}else{
engineAudio.volume= 0;
}
}
}
float scale => Mathf.Clamp(1 + (trailTime * _scaleMultiplier), 1, 10);
void Update()
{
#if UNITY_EDITOR
// Debug.Log(FindObjectsOfType<PickupItem>().Length);
#endif
if (MinigameManager.instance.isRanked && !MinigameManager.instance.RankedGameStarted) { return; }
distanceFromCenter = Vector3.Distance(transform.position, Vector3.zero);
pnameTxt.rectTransform.rotation = Quaternion.Euler(Vector3.zero);
//Update size of trail and spaceship
transform.localScale = Vector3.Lerp(transform.localScale, new Vector3(scale, scale, scale), 0.1f);
trailMgr.trail.startWidth = Mathf.Lerp(trailMgr.trail.startWidth, scale, 0.1f);
if (dead) { return; }
if(isLocalPlayer){
if (joystick == null) { joystick = FindObjectOfType<Joystick>(); if(joystick==null){return;} }
input = joystick.input;
if (Input.GetKeyDown(KeyCode.F))
{
CmdCheatKills();
}
if(Input.GetKeyDown(KeyCode.Space)){
OnBoostDown();
}
if(Input.GetKeyUp(KeyCode.Space)){
OnBoostUp();
}
// Debug.Log(startedTime-NetworkTime.time);
double survivalTime = (startedTime == 0) ? 0 : NetworkTime.time - ((MinigameManager.instance.isRanked) ? MinigameManager.instance.startedTime : startedTime);
if (DBmanager.MostTime < (int)survivalTime)
{
DBmanager.SetMostTime((int)survivalTime);
}
SceneData.SetTimerTxt(survivalTime);
// Debug.Log(lastTime - currentTick);
}
timer += Time.deltaTime;
while(timer >= minTimeBetweenTicks){
timer -= minTimeBetweenTicks;
if(isServer){
HandleTick();
}else if(isLocalPlayer){
ClientHandleTick();
}
currentTick++;
}
// return;
}
void FixedUpdate(){
if(!isLocalPlayer && !isServer){
transform.position = latestServerState.Position;
transform.rotation = latestServerState.Rotation;
}
}
#region Movement
IEnumerator SendToClient(PlayerState statePayload)
{
yield return new WaitForSeconds(0.02f);
OnServerMovementState(statePayload);
}
void HandleTick(){
#region obsoleteCommented
/*
curBufferIndex = bufferIndex;
if(isLocalPlayer){
// HandleInput(input);
InputState curInputState = new InputState(){Tick=currentTick, Input = input};
PlayerState curState = new PlayerState(){Tick=currentTick, Position= transform.position, Rotation = transform.rotation};
clientInputBuffer[bufferIndex] = curInputState;
clientStateBuffer[bufferIndex] = curState;
// transform.Translate(transform.forward * input.y);
// transform.Rotate(transform.up * input.x);
UpdateStates(currentTick, NetworkTime.rtt, input, curState.Position, curState.Rotation);
// body.position = targetState.Position;
// body.rotation = targetState.Rotation;
// body.position = Vector3.Lerp(body.position,targetState.Position,MovementSmoothnessFactor * movingSpeed);
// body.rotation = Quaternion.Lerp(body.rotation, targetState.Rotation,MovementSmoothnessFactor*movingSpeed);
}else if (isServer){
HandleInput(m_Input);
if(CUSTOM_NET_TRANSFORM){
RpcUpdateOnClient(body.position, body.rotation, m_Input);
}
CheckForPickups();
}else{
//client but not localPlayer
body.position = targetState.Position;
body.rotation = targetState.Rotation;
// for(int i = 0; i < ticksGap; i++){
// HandleInput(m_Input);
// }
}
// if(isLocalPlayer){CameraFollower.UpdateFrame();}
float stateError = clientStateBuffer[bufferIndex].Difference(serverStateBuffer[latencyBufferIndex]);
foreach(ParticleSystem boostEffect in boostEffects){
if(boostEffect.isEmitting && !boosting){
boostEffect.Stop();
}else if(!boostEffect.isEmitting && boosting){
boostEffect.Play();
}
}
if(isServer){
InputState curServerInputState = new InputState(){Tick=currentTick, Input = m_Input};
PlayerState curServerState = new PlayerState(){Tick=currentTick, Position = transform.position, Rotation = transform.rotation};
serverInputBuffer[bufferIndex] = curServerInputState;
serverStateBuffer[bufferIndex] = curServerState;
if(!clientInputBuffer[bufferIndex].CloseEnough(serverInputBuffer[latencyBufferIndex],ERROR_THRESHOLD)){
ErrorInputCount++;
}
// if(!clientStateBuffer[bufferIndex].CloseEnough(serverStateBuffer[latencyBufferIndex],ERROR_THRESHOLD)){
if(stateError > ERROR_THRESHOLD){
ErrorStateCount++;
errorCounter++;
if(errorCounter> MIN_ERROR_COUNT){RpcRubberband(transform.position, transform.rotation); errorCounter=0;}
}else{
errorCounter = 0;
}
//boost check
if (boosting && scale > 1)
{
speed = movingSpeed * 2 * speedMultiplier;
DecreaseTrail(Time.deltaTime * boostConsumption * 0.5f);
// scaleMultiplier -= Time.deltaTime;
// if (scaleMultiplier < 1) { scaleMultiplier = 1; } //Clamp in case gets lower
}
else
{
speed = movingSpeed * speedMultiplier;
}
}*/
#endregion
CheckForPickups();
UpdateSpeed();
int bufferIndex = -1;
while(inputQueue.Count > 0){
InputState inputState = inputQueue.Dequeue();
bufferIndex = inputState.Tick % BUFFER_SIZE;
PlayerState statePayload = ProcessMovement(inputState);
stateBuffer[bufferIndex] = statePayload;
}
if(bufferIndex != -1){
StartCoroutine(SendToClient(stateBuffer[bufferIndex]));
}
}
void UpdateSpeed(){
if (boosting && trailTime >= minTrailTime)
{
speed = movingSpeed * 2 * speedMultiplier;
DecreaseTrail(Time.deltaTime * boostConsumption * 0.5f);
}
else
{
boosting = false;
speed = movingSpeed * speedMultiplier;
}
}
public float speedLocal = 0;
void UpdateSpeedLocal(){
if (boosting_local && trailTime >= minTrailTime)
{
speedLocal = movingSpeed * 2 * speedMultiplier;
DecreaseTrail(Time.deltaTime * boostConsumption * 0.5f);
}
else
{
boosting_local = false;
OnBoostUp();
speedLocal = movingSpeed * speedMultiplier;
}
}
void ClientHandleTick(){
if(isLocalPlayer){
UpdateSpeedLocal();
}
engineAudio.pitch = Mathf.Lerp(engineAudio.pitch, (boosting) ? boostedPitch : normalPitch, 0.1f);
if (!latestServerState.Equals(default(PlayerState)) &&
(lastProcessedState.Equals(default(PlayerState)) ||
!latestServerState.Equals(lastProcessedState)))
{
// Debug.Log("Consider Reconciliation");
HandleServerReconciliation();
}
int bufferIndex = currentTick % BUFFER_SIZE;
// Add payload to inputBuffer
InputState inputPayload = new InputState();
inputPayload.Tick = currentTick;
inputPayload.Input = joystick.input;
clientInputBuffer[bufferIndex] = inputPayload;
// Add payload to stateBuffer
stateBuffer[bufferIndex] = ProcessMovement(inputPayload);
if(isLocalPlayer){
CameraFollower.UpdateFrame();
}
// Send input to server
StartCoroutine(SendToServer(inputPayload));
}
public void OnClientInput(InputState inputPayload){
if(isServer){
m_OnClientInput(inputPayload);
}else{
CmdOnClientInput(inputPayload);
}
}
[Command]
public void CmdOnClientInput(InputState inputPayload){
m_OnClientInput(inputPayload);
}
public void m_OnClientInput(InputState inputPayload)
{
inputQueue.Enqueue(inputPayload);
}
private PlayerState latestServerState;
private PlayerState lastProcessedState;
void HandleServerReconciliation()
{
lastProcessedState = latestServerState;
int serverStateBufferIndex = latestServerState.Tick % BUFFER_SIZE;
float positionError = Vector3.Distance(latestServerState.Position, stateBuffer[serverStateBufferIndex].Position);
float rotationError = CustomExtensions.QuaternionExtensions.Difference(latestServerState.Rotation, stateBuffer[serverStateBufferIndex].Rotation);
if (positionError > 0.001f || !latestServerState.Rotation.Approximately(stateBuffer[serverStateBufferIndex].Rotation, 0.0001f))
{
Debug.Log($"We have to reconcile bro, Errors\npos:{positionError}, rot:{rotationError}");
// Rewind & Replay
transform.position = latestServerState.Position;
transform.rotation = latestServerState.Rotation;
// Update buffer at index of latest server state
stateBuffer[serverStateBufferIndex] = latestServerState;
// Now re-simulate the rest of the ticks up to the current tick on the client
int tickToProcess = latestServerState.Tick + 1;
while (tickToProcess < currentTick)
{
int bufferIndex = tickToProcess % BUFFER_SIZE;
// Process new movement with reconciled state
PlayerState statePayload = ProcessMovement(clientInputBuffer[bufferIndex]);
// Update buffer with recalculated state
stateBuffer[bufferIndex] = statePayload;
tickToProcess++;
}
}else{
// Debug.Log($"Reconciliation cancelled\n, Errors\npos:{positionError}, rot:{rotationError}");
}
}
public void m_OnServerMovementState(PlayerState serverState)
{
latestServerState = serverState;
}
public void OnServerMovementState(PlayerState serverState){
if(isServer){
RpcOnServerMovementState(serverState);
}else{
m_OnServerMovementState(serverState);
// CmdOnServerMovementState(serverState);
}
}
[ClientRpc]
public void RpcOnServerMovementState(PlayerState serverState){
m_OnServerMovementState(serverState);
// Debug.Log(serverState.Position + ":" + transform.position);
}
IEnumerator SendToServer(InputState inputPayload)
{
yield return new WaitForSeconds(0.02f);
OnClientInput(inputPayload);
}
PlayerState ProcessMovement(InputState input)
{
// Should always be in sync with same function on Client
body.Translate(new Vector3(0, (isLocalPlayer) ? speedLocal: speed), body);
Turn(input.Input);
return new PlayerState()
{
Tick = input.Tick,
Position = transform.position,
Rotation = transform.rotation
};
}
#endregion
void CheckForPickups(){
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, 3, pickupsLayer);
foreach(Collider2D hit in hits){
if(hit!=null ){
// Debug.Log(hit.name);
PickupItem pickupItem = hit.GetComponent<PickupItem>();
if(pickupItem !=null && pickupItem.active){
pickupItem.active=false;
pickupItem.Deactivate(transform);
CollectPickup(pickupItem.type);
}
}
}
}
// void HandleInput(Vector2 _input){
// // transform.Translate(transform.forward * _input.y);
// // transform.Rotate(transform.up * _input.x);
// body.Translate(new Vector3(0, speed), body);
// Turn(_input);
// }
void Turn(Vector2 input)
{
body.rotation = Quaternion.Lerp(body.rotation, getTurnAngle(input), turningSmoothFactor * input.magnitude);
}
Quaternion getTurnAngle(Vector2 input)
{
var angle1 = Mathf.Atan2(-input.y, -input.x) * Mathf.Rad2Deg;
return Quaternion.AngleAxis(angle1 + 90, Vector3.forward);
}
[ClientRpc]
void RpcUpdateTrail(Vector3[] positions)
{
//trailMgr.trail.SetPositions(positions);
}
public float Angle(Vector2 vector2)
{
return 360 - (Mathf.Atan2(vector2.x, vector2.y) * Mathf.Rad2Deg * Mathf.Sign(vector2.x));
}
//Auto assign default variables [Editor only]
void OnValidate()
{
if (body == null)
{
body = transform;
}
if (trailMgr == null)
{
trailMgr = GetComponent<TrailMgr>();
}
}
public void TrailCollided(Collider2D hit)
{
if (!isServer)
{
Debug.Log("Got hit : " + hit.name);
// Debug.Log("This cannot run on client, That's illegal!"); // <-- What this log says
return;
}
SpaceshipController deadPlayer = hit.GetComponent<SpaceshipController>();
// Debug.Log("got hit by player? : " + (deadPlayer != null));
if (deadPlayer != null && !deadPlayer.dead && (NetworkTime.time - deadPlayer.startedTime) > 5)
{ // <-- okay we killed someone | KILLCODE
// deadPlayer.RpcShowDeathEffect(deadPlayer.transform.position);
deadPlayer.Die(pname);
Debug.Log($"{pname} killed {deadPlayer.pname}");
OnKill();
}
SpaceshipNetworkBot deadBot = hit.GetComponent<SpaceshipNetworkBot>();
// Debug.Log("got hit by bot? : " + (deadPlayer != deadBot));
if(deadBot != null){
deadBot.Die();
Kills++;
return;
}
}
public void ShowDeathEffect(Vector2 position){
if(isServer){
// MinigameManager.instance.ShowDeathEffect(position);
EffectPool.Spawn(DeathEffect, position);
RpcShowDeathEffect(position);
}else{
CmdShowDeathEffect(position);
}
}
[Command]
void CmdShowDeathEffect(Vector2 position){
EffectPool.Spawn(DeathEffect, position);
RpcShowDeathEffect(position);
}
[ClientRpc]
void RpcShowDeathEffect(Vector2 position){
EffectPool.Spawn(DeathEffect, position);
// EffectPool.Spawn(debrisEffect, position).GetComponent<DebrisEffect>().Play();
}
void OnKill()
{
Kills++;
// Scores += 10; //TODO: Need to change Scores on kills?
// scaleMultiplier += 0.05f;
// OnScaleChanged(scaleMultiplier, scaleMultiplier);
IncreaseTrail(trailIncrementRate);
RpcOnKill();
}
[ClientRpc]
void RpcOnKill()
{
Vibrate();
}
void OnKillsChanged(int oldVal, int newVal)
{
if (isLocalPlayer)
{
Debug.Log("Show kills for " + newVal);
KillText.Show(newVal);
}
}
void IncreaseTrail(float rate)
{
trailTime = Mathf.Clamp(trailMgr.trail.time + rate, minTrailTime, maxTrailTime);
trailMgr.trail.time = trailTime;
// Debug.Log("Increasing trail of" + pname);
}
public void DecreaseTrail(float rate)
{
trailTime = Mathf.Clamp(trailMgr.trail.time - rate, minTrailTime, maxTrailTime);
trailMgr.trail.time = trailTime;
// Debug.Log("Decreasing trail of" + pname);
}
[Command]
void CmdCheatKills()
{
OnKill();
}
public void CollectPickup(PickupItem.PickupType type)
{
if (!isServer) { Debug.Log("Server function ran on client. That's illegal!"); } // <-- What this log says
if(type == PickupItem.PickupType.Moon1 || type == PickupItem.PickupType.Moon2|| type == PickupItem.PickupType.Moon3|| type == PickupItem.PickupType.Moon4|| type == PickupItem.PickupType.Moon5){
//Moon!
IncreaseTrail(trailIncrementRate);
// scaleMultiplier += 0.05f;
moonsCollected++;
Scores += 2;
}else {
IncreaseTrail(trailIncrementRate / 2f);
Scores += 1;
}
RpcCollectPickup(type);
}
[ClientRpc]
void RpcCollectPickup(PickupItem.PickupType type)
{
if (isLocalPlayer)
{
if (type == PickupItem.PickupType.Twep)
{
DBmanager.SetTweps(DBmanager.Tweps + 1);
}
else
{
int gainedEnergy = (int)(energyGain * type.GetEnergy());
MinigameManager.instance.GainMetals(gainedEnergy);
}
AudioManager.instnace.CollectMoon(trailTime,maxTrailTime);
}
}
public void Die(string killer)
{
MinigameManager.instance.SpawnLeftoverPickups(transform.position, (int)((float)Scores / 4f));
RpcShowDeathEffect(transform.position);
Debug.Log($"Sending death signal to {pname} by {killer}");
//Handle Respawning
// OnScaleChanged(scaleMultiplier, 1);
// scaleMultiplier = 1;
dead = true;
Scores = 0;
Kills = 0;
startedTime = NetworkTime.time;
DecreaseTrail(trailTime);
trailMgr.trail.time = trailTime;
RpcDie(killer);
gameObject.SetActive(false);
//MinigameManager.instance.SetRespawn(gameObject);
}
private int startedXp;
private int startedMetal;
bool RewardedRankedMetal = false;
[ClientRpc]
public void RpcDie(string killer)
{
Debug.Log($"{killer} killed {pname} : isItMe? -> {isLocalPlayer}");
KillfeedMgr.instance.AddNewEntry($"<b>{pname}</b> was killed by <b>{killer}</b>");
gameObject.SetActive(false);
if (isLocalPlayer)
{
//TODO: Death message goes here
SceneData.holder.ShowDeadscreen(DBmanager.Xp - startedXp, DBmanager.Metal - startedMetal, NetworkTime.time - startedTime);
if (MinigameManager.instance.isRanked && RankedSplash.instance.gameObject.activeSelf)
{
// MinigameManager.instance.rankedSummary.ShowLoss();
// StartCoroutine(ShowRankedResults());
if (MinigameManager.instance.winnerId <= 0)
{
Debug.LogError("Winner ID not synced yet");
checkWinner(1000);
}
if (MinigameManager.instance.winnerId != netId)
{
//LOSER!
MinigameManager.instance.rankedSummary.ShowLoss();
AudioManager.instnace.MinigameLost();
}
else
{
MinigameManager.instance.rankedSummary.ShowWin();
AudioManager.instnace.MinigameWon();
}
}
}
}
async void checkWinner(int delay){
await System.Threading.Tasks.Task.Delay(delay);
if (MinigameManager.instance.winnerId != netId)
{
//LOSER!
MinigameManager.instance.rankedSummary.ShowLoss();
AudioManager.instnace.MinigameLost();
}
else
{
MinigameManager.instance.rankedSummary.ShowWin();
AudioManager.instnace.MinigameWon();
}
}
IEnumerator ShowRankedResults()
{
while (MinigameManager.instance.winnerId <= 0)
{
yield return new WaitForFixedUpdate();
}
}
public void Respawn(Vector3 respawnPoint)
{
Debug.Log("Respawning " + pname);
if (isServer)
{
respawn(respawnPoint);
}
else
{
CmdRespawn(respawnPoint);
}
}
[Command]
void CmdRespawn(Vector3 respawnPoint)
{
respawn(respawnPoint);
}
public void respawn(Vector3 respawnPoint)
{
dead = false;
trailMgr.trail.emitting = false;
trailMgr.trail.Clear();
RpcRespawn(respawnPoint);
transform.position = respawnPoint;
trailMgr.trail.emitting = true;
gameObject.SetActive(true);
}
[ClientRpc]
public void RpcRespawn(Vector3 respawnPoint)
{
GetComponent<NetworkTrail>().enableValidation = false;
trailMgr.trail.Clear();
trailMgr.positions = new Vector3[0];
trailMgr.trail.emitting = false;
transform.position = respawnPoint;
trailMgr.trail.emitting = true;
GetComponent<NetworkTrail>().enableValidation = true;
gameObject.SetActive(true);
if (isLocalPlayer)
{
SceneData.holder.deadScreen.SetActive(false);
ResetStats();
}
}
[Command]
public void CmdWonRanked()
{
WonRanked();
}
[Command]
public void CmdLostRanked()
{
LostRanked();
}
public void WonRanked()
{
if (!isServer)
{
return;
}
RpcWonRanked();
Die("server");
}
[ClientRpc]
void RpcWonRanked()
{
if (isLocalPlayer)
{
DBmanager.SetMetal(DBmanager.Metal + 500);
MinigameManager.instance.rankedSummary.ShowWin();
//Add trophies
DBmanager.SetTrophies(DBmanager.Trophies + 30);
}
}
public void LostRanked()
{
if (!isServer)
{
return;
}
RpcLostRanked();
Die("server");
}
[ClientRpc]
void RpcLostRanked()
{
if (isLocalPlayer)
{
DBmanager.SetMetal(DBmanager.Metal + 250);
MinigameManager.instance.rankedSummary.ShowLoss();
// DBmanager.SetTrophies(Mathf.Clamp(DBmanager.Trophies - 15, 0, int.MaxValue));
DBmanager.SetTrophies(Mathf.Clamp(DBmanager.Trophies - DBmanager.CurrentRank.trophieLoss, 0, int.MaxValue));
}
}
//Emojis
public void ShowEmoji(int index, Vector3 position){
if(isServer){
RpcShowEmoji(index, position);
}else{
CmdShowEmoji(index, position);
EmojiButton.instance.showEmoji(index,position);
}
}
[Command]
void CmdShowEmoji(int index, Vector3 position){
RpcShowEmoji(index,position);
}
[ClientRpc]
void RpcShowEmoji(int index, Vector3 position){
if(isLocalPlayer){ Debug.Log("ClientRPC for emoji received. I already showed it");return;}
EmojiButton.instance.showEmoji(index, position);
}
}