prod ready
This commit is contained in:
parent
d09b48c01a
commit
71354308de
|
|
@ -1208,7 +1208,7 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 559a535836e3be843a23b9fc3cc5a0cf, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
start_on_dummy: 1
|
||||
start_on_dummy: 0
|
||||
loadingScreen: {fileID: 3571457582356105321}
|
||||
helperScreen: {fileID: 0}
|
||||
txtLoadingStatus: {fileID: 3586273892319143354}
|
||||
|
|
@ -3460,6 +3460,8 @@ MonoBehaviour:
|
|||
syncMode: 0
|
||||
syncInterval: 0
|
||||
statusText: {fileID: 1110060053}
|
||||
scoreText_me: {fileID: 517343105}
|
||||
scoreText_enemy: {fileID: 1914728796}
|
||||
gameOverScreen: {fileID: 400480993}
|
||||
gameStarted: 0
|
||||
winner: 1
|
||||
|
|
@ -3686,7 +3688,7 @@ MonoBehaviour:
|
|||
sendTimeout: 5000
|
||||
receiveTimeout: 20000
|
||||
noDelay: 1
|
||||
sslEnabled: 0
|
||||
sslEnabled: 1
|
||||
sslProtocols: 3072
|
||||
sslCertJson: ./cert.json
|
||||
port: 27777
|
||||
|
|
@ -3704,7 +3706,7 @@ MonoBehaviour:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2131586989}
|
||||
m_Enabled: 1
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3}
|
||||
m_Name:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ public class NetGameManager : NetworkBehaviour
|
|||
public const int WAITING_TIME = 120;
|
||||
public static NetGameManager instance;
|
||||
public TMP_Text statusText;
|
||||
public TMP_Text scoreText_me;
|
||||
public TMP_Text scoreText_enemy;
|
||||
public GameOverScreen gameOverScreen;
|
||||
public bool gameStarted = false;
|
||||
float waitingTimer = WAITING_TIME;
|
||||
|
|
@ -31,6 +33,13 @@ public class NetGameManager : NetworkBehaviour
|
|||
Application.targetFrameRate = 60;
|
||||
}
|
||||
|
||||
public void UpdateScore(bool isLocalPlayer, int score){
|
||||
if(isLocalPlayer){
|
||||
scoreText_me.text = score.ToString();
|
||||
}else{
|
||||
scoreText_enemy.text = score.ToString();
|
||||
}
|
||||
}
|
||||
public bool playerSpawned = false;
|
||||
|
||||
// Update is called once per frame
|
||||
|
|
@ -47,18 +56,20 @@ public class NetGameManager : NetworkBehaviour
|
|||
StartCoroutine(StartGame());
|
||||
}else{
|
||||
if(players.Length == 1){
|
||||
waitingTimer -= Time.deltaTime;
|
||||
SetStatusText("Waiting for another player...\nRemaining time: " + waitingTimer.ToString("F0") + " seconds");
|
||||
}else{
|
||||
SetStatusText("Opponent abandoned the game");
|
||||
//TODO: GAME OVER
|
||||
if(waitingTimer >0){
|
||||
waitingTimer -= Time.deltaTime;
|
||||
SetStatusText("Waiting for another player...\nRemaining time: " + waitingTimer.ToString("F0") + " seconds");
|
||||
}else{
|
||||
SetStatusText("Opponent abandoned the game");
|
||||
GameOver(players[0].playerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(players.Length == 1){
|
||||
if(playerSpawned){
|
||||
SetStatusText("Opponent left the game");
|
||||
//TODO: GAME OVER
|
||||
GameOver(players[0].playerType);
|
||||
}else{
|
||||
gameStarted = false;
|
||||
SetStatusText("Waiting for another player...");
|
||||
|
|
@ -69,6 +80,7 @@ public class NetGameManager : NetworkBehaviour
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
[ClientRpc]
|
||||
void RpcSetGameStarted(bool started){
|
||||
gameStarted = started;
|
||||
|
|
@ -86,12 +98,17 @@ public class NetGameManager : NetworkBehaviour
|
|||
spawnedFruits.Add(fruit);
|
||||
}
|
||||
public void DestroyFruit(Vector2 position){
|
||||
foreach(GameObject fruit in spawnedFruits){
|
||||
if(fruit.transform.position == (Vector3)position){
|
||||
NetworkServer.Destroy(fruit);
|
||||
spawnedFruits.Remove(fruit);
|
||||
int index = -1;
|
||||
for(int i=0; i < spawnedFruits.Count; i++){
|
||||
if(spawnedFruits[i].transform.position == (Vector3)position){
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(index != -1){
|
||||
NetworkServer.Destroy(spawnedFruits[index]);
|
||||
spawnedFruits.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 GetRandomPoint(){
|
||||
|
|
@ -185,7 +202,10 @@ public class NetGameManager : NetworkBehaviour
|
|||
}
|
||||
queryString = queryString.TrimEnd('&');
|
||||
|
||||
WWW www = new WWW(Constants.VALIDATOR_URL + "finalize" + queryString);
|
||||
string validator_url = GameData.isDev ? Constants.VALIDATOR_URL_DEV : Constants.VALIDATOR_URL_PROD;
|
||||
string url = validator_url + "finalize" + queryString;
|
||||
Debug.Log("Finalizing game on " + url);
|
||||
WWW www = new WWW(url);
|
||||
yield return www;
|
||||
|
||||
if(www.error == null){
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ public class SnakeController : NetworkBehaviour
|
|||
{
|
||||
[SyncVar]
|
||||
public string userId;
|
||||
[SyncVar(hook = nameof(OnScoreChange))]
|
||||
public int Score=0;
|
||||
public Vector2 startOffset = new Vector3(-10, -10);
|
||||
public float movingInterval = 0.2f;
|
||||
public Vector2 curDirection = Vector3.right;
|
||||
|
|
@ -24,29 +26,40 @@ public class SnakeController : NetworkBehaviour
|
|||
public float leftEdge => transform.position.x - fieldSize.x / 2f;
|
||||
public float rightEdge => transform.position.x + fieldSize.x / 2f;
|
||||
|
||||
// Add new fields for client prediction
|
||||
private List<Vector2> predictedPositions = new List<Vector2>();
|
||||
private List<Vector2> predictedDirections = new List<Vector2>();
|
||||
private float lastServerUpdateTime;
|
||||
private const float MAX_PREDICTION_TIME = 0.5f; // Maximum time to keep predictions
|
||||
|
||||
void Start()
|
||||
{
|
||||
|
||||
|
||||
ButtonSet.OnUp += OnUp;
|
||||
ButtonSet.OnDown += OnDown;
|
||||
ButtonSet.OnLeft += OnLeft;
|
||||
ButtonSet.OnRight += OnRight;
|
||||
|
||||
|
||||
playerType = GameData.isMaster ? PlayerType.Master : PlayerType.Client;
|
||||
if(FindObjectsOfType<SnakeController>().Length >1){
|
||||
startOffset+=new Vector2(0, 10);
|
||||
}
|
||||
|
||||
if(!isServer&& isLocalPlayer){
|
||||
CmdSetUserId(GameData.user_id);
|
||||
}
|
||||
|
||||
if (isLocalPlayer)
|
||||
{
|
||||
lastServerUpdateTime = Time.time;
|
||||
playerType = GameData.isMaster ? PlayerType.Master : PlayerType.Client;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdSetUserId(string userId){
|
||||
|
||||
if(userId == GameData.betData.owner_id){
|
||||
startOffset.y += 10;
|
||||
}
|
||||
this.userId = userId;
|
||||
playerType = userId == GameData.betData.owner_id ? PlayerType.Master : PlayerType.Client;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
|
|
@ -77,22 +90,34 @@ public class SnakeController : NetworkBehaviour
|
|||
public bool controlling = false;
|
||||
void Update()
|
||||
{
|
||||
if (NetGameManager.instance.gameOver) { return; }
|
||||
if (!isKickstarted) { return; }
|
||||
|
||||
if (isLocalPlayer)
|
||||
{
|
||||
ProcessInput();
|
||||
}
|
||||
if (NetGameManager.instance.gameOver) { return; }
|
||||
if (!isKickstarted) { return; }
|
||||
|
||||
if (!isServer) { return; }
|
||||
|
||||
CheckHead();
|
||||
if (isDead) { return; }
|
||||
Move();
|
||||
if (isServer)
|
||||
{
|
||||
CheckHead();
|
||||
if (isDead) { return; }
|
||||
Move();
|
||||
}
|
||||
else if (isLocalPlayer)
|
||||
{
|
||||
// Client-side prediction
|
||||
if (moveTimer > 0)
|
||||
{
|
||||
moveTimer -= Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
moveTimer = movingInterval;
|
||||
PredictMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProcessInput()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow))
|
||||
|
|
@ -133,12 +158,26 @@ public class SnakeController : NetworkBehaviour
|
|||
ChangeDir(-Vector2.up);
|
||||
}
|
||||
|
||||
|
||||
public int Score;
|
||||
public void AddScore(int amount = 1)
|
||||
{
|
||||
Score += amount;
|
||||
if(isServer){
|
||||
RpcOnScore();
|
||||
}else{
|
||||
OnScore();
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcOnScore(){
|
||||
OnScore();
|
||||
}
|
||||
|
||||
void OnScoreChange(int oldScore, int newScore){
|
||||
NetGameManager.instance.UpdateScore(isLocalPlayer, newScore);
|
||||
}
|
||||
|
||||
void OnScore(){
|
||||
SFXManager.instance.PlayCrunch();
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +211,90 @@ public class SnakeController : NetworkBehaviour
|
|||
}
|
||||
|
||||
bool queueNewPiece = false;
|
||||
void PredictMove()
|
||||
{
|
||||
if (moveInputQueue.Count > 0)
|
||||
{
|
||||
Vector2 dir = Vector2.zero;
|
||||
if (curDirection.x != 0)
|
||||
{
|
||||
dir = new Vector2(-curDirection.x, moveInputQueue[0].y);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = new Vector2(moveInputQueue[0].x, -curDirection.y);
|
||||
}
|
||||
curDirection = moveInputQueue[0];
|
||||
moveInputQueue.RemoveAt(0);
|
||||
|
||||
bends.Add(new BendData()
|
||||
{
|
||||
position = snakePieces[0].transform.position,
|
||||
direction = dir
|
||||
});
|
||||
}
|
||||
|
||||
// Store current state for prediction
|
||||
Vector2 curPosition = snakePieces[0].transform.position;
|
||||
Vector2 lastPosition = snakePieces[snakePieces.Count - 1].transform.position;
|
||||
|
||||
// Update snake pieces
|
||||
for (int i = snakePieces.Count - 1; i > 0; i--)
|
||||
{
|
||||
Vector3 dir = (snakePieces[i - 1].transform.position - snakePieces[i].transform.position).normalized;
|
||||
snakePieces[i].direction = dir;
|
||||
snakePieces[i].isHead = false;
|
||||
snakePieces[i].transform.position = snakePieces[i - 1].transform.position;
|
||||
|
||||
BendData bendToRemove = null;
|
||||
foreach (BendData bend in bends)
|
||||
{
|
||||
if (bend.position == snakePieces[i].transform.position)
|
||||
{
|
||||
snakePieces[i].direction = bend.direction;
|
||||
if (i == snakePieces.Count - 1)
|
||||
{
|
||||
bendToRemove = bend;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bendToRemove != null)
|
||||
{
|
||||
bends.Remove(bendToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
// Move head
|
||||
snakePieces[0].transform.position = curPosition + curDirection;
|
||||
snakePieces[0].direction = curDirection;
|
||||
snakePieces[0].isHead = true;
|
||||
|
||||
// Handle wrapping
|
||||
if (snakePieces[0].transform.position.x > rightEdge)
|
||||
{
|
||||
snakePieces[0].transform.position = new Vector2(leftEdge, snakePieces[0].transform.position.y);
|
||||
}
|
||||
else if (snakePieces[0].transform.position.x < leftEdge)
|
||||
{
|
||||
snakePieces[0].transform.position = new Vector2(rightEdge, snakePieces[0].transform.position.y);
|
||||
}
|
||||
|
||||
if (snakePieces[0].transform.position.y > topEdge)
|
||||
{
|
||||
snakePieces[0].transform.position = new Vector2(snakePieces[0].transform.position.x, botEdge);
|
||||
}
|
||||
else if (snakePieces[0].transform.position.y < botEdge)
|
||||
{
|
||||
snakePieces[0].transform.position = new Vector2(snakePieces[0].transform.position.x, topEdge);
|
||||
}
|
||||
|
||||
// Store prediction
|
||||
predictedPositions.Add(snakePieces[0].transform.position);
|
||||
predictedDirections.Add(curDirection);
|
||||
}
|
||||
|
||||
void Move()
|
||||
{
|
||||
if (moveTimer > 0)
|
||||
|
|
@ -201,18 +324,17 @@ public class SnakeController : NetworkBehaviour
|
|||
direction = dir
|
||||
});
|
||||
}
|
||||
|
||||
Vector2 curPosition = snakePieces[0].transform.position;
|
||||
Vector2 lastPosition = snakePieces[snakePieces.Count - 1].transform.position;
|
||||
|
||||
for (int i = snakePieces.Count - 1; i > 0; i--)
|
||||
{
|
||||
Vector3 dir = (snakePieces[i - 1].transform.position - snakePieces[i].transform.position).normalized;
|
||||
|
||||
snakePieces[i].direction = dir;
|
||||
|
||||
snakePieces[i].isHead = false;
|
||||
snakePieces[i].transform.position = snakePieces[i - 1].transform.position;
|
||||
snakePieces[i].transform.position = snakePieces[i].transform.position;
|
||||
|
||||
BendData bendToRemove = null;
|
||||
foreach (BendData bend in bends)
|
||||
{
|
||||
|
|
@ -267,8 +389,63 @@ public class SnakeController : NetworkBehaviour
|
|||
{
|
||||
snakePieces[0].transform.position = new Vector2(snakePieces[0].transform.position.x, topEdge);
|
||||
}
|
||||
|
||||
// After server movement, send state to clients
|
||||
if (isServer)
|
||||
{
|
||||
Vector2[] positions = new Vector2[snakePieces.Count];
|
||||
Vector2[] directions = new Vector2[snakePieces.Count];
|
||||
|
||||
for (int i = 0; i < snakePieces.Count; i++)
|
||||
{
|
||||
positions[i] = snakePieces[i].transform.position;
|
||||
directions[i] = snakePieces[i].direction;
|
||||
}
|
||||
|
||||
RpcReconcileState(positions, directions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
void RpcReconcileState(Vector2[] serverPositions, Vector2[] serverDirections)
|
||||
{
|
||||
if (!isLocalPlayer) return;
|
||||
|
||||
// Find the oldest prediction that matches the server state
|
||||
int matchIndex = -1;
|
||||
for (int i = 0; i < predictedPositions.Count; i++)
|
||||
{
|
||||
if (Vector2.Distance(predictedPositions[i], serverPositions[0]) < 0.1f)
|
||||
{
|
||||
matchIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchIndex >= 0)
|
||||
{
|
||||
// Remove all predictions up to the matching one
|
||||
predictedPositions.RemoveRange(0, matchIndex + 1);
|
||||
predictedDirections.RemoveRange(0, matchIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No match found, reset to server state
|
||||
predictedPositions.Clear();
|
||||
predictedDirections.Clear();
|
||||
|
||||
// Update snake pieces to match server state
|
||||
for (int i = 0; i < snakePieces.Count; i++)
|
||||
{
|
||||
snakePieces[i].transform.position = serverPositions[i];
|
||||
snakePieces[i].direction = serverDirections[i];
|
||||
}
|
||||
}
|
||||
|
||||
lastServerUpdateTime = Time.time;
|
||||
}
|
||||
|
||||
bool isDead = false;
|
||||
public PlayerType playerType;
|
||||
void CheckHead()
|
||||
|
|
@ -286,7 +463,7 @@ public class SnakeController : NetworkBehaviour
|
|||
{
|
||||
Debug.Log($"Crashed into {obstacle.name}", gameObject);
|
||||
isDead = true;
|
||||
NetGameManager.instance.GameOver(playerType);
|
||||
NetGameManager.instance.GameOver(playerType == PlayerType.Master ? PlayerType.Client : PlayerType.Master);
|
||||
SFXManager.instance.PlayDeath();
|
||||
}
|
||||
}
|
||||
|
|
@ -296,7 +473,6 @@ public class SnakeController : NetworkBehaviour
|
|||
queueNewPiece = true;
|
||||
|
||||
NetGameManager.instance.DestroyFruit(obstacle.transform.position);
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public class ClientKickstarter : MonoBehaviour
|
|||
|
||||
IEnumerator startTest(int user_id = 1)
|
||||
{
|
||||
WWW www = new WWW(Constants.MATCHMAKER_URL + "getGamePort?address=" + GameData.address + "&gameName=" + GAME_NAME);
|
||||
WWW www = new WWW(Constants.MATCHMAKER_URL + "getGamePort?address=" + GameData.address + "&gameName=" + GAME_NAME + "&isDev=" + (GameData.isDev ? "true" : "false"));
|
||||
yield return www;
|
||||
Debug.Log("test port: " + www.text);
|
||||
string port = www.text;
|
||||
|
|
@ -108,7 +108,7 @@ public class ClientKickstarter : MonoBehaviour
|
|||
|
||||
IEnumerator CoroutineKickstarterWatcher()
|
||||
{
|
||||
yield return new WaitForSeconds(6f);
|
||||
yield return new WaitForSeconds(10f);
|
||||
SnakeController[] players = FindObjectsOfType<SnakeController>();
|
||||
if(players.Length == 0){
|
||||
txtLoadingStatus.text = "Connection failed. Retrying...";
|
||||
|
|
@ -127,7 +127,7 @@ public class ClientKickstarter : MonoBehaviour
|
|||
|
||||
while (reconnectAttempts < MAX_RECONNECT_ATTEMPTS)
|
||||
{
|
||||
WWW www = new WWW(Constants.MATCHMAKER_URL + "getGamePort?address=" + GameData.address + "&gameName=" + GAME_NAME);
|
||||
WWW www = new WWW(Constants.MATCHMAKER_URL + "getGamePort?address=" + GameData.address + "&gameName=" + GAME_NAME + "&isDev=" + (GameData.isDev ? "true" : "false"));
|
||||
yield return www;
|
||||
|
||||
if (string.IsNullOrEmpty(www.error))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
|
||||
public static class Constants{
|
||||
public static string VALIDATOR_URL = "https://validator.duelfi.io/";
|
||||
public static string VALIDATOR_URL_PROD = "https://validator.duelfi.io/";
|
||||
public static string VALIDATOR_URL_DEV = "https://validatordev.duelfi.io/";
|
||||
public static string MATCHMAKER_URL = "https://matchmaker.duelfi.io/";
|
||||
public static string API_URL = "https://api.duelfi.io/v1/";
|
||||
|
||||
|
|
|
|||
|
|
@ -28,12 +28,17 @@ public class ServerKickstarter : MonoBehaviour
|
|||
{
|
||||
arguments["port"] = "5000";
|
||||
arguments["address"] = "2h6hptZhts119MhaY39SyxSCYp966Y9EkKubEReb7wbT";
|
||||
arguments["isDev"] = "true";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NetworkManager.singleton.GetComponent<SimpleWebTransport>().port = (ushort)int.Parse(arguments["port"]);
|
||||
GameData.port = int.Parse(arguments["port"]);
|
||||
GameData.isDev = arguments["isDev"] == "true";
|
||||
if(GameData.isDev){
|
||||
Debug.Log("Starting server in dev mode");
|
||||
}
|
||||
StartCoroutine(CoroutineUpdateGameData(arguments["address"]));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -52,10 +57,11 @@ public class ServerKickstarter : MonoBehaviour
|
|||
IEnumerator CoroutineUpdateGameData(string address)
|
||||
{
|
||||
GameData.address = address;
|
||||
|
||||
WWW www = new WWW(Constants.VALIDATOR_URL + "fetchBet?address=" + address);
|
||||
string validator_url = GameData.isDev ? Constants.VALIDATOR_URL_DEV : Constants.VALIDATOR_URL_PROD;
|
||||
string url = validator_url + "fetchBet?address=" + address;
|
||||
WWW www = new WWW(url);
|
||||
yield return www;
|
||||
|
||||
Debug.Log(url);
|
||||
Debug.Log("bet: " + www.text);
|
||||
try
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user