using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Cute; using UnityEngine; using ZXing; using ZXing.QrCode; using ZXing.QrCode.Internal; namespace Wizard; public class QRCodeUtility { public struct DeckDataFromQRCode { public CardBasePrm.ClanType ClanId; public CardBasePrm.ClanType SubClanId; public int[] CardIds; public bool IsSubClassSet; public Format Format; public MyRotationInfo MyRotationInfo { get; } public DeckDataFromQRCode(Format format, CardBasePrm.ClanType clanId, CardBasePrm.ClanType subClanId, int[] cardIds, MyRotationInfo myRotationInfo) { ClanId = clanId; CardIds = cardIds; SubClanId = subClanId; IsSubClassSet = CardBasePrm.ClanTypeIsUseable(subClanId); Format = format; MyRotationInfo = myRotationInfo; } } public const int SIZE_SMALL = 207; public const int SIZE_BIG = 508; public const int BIGQRCODE_TEXTURE_WIDGIT_SIZE = 400; private const string NORMAL_URL_TAIL = "/deck/"; private const string CROSSOVER_URL_TAIL = "/deck_co/"; private const string MY_ROTATION_URL_TAIL = "/deck_my/"; public static DeckDataFromQRCode deckDataFromQRCode; public static Texture2D CreateQrCodeTexture(int width, int height, string content) { BarcodeWriter barcodeWriter = new BarcodeWriter { Format = BarcodeFormat.QR_CODE, Options = new QrCodeEncodingOptions { ErrorCorrection = ErrorCorrectionLevel.L, Width = width, Height = height } }; Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, mipChain: false); Color32[] pixels = barcodeWriter.Write(content); texture2D.SetPixels32(pixels); texture2D.Apply(); return texture2D; } private static string GetAppendUrlFromDeckType(IFormatBehavior formatBehavior, Format format) { if (formatBehavior.UseSubClass) { return "/deck_co/"; } if (format == Format.MyRotation) { return "/deck_my/"; } return "/deck/"; } public static string GenerateQRCodeText(List deckList, CardBasePrm.ClanType? clanType, ClassSet classSet, IFormatBehavior formatBehavior, Format format, MyRotationInfo myRotationInfo) { bool useSubClass = formatBehavior.UseSubClass; StringBuilder tempStringBuilder = UIUtil.GetTempStringBuilder(); tempStringBuilder.Append("https://").Append("shadowverse-portal.com/api/v1/game_api/".Split('/')[0]); tempStringBuilder.Append(GetAppendUrlFromDeckType(formatBehavior, format)); tempStringBuilder.Append(((int)formatBehavior.DeckCodeType).ToString()).Append("."); string value; if (classSet == null) { value = ((int)clanType.Value).ToString(); } else { int mainClass = (int)classSet.MainClass; value = mainClass.ToString(); } tempStringBuilder.Append(value).Append("."); if (useSubClass) { int mainClass = (int)classSet.SubClass; tempStringBuilder.Append(mainClass.ToString()).Append("."); } if (format == Format.MyRotation) { tempStringBuilder.Append(myRotationInfo.Id).Append("."); } CardMaster instance = CardMaster.GetInstance(formatBehavior.CardMasterId); for (int i = 0; i < deckList.Count; i++) { int normalCardId = instance.GetCardParameterFromId(deckList[i]).NormalCardId; tempStringBuilder.Append(instance.GetCardParameterFromId(normalCardId).CardHashId); if (i != deckList.Count - 1) { tempStringBuilder.Append("."); } } tempStringBuilder.Append("?lang=").Append(GetLanguageCode()); return tempStringBuilder.ToString(); } public static string GetLanguageCode() { string result = ""; switch (CustomPreference.GetTextLanguage()) { case "Jpn": result = "ja"; break; case "Ger": result = "de"; break; case "Fre": result = "fr"; break; case "Ita": result = "it"; break; case "Cht": result = "zh-tw"; break; case "Kor": result = "ko"; break; case "Spa": result = "es"; break; case "Chs": case "Eng": result = "en"; break; } return result; } public static string DecodeContentText(WebCamTexture webCamTexture) { if (webCamTexture == null) { return string.Empty; } return DecodeContentText(webCamTexture.GetPixels32(), webCamTexture.width, webCamTexture.height, isFromCamera: true); } public static string DecodeContentText(Color32[] pixels, int width, int height, bool isFromCamera) { BarcodeReader barcodeReader = new BarcodeReader { AutoRotate = !isFromCamera }; Result result; try { result = barcodeReader.Decode(pixels, width, height); } catch (Exception ex) { LocalLog.AccumulateTraceLog("#699501 :" + ex); result = null; } if (result == null) { return string.Empty; } return result.Text; } public static bool SetDeckFromQRCodeText(string qrCodeText, CardMaster.CardMasterId cardMasterId) { bool result = false; string text = "https://" + "shadowverse-portal.com/api/v1/game_api/".Split('/')[0] + "/deck/"; string text2 = "https://" + "shadowverse-portal.com/api/v1/game_api/".Split('/')[0] + "/deck_co/"; string text3 = "https://" + "shadowverse-portal.com/api/v1/game_api/".Split('/')[0] + "/deck_my/"; bool flag = qrCodeText.StartsWith(text); bool flag2 = qrCodeText.StartsWith(text2); bool flag3 = qrCodeText.StartsWith(text3); if (!flag && !flag2 && !flag3) { return result; } if (!Regex.IsMatch(qrCodeText, "\\?lang=(\\w+$|zh-tw)")) { return result; } if (flag) { qrCodeText = Regex.Replace(qrCodeText, text, ""); } else if (flag2) { qrCodeText = Regex.Replace(qrCodeText, text2, ""); } else if (flag3) { qrCodeText = Regex.Replace(qrCodeText, text3, ""); } qrCodeText = Regex.Replace(qrCodeText, "\\?lang=(\\w+$|zh-tw)", ""); string[] array = qrCodeText.Split('.'); CardBasePrm.ClanType clanType = CardBasePrm.ClanType.NONE; CardBasePrm.ClanType subClanId = CardBasePrm.ClanType.NONE; MyRotationInfo myRotationInfo = null; Format format = Format.Max; try { format = GetFormatFromDeckCodeType((GenerateDeckCodeTask.SubmitDeckType)int.Parse(array[0])); clanType = (CardBasePrm.ClanType)int.Parse(array[1]); if (flag2) { subClanId = (CardBasePrm.ClanType)int.Parse(array[2]); } if (flag3) { myRotationInfo = Data.MyRotationAllInfo.Get(array[2]); } if (clanType < CardBasePrm.ClanType.MIN || clanType > CardBasePrm.ClanType.MAX) { return result; } } catch (Exception ex) { if (array.Length >= 3) { Debug.LogError($"フォーマット: {array[0].ToString()}、クラス: {array[1].ToString()}、サブクラス: {array[2].ToString()}のいずれかの情報取得に失敗。{ex.ToString()}"); } else { Debug.LogError($"cardHashIdListの長さが{array.Length.ToString()}です。{ex.ToString()}"); } return result; } List list = new List(); int num = 2; if (flag2 || flag3) { num = 3; } for (int i = num; i < array.Length; i++) { try { int cardId = CardMaster.GetInstance(cardMasterId).GetCardParamFromCardHashId(array[i]).CardId; if (!CardMaster.GetInstance(cardMasterId).CardExists(cardId)) { return result; } list.Add(cardId); } catch (Exception ex2) { Debug.LogError($"カードリストの{i.ToString()}番目要素の取得に失敗。{ex2.ToString()}"); return result; } } deckDataFromQRCode = new DeckDataFromQRCode(format, clanType, subClanId, list.ToArray(), myRotationInfo); return true; } public static Format GetFormatFromDeckCodeType(GenerateDeckCodeTask.SubmitDeckType type) { return type switch { GenerateDeckCodeTask.SubmitDeckType.NORMAL => Format.Unlimited, GenerateDeckCodeTask.SubmitDeckType.Crossover => Format.Crossover, _ => Format.Max, }; } public static bool IsShowQRCode(UICardList deckViewer, IFormatBehavior formatBehavior, Format format) { bool flag = deckViewer.getCardNum() == 40; if (formatBehavior.UseSubClass) { flag &= deckViewer.CanShowQRCodeUseSubclass(); } if (format == Format.MyRotation && !deckViewer.IsDeckNull()) { flag &= deckViewer.IsAllCardCorrectMyRotation(); } if (format == Format.Avatar) { flag = false; } return flag; } }