Files
2026-08-20 19:45:38 +05:30

609 lines
18 KiB
C#

using UnityEngine;
using Mirror;
using UnityEngine.EventSystems;
using System.Collections;
using LegacyTouchPhase = UnityEngine.TouchPhase;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
public class NetPlayer : NetworkBehaviour
{
const float PingReportIntervalSeconds = 30f;
[SyncVar]
public int userId;
[SyncVar]
public Team myTeam;
// set the team to red if there are no other players, if not set blue
public override void OnStartLocalPlayer()
{
base.OnStartLocalPlayer();
#if UNITY_EDITOR
// Count current NetPlayers in the scene
if(Cupid.RoomPort == -1){
//Without cupid, set the team to red
bool cloneWorkspace = LoginManager.EditorWorkspaceLooksLikeClone();
SetMyTeam(cloneWorkspace ? Team.Red : Team.Blue);
SetMyData(cloneWorkspace ? 0: 1 );
}else{
SetMyTeam(GameManager.MyTeam);
SetMyData(GameManager.MyTeam == Team.Red ? GameManager.RedPlayer.UserId : GameManager.BluePlayer.UserId);
}
#else
SetMyTeam(GameManager.MyTeam);
SetMyData(GameManager.MyTeam == Team.Red ? GameManager.RedPlayer.UserId : GameManager.BluePlayer.UserId);
#endif
TeamSpecificEffects.instance.SetTeamSpecificEffects(myTeam);
if (GameManager.instance != null)
GameManager.instance.OnLocalPlayerJoinedMatch();
}
void SetMyData(int uid){
if(isServer){
setMyData(uid);
}else{
CmdSetMyData(uid);
setMyData(uid);
}
}
void setMyData(int uid){
userId= uid;
}
[Command]
void CmdSetMyData(int uid){
userId=uid;
}
void SetMyTeam(Team team){
if(isServer){
setMyTeam(team);
}else{
CmdSetTeam(team);
setMyTeam(team);
}
}
void setMyTeam(Team team){
myTeam = team;
if (GameManager.instance != null)
GameManager.instance.OnMatchPlayerTeamAssigned(team);
}
[Command]
void CmdSetTeam(Team team){
setMyTeam(team);
Logger.Log($"Client {netId} set team to {team}");
if(team == Team.Red){
RedPlayer = this;
}else{
BluePlayer = this;
}
}
public static NetPlayer localPlayer;
public static NetPlayer RedPlayer;
public static NetPlayer BluePlayer;
public static Vector2 curPosition;
public Vector2 startPosition;
public float curPuckPullForce;
// Single drag at a time; extra fingers are ignored while isDragging.
bool isDragging;
Vector2 lastDragScreenPosition;
bool serverDragActive;
Coroutine pingReportCoroutine;
#region EMOTES
public void SendTextEmote(string txtName){
if(isServer){
RpcSendTextEmote(txtName);
ShowTextEmote(txtName);
}else{
CmdSendTextEmote(txtName);
}
}
[Command]
void CmdSendTextEmote(string txtName){
RpcSendTextEmote(txtName);
ShowTextEmote(txtName);
Logger.Log($"Client {netId} sent text emote {txtName}");
}
[ClientRpc]
void RpcSendTextEmote(string txtName){
ShowTextEmote(txtName);
}
void ShowTextEmote(string txtName){
GameCanvas.instance.ShowTextEmote(txtName, myTeam);
}
public void SendEmojiEmote(int id){
if(isServer){
RpcSendEmojiEmote(id);
ShowEmojiEmote(id);
}else{
CmdSendEmojiEmote(id);
}
}
[Command]
void CmdSendEmojiEmote(int id){
RpcSendEmojiEmote(id);
ShowEmojiEmote(id);
Logger.Log($"Client {netId} sent emoji emote {id}");
}
[ClientRpc]
void RpcSendEmojiEmote(int id){
ShowEmojiEmote(id);
}
void ShowEmojiEmote(int id){
GameCanvas.instance.ShowEmojiEmote(id, myTeam);
}
#endregion
void Start(){
if(isLocalPlayer){
localPlayer = this;
SetupInputPanel();
pingReportCoroutine = StartCoroutine(CoReportPingPeriodically());
}
}
void OnDestroy(){
if (pingReportCoroutine != null)
{
StopCoroutine(pingReportCoroutine);
pingReportCoroutine = null;
}
if(localPlayer == this){
localPlayer = null;
}
}
void SetupInputPanel(){
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerDown;
entry.callback.AddListener(OnPointerDown);
GameCanvas.instance.gameInputPanel.triggers.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerUp;
entry.callback.AddListener(OnPointerUp);
GameCanvas.instance.gameInputPanel.triggers.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.Drag;
entry.callback.AddListener(OnDrag);
GameCanvas.instance.gameInputPanel.triggers.Add(entry);
}
bool TryGetPointerEvent(BaseEventData eventData, out PointerEventData pointerEventData)
{
pointerEventData = eventData as PointerEventData;
return pointerEventData != null;
}
static int CountPressedTouches()
{
#if ENABLE_INPUT_SYSTEM
if (Touchscreen.current != null)
{
int count = 0;
var touches = Touchscreen.current.touches;
for (int i = 0; i < touches.Count; i++)
{
if (touches[i].press.isPressed)
count++;
}
return count;
}
#endif
return Input.touchCount;
}
void UpdateDragScreenPosition(Vector2 screenPosition)
{
lastDragScreenPosition = screenPosition;
curPosition = screenPosition;
if (GameManager.SelectedPuck != null)
curPuckPullForce = GameManager.SelectedPuck.lineEnd.magnitude;
}
void Update()
{
if (!isLocalPlayer || !isDragging)
return;
if (!TryReadPointerHeld(out Vector2 screenPosition, out bool isPressed))
{
curPosition = lastDragScreenPosition;
return;
}
UpdateDragScreenPosition(screenPosition);
if (!isPressed && CountPressedTouches() == 0)
CompleteActivePointerDrag();
}
bool TryReadPointerHeld(out Vector2 screenPosition, out bool isPressed)
{
screenPosition = lastDragScreenPosition;
isPressed = false;
#if ENABLE_INPUT_SYSTEM
if (Touchscreen.current != null)
{
var primary = Touchscreen.current.primaryTouch;
if (primary.press.isPressed)
{
screenPosition = primary.position.ReadValue();
isPressed = true;
return true;
}
if (primary.press.wasReleasedThisFrame)
{
screenPosition = primary.position.ReadValue();
return true;
}
var touches = Touchscreen.current.touches;
for (int i = 0; i < touches.Count; i++)
{
var touch = touches[i];
if (!touch.press.isPressed)
continue;
screenPosition = touch.position.ReadValue();
isPressed = true;
return true;
}
}
if (Mouse.current != null)
{
if (Mouse.current.leftButton.isPressed)
{
screenPosition = Mouse.current.position.ReadValue();
isPressed = true;
return true;
}
if (Mouse.current.leftButton.wasReleasedThisFrame)
{
screenPosition = Mouse.current.position.ReadValue();
return true;
}
}
#endif
if (Input.touchCount > 0)
{
UnityEngine.Touch touch = Input.GetTouch(0);
screenPosition = touch.position;
isPressed = touch.phase != LegacyTouchPhase.Ended && touch.phase != LegacyTouchPhase.Canceled;
return true;
}
if (Input.GetMouseButton(0))
{
screenPosition = Input.mousePosition;
isPressed = true;
return true;
}
if (Input.GetMouseButtonUp(0))
{
screenPosition = Input.mousePosition;
return true;
}
return false;
}
void CompleteActivePointerDrag()
{
if (!isDragging)
return;
if (CountPressedTouches() > 0)
return;
isDragging = false;
if (GameManager.SelectedPuck == null)
return;
if (GameManager.instance == null)
return;
if (GameManager.instance.SelectedTeam != myTeam)
return;
Vector2 direction = GameManager.SelectedPuck.lineEnd;
CmdOnPointerUp(direction);
if (CameraEffects.instance != null)
CameraEffects.instance.ReleaseStretchFactor();
}
void OnPointerDown(BaseEventData eventData){
if(GameManager.instance == null){return;}
if(GameManager.instance.SelectedTeam != myTeam){return;}
if(GameManager.instance.m_isMoving){return;}
if(isDragging){return;}
if(CountPressedTouches() > 1){return;}
if(!TryGetPointerEvent(eventData, out PointerEventData pointerEventData)){return;}
Vector2 position = pointerEventData.position;
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(position.x, position.y, Camera.main.nearClipPlane));
Puck closestPuck = GameManager.instance.GetClosestPuck(worldPosition);
if (closestPuck == null)
return;
isDragging = true;
UpdateDragScreenPosition(position);
GameManager.SelectedPuck = closestPuck;
CmdOnPointerDown(worldPosition);
}
[Command]
void CmdOnPointerDown(Vector2 position){
if (GameManager.instance == null)
return;
if (serverDragActive)
return;
if (GameManager.instance.SelectedTeam != myTeam)
return;
Puck closestPuck = GameManager.instance.GetClosestPuck(position);
if (closestPuck == null || closestPuck.gameObject == null)
return;
serverDragActive = true;
GameManager.SelectedPuck = closestPuck;
RpcOnPointerDown(closestPuck.gameObject);
}
[ClientRpc]
void RpcOnPointerDown(GameObject puckGo){
if(puckGo == null){return;}
if(!isLocalPlayer){return;}
Puck puck = puckGo.GetComponent<Puck>();
if(puck!=GameManager.SelectedPuck){
Debug.LogError("Selected puck changed on client, This cant happen. Resetting to servers choice", gameObject);
}
GameManager.SelectedPuck = puck;
}
void OnDrag(BaseEventData eventData){
if(!isDragging){return;}
if(!TryGetPointerEvent(eventData, out PointerEventData pointerEventData)){return;}
UpdateDragScreenPosition(pointerEventData.position);
}
void OnPointerUp(BaseEventData eventData){
if(!isDragging){return;}
if(TryGetPointerEvent(eventData, out PointerEventData pointerEventData))
UpdateDragScreenPosition(pointerEventData.position);
if (CountPressedTouches() > 0)
return;
CompleteActivePointerDrag();
}
[Command]
void CmdOnPointerUp(Vector2 direction){
serverDragActive = false;
if (GameManager.instance == null)
return;
if (GameManager.instance.SelectedTeam != myTeam)
return;
Debug.Log("Pointer up");
GameManager.instance.OnPointerUp(direction);
RpcOnPointerUp();
}
[ClientRpc]
void RpcOnPointerUp(){
}
/// <summary>
/// Request a rematch with the opponent.
/// </summary>
public void RequestRematch(){
int maxBetLimitCoins = GameOverCanvas.GetPersonalBetLimit();
if(isServer){
GameOverCanvas.instance.OnRematchRequested(maxBetLimitCoins);
RpcRequestRematch(maxBetLimitCoins);
}else{
CmdRequestRematch(maxBetLimitCoins);
}
}
[Command]
void CmdRequestRematch(int maxBetLimitCoins){
Logger.Log("Rematch requested, max bet limit coins: " + maxBetLimitCoins);
if(isServerOnly){
//server
}else{
GameOverCanvas.instance.OnRematchRequested(maxBetLimitCoins);
}
RpcRequestRematch(maxBetLimitCoins);
}
[ClientRpc]
void RpcRequestRematch(int maxBetLimitCoins){
GameOverCanvas.instance.OnRematchRequested(maxBetLimitCoins);
}
public void AcceptRematch( int betRcCoins){
if(isServer){
OnRematchAcceptedServer(betRcCoins);
}else{
CmdAcceptRematch(betRcCoins);
}
}
[Command]
void CmdAcceptRematch(int betRcCoins){
OnRematchAcceptedServer(betRcCoins);
}
void OnRematchAcceptedServer(int betRcCoins ){
if(!isServer){ return; }
if(betRcCoins <= 0){
OnRematchCancelledServer();
return;
}
GameManager.DedicatedRematchResult resp = GameManager.RequestDedicatedRematch(RedPlayer.userId, BluePlayer.userId, betRcCoins);
if(resp.Success && resp.Response != null){
string matchmadeResponseString = JsonUtility.ToJson(resp.Response);
RpcRematchConfirmed(matchmadeResponseString);
Logger.Log("Rematch was confirmed, closing in 5 secs. new room :");
Logger.Log(matchmadeResponseString);
StartCoroutine(CoroutineOnRematchConfirmedServer());
}
else
{
string error = string.IsNullOrEmpty(resp.ErrorMessage)
? "Could not start a rematch."
: resp.ErrorMessage;
Logger.Log("Rematch failed: " + error);
RpcRematchFailed(error);
}
}
IEnumerator CoroutineOnRematchConfirmedServer(){
yield return new WaitForSeconds(5f);
Logger.Log("Exiting for rematch.");
GameManager.ReportDedicatedMatchRoomClosed();
Application.Quit();
}
[ClientRpc]
void RpcRematchConfirmed(string matchmadeResponseString){
if (string.IsNullOrEmpty(matchmadeResponseString))
return;
MatchmadeResponse env = JsonUtility.FromJson<MatchmadeResponse>(matchmadeResponseString);
if (env == null || !env.ok)
return;
Team? teamHint = LoginManager.MatchYourTeam;
if (!teamHint.HasValue)
teamHint = GameManager.MyTeam;
int userId = localPlayer != null ? localPlayer.userId : (LoginManager.CurrentUser != null ? LoginManager.CurrentUser.id : 0);
MatchmadeTeamPayload branch = MatchmadeResponse.SelectTeamPayload(env, userId, teamHint);
if (branch == null || !MatchmadeResponse.TryResolveMyAndOpponent(env, branch, userId, out MatchmadePlayer myPlayer, out MatchmadePlayer opponentPlayer))
{
Debug.LogWarning("RpcRematchConfirmed: could not resolve roster for rematch UI");
return;
}
string yt = (branch.your_team ?? "").Trim().ToLowerInvariant();
Team myTeam = yt == "blue" ? Team.Blue : Team.Red;
if (myTeam == Team.Red)
{
GameManager.RedPlayer = myPlayer;
GameManager.BluePlayer = opponentPlayer;
}
else
{
GameManager.BluePlayer = myPlayer;
GameManager.RedPlayer = opponentPlayer;
}
GameManager.MyTeam = myTeam;
int rcPrizeCoins = env.rc_prize > 0 ? env.rc_prize : branch.rc_prize;
GameManager.MatchRcPrizeCoins = rcPrizeCoins;
if (LevelLoadManager.instance != null)
LevelLoadManager.instance.SetupMatchMade(myTeam, myPlayer, opponentPlayer, CoinHelper.FormatString(rcPrizeCoins) + " RC");
GameManager.ConfigureDedicatedMatchReporting(branch.match_id);
Cupid.RoomPort = branch.Port;
LoginManager.SetMatchYourTeam(branch.your_team);
LevelLoadManager.instance.Leave("Game");
}
[ClientRpc]
void RpcRematchFailed(string errorMessage)
{
if (GameOverCanvas.instance != null)
GameOverCanvas.instance.OnRematchFailed(errorMessage);
else
MessageBoxDialog.Show("Rematch failed", string.IsNullOrEmpty(errorMessage) ? "Could not start a rematch." : errorMessage);
}
void OnRematchCancelledServer(){
if(!isServer){ return; }
RpcCancelRematch();
if(!isServerOnly){
CancelRematch();
}
}
[ClientRpc]
void RpcCancelRematch(){
CancelRematch();
}
void CancelRematch(){
GameOverCanvas.instance.OnRematchCancelled();
}
IEnumerator CoReportPingPeriodically()
{
var wait = new WaitForSecondsRealtime(PingReportIntervalSeconds);
while (isLocalPlayer)
{
yield return wait;
if (!NetworkClient.active || !NetworkClient.isConnected)
continue;
if (LoginManager.instance == null || string.IsNullOrEmpty(LoginManager.AuthToken))
continue;
int matchId = GameManager.DedicatedMatchId;
if (matchId <= 0)
continue;
int pingMs = Mathf.Max(0, Mathf.RoundToInt((float)(NetworkTime.rtt * 1000.0)));
LoginManager.instance.ReportPing(matchId, pingMs, (ok, err, report) =>
{
if (!ok && !string.IsNullOrEmpty(err))
Logger.Log("Ping report failed: " + err);
});
}
}
}