initial upload
This commit is contained in:
378
Unity-Master/Assets/Scripts/AvatarSyncClient.cs
Normal file
378
Unity-Master/Assets/Scripts/AvatarSyncClient.cs
Normal file
@ -0,0 +1,378 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public class AvatarSyncClient : MonoBehaviour
|
||||
{
|
||||
[Header("Server Configuration")]
|
||||
[SerializeField] private string serverHost = "127.0.0.1";
|
||||
[SerializeField] private int serverPort = 8080;
|
||||
[SerializeField] private string targetPlayer = "player1"; // Which player data to fetch
|
||||
|
||||
[Header("Sync Configuration")]
|
||||
[SerializeField] private bool autoSync = true;
|
||||
[SerializeField] private float syncInterval = 0.1f; // How often to fetch data (in seconds)
|
||||
[SerializeField] private string localFileName = ""; // Leave empty to use targetPlayer name
|
||||
|
||||
[Header("Upload Configuration")]
|
||||
[SerializeField] private bool uploadLocalData = false; // Upload this client's data to server
|
||||
[SerializeField] private string localDataFile = "avatar_sync_data.json"; // Local file to upload
|
||||
[SerializeField] private string uploadAsPlayer = "player2"; // Upload as which player
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField] private bool enableDebugMode = false;
|
||||
[SerializeField] private bool showConnectionStatus = true;
|
||||
|
||||
private string syncFilesPath;
|
||||
private string outputFilePath;
|
||||
private Coroutine syncCoroutine;
|
||||
private bool isConnected = false;
|
||||
private float lastSuccessfulSync = 0f;
|
||||
private int totalRequests = 0;
|
||||
private int successfulRequests = 0;
|
||||
|
||||
// Connection status
|
||||
public bool IsConnected => isConnected;
|
||||
public string ServerUrl => $"http://{serverHost}:{serverPort}";
|
||||
public float LastSyncTime => lastSuccessfulSync;
|
||||
public float SuccessRate => totalRequests > 0 ? (float)successfulRequests / totalRequests : 0f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Set up file paths
|
||||
syncFilesPath = Path.Combine(Application.dataPath, "Sync-Files");
|
||||
if (!Directory.Exists(syncFilesPath))
|
||||
{
|
||||
Directory.CreateDirectory(syncFilesPath);
|
||||
}
|
||||
|
||||
// Determine output file name
|
||||
string fileName = string.IsNullOrEmpty(localFileName) ? $"{targetPlayer}.json" : localFileName;
|
||||
outputFilePath = Path.Combine(syncFilesPath, fileName);
|
||||
|
||||
Debug.Log($"Avatar Sync Client initialized");
|
||||
Debug.Log($"Server: {ServerUrl}");
|
||||
Debug.Log($"Target Player: {targetPlayer}");
|
||||
Debug.Log($"Output File: {outputFilePath}");
|
||||
Debug.Log($"Upload Mode: {(uploadLocalData ? $"Yes (as {uploadAsPlayer})" : "No")}");
|
||||
|
||||
// Start syncing if auto-sync is enabled
|
||||
if (autoSync)
|
||||
{
|
||||
StartSync();
|
||||
}
|
||||
|
||||
// Test connection
|
||||
StartCoroutine(TestConnection());
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
// Ensure valid values
|
||||
if (syncInterval < 0.01f)
|
||||
syncInterval = 0.01f;
|
||||
|
||||
if (serverPort < 1 || serverPort > 65535)
|
||||
serverPort = 8080;
|
||||
}
|
||||
|
||||
public void StartSync()
|
||||
{
|
||||
if (syncCoroutine == null)
|
||||
{
|
||||
syncCoroutine = StartCoroutine(SyncLoop());
|
||||
Debug.Log("Avatar sync started");
|
||||
}
|
||||
}
|
||||
|
||||
public void StopSync()
|
||||
{
|
||||
if (syncCoroutine != null)
|
||||
{
|
||||
StopCoroutine(syncCoroutine);
|
||||
syncCoroutine = null;
|
||||
Debug.Log("Avatar sync stopped");
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator TestConnection()
|
||||
{
|
||||
string url = $"{ServerUrl}/status";
|
||||
|
||||
using (UnityWebRequest request = UnityWebRequest.Get(url))
|
||||
{
|
||||
request.timeout = 5; // 5 second timeout for connection test
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
isConnected = true;
|
||||
if (showConnectionStatus)
|
||||
{
|
||||
Debug.Log($"Successfully connected to avatar sync server at {ServerUrl}");
|
||||
}
|
||||
|
||||
// Try to parse server status
|
||||
try
|
||||
{
|
||||
var status = JsonConvert.DeserializeObject<Dictionary<string, object>>(request.downloadHandler.text);
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.Log($"Server status: {request.downloadHandler.text}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning($"Could not parse server status: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isConnected = false;
|
||||
if (showConnectionStatus)
|
||||
{
|
||||
Debug.LogWarning($"Failed to connect to avatar sync server at {ServerUrl}: {request.error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator SyncLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Upload local data if enabled
|
||||
if (uploadLocalData)
|
||||
{
|
||||
yield return StartCoroutine(UploadLocalData());
|
||||
}
|
||||
|
||||
// Fetch remote player data
|
||||
yield return StartCoroutine(FetchPlayerData());
|
||||
|
||||
yield return new WaitForSeconds(syncInterval);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator FetchPlayerData()
|
||||
{
|
||||
string url = $"{ServerUrl}/{targetPlayer}";
|
||||
totalRequests++;
|
||||
|
||||
using (UnityWebRequest request = UnityWebRequest.Get(url))
|
||||
{
|
||||
request.timeout = 10; // 10 second timeout
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Validate JSON
|
||||
var avatarData = JsonConvert.DeserializeObject<AvatarSyncData>(request.downloadHandler.text);
|
||||
|
||||
if (avatarData != null)
|
||||
{
|
||||
// Write to local file
|
||||
File.WriteAllText(outputFilePath, request.downloadHandler.text);
|
||||
|
||||
successfulRequests++;
|
||||
lastSuccessfulSync = Time.time;
|
||||
isConnected = true;
|
||||
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.Log($"Successfully fetched and saved data for {targetPlayer}. Timestamp: {avatarData.timestamp}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning($"Received null avatar data for {targetPlayer}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Error processing avatar data for {targetPlayer}: {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isConnected = false;
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning($"Failed to fetch data for {targetPlayer}: {request.error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator UploadLocalData()
|
||||
{
|
||||
string localFilePath = Path.Combine(syncFilesPath, localDataFile);
|
||||
|
||||
if (!File.Exists(localFilePath))
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning($"Local data file not found: {localFilePath}");
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
string jsonData = null;
|
||||
AvatarSyncData avatarData = null;
|
||||
|
||||
// Read and validate file outside of try block with yield
|
||||
try
|
||||
{
|
||||
jsonData = File.ReadAllText(localFilePath);
|
||||
avatarData = JsonConvert.DeserializeObject<AvatarSyncData>(jsonData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Error reading/parsing local data file: {e.Message}");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (avatarData == null)
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning("Local avatar data is invalid, skipping upload");
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
// Network request without try-catch since we can't yield in try-catch
|
||||
string url = $"{ServerUrl}/{uploadAsPlayer}";
|
||||
|
||||
using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
|
||||
{
|
||||
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonData);
|
||||
request.uploadHandler = new UploadHandlerRaw(jsonBytes);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
request.timeout = 10;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.Log($"Successfully uploaded data as {uploadAsPlayer}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enableDebugMode)
|
||||
{
|
||||
Debug.LogWarning($"Failed to upload data as {uploadAsPlayer}: {request.error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public methods for runtime control
|
||||
public void SetServerAddress(string host, int port)
|
||||
{
|
||||
serverHost = host;
|
||||
serverPort = port;
|
||||
|
||||
// Test new connection
|
||||
StartCoroutine(TestConnection());
|
||||
}
|
||||
|
||||
public void SetTargetPlayer(string player)
|
||||
{
|
||||
targetPlayer = player;
|
||||
|
||||
// Update output file path
|
||||
string fileName = string.IsNullOrEmpty(localFileName) ? $"{targetPlayer}.json" : localFileName;
|
||||
outputFilePath = Path.Combine(syncFilesPath, fileName);
|
||||
}
|
||||
|
||||
public void ManualSync()
|
||||
{
|
||||
if (gameObject.activeInHierarchy)
|
||||
{
|
||||
StartCoroutine(FetchPlayerData());
|
||||
}
|
||||
}
|
||||
|
||||
// Get current stats for UI display
|
||||
public string GetConnectionStats()
|
||||
{
|
||||
return $"Connected: {isConnected}\n" +
|
||||
$"Success Rate: {(SuccessRate * 100):F1}%\n" +
|
||||
$"Total Requests: {totalRequests}\n" +
|
||||
$"Last Sync: {(Time.time - lastSuccessfulSync):F1}s ago";
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
StopSync();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
StopSync();
|
||||
}
|
||||
|
||||
// GUI for runtime debugging
|
||||
void OnGUI()
|
||||
{
|
||||
if (!enableDebugMode)
|
||||
return;
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 10, 300, 200));
|
||||
GUILayout.BeginVertical("box");
|
||||
|
||||
GUILayout.Label($"Avatar Sync Client - {targetPlayer}");
|
||||
GUILayout.Label($"Server: {ServerUrl}");
|
||||
GUILayout.Label($"Status: {(isConnected ? "Connected" : "Disconnected")}");
|
||||
GUILayout.Label($"Success Rate: {(SuccessRate * 100):F1}%");
|
||||
GUILayout.Label($"Last Sync: {(Time.time - lastSuccessfulSync):F1}s ago");
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Manual Sync"))
|
||||
{
|
||||
ManualSync();
|
||||
}
|
||||
if (GUILayout.Button("Test Connection"))
|
||||
{
|
||||
StartCoroutine(TestConnection());
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (syncCoroutine == null)
|
||||
{
|
||||
if (GUILayout.Button("Start Auto Sync"))
|
||||
{
|
||||
StartSync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Stop Auto Sync"))
|
||||
{
|
||||
StopSync();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user