fix: load lobby characters from config
This commit is contained in:
@@ -70,6 +70,12 @@ namespace XGame
|
||||
|
||||
return GetDefault();
|
||||
}
|
||||
|
||||
public string GetPrefabPath(int figure)
|
||||
{
|
||||
CharacterConfigItem item = GetByFigure(figure);
|
||||
return item == null ? null : item.prefabPath;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -29,18 +29,8 @@ namespace XGame
|
||||
public bool IsPlaceholder; // Obj 当前是胶囊占位(真实角色预设还在异步加载),加载完成后会原地升级
|
||||
}
|
||||
|
||||
private static readonly string[] ActorPaths =
|
||||
{
|
||||
"Game/Art/Actor/Prefab/Assasin.prefab",
|
||||
"Game/Art/Actor/Prefab/bls.prefab",
|
||||
"Game/Art/Actor/Prefab/boy.prefab",
|
||||
"Game/Art/Actor/Prefab/captain.prefab",
|
||||
"Game/Art/Actor/Prefab/habit.prefab",
|
||||
"Game/Art/Actor/Prefab/rhino.prefab",
|
||||
"Game/Art/Actor/Prefab/tiger.prefab",
|
||||
};
|
||||
|
||||
private const string JoystickPrefabPath = "Assets/Game/Art/UI/Prefab/UI_LobbyJoystick.prefab";
|
||||
private const string CharacterConfigResourcePath = "Config/CharacterConfig";
|
||||
private const string SelectedCharacterKey = "CharacterSwitch.SelectedCharacterId";
|
||||
private const float MoveSpeed = 1f;
|
||||
private const float StopDistance = 0.05f;
|
||||
@@ -68,6 +58,7 @@ namespace XGame
|
||||
private readonly Dictionary<int, GameObject> prefabCache = new Dictionary<int, GameObject>();
|
||||
private readonly HashSet<int> prefabLoading = new HashSet<int>();
|
||||
private Action<FrameworkOpcode, byte[]> send;
|
||||
private CharacterConfigData characterConfig;
|
||||
private Transform worldRoot;
|
||||
private int selfPlayerId;
|
||||
private int selfFigure;
|
||||
@@ -103,12 +94,25 @@ namespace XGame
|
||||
send = sendFramework;
|
||||
selfPlayerId = playerId;
|
||||
selfName = string.IsNullOrEmpty(playerName) ? "P" + playerId : playerName;
|
||||
selfFigure = Mathf.Clamp(figure <= 0 ? GetSelectedFigure() : figure, 1, ActorPaths.Length);
|
||||
if (!EnsureCharacterConfig())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
selfFigure = figure <= 0 ? GetSelectedFigure() : ResolveFigure(figure);
|
||||
if (selfFigure <= 0)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] cannot initialize without a valid character figure.");
|
||||
return;
|
||||
}
|
||||
EnsureWorldRoot();
|
||||
worldRoot.gameObject.SetActive(true);
|
||||
EnsureCamera();
|
||||
StartCoroutine(EnsureJoystickUIAsync());
|
||||
GetOrCreateAvatar(selfPlayerId, selfFigure, selfName);
|
||||
if (GetOrCreateAvatar(selfPlayerId, selfFigure, selfName) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
receivedSelfState = false;
|
||||
lastMoveDirection = Vector3.zero;
|
||||
nextMoveCommandTime = 0f;
|
||||
@@ -151,7 +155,12 @@ namespace XGame
|
||||
|
||||
public void RefreshSelectedFigure()
|
||||
{
|
||||
int nextFigure = Mathf.Clamp(GetSelectedFigure(), 1, ActorPaths.Length);
|
||||
int nextFigure = GetSelectedFigure();
|
||||
if (nextFigure <= 0)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] cannot refresh the selected figure because the character catalog is unavailable.");
|
||||
return;
|
||||
}
|
||||
if (selfFigure == nextFigure)
|
||||
{
|
||||
return;
|
||||
@@ -174,6 +183,10 @@ namespace XGame
|
||||
}
|
||||
|
||||
Avatar nextAvatar = GetOrCreateAvatar(selfPlayerId, selfFigure, selfName);
|
||||
if (nextAvatar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (hadAvatar && nextAvatar.Obj != null)
|
||||
{
|
||||
nextAvatar.Obj.transform.position = position;
|
||||
@@ -214,6 +227,10 @@ namespace XGame
|
||||
{
|
||||
seen.Add(player.PlayerId);
|
||||
Avatar avatar = GetOrCreateAvatar(player.PlayerId, player.Figure, player.Name);
|
||||
if (avatar == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3 pos = new Vector3(player.X, player.Y, player.Z);
|
||||
if (player.PlayerId == selfPlayerId)
|
||||
{
|
||||
@@ -330,6 +347,10 @@ namespace XGame
|
||||
{
|
||||
avatar = GetOrCreateAvatar(move.PlayerId, 1, "P" + move.PlayerId);
|
||||
}
|
||||
if (avatar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 target = new Vector3(move.X, move.Y, move.Z);
|
||||
if (!avatar.HasServerPosition && avatar.Obj != null)
|
||||
{
|
||||
@@ -511,7 +532,12 @@ namespace XGame
|
||||
|
||||
private Avatar GetOrCreateAvatar(int playerId, int figure, string name)
|
||||
{
|
||||
figure = Mathf.Clamp(figure <= 0 ? 1 : figure, 1, ActorPaths.Length);
|
||||
figure = ResolveFigure(figure);
|
||||
if (figure <= 0)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] cannot resolve figure because the character catalog is unavailable.");
|
||||
return null;
|
||||
}
|
||||
if (avatars.TryGetValue(playerId, out Avatar avatar))
|
||||
{
|
||||
if (avatar.Figure == figure)
|
||||
@@ -594,8 +620,16 @@ namespace XGame
|
||||
|
||||
private IEnumerator CoLoadActorPrefab(int figure)
|
||||
{
|
||||
string prefabPath = GetPrefabPath(figure);
|
||||
if (string.IsNullOrEmpty(prefabPath))
|
||||
{
|
||||
prefabLoading.Remove(figure);
|
||||
Debug.LogError("[LobbyWorldController] missing prefab path for figure=" + figure);
|
||||
yield break;
|
||||
}
|
||||
|
||||
UObject loaded = null;
|
||||
yield return XResLoader.coLoadRes(ActorPaths[figure - 1], typeof(GameObject), o => loaded = o);
|
||||
yield return XResLoader.coLoadRes(prefabPath, typeof(GameObject), o => loaded = o);
|
||||
prefabLoading.Remove(figure);
|
||||
GameObject prefab = loaded as GameObject;
|
||||
if (prefab == null)
|
||||
@@ -1201,21 +1235,63 @@ namespace XGame
|
||||
return Vector2.Distance(screenPosition, center) <= radius * JoystickAcquireRadiusMultiplier;
|
||||
}
|
||||
|
||||
private static int GetSelectedFigure()
|
||||
private bool EnsureCharacterConfig()
|
||||
{
|
||||
string selected = PlayerPrefs.GetString(SelectedCharacterKey, string.Empty).ToLowerInvariant();
|
||||
for (int i = 0; i < ActorPaths.Length; i++)
|
||||
if (characterConfig != null)
|
||||
{
|
||||
string path = ActorPaths[i].ToLowerInvariant();
|
||||
int slash = path.LastIndexOf('/');
|
||||
int dot = path.LastIndexOf('.');
|
||||
string id = dot > slash ? path.Substring(slash + 1, dot - slash - 1) : path;
|
||||
if (id == selected)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
return characterConfig.GetDefault() != null;
|
||||
}
|
||||
return 1;
|
||||
|
||||
TextAsset asset = Resources.Load<TextAsset>(CharacterConfigResourcePath);
|
||||
if (asset == null)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] missing character config: Resources/" + CharacterConfigResourcePath + ".json");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
characterConfig = JsonUtility.FromJson<CharacterConfigData>(asset.text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] parse character config failed: " + ex.Message);
|
||||
characterConfig = null;
|
||||
}
|
||||
|
||||
if (characterConfig == null || characterConfig.GetDefault() == null)
|
||||
{
|
||||
Debug.LogError("[LobbyWorldController] character config is empty or invalid.");
|
||||
characterConfig = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private int ResolveFigure(int figure)
|
||||
{
|
||||
if (!EnsureCharacterConfig())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return characterConfig.GetFigure(characterConfig.GetByFigure(figure));
|
||||
}
|
||||
|
||||
private int GetSelectedFigure()
|
||||
{
|
||||
if (!EnsureCharacterConfig())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return characterConfig.GetFigure(PlayerPrefs.GetString(SelectedCharacterKey, string.Empty));
|
||||
}
|
||||
|
||||
private string GetPrefabPath(int figure)
|
||||
{
|
||||
return EnsureCharacterConfig() ? characterConfig.GetPrefabPath(figure) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user