Téléverser les fichiers vers "/"
This commit is contained in:
parent
fd4deaaa07
commit
b052a0ef10
94
DebugFalling.cs
Normal file
94
DebugFalling.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// TEMPORAIRE - Debug pour diagnostiquer le problème de chute sous la map.
|
||||
/// Ajouter sur le prefab PlayerCapsule, supprimer après diagnostic.
|
||||
/// </summary>
|
||||
public class DebugFalling : MonoBehaviour, IClientOnly
|
||||
{
|
||||
private CharacterController _cc;
|
||||
private StarterAssets.FirstPersonController _fpc;
|
||||
private float _lastLogTime = 0f;
|
||||
private float _lastY;
|
||||
private bool _wasFalling = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_cc = GetComponent<CharacterController>();
|
||||
_fpc = GetComponent<StarterAssets.FirstPersonController>();
|
||||
_lastY = transform.position.y;
|
||||
|
||||
if (_cc != null)
|
||||
{
|
||||
Debug.Log($"[DebugFall] CharacterController: center={_cc.center} height={_cc.height} radius={_cc.radius} skinWidth={_cc.skinWidth}");
|
||||
Debug.Log($"[DebugFall] Layer joueur: {gameObject.layer} ({LayerMask.LayerToName(gameObject.layer)})");
|
||||
}
|
||||
|
||||
if (_fpc != null)
|
||||
{
|
||||
Debug.Log($"[DebugFall] FPC enabled={_fpc.enabled} GroundLayers={_fpc.GroundLayers.value} GroundedOffset={_fpc.GroundedOffset} GroundedRadius={_fpc.GroundedRadius}");
|
||||
}
|
||||
|
||||
// Test : y a-t-il un sol sous nous ?
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast(transform.position + Vector3.up * 0.5f, Vector3.down, out hit, 50f))
|
||||
Debug.Log($"[DebugFall] Sol détecté: {hit.collider.gameObject.name} layer={LayerMask.LayerToName(hit.collider.gameObject.layer)} distance={hit.distance:F2} point={hit.point}");
|
||||
else
|
||||
Debug.Log("[DebugFall] AUCUN SOL DÉTECTÉ sous le joueur !");
|
||||
|
||||
// Test GroundLayers
|
||||
if (_fpc != null)
|
||||
{
|
||||
int solLayer = LayerMask.NameToLayer("Sol");
|
||||
bool solInclus = (_fpc.GroundLayers.value & (1 << solLayer)) != 0;
|
||||
Debug.Log($"[DebugFall] Layer Sol ({solLayer}) inclus dans GroundLayers: {solInclus}");
|
||||
|
||||
// Test CheckSphere comme le fait le FPC
|
||||
Vector3 spherePos = new Vector3(transform.position.x, transform.position.y - _fpc.GroundedOffset, transform.position.z);
|
||||
bool grounded = Physics.CheckSphere(spherePos, _fpc.GroundedRadius, _fpc.GroundLayers, QueryTriggerInteraction.Ignore);
|
||||
Debug.Log($"[DebugFall] CheckSphere grounded={grounded} spherePos={spherePos} radius={_fpc.GroundedRadius}");
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_fpc == null || _cc == null) return;
|
||||
|
||||
float y = transform.position.y;
|
||||
bool falling = y < _lastY - 0.01f;
|
||||
|
||||
// Log quand on commence à tomber
|
||||
if (falling && !_wasFalling)
|
||||
{
|
||||
Debug.LogWarning($"[DebugFall] DÉBUT CHUTE à Y={y:F2} pos={transform.position} Grounded={_fpc.Grounded} FPC.enabled={_fpc.enabled} CC.enabled={_cc.enabled} CC.isGrounded={_cc.isGrounded}");
|
||||
|
||||
// Vérifier ce qu'il y a sous nous
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast(transform.position, Vector3.down, out hit, 50f))
|
||||
Debug.LogWarning($"[DebugFall] Sous nous: {hit.collider.gameObject.name} layer={LayerMask.LayerToName(hit.collider.gameObject.layer)} dist={hit.distance:F2}");
|
||||
else
|
||||
Debug.LogWarning("[DebugFall] RIEN sous le joueur !");
|
||||
}
|
||||
|
||||
// Log continu pendant la chute (1x par seconde)
|
||||
if (falling && Time.time - _lastLogTime > 1f)
|
||||
{
|
||||
_lastLogTime = Time.time;
|
||||
Debug.LogWarning($"[DebugFall] EN CHUTE Y={y:F2} velocity.y={_cc.velocity.y:F2} Grounded={_fpc.Grounded} CC.isGrounded={_cc.isGrounded}");
|
||||
}
|
||||
|
||||
// Log quand on tombe trop bas
|
||||
if (y < -5f && Time.time - _lastLogTime > 2f)
|
||||
{
|
||||
_lastLogTime = Time.time;
|
||||
Debug.LogError($"[DebugFall] SOUS LA MAP Y={y:F2} téléportation de secours !");
|
||||
// Téléporter au spawn de secours
|
||||
_cc.enabled = false;
|
||||
transform.position = new Vector3(0, 2, 0);
|
||||
_cc.enabled = true;
|
||||
}
|
||||
|
||||
_wasFalling = falling;
|
||||
_lastY = y;
|
||||
}
|
||||
}
|
||||
422
MasterServerClient.cs
Normal file
422
MasterServerClient.cs
Normal file
@ -0,0 +1,422 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Mirror;
|
||||
|
||||
/// <summary>
|
||||
/// MasterServerClient.cs - v6.6
|
||||
///
|
||||
/// v6.6 : Robustesse du heartbeat pour dedicated server
|
||||
/// - Heartbeat passe de 30s a 10s par defaut (reduit la fenetre
|
||||
/// ou le master server peut purger un serveur inactif)
|
||||
/// - Sur reponse 404 (serveur inconnu), re-enregistrement AUTOMATIQUE
|
||||
/// immediat avec les memes parametres que le register initial (au lieu
|
||||
/// de juste reset les variables et attendre le prochain heartbeat)
|
||||
/// - Memoire des parametres de registration pour pouvoir re-register
|
||||
/// sans intervention exterieure
|
||||
/// - Apres 3 echecs consecutifs, abandon et log d'erreur
|
||||
///
|
||||
/// v6.5 : Version originale
|
||||
///
|
||||
/// Usage :
|
||||
/// Placer sur le meme GameObject que le NetworkManager (ou un singleton).
|
||||
/// Configurer masterServerUrl dans l'Inspector.
|
||||
/// </summary>
|
||||
public class MasterServerClient : MonoBehaviour
|
||||
{
|
||||
// ══════════════════════════════════════════════════
|
||||
// CONFIGURATION
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
[Header("Master Server")]
|
||||
[Tooltip("URL du master server (ex: http://192.168.1.50:8080)")]
|
||||
public string masterServerUrl = "http://localhost:8080";
|
||||
|
||||
[Tooltip("Token d'authentification (doit correspondre au serveur)")]
|
||||
public string token = "dcsim-2026-secret";
|
||||
|
||||
[Header("Heartbeat")]
|
||||
[Tooltip("Intervalle du heartbeat en secondes (10s recommande pour dedicated)")]
|
||||
public float heartbeatInterval = 10f;
|
||||
|
||||
[Tooltip("Nombre max d'echecs consecutifs avant abandon (reset si succes)")]
|
||||
public int maxEchecsConsecutifs = 3;
|
||||
|
||||
// ══════════════════════════════════════════════════
|
||||
// ETAT
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
[HideInInspector] public string serverId = "";
|
||||
[HideInInspector] public bool estEnregistre = false;
|
||||
[HideInInspector] public List<ServerData> derniereListeServeurs = new List<ServerData>();
|
||||
[HideInInspector] public bool requeteEnCours = false;
|
||||
[HideInInspector] public string dernierStatut = "";
|
||||
|
||||
// Singleton
|
||||
public static MasterServerClient Instance { get; private set; }
|
||||
|
||||
private Coroutine _heartbeatCoroutine;
|
||||
private int _echecsConsecutifs = 0;
|
||||
|
||||
// v6.6 : memoire des parametres d'enregistrement pour re-register automatique
|
||||
private string _dernierNom = "";
|
||||
private int _dernierPort = 7777;
|
||||
private int _dernierMaxJoueurs = 4;
|
||||
private int _derniereLangue = 1;
|
||||
private string _dernierMode = "Sandbox";
|
||||
private string _derniereVersion = "v6.5g";
|
||||
private bool _dernierMotDePasse = false;
|
||||
|
||||
// ══════════════════════════════════════════════════
|
||||
// MODELES DE DONNEES
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
[System.Serializable]
|
||||
public class ServerData
|
||||
{
|
||||
public string id;
|
||||
public string nom;
|
||||
public string ip;
|
||||
public int port;
|
||||
public int joueurs;
|
||||
public int max_joueurs;
|
||||
public int ping;
|
||||
public int langue;
|
||||
public string mode;
|
||||
public string version;
|
||||
public bool mot_de_passe;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class ServerListWrapper
|
||||
{
|
||||
public List<ServerData> servers;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class RegisterRequest
|
||||
{
|
||||
public string nom;
|
||||
public int port;
|
||||
public int max_joueurs;
|
||||
public int langue;
|
||||
public string mode;
|
||||
public string version;
|
||||
public bool mot_de_passe;
|
||||
public string token;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class RegisterResponse
|
||||
{
|
||||
public string server_id;
|
||||
public string status;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class HeartbeatRequest
|
||||
{
|
||||
public int joueurs;
|
||||
public string token;
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════
|
||||
// LIFECYCLE
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
Debug.Log($"[MasterServer] Awake → Instance initialisee, URL={masterServerUrl}");
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
if (estEnregistre && !string.IsNullOrEmpty(serverId))
|
||||
{
|
||||
var request = new UnityWebRequest(
|
||||
$"{masterServerUrl}/unregister/{serverId}", "DELETE");
|
||||
request.timeout = 2;
|
||||
request.SendWebRequest();
|
||||
Debug.Log($"[MasterServer] Desenregistrement envoye ({serverId})");
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════
|
||||
// API PUBLIQUE
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
public void EnregistrerServeur(string nom, int port, int maxJoueurs,
|
||||
int langue, string mode, string version, bool motDePasse)
|
||||
{
|
||||
// v6.6 : memorise les parametres pour pouvoir re-register en cas de 404
|
||||
_dernierNom = nom;
|
||||
_dernierPort = port;
|
||||
_dernierMaxJoueurs = maxJoueurs;
|
||||
_derniereLangue = langue;
|
||||
_dernierMode = mode;
|
||||
_derniereVersion = version;
|
||||
_dernierMotDePasse = motDePasse;
|
||||
|
||||
StartCoroutine(Register(nom, port, maxJoueurs, langue, mode, version, motDePasse));
|
||||
}
|
||||
|
||||
public void DesenregistrerServeur()
|
||||
{
|
||||
if (estEnregistre && !string.IsNullOrEmpty(serverId))
|
||||
StartCoroutine(Unregister());
|
||||
}
|
||||
|
||||
public void RecupererServeurs(System.Action<List<ServerData>, string> callback)
|
||||
{
|
||||
StartCoroutine(FetchServers(callback));
|
||||
}
|
||||
|
||||
public void VerifierConnexion(System.Action<bool> callback)
|
||||
{
|
||||
StartCoroutine(CheckHealth(callback));
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════
|
||||
// COROUTINES HTTP
|
||||
// ══════════════════════════════════════════════════
|
||||
|
||||
private IEnumerator Register(string nom, int port, int maxJoueurs,
|
||||
int langue, string mode, string version, bool motDePasse)
|
||||
{
|
||||
requeteEnCours = true;
|
||||
dernierStatut = "Enregistrement...";
|
||||
|
||||
var body = new RegisterRequest
|
||||
{
|
||||
nom = nom,
|
||||
port = port,
|
||||
max_joueurs = maxJoueurs,
|
||||
langue = langue,
|
||||
mode = mode,
|
||||
version = version,
|
||||
mot_de_passe = motDePasse,
|
||||
token = token
|
||||
};
|
||||
|
||||
string json = JsonUtility.ToJson(body);
|
||||
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);
|
||||
|
||||
var request = new UnityWebRequest($"{masterServerUrl}/register", "POST");
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
request.timeout = 10;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
var response = JsonUtility.FromJson<RegisterResponse>(request.downloadHandler.text);
|
||||
serverId = response.server_id;
|
||||
estEnregistre = true;
|
||||
_echecsConsecutifs = 0;
|
||||
dernierStatut = $"Enregistre ({serverId})";
|
||||
Debug.Log($"[MasterServer] Serveur enregistre : {nom} → ID={serverId}");
|
||||
|
||||
// Demarrer le heartbeat (une seule coroutine active a la fois)
|
||||
if (_heartbeatCoroutine != null)
|
||||
StopCoroutine(_heartbeatCoroutine);
|
||||
_heartbeatCoroutine = StartCoroutine(HeartbeatLoop());
|
||||
}
|
||||
else
|
||||
{
|
||||
dernierStatut = $"Erreur enregistrement : {request.error}";
|
||||
Debug.LogWarning($"[MasterServer] Erreur register : {request.error} (code {request.responseCode})");
|
||||
}
|
||||
|
||||
requeteEnCours = false;
|
||||
request.Dispose();
|
||||
}
|
||||
|
||||
private IEnumerator Unregister()
|
||||
{
|
||||
requeteEnCours = true;
|
||||
dernierStatut = "Desenregistrement...";
|
||||
|
||||
if (_heartbeatCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_heartbeatCoroutine);
|
||||
_heartbeatCoroutine = null;
|
||||
}
|
||||
|
||||
var request = UnityWebRequest.Delete($"{masterServerUrl}/unregister/{serverId}");
|
||||
request.timeout = 5;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
Debug.Log($"[MasterServer] Serveur desenregistre : {serverId}");
|
||||
dernierStatut = "Serveur retire de la liste";
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[MasterServer] Erreur unregister : {request.error}");
|
||||
dernierStatut = "Erreur desenregistrement (le cleanup nettoiera)";
|
||||
}
|
||||
|
||||
estEnregistre = false;
|
||||
serverId = "";
|
||||
requeteEnCours = false;
|
||||
request.Dispose();
|
||||
}
|
||||
|
||||
private IEnumerator HeartbeatLoop()
|
||||
{
|
||||
while (estEnregistre && !string.IsNullOrEmpty(serverId))
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(heartbeatInterval);
|
||||
|
||||
if (!estEnregistre || string.IsNullOrEmpty(serverId))
|
||||
yield break;
|
||||
|
||||
int nbJoueurs = NetworkServer.active ? NetworkServer.connections.Count : 0;
|
||||
|
||||
var body = new HeartbeatRequest
|
||||
{
|
||||
joueurs = nbJoueurs,
|
||||
token = token
|
||||
};
|
||||
|
||||
string json = JsonUtility.ToJson(body);
|
||||
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);
|
||||
|
||||
var request = new UnityWebRequest(
|
||||
$"{masterServerUrl}/heartbeat/{serverId}", "PUT");
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
request.timeout = 10;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
// Reset du compteur d'echecs
|
||||
_echecsConsecutifs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_echecsConsecutifs++;
|
||||
long code = request.responseCode;
|
||||
string err = request.error;
|
||||
Debug.LogWarning($"[MasterServer] Heartbeat echoue ({_echecsConsecutifs}/{maxEchecsConsecutifs}) : HTTP {code} - {err}");
|
||||
|
||||
// v6.6 : si 404, le master server nous a purges → on re-register AUTOMATIQUEMENT
|
||||
// et IMMEDIATEMENT, sans attendre le prochain cycle de heartbeat
|
||||
if (code == 404)
|
||||
{
|
||||
Debug.Log("[MasterServer] Serveur inconnu (404), re-enregistrement automatique...");
|
||||
request.Dispose();
|
||||
|
||||
// Reset de l'etat
|
||||
estEnregistre = false;
|
||||
string ancienId = serverId;
|
||||
serverId = "";
|
||||
|
||||
// Relance Register() avec les parametres memorises
|
||||
yield return StartCoroutine(Register(
|
||||
_dernierNom, _dernierPort, _dernierMaxJoueurs,
|
||||
_derniereLangue, _dernierMode, _derniereVersion, _dernierMotDePasse
|
||||
));
|
||||
|
||||
if (estEnregistre)
|
||||
{
|
||||
Debug.Log($"[MasterServer] Re-enregistrement OK : {ancienId} → {serverId}");
|
||||
// Le HeartbeatLoop continue, mais on vient de demarrer un nouveau via Register.
|
||||
// On sort de cette boucle pour eviter d'en avoir deux en parallele.
|
||||
yield break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[MasterServer] Re-enregistrement echoue, abandon du heartbeat");
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apres trop d'echecs consecutifs (pas 404 mais reseau/timeout/etc), abandon
|
||||
if (_echecsConsecutifs >= maxEchecsConsecutifs)
|
||||
{
|
||||
Debug.LogError($"[MasterServer] Abandon du heartbeat apres {maxEchecsConsecutifs} echecs consecutifs");
|
||||
estEnregistre = false;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
request.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator FetchServers(System.Action<List<ServerData>, string> callback)
|
||||
{
|
||||
requeteEnCours = true;
|
||||
dernierStatut = "Recherche de serveurs...";
|
||||
|
||||
float startTime = Time.realtimeSinceStartup;
|
||||
|
||||
var request = UnityWebRequest.Get($"{masterServerUrl}/servers");
|
||||
request.timeout = 10;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
int pingMs = Mathf.RoundToInt((Time.realtimeSinceStartup - startTime) * 1000f);
|
||||
|
||||
if (request.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
string responseText = request.downloadHandler.text;
|
||||
string wrapped = "{\"servers\":" + responseText + "}";
|
||||
var wrapper = JsonUtility.FromJson<ServerListWrapper>(wrapped);
|
||||
|
||||
derniereListeServeurs = wrapper.servers ?? new List<ServerData>();
|
||||
|
||||
foreach (var srv in derniereListeServeurs)
|
||||
srv.ping = pingMs;
|
||||
|
||||
dernierStatut = $"{derniereListeServeurs.Count} serveur(s) trouve(s)";
|
||||
Debug.Log($"[MasterServer] {derniereListeServeurs.Count} serveurs recuperes (ping={pingMs}ms)");
|
||||
|
||||
callback?.Invoke(derniereListeServeurs, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
string erreur = $"Erreur : {request.error}";
|
||||
dernierStatut = erreur;
|
||||
Debug.LogWarning($"[MasterServer] Erreur fetch : {request.error}");
|
||||
callback?.Invoke(new List<ServerData>(), erreur);
|
||||
}
|
||||
|
||||
requeteEnCours = false;
|
||||
request.Dispose();
|
||||
}
|
||||
|
||||
private IEnumerator CheckHealth(System.Action<bool> callback)
|
||||
{
|
||||
var request = UnityWebRequest.Get($"{masterServerUrl}/health");
|
||||
request.timeout = 5;
|
||||
|
||||
yield return request.SendWebRequest();
|
||||
|
||||
bool ok = request.result == UnityWebRequest.Result.Success;
|
||||
callback?.Invoke(ok);
|
||||
request.Dispose();
|
||||
}
|
||||
}
|
||||
47
README_PATCHES_V2.md
Normal file
47
README_PATCHES_V2.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Patches v2 - Correction des problèmes du premier déploiement
|
||||
|
||||
## Ce qui est dans ce ZIP
|
||||
|
||||
### Scripts modifiés (2)
|
||||
|
||||
- **`MasterServerClient.cs` v6.6**
|
||||
- Heartbeat passe de 30s → 10s par défaut
|
||||
- Sur 404, re-registration automatique IMMÉDIATE (mémoise les paramètres)
|
||||
- Compteur d'échecs consécutifs (abandon après 3)
|
||||
|
||||
- **`DebugFalling.cs`**
|
||||
- Marqué `IClientOnly` → détruit au boot serveur, zéro log parasite
|
||||
|
||||
## Actions manuelles dans Unity (à faire AVANT de rebuild)
|
||||
|
||||
### 1. Remplacer les 2 scripts
|
||||
Copie les 2 `.cs` dans `Assets/Scripts/`, écrase les fichiers existants.
|
||||
|
||||
### 2. Assigner le catalogue à BoutiqueReseau (Inspector)
|
||||
|
||||
Dans la scène `Datacenter_01` :
|
||||
1. Sélectionne le GameObject qui porte le composant `BoutiqueReseau` (probablement sur le même GameObject que le `NetworkManager` ou sur un "Managers")
|
||||
2. Dans l'Inspector, déplie le composant `BoutiqueReseau`
|
||||
3. Champ **Catalogue** → clique sur le petit triangle pour déplier, mets la taille à X
|
||||
4. Glisse-dépose tes `ArticleCatalogue` ScriptableObjects depuis le Project Window vers les slots
|
||||
5. Sauvegarde la scène (Ctrl+S)
|
||||
|
||||
💡 **Pour retrouver tes articles plus rapidement** : sélectionne l'objet qui porte `UIBoutique` actuellement et regarde son champ `catalogue`, tu dois y voir tous les ScriptableObjects. Note-les ou fais un drag multi-sélection.
|
||||
|
||||
### 3. Rebuild
|
||||
|
||||
Build settings → Linux Dedicated Server → Build → déploie sur la Debian.
|
||||
|
||||
## Effet attendu
|
||||
|
||||
Après ces patches, plus de :
|
||||
- ❌ `[MasterServer] Heartbeat échoué : HTTP/1.1 404 Not Found`
|
||||
→ Résolu par re-registration automatique + intervalle réduit à 10s
|
||||
|
||||
- ❌ `[BoutiqueReseau] Article introuvable : Baie 42U`
|
||||
→ Résolu par l'assignation directe du catalogue dans l'Inspector
|
||||
|
||||
- ❌ Spam de logs `[DebugFall] ...`
|
||||
→ Résolu par le marqueur IClientOnly
|
||||
|
||||
Logs serveur propres = monitoring plus efficace.
|
||||
Loading…
x
Reference in New Issue
Block a user