rc
This commit is contained in:
+166
-16
@@ -16,6 +16,15 @@ public class GameManager : NetworkBehaviour
|
||||
public static MatchmadePlayer BluePlayer { get; set; }
|
||||
/// <summary>Coin units from matchmaker <c>rc_prize</c>; used for in-game prize UI.</summary>
|
||||
public static int MatchRcPrizeCoins { get; set; }
|
||||
/// <summary>Participation CC amount shown on game over. Actual credit is decided by the winner PATCH.</summary>
|
||||
public const int ParticipationCcAmount = 100;
|
||||
/// <summary>Server-reported: red was still connected when the match ended (eligible for participation CC).</summary>
|
||||
public static bool RedFinishedMatch { get; private set; } = true;
|
||||
/// <summary>Server-reported: blue was still connected when the match ended (eligible for participation CC).</summary>
|
||||
public static bool BlueFinishedMatch { get; private set; } = true;
|
||||
/// <summary>Local player stayed connected through match end and should see +CC on game over.</summary>
|
||||
public static bool LocalPlayerEarnedParticipationCc =>
|
||||
MyTeam == Team.Blue ? BlueFinishedMatch : RedFinishedMatch;
|
||||
/// <summary>Set by dedicated server startup (e.g. CupidConnector parsing <c>-matchId</c>). PATCH is skipped if id ≤ 0 or secret is empty.</summary>
|
||||
public static int DedicatedMatchId { get; private set; }
|
||||
/// <summary>Sent as <c>X-Dedicated-Server-Secret</c>. From <c>-dedicatedSecret</c> arg or <c>DEDICATED_SERVER_SECRET</c> env.</summary>
|
||||
@@ -504,10 +513,57 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
bool _abortLeaveStarted;
|
||||
|
||||
void AbortMatchCollectFailed()
|
||||
{
|
||||
RpcAbortMatch("Match cancelled", "The match could not start. Please try again.");
|
||||
StartCoroutine(CoDisconnectAfterAbortRpc());
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcAbortMatch(string title, string message)
|
||||
{
|
||||
ShowMatchAbortMessage(title, message);
|
||||
// Host keeps the server up so the Rpc can reach the other client first.
|
||||
if (!NetworkServer.active)
|
||||
LeaveToMenuAfterAbort();
|
||||
}
|
||||
|
||||
IEnumerator CoDisconnectAfterAbortRpc()
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.5f);
|
||||
if (NetworkServer.active)
|
||||
NetworkServer.DisconnectAll();
|
||||
if (isClient)
|
||||
LeaveToMenuAfterAbort();
|
||||
}
|
||||
|
||||
void NotifyAndLeaveMatch(string title, string message)
|
||||
{
|
||||
ShowMatchAbortMessage(title, message);
|
||||
LeaveToMenuAfterAbort();
|
||||
}
|
||||
|
||||
void ShowMatchAbortMessage(string title, string message)
|
||||
{
|
||||
NetManager.MarkIntentionalClientDisconnect();
|
||||
if (CupidLobby.instance != null)
|
||||
CupidLobby.instance.Cancel();
|
||||
LoginManager.ClearMatchYourTeam();
|
||||
MessageBoxDialog.Show(title, message);
|
||||
}
|
||||
|
||||
void LeaveToMenuAfterAbort()
|
||||
{
|
||||
if (_abortLeaveStarted)
|
||||
return;
|
||||
_abortLeaveStarted = true;
|
||||
|
||||
if (LevelLoadManager.instance != null)
|
||||
LevelLoadManager.instance.Leave();
|
||||
else
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
}
|
||||
|
||||
IEnumerator DedicatedMatchPatch(string baseUrl, int matchId, string secret, string json)
|
||||
@@ -522,12 +578,12 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator DedicatedMatchPatchWinner(string baseUrl, int matchId, string secret, string winnerLower)
|
||||
public IEnumerator DedicatedMatchPatchWinner(string baseUrl, int matchId, string secret, string winnerLower, bool redConnected, bool blueConnected)
|
||||
{
|
||||
if (matchId <= 0 || string.IsNullOrEmpty(secret))
|
||||
yield break;
|
||||
|
||||
string jsonBody = "{\"winner\":\"" + winnerLower + "\"}";
|
||||
string jsonBody = DedicatedMatschInternalApi.BuildWinnerPatchJson(winnerLower, redConnected, blueConnected);
|
||||
using (var req = DedicatedMatschInternalApi.BuildWinnerRequest(baseUrl, matchId, secret, jsonBody))
|
||||
{
|
||||
yield return req.SendWebRequest();
|
||||
@@ -535,7 +591,7 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
void ReportDedicatedMatchGameOver(Team winningTeam)
|
||||
void ReportDedicatedMatchGameOver(Team winningTeam, bool redConnected, bool blueConnected)
|
||||
{
|
||||
if (!isServer || DedicatedMatchId <= 0 || string.IsNullOrEmpty(DedicatedMatchSecret) || _winnerSettled)
|
||||
return;
|
||||
@@ -545,14 +601,14 @@ public class GameManager : NetworkBehaviour
|
||||
return;
|
||||
}
|
||||
_winnerSettled = true;
|
||||
StartCoroutine(CoReportDedicatedMatchGameOver(winningTeam));
|
||||
StartCoroutine(CoReportDedicatedMatchGameOver(winningTeam, redConnected, blueConnected));
|
||||
}
|
||||
|
||||
IEnumerator CoReportDedicatedMatchGameOver(Team winningTeam)
|
||||
IEnumerator CoReportDedicatedMatchGameOver(Team winningTeam, bool redConnected, bool blueConnected)
|
||||
{
|
||||
yield return DedicatedMatchPatch(DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, "{\"status\":3}");
|
||||
string winner = winningTeam == Team.Red ? "red" : "blue";
|
||||
yield return DedicatedMatchPatchWinner(DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, winner);
|
||||
yield return DedicatedMatchPatchWinner(DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, winner, redConnected, blueConnected);
|
||||
}
|
||||
|
||||
/// <summary>Score or forfeit end: latch game over, report winner if escrowed, notify clients.</summary>
|
||||
@@ -563,11 +619,58 @@ public class GameManager : NetworkBehaviour
|
||||
|
||||
isGameEnded = true;
|
||||
ReplayRecorder.StopAndFlush();
|
||||
ReportDedicatedMatchGameOver(winningTeam);
|
||||
RpcGameOver(winningTeam);
|
||||
bool redConnected = IsSideConnectedForParticipation(Team.Red);
|
||||
bool blueConnected = IsSideConnectedForParticipation(Team.Blue);
|
||||
Logger.Log($"Dedicated match: end winner={winningTeam} red_connected={redConnected} blue_connected={blueConnected}");
|
||||
ApplyParticipationCcFlags(redConnected, blueConnected);
|
||||
ReportDedicatedMatchGameOver(winningTeam, redConnected, blueConnected);
|
||||
RpcGameOver(winningTeam, redConnected, blueConnected);
|
||||
gameOver(winningTeam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server-side: participation CC is only for players still connected at settle.
|
||||
/// Voluntary leave clears the connected flag before <see cref="EndMatch"/>.
|
||||
/// </summary>
|
||||
bool IsSideConnectedForParticipation(Team team)
|
||||
{
|
||||
if (team == Team.Red)
|
||||
{
|
||||
if (!_redConnected)
|
||||
return false;
|
||||
}
|
||||
else if (team == Team.Blue)
|
||||
{
|
||||
if (!_blueConnected)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var player in FindObjectsByType<NetPlayer>(FindObjectsSortMode.None))
|
||||
{
|
||||
if (player == null || player.myTeam != team)
|
||||
continue;
|
||||
|
||||
if (player.connectionToClient != null)
|
||||
return player.connectionToClient.isReady;
|
||||
|
||||
// Listen-server host has no connectionToClient.
|
||||
if (player.isLocalPlayer)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ApplyParticipationCcFlags(bool redConnected, bool blueConnected)
|
||||
{
|
||||
RedFinishedMatch = redConnected;
|
||||
BlueFinishedMatch = blueConnected;
|
||||
}
|
||||
|
||||
void HandleDisconnectForfeitTimers()
|
||||
{
|
||||
if (!_entriesCollected || _winnerSettled || !gameStarted || isGameEnded)
|
||||
@@ -620,9 +723,13 @@ public class GameManager : NetworkBehaviour
|
||||
return;
|
||||
|
||||
Team winningTeam = ResolveForfeitWinnerForShutdown();
|
||||
bool redConnected = IsSideConnectedForParticipation(Team.Red);
|
||||
bool blueConnected = IsSideConnectedForParticipation(Team.Blue);
|
||||
_winnerSettled = true;
|
||||
isGameEnded = true;
|
||||
Logger.Log("Dedicated match: blocking winner settle before shutdown → " + winningTeam);
|
||||
ApplyParticipationCcFlags(redConnected, blueConnected);
|
||||
Logger.Log("Dedicated match: blocking winner settle before shutdown → " + winningTeam
|
||||
+ " red_connected=" + redConnected + " blue_connected=" + blueConnected);
|
||||
|
||||
using (var statusReq = DedicatedMatschInternalApi.BuildRequest(
|
||||
DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, "{\"status\":3}"))
|
||||
@@ -634,7 +741,7 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
|
||||
string winner = winningTeam == Team.Red ? "red" : "blue";
|
||||
string jsonBody = "{\"winner\":\"" + winner + "\"}";
|
||||
string jsonBody = DedicatedMatschInternalApi.BuildWinnerPatchJson(winner, redConnected, blueConnected);
|
||||
using (var winReq = DedicatedMatschInternalApi.BuildWinnerRequest(
|
||||
DedicatedInternalApiBase, DedicatedMatchId, DedicatedMatchSecret, jsonBody))
|
||||
{
|
||||
@@ -1157,6 +1264,7 @@ public class GameManager : NetworkBehaviour
|
||||
RpcPlayGoalScoredSfx();
|
||||
|
||||
freezeInput=true;
|
||||
CancelInGoalPuckResets();
|
||||
Team concedingTeam = team;
|
||||
|
||||
if(hitCounter == 1){
|
||||
@@ -1236,7 +1344,8 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcGameOver(Team team){
|
||||
void RpcGameOver(Team team, bool redConnected, bool blueConnected){
|
||||
ApplyParticipationCcFlags(redConnected, blueConnected);
|
||||
gameOver(team);
|
||||
}
|
||||
|
||||
@@ -1245,7 +1354,11 @@ public class GameManager : NetworkBehaviour
|
||||
}
|
||||
|
||||
IEnumerator CoroutineGameOver(Team team){
|
||||
yield return new WaitForSeconds(2f);
|
||||
if (GameCanvas.instance != null)
|
||||
yield return GameCanvas.instance.ShowRandomPostGamePanelThenHide();
|
||||
else
|
||||
yield return new WaitForSeconds(2f);
|
||||
|
||||
yield return CoroutineFetchBothPlayersL10();
|
||||
|
||||
// StopClient();
|
||||
@@ -1368,6 +1481,11 @@ public class GameManager : NetworkBehaviour
|
||||
if (leavingTeam != Team.Red && leavingTeam != Team.Blue)
|
||||
return;
|
||||
|
||||
if (leavingTeam == Team.Red)
|
||||
_redConnected = false;
|
||||
else if (leavingTeam == Team.Blue)
|
||||
_blueConnected = false;
|
||||
|
||||
Team winner = GetOpposingTeam(leavingTeam);
|
||||
Logger.Log($"Match: {leavingTeam} forfeited by leave — {winner} wins");
|
||||
EndMatch(winner);
|
||||
@@ -1383,10 +1501,7 @@ public class GameManager : NetworkBehaviour
|
||||
{
|
||||
_thirdPlayerLeaveTriggered = true;
|
||||
Logger.Log("Third player in a 2-player match (matchmaker bug); leaving to main menu.");
|
||||
if (LevelLoadManager.instance != null)
|
||||
LevelLoadManager.instance.Leave();
|
||||
else
|
||||
LevelLoadManager.LoadLevel("MainMenu");
|
||||
NotifyAndLeaveMatch("Unable to join", "This match is already full.");
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
@@ -1456,6 +1571,15 @@ public class GameManager : NetworkBehaviour
|
||||
bool freezeInput = false;
|
||||
public bool CanProcessGoal => isServer && !freezeInput && !isGameEnded;
|
||||
|
||||
void CancelInGoalPuckResets()
|
||||
{
|
||||
foreach (Puck puck in pucks)
|
||||
{
|
||||
if (puck != null)
|
||||
puck.CancelInGoalReset();
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator CoroutineOnGoal(Team team, bool kickoff = false){
|
||||
if(coroutinePostLaunch!=null){
|
||||
StopCoroutine(coroutinePostLaunch);
|
||||
@@ -1521,6 +1645,16 @@ static class DedicatedMatschInternalApi
|
||||
return BuildPatchJson(url, secret, jsonBody);
|
||||
}
|
||||
|
||||
public static string BuildWinnerPatchJson(string winnerLower, bool redConnected, bool blueConnected)
|
||||
{
|
||||
return JsonUtility.ToJson(new DedicatedWinnerPatchRequest
|
||||
{
|
||||
winner = winnerLower,
|
||||
red_connected = redConnected,
|
||||
blue_connected = blueConnected
|
||||
});
|
||||
}
|
||||
|
||||
public static UnityWebRequest BuildRematchRequest(string baseUrl, string secret, string jsonBody)
|
||||
{
|
||||
string url = baseUrl.TrimEnd('/') + "/internal/rematch";
|
||||
@@ -1570,7 +1704,13 @@ static class DedicatedMatschInternalApi
|
||||
{
|
||||
var parsed = JsonUtility.FromJson<DedicatedWinnerPatchResponse>(body);
|
||||
if (parsed != null && parsed.ok && parsed.economy != null)
|
||||
{
|
||||
GameManager.MatchRcPrizeCoins = parsed.economy.rc_prize;
|
||||
Logger.Log("Dedicated winner PATCH economy: rc_prize=" + parsed.economy.rc_prize
|
||||
+ " participant_cc=" + parsed.economy.participant_cc
|
||||
+ " cc_awarded_red=" + parsed.economy.cc_awarded_red
|
||||
+ " cc_awarded_blue=" + parsed.economy.cc_awarded_blue);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1602,12 +1742,22 @@ class DedicatedJoinPatchResponse
|
||||
public int escrow_user_id;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class DedicatedWinnerPatchRequest
|
||||
{
|
||||
public string winner;
|
||||
public bool red_connected;
|
||||
public bool blue_connected;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class DedicatedWinnerPatchEconomy
|
||||
{
|
||||
public int entry_fee_rc;
|
||||
public int rc_prize;
|
||||
public int participant_cc;
|
||||
public bool cc_awarded_red;
|
||||
public bool cc_awarded_blue;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
Reference in New Issue
Block a user