Commit 4f20c828 authored by Senator John's avatar Senator John 💬

Merge branch 'patch' into 'master'

Patch

See merge request !30
parents 6cb91510 d94a1ad4
......@@ -96,6 +96,10 @@ namespace MDPro3.Duel
&& File.Exists(Program.PATH_DECK + deckName + Program.EXPANSION_YDK))
deck = new Deck(Program.PATH_DECK + deckName + Program.EXPANSION_YDK);
var hasSide0Appearance = RoomServant.TryGetOnlineAppearanceForSide(0, out var side0Appearance);
var hasSide1Appearance = RoomServant.TryGetOnlineAppearanceForSide(1, out var side1Appearance);
var overrideDeckAppearance = Config.GetBool("OverrideDeckAppearance", false);
UIManager.UIBlackIn(Core.TransitionTime);
await UniTask.WaitForSeconds(Core.TransitionTime);
await UniTask.WaitUntil(() => Appearance.loaded);
......@@ -142,16 +146,21 @@ namespace MDPro3.Duel
var path = Program.items.GetAssetPath(
Config.Get(condition.ToString() + "Field0",
Program.items.mats[0].id.ToString()), Items.ItemType.Mat);
if (deck != null && !Config.GetBool("OverrideDeckAppearance", false))
if (condition == Condition.Watch && hasSide0Appearance)
path = Program.items.GetAssetPath(side0Appearance.Field.ToString(), Items.ItemType.Mat);
else if (deck != null && !overrideDeckAppearance)
path = Program.items.GetAssetPath(deck.Field.ToString(), Items.ItemType.Mat);
path = "MasterDuel/" + path;
var field0 = await ABLoader.LoadFromFileAsync(path + "_near", false, true);
field0.transform.SetParent(Program.instance.container_3D, false);
field0Manager = field0.GetComponent<BgEffectManager>();
var field1Config = Config.Get(condition.ToString() + "Field1",
Program.items.mats[0].id.ToString());
if (hasSide1Appearance)
field1Config = side1Appearance.Field.ToString();
var field1 = await ABLoader.LoadFromFileAsync("MasterDuel/" +
Program.items.GetAssetPath(Config.Get(condition.ToString() + "Field1",
Program.items.mats[0].id.ToString()), Items.ItemType.Mat, 1) + "_far"
Program.items.GetAssetPath(field1Config, Items.ItemType.Mat, 1) + "_far"
, false, true);
field1.transform.SetParent(Program.instance.container_3D, false);
field1Manager = field1.GetComponent<BgEffectManager>();
......@@ -180,7 +189,9 @@ namespace MDPro3.Duel
path = Program.items.GetAssetPath(
Config.Get(condition.ToString() + "Grave0",
Program.items.graves[0].id.ToString()), Items.ItemType.Grave);
if (deck != null && !Config.GetBool("OverrideDeckAppearance", false))
if (condition == Condition.Watch && hasSide0Appearance)
path = Program.items.GetAssetPath(side0Appearance.Grave.ToString(), Items.ItemType.Grave);
else if (deck != null && !overrideDeckAppearance)
path = Program.items.GetAssetPath(deck.Grave.ToString(), Items.ItemType.Grave);
path = "MasterDuel/" + path;
......@@ -188,9 +199,12 @@ namespace MDPro3.Duel
grave0.transform.SetParent(pos_Grave_near, false);
grave0Manager = grave0.GetComponent<BgEffectManager>();
var grave1Config = Config.Get(condition.ToString() + "Grave1",
Program.items.graves[0].id.ToString());
if (hasSide1Appearance)
grave1Config = side1Appearance.Grave.ToString();
var grave1 = await ABLoader.LoadFromFileAsync("MasterDuel/" +
Program.items.GetAssetPath(Config.Get(condition.ToString() + "Grave1",
Program.items.graves[0].id.ToString()), Items.ItemType.Grave, 1) + "_far"
Program.items.GetAssetPath(grave1Config, Items.ItemType.Grave, 1) + "_far"
, false, true);
grave1.transform.SetParent(pos_Grave_far, false);
grave1Manager = grave1.GetComponent<BgEffectManager>();
......@@ -211,10 +225,12 @@ namespace MDPro3.Duel
#region Stand
var standConfig = Config.Get(condition.ToString() + "Stand0", Program.items.stands[0].id.ToString());
if (condition == Condition.Watch && hasSide0Appearance)
standConfig = side0Appearance.Stand.ToString();
if (standConfig != Items.CODE_NONE.ToString() || deck != null)
{
path = Program.items.GetAssetPath(standConfig, Items.ItemType.Stand);
if (deck != null && !Config.GetBool("OverrideDeckAppearance", false))
if (deck != null && !overrideDeckAppearance)
path = Program.items.GetAssetPath(deck.Stand.ToString(), Items.ItemType.Stand);
path = "MasterDuel/" + path;
var stand0 = await ABLoader.LoadFromFileAsync(path + "_near", false, true);
......@@ -226,6 +242,8 @@ namespace MDPro3.Duel
}
standConfig = Config.Get(condition.ToString() + "Stand1", Program.items.stands[0].id.ToString());
if (hasSide1Appearance)
standConfig = side1Appearance.Stand.ToString();
if (standConfig != Items.CODE_NONE.ToString())
{
var stand1 = await ABLoader.LoadFromFileAsync("MasterDuel/" +
......@@ -243,27 +261,25 @@ namespace MDPro3.Duel
#region Mate
var mateConfig = Config.Get(condition.ToString() + "Mate0", Program.items.mates[0].id.ToString());
var overrideDeckAppearance = Config.GetBool("OverrideDeckAppearance", false);
var mateConfigIsNone = mateConfig == Items.CODE_NONE.ToString();
if (!mateConfigIsNone || (deck != null && !overrideDeckAppearance))
{
int mateCode = int.Parse(mateConfig);
if (deck != null && !overrideDeckAppearance && !mateConfigIsNone)
mateCode = deck.Mate;
if (mateCode != Items.CODE_NONE)
if (condition == Condition.Watch && hasSide0Appearance)
mateConfig = side0Appearance.Mate.ToString();
int mateCode = int.Parse(mateConfig);
if (deck != null && !overrideDeckAppearance)
mateCode = deck.Mate;
if (mateCode != Items.CODE_NONE)
{
var mate = await ABLoader.LoadMateAsync(mateCode);
if (mate != null)
{
var mate = await ABLoader.LoadMateAsync(mateCode);
if (mate != null)
{
mate0 = mate;
mate0.parent = pos_Avatar_near;
mate0.gameObject.SetActive(false);
}
mate0 = mate;
mate0.parent = pos_Avatar_near;
mate0.gameObject.SetActive(false);
}
}
mateConfig = Config.Get(condition.ToString() + "Mate1", Program.items.mates[0].id.ToString());
if (hasSide1Appearance)
mateConfig = side1Appearance.Mate.ToString();
if (mateConfig != Items.CODE_NONE.ToString())
{
var mate = await ABLoader.LoadMateAsync(int.Parse(mateConfig));
......@@ -343,20 +359,44 @@ namespace MDPro3.Duel
#region Deck Model
var deckMat = Appearance.duelProtector0;
if (deck != null && !Config.GetBool("OverrideDeckAppearance", false))
if (deck != null && !overrideDeckAppearance)
deckMat = await ABLoader.LoadProtectorMaterial(deck.Protector.ToString(), Application.exitCancellationToken);
if (condition == Condition.Duel)
myProtector = deckMat;
else if (condition == Condition.Watch)
{
myProtector = Appearance.watchProtector0;
if (hasSide0Appearance)
{
var mat = await ABLoader.LoadProtectorMaterial(side0Appearance.Protector.ToString(), Application.exitCancellationToken);
if (mat != null)
myProtector = mat;
}
}
else if (condition == Condition.Replay)
myProtector = Appearance.replayProtector0;
if (condition == Condition.Duel)
{
opProtector = Appearance.duelProtector1;
if (hasSide1Appearance)
{
var mat = await ABLoader.LoadProtectorMaterial(side1Appearance.Protector.ToString(), Application.exitCancellationToken);
if (mat != null)
opProtector = mat;
}
}
else if (condition == Condition.Watch)
{
opProtector = Appearance.watchProtector1;
if (hasSide1Appearance)
{
var mat = await ABLoader.LoadProtectorMaterial(side1Appearance.Protector.ToString(), Application.exitCancellationToken);
if (mat != null)
opProtector = mat;
}
}
else if (condition == Condition.Replay)
opProtector = Appearance.replayProtector1;
......
......@@ -523,15 +523,14 @@ namespace MDPro3
handsCount = Program.instance.ocgcore.GetOpHandCount();
float x = p.sequence * 4 - (handsCount - 1) * 2;
if (p.controller == 0)
{
var z = -28 + (30 - Program.instance.camera_.cameraMain.fieldOfView) * 0.7f;
var z = GetMyHandBaseZ();
return new Vector3(x + handOffset * UIManager.ScreenLengthWithoutScalerX(0.038f), 15, z);
}
else
{
var z = 17 - (30 - Program.instance.camera_.cameraMain.fieldOfView) * 0.7f;
var z = GetOpHandBaseZ();
return new Vector3(-x, 15, z);
}
}
......@@ -713,6 +712,35 @@ namespace MDPro3
return returnValue;
}
private static float GetMyHandBaseZ()
{
return -28f + GetHandDepthOffsetByFov();
}
private static float GetOpHandBaseZ()
{
return 17f - GetHandDepthOffsetByFov();
}
private static float GetHandDepthOffsetByFov()
{
var camera = Program.instance?.camera_?.cameraMain;
if (camera == null)
return 0f;
var fovDelta = Mathf.Clamp(30f - camera.fieldOfView, 0f, 6f);
var fovCompensation = fovDelta * 0.7f;
// After widening duel camera framing, retract hand outward on ultrawide displays.
var aspect = Tools.GetScreenAspectRatio();
var ultraWide21x9T = Mathf.InverseLerp(16f / 9f, 21f / 9f, aspect);
var ultraWide32x9T = Mathf.InverseLerp(21f / 9f, 32f / 9f, aspect);
// Strong ultrawide push so hand cards sit lower while keeping a little more text visible.
var ultraWideOutward = Mathf.Lerp(0f, 1.60f, ultraWide21x9T) + Mathf.Lerp(0f, 1.10f, ultraWide32x9T);
return fovCompensation - ultraWideOutward;
}
public static Vector3 GetCardRotation(GPS p, int code = 0)
{
var condition = CardRuleCondition.MeUpAtk;
......@@ -1915,9 +1943,9 @@ namespace MDPro3
var targetPosition = GetCardPosition(p, this);
var x = targetPosition.x;
if (HideMyHandCard && p.InMyControl())
targetPosition.z = -28f;
targetPosition.z = GetMyHandBaseZ();
if (HideOpHandCard && !p.InMyControl())
targetPosition.z = 17f;
targetPosition.z = GetOpHandBaseZ();
model.transform.DOLocalMove(targetPosition, time);
}
......
This diff is collapsed.
fileFormatVersion: 2
guid: 2cbd8637a7f820c4caacc6106ddc0dbb
\ No newline at end of file
......@@ -270,6 +270,8 @@ namespace MDPro3
}
onDisConnected = false;
tcpClient = null;
deck = null;
deckStrings.Clear();
canJoin = true;
if (Program.instance.ocgcore.showing)
{
......@@ -375,6 +377,7 @@ namespace MDPro3
for (var i = 0; i < deckFor.Extra.Count; i++) message.Data.writer.Write(deckFor.Extra[i]);
for (var i = 0; i < deckFor.Side.Count; i++) message.Data.writer.Write(deckFor.Side[i]);
Send(message);
CtosMessage_UpdateAppearance(deckFor);
}
public static void CtosMessage_HandResult(int res)
......@@ -420,6 +423,7 @@ namespace MDPro3
public static void CtosMessage_JoinGame(string psw)
{
deckStrings.Clear();
deck = null;
var message = new Package();
message.Function = (int)CtosMessage.JoinGame;
message.Data.writer.Write((short)Config.ClientVersion);
......@@ -432,6 +436,8 @@ namespace MDPro3
public static void CtosMessage_LeaveGame()
{
deck = null;
deckStrings.Clear();
var message = new Package();
message.Function = (int)CtosMessage.LeaveGame;
Send(message);
......@@ -459,6 +465,30 @@ namespace MDPro3
Send(message);
}
public static void CtosMessage_UpdateAppearance(Deck deckFor)
{
if (deckFor == null)
return;
var syncMessage = OnlineAppearanceSync.BuildMessageForLocalPlayer(deckFor);
CtosMessage_Chat(syncMessage);
Debug.Log($"[OnlineAppearance] Sent sync payload: {syncMessage}");
}
public static void CtosMessage_UpdateAppearanceFromCurrentDeck()
{
if (deck != null)
{
CtosMessage_UpdateAppearance(deck);
return;
}
var deckPath = Program.PATH_DECK + Config.GetConfigDeckName() + Program.EXPANSION_YDK;
if (!File.Exists(deckPath))
return;
CtosMessage_UpdateAppearance(new Deck(deckPath));
}
public static void CtosMessage_HsToDuelist()
{
var message = new Package();
......
......@@ -56,16 +56,28 @@ namespace MDPro3
public static void ChangeCameraFOV()
{
float aspect = (float)Screen.width * 9 / Screen.height;
if (aspect > 16)
{
Program.instance.camera_.cameraMain.fieldOfView = 30 + 16 - aspect;
Program.instance.camera_.cameraDuelOverlay3D.fieldOfView = Program.instance.camera_.cameraMain.fieldOfView;
}
else
var camera = Program.instance.camera_;
if (camera == null || camera.cameraMain == null || camera.cameraDuelOverlay3D == null)
return;
var aspect = Tools.GetScreenAspectRatio();
var ultraWideT = Mathf.InverseLerp(16f / 9f, 32f / 9f, aspect);
// Keep 16:9 unchanged while widening ultrawide framing to match MD-style composition.
var duelFov = Mathf.Lerp(30f, 33f, ultraWideT);
camera.cameraMain.fieldOfView = duelFov;
camera.cameraDuelOverlay3D.fieldOfView = duelFov;
mainCameraDefaultPosition = new Vector3(
0f,
95f + Mathf.Lerp(0f, 4f, ultraWideT),
-37f - Mathf.Lerp(0f, 5f, ultraWideT));
if (Program.instance.ocgcore != null && Program.instance.ocgcore.showing)
{
Program.instance.camera_.cameraMain.fieldOfView = 30;
Program.instance.camera_.cameraDuelOverlay3D.fieldOfView = 30;
camera.cameraMain.transform.localPosition = mainCameraDefaultPosition;
if (!overlaySticking)
camera.cameraDuelOverlay3D.transform.localPosition = mainCameraDefaultPosition;
}
}
......@@ -89,7 +101,7 @@ namespace MDPro3
public static void Overlay3DReset()
{
Program.instance.camera_.cameraDuelOverlay3D.transform.localPosition = new Vector3(0, 95, -37);
Program.instance.camera_.cameraDuelOverlay3D.transform.localPosition = mainCameraDefaultPosition;
Program.instance.camera_.cameraDuelOverlay3D.transform.localEulerAngles = new Vector3(70, 0, 0);
}
......
......@@ -1498,6 +1498,8 @@ namespace MDPro3.Servant
GetUI<OcgCoreUI>().AvatarPlayer1.material = Appearance.duelFrameMat1Tag;
SetFaceWhenCharaOff(Appearance.duelFace1Tag, 1);
}
_ = ApplyOnlineOpponentFaceAsync();
}
else if (condition == Condition.Watch)
{
......@@ -1549,6 +1551,49 @@ namespace MDPro3.Servant
_ = SetMyCardFace();
}
private async UniTask ApplyOnlineOpponentFaceAsync()
{
if (condition != Condition.Duel)
return;
var useTagOpponent = isTag && GetUI<OcgCoreUI>().TextPlayer1Name.text != name_1;
if (!RoomServant.TryGetOnlineAppearanceForOpponent(useTagOpponent, out var appearance))
{
if (!useTagOpponent || !RoomServant.TryGetOnlineAppearanceForOpponent(false, out appearance))
return;
}
var iconPlayer = useTagOpponent ? 3 : 1;
var frameCode = appearance.Frame.ToString();
var frameSprite = await Program.items.LoadConcreteItemIconAsync(frameCode, Items.ItemType.Frame, iconPlayer);
Material frameMaterial;
if (appearance.Frame == Items.CODE_DIY)
frameMaterial = Appearance.matForFace == null ? null : new Material(Appearance.matForFace);
else
frameMaterial = await ABLoader.LoadFrameMaterial(frameCode);
if (frameMaterial != null && frameSprite != null)
frameMaterial.SetTexture("_ProfileFrameTex", frameSprite.texture);
var faceSprite = await Program.items.LoadConcreteItemIconAsync(appearance.Face.ToString(), Items.ItemType.Face, iconPlayer);
var latestUseTagOpponent = isTag && GetUI<OcgCoreUI>().TextPlayer1Name.text != name_1;
if (latestUseTagOpponent != useTagOpponent)
return;
if (!RoomServant.TryGetOnlineAppearanceForOpponent(useTagOpponent, out var latest))
{
if (!useTagOpponent || !RoomServant.TryGetOnlineAppearanceForOpponent(false, out latest))
return;
}
if (latest.Face != appearance.Face || latest.Frame != appearance.Frame)
return;
if (frameMaterial != null)
GetUI<OcgCoreUI>().AvatarPlayer1.material = frameMaterial;
if (faceSprite != null)
SetFaceWhenCharaOff(faceSprite, 1);
}
private async UniTask SetMyCardFace()
{
if (MyCard.account == null || !mycardDuel)
......
......@@ -47,6 +47,7 @@ namespace MDPro3.Servant
public bool ready;
}
public static Player[] players = new Player[32];
private static readonly Dictionary<int, OnlineAppearanceData> onlineAppearances = new();
private Deck deck;
......@@ -88,6 +89,7 @@ namespace MDPro3.Servant
if (FromLocalHost)
YgoServer.StopServer();
}
onlineAppearances.Clear();
base.OnExit();
Program.instance.ocgcore.CloseConnection();
}
......@@ -136,6 +138,77 @@ namespace MDPro3.Servant
return true;
}
public static bool TryGetOnlineAppearanceForSide(int side, out OnlineAppearanceData appearance)
{
appearance = default;
if (!TryGetTeamPlayer(side, false, out var player))
return false;
return onlineAppearances.TryGetValue(player, out appearance);
}
public static bool TryGetOnlineAppearanceForOpponent(bool tag, out OnlineAppearanceData appearance)
{
appearance = default;
if (!TryGetTeamPlayer(1, tag, out var player))
return false;
return onlineAppearances.TryGetValue(player, out appearance);
}
public static bool TryGetOnlineAppearanceForPlayer(int player, out OnlineAppearanceData appearance)
{
appearance = default;
if (player < 0 || player >= 4)
return false;
return onlineAppearances.TryGetValue(player, out appearance);
}
private static bool TryGetTeamPlayer(int side, bool tag, out int player)
{
player = -1;
if (side != 0 && side != 1)
return false;
if (Mode != 2)
{
if (tag)
return false;
if (SelfType == 7)
player = side;
else
player = side == 0 ? SelfType : 1 - SelfType;
return player >= 0 && player < 4;
}
var hostTeamAsSide0 = SelfType == 7 || SelfType < 2;
var useHostTeam = hostTeamAsSide0 ? side == 0 : side == 1;
if (useHostTeam)
player = tag ? 1 : 0;
else
player = tag ? 3 : 2;
return true;
}
private static void MoveOnlineAppearance(int from, int to)
{
if (onlineAppearances.TryGetValue(from, out var appearance))
{
onlineAppearances[to] = appearance;
onlineAppearances.Remove(from);
}
else
{
onlineAppearances.Remove(to);
}
}
private static void RemoveOnlineAppearance(int player)
{
onlineAppearances.Remove(player);
}
private void ShowOcgCore()
{
if(CoreShowing == 0)
......@@ -415,6 +488,7 @@ namespace MDPro3.Servant
for (int i = 0; i < 4; i++)
players[i] = null;
onlineAppearances.Clear();
if(!FromHandTest)
Program.instance.ShiftToServant(Program.instance.room);
......@@ -427,6 +501,8 @@ namespace MDPro3.Servant
IsHost = ((type >> 4) & 0xF) != 0;
if (SelfType < 4 && players[SelfType] != null)
players[SelfType].ready = false;
if (SelfType < 4)
TcpHelper.CtosMessage_UpdateAppearanceFromCurrentDeck();
Realize();
}
......@@ -469,8 +545,23 @@ namespace MDPro3.Servant
public void StocMessage_Chat(BinaryReader r)
{
int player = r.ReadInt16();
var length = r.BaseStream.Length - 3;
var length = (int)((r.BaseStream.Length - r.BaseStream.Position) / 2);
var content = r.ReadUnicode((int)length);
if (OnlineAppearanceSync.IsSyncMessage(content))
{
if (player >= 0 && player < 4 && OnlineAppearanceSync.TryParse(content, out var appearance))
{
onlineAppearances[player] = appearance;
if (showing)
Realize();
Debug.Log($"[OnlineAppearance] Received sync from seat {player}: {appearance.Case},{appearance.Protector},{appearance.Field},{appearance.Grave},{appearance.Stand},{appearance.Mate},{appearance.Face},{appearance.Frame}");
}
else
{
Debug.LogWarning($"[OnlineAppearance] Ignored sync chat. seat={player}, content='{content}'");
}
return;
}
//Debug.Log($"{player}: {content} {OcgCore.isFirst} {RoomServant.SelfType}");
Program.instance.ui_.chatPanel.AddChatItem(player, content);
}
......@@ -485,6 +576,9 @@ namespace MDPro3.Servant
player.name = name;
player.ready = false;
players[pos] = player;
RemoveOnlineAppearance(pos);
if (SelfType < 4 && players[SelfType] != null && pos != SelfType)
TcpHelper.CtosMessage_UpdateAppearanceFromCurrentDeck();
Realize();
}
......@@ -499,16 +593,21 @@ namespace MDPro3.Servant
{
players[state] = players[pos];
players[pos] = null;
MoveOnlineAppearance(pos, state);
}
if (state == 0x9)
players[pos].ready = true;
if (state == 0xA)
players[pos].ready = false;
if (state == 0xB)
{
players[pos] = null;
RemoveOnlineAppearance(pos);
}
if (state == 0x8)
{
players[pos] = null;
RemoveOnlineAppearance(pos);
ObserverCount++;
}
Realize();
......
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
......@@ -62,63 +63,82 @@ namespace MDPro3.UI
public void Refresh()
{
_ = RefreshAsync();
_ = RefreshAsync(this.GetCancellationTokenOnDestroy());
}
private async UniTask RefreshAsync()
private async UniTask RefreshAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < index; i++)
await UniTask.Yield();
if (path.StartsWith("Protector"))
{
protectorMaterial = await ABLoader.LoadProtectorMaterial(itemID.ToString(), destroyCancellationToken);
if (protectorMaterial != null)
protectorMaterial.renderQueue = 3000;
// Use default UI material for list rendering so viewport/mask clipping works while scrolling.
Protector.texture = protectorMaterial == null ? null : protectorMaterial.mainTexture;
Protector.material = null;
Protector.color = Color.white;
Icon.gameObject.SetActive(false);
}
else if (path.Length > 0)
try
{
Icon.sprite = await Program.items.LoadItemIconAsync(itemID.ToString(), Items.ItemType.Unknown);
if (Manager == null)
for (int i = 0; i < index; i++)
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
if (cancellationToken.IsCancellationRequested || this == null)
return;
Icon.color = Color.white;
if (path.StartsWith("ProfileFrame"))
if (path.StartsWith("Protector"))
{
Icon.rectTransform.localScale = Vector3.one * 0.8f;
Icon.material = await ABLoader.LoadFrameMaterial(itemID.ToString());
Icon.material.SetTexture("_ProfileFrameTex", Icon.sprite.texture);
Icon.sprite = TextureManager.container.black;
Icon.color = Color.white;
protectorMaterial = await ABLoader.LoadProtectorMaterial(itemID.ToString(), cancellationToken);
if (protectorMaterial != null)
protectorMaterial.renderQueue = 3000;
if (cancellationToken.IsCancellationRequested || this == null)
return;
// Use default UI material for list rendering so viewport/mask clipping works while scrolling.
Protector.texture = protectorMaterial == null ? null : protectorMaterial.mainTexture;
Protector.material = null;
Protector.color = Color.white;
Icon.gameObject.SetActive(false);
}
else if (path.StartsWith("DeckCase"))
else if (path.Length > 0)
{
Icon.transform.localPosition = new Vector3(0f, 15f, 0f);
Icon.sprite = await Program.items.LoadItemIconAsync(itemID.ToString(), Items.ItemType.Unknown);
if (cancellationToken.IsCancellationRequested || this == null || Manager == null)
return;
Icon.color = Color.white;
if (path.StartsWith("ProfileFrame"))
{
Icon.rectTransform.localScale = Vector3.one * 0.8f;
Icon.material = await ABLoader.LoadFrameMaterial(itemID.ToString());
if (cancellationToken.IsCancellationRequested || this == null)
return;
Icon.material.SetTexture("_ProfileFrameTex", Icon.sprite.texture);
Icon.sprite = TextureManager.container.black;
Icon.color = Color.white;
}
else if (path.StartsWith("DeckCase"))
{
Icon.transform.localPosition = new Vector3(0f, 15f, 0f);
}
else if (path.StartsWith("WallPaperIcon"))
{
WallpaperBG.gameObject.SetActive(true);
}
Protector.gameObject.SetActive(false);
}
else if (path.StartsWith("WallPaperIcon"))
else //CrossDuel Mate
{
WallpaperBG.gameObject.SetActive(true);
var art = await CardImageLoader.LoadArtAsync(itemID, true, cancellationToken);
if (cancellationToken.IsCancellationRequested || this == null)
return;
Icon.color = Color.white;
Icon.sprite = TextureManager.Texture2Sprite(art);
Protector.gameObject.SetActive(false);
}
Protector.gameObject.SetActive(false);
if (path.StartsWith("ProfileIcon") && !cancellationToken.IsCancellationRequested && this != null)
Icon.material = Appearance.matForFace;
loaded = true;
}
else //CrossDuel Mate
catch (OperationCanceledException)
{
var art = await CardImageLoader.LoadArtAsync(itemID, true, destroyCancellationToken);
Icon.color = Color.white;
Icon.sprite = TextureManager.Texture2Sprite(art);
Protector.gameObject.SetActive(false);
}
if (path.StartsWith("ProfileIcon"))
Icon.material = Appearance.matForFace;
loaded = true;
refreshCoroutine = null;
finally
{
refreshCoroutine = null;
}
}
protected override void CallHoverOnEvent()
......@@ -202,6 +222,14 @@ namespace MDPro3.UI
Config.Set("Wallpaper", itemID.ToString());
else
Config.Set(Appearance.condition.ToString() + AppearanceUI.currentContent + Appearance.player, itemID.ToString());
if (Appearance.condition == Appearance.Condition.Duel
&& Appearance.player == "0"
&& Config.GetBool("OverrideDeckAppearance", false)
&& Program.instance.room != null
&& Program.instance.room.showing
&& RoomServant.SelfType < 4)
TcpHelper.CtosMessage_UpdateAppearanceFromCurrentDeck();
}
StartCoroutine(ConfigSetAsync());
......
......@@ -3,8 +3,10 @@ using MDPro3.Servant;
using MDPro3.Utility;
using System.Collections.Generic;
using System.IO;
using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using static MDPro3.UI.ChatPanel;
namespace MDPro3.UI.ServantUI
......@@ -83,6 +85,10 @@ namespace MDPro3.UI.ServantUI
#endregion
private List<SelectionButton_RoomPlayer> roomPlayers;
private readonly Dictionary<int, Sprite> syncedFaces = new();
private readonly Dictionary<int, Material> syncedFrames = new();
private readonly Dictionary<int, int> syncedFaceIds = new();
private readonly Dictionary<int, int> syncedFrameIds = new();
private void Awake()
{
......@@ -197,6 +203,7 @@ namespace MDPro3.UI.ServantUI
roomPlayers[i].GetAvatar().sprite = Appearance.watchFace1Tag;
break;
}
TryApplyOnlineAvatar(i);
}
}
if (RoomServant.IsHost)
......@@ -285,5 +292,79 @@ namespace MDPro3.UI.ServantUI
Program.instance.ShiftToServant(Program.instance.deckSelector);
}
private void TryApplyOnlineAvatar(int player)
{
if (!RoomServant.TryGetOnlineAppearanceForPlayer(player, out var appearance))
return;
var iconPlayer = GetIconPlayerIndex(GetPlayerPosition(player));
if (syncedFaceIds.TryGetValue(player, out var cachedFaceId) &&
syncedFrameIds.TryGetValue(player, out var cachedFrameId) &&
cachedFaceId == appearance.Face &&
cachedFrameId == appearance.Frame &&
syncedFaces.TryGetValue(player, out var cachedFace) &&
syncedFrames.TryGetValue(player, out var cachedFrame) &&
cachedFace != null &&
cachedFrame != null)
{
roomPlayers[player].GetAvatar().sprite = cachedFace;
roomPlayers[player].GetAvatar().material = cachedFrame;
return;
}
_ = ApplyOnlineAvatarAsync(player, appearance, iconPlayer);
}
private async UniTask ApplyOnlineAvatarAsync(int player, OnlineAppearanceData appearance, int iconPlayer)
{
var frameCode = appearance.Frame.ToString();
var frameSprite = await Program.items.LoadConcreteItemIconAsync(frameCode, Items.ItemType.Frame, iconPlayer);
Material frameMaterial;
if (appearance.Frame == Items.CODE_DIY)
frameMaterial = Appearance.matForFace == null ? null : new Material(Appearance.matForFace);
else
frameMaterial = await ABLoader.LoadFrameMaterial(frameCode);
if (frameMaterial != null && frameSprite != null)
frameMaterial.SetTexture("_ProfileFrameTex", frameSprite.texture);
var faceSprite = await Program.items.LoadConcreteItemIconAsync(appearance.Face.ToString(), Items.ItemType.Face, iconPlayer);
if (!RoomServant.TryGetOnlineAppearanceForPlayer(player, out var latest))
return;
if (latest.Face != appearance.Face || latest.Frame != appearance.Frame)
return;
if (player < 0 || player >= roomPlayers.Count)
return;
if (!roomPlayers[player].gameObject.activeInHierarchy)
return;
if (frameMaterial != null)
roomPlayers[player].GetAvatar().material = frameMaterial;
if (faceSprite != null)
roomPlayers[player].GetAvatar().sprite = faceSprite;
syncedFaceIds[player] = appearance.Face;
syncedFrameIds[player] = appearance.Frame;
syncedFaces[player] = faceSprite;
syncedFrames[player] = frameMaterial;
}
private static int GetIconPlayerIndex(PlayerPosition position)
{
switch (position)
{
case PlayerPosition.Op:
case PlayerPosition.WatchOp:
return 1;
case PlayerPosition.MyTag:
case PlayerPosition.WatchMyTag:
return 2;
case PlayerPosition.OpTag:
case PlayerPosition.WatchOpTag:
return 3;
default:
return 0;
}
}
}
}
\ No newline at end of file
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment