From 846a4fda9c43f9cab4ee1526cbdfb5730c067197 Mon Sep 17 00:00:00 2001 From: Savya Bikram Shah Date: Thu, 7 May 2026 16:43:28 +0545 Subject: [PATCH] QR and payment fixes --- Assets/SamplePayment.cs | 6 +- .../Runtime/API/FonepayApiClient.cs | 21 +- .../Runtime/API/FonepayWebsocketClient.cs | 12 +- .../Runtime/Models/QrResponse.cs | 1 + .../Models/Websocket/QRPaymentStatus.cs | 2 +- .../Models/Websocket/WebsocketMessage.cs | 3 +- .../Runtime/Plugins.meta | 8 + .../Runtime/Plugins/QRCoder-LICENSE.txt | 21 ++ .../Runtime/Plugins/QRCoder-LICENSE.txt.meta | 7 + .../Runtime/Plugins/QRCoder.dll | Bin 0 -> 78848 bytes .../Runtime/Plugins/QRCoder.dll.meta | 33 +++ .../Runtime/QR/FonepayQRGenerator.Capacity.cs | 40 --- .../QR/FonepayQRGenerator.Capacity.cs.meta | 2 - .../QR/FonepayQRGenerator.Codewords.cs | 62 ----- .../QR/FonepayQRGenerator.Codewords.cs.meta | 2 - .../Runtime/QR/FonepayQRGenerator.Matrix.cs | 234 ------------------ .../QR/FonepayQRGenerator.Matrix.cs.meta | 2 - .../QR/FonepayQRGenerator.ReedSolomon.cs | 67 ----- .../QR/FonepayQRGenerator.ReedSolomon.cs.meta | 2 - .../Runtime/QR/FonepayQRGenerator.cs | 43 +++- 20 files changed, 135 insertions(+), 433 deletions(-) create mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/Plugins.meta create mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt create mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt.meta create mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll create mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll.meta delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs.meta delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs.meta delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs.meta delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs delete mode 100644 Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs.meta diff --git a/Assets/SamplePayment.cs b/Assets/SamplePayment.cs index 735c166..98b2967 100644 --- a/Assets/SamplePayment.cs +++ b/Assets/SamplePayment.cs @@ -27,7 +27,7 @@ namespace Darkmatter.Fonepay.Samples var fonepay = new FonepayClient(); var request = new QrRequest { - amount = 1, + amount = 0.5f, remarks1 = "mausham ko paisa" }; var qr = await fonepay.PurchaseAsync(request, destroyCancellationToken); @@ -45,9 +45,9 @@ namespace Darkmatter.Fonepay.Samples qr.thirdpartyQrWebSocketUrl, onQrVerified: v => Debug.Log($"Fonepay QR verified: {v}"), ct: destroyCancellationToken); - + Debug.Log($"{JsonUtility.ToJson(payment)}"); var ok = payment.Outcome == PaymentOutcome.Complete; - + qrImage.gameObject.SetActive(false); successObject.SetActive(ok); failedObject.SetActive(!ok); diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayApiClient.cs b/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayApiClient.cs index 7de4e55..3c31aa9 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayApiClient.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayApiClient.cs @@ -177,14 +177,29 @@ namespace Darkmatter.Fonepay return new QrResult { message = response.message, - qrCode = string.IsNullOrEmpty(response.qrMessage) - ? null - : FonepayQRGenerator.GenerateTexture(response.qrMessage), + qrCode = TryGenerateQr(response.qrMessage), status = response.status, statusCode = response.statusCode, success = response.success, thirdpartyQrWebSocketUrl = response.thirdpartyQrWebSocketUrl, + qrMessage = response.qrMessage, }; } + + private static Texture2D TryGenerateQr(string qrMessage) + { + if (string.IsNullOrEmpty(qrMessage)) + return null; + try + { + return FonepayQRGenerator.GenerateTexture(qrMessage); + } + catch (Exception ex) + { + Debug.LogWarning($"Fonepay QR render failed ({ex.Message}). " + + "Use QrResult.qrMessage with an external renderer."); + return null; + } + } } } \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayWebsocketClient.cs b/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayWebsocketClient.cs index 1738d3d..0a19d30 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayWebsocketClient.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/API/FonepayWebsocketClient.cs @@ -13,6 +13,7 @@ namespace Darkmatter.Fonepay internal event Action OnQrVerified; internal event Action> OnPaymentReceived; internal event Action OnRawMessage; + internal event Action OnClosed; private ClientWebSocket _client; private CancellationTokenSource _cts; @@ -51,6 +52,7 @@ namespace Darkmatter.Fonepay CancellationToken cancellationToken) { var buffer = new byte[4096]; + Exception error = null; try { @@ -70,9 +72,9 @@ namespace Darkmatter.Fonepay { // Expected during disconnect. } - catch (WebSocketException) + catch (WebSocketException ex) { - // Network disconnect or broken socket. + error = ex; } catch (ObjectDisposedException) { @@ -80,7 +82,11 @@ namespace Darkmatter.Fonepay } catch (Exception ex) { - Console.WriteLine($"WebSocket receive error: {ex.Message}"); + error = ex; + } + finally + { + OnClosed?.Invoke(error); } } diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Models/QrResponse.cs b/Packages/com.voidbotz.fonepayunity/Runtime/Models/QrResponse.cs index 61fff06..a655cf5 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/Models/QrResponse.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Models/QrResponse.cs @@ -12,6 +12,7 @@ namespace Darkmatter.Fonepay public int statusCode; public bool success; public string thirdpartyQrWebSocketUrl; + public string qrMessage; } diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/QRPaymentStatus.cs b/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/QRPaymentStatus.cs index 1992e51..1771464 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/QRPaymentStatus.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/QRPaymentStatus.cs @@ -7,7 +7,7 @@ namespace Darkmatter.Fonepay { public string remarks1; public string remarks2; - public DateTime transactionDate; + public string transactionDate; public string productNumber; public float amount; public string message; diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/WebsocketMessage.cs b/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/WebsocketMessage.cs index a330efb..f733975 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/WebsocketMessage.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Models/Websocket/WebsocketMessage.cs @@ -9,7 +9,6 @@ namespace Darkmatter.Fonepay public string merchantId; public string deviceId; public string transactionStatus; - private T _status; - public T Status => _status ??= JsonUtility.FromJson(transactionStatus); + public T Status => JsonUtility.FromJson(transactionStatus); } } \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Plugins.meta b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins.meta new file mode 100644 index 0000000..0b44ed1 --- /dev/null +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: debdfefd8b01242e8b95f0e29bb09c0d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt new file mode 100644 index 0000000..90b272f --- /dev/null +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2025 Raffael Herrmann +Copyright (c) 2024-2025 Shane Krueger + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt.meta b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt.meta new file mode 100644 index 0000000..af80b69 --- /dev/null +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder-LICENSE.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3902a28335b7043bf831aab193145f4c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll new file mode 100644 index 0000000000000000000000000000000000000000..2d2d7f2a4fbc0444b8aefcbe173b311872253c2e GIT binary patch literal 78848 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 literal 0 HcmV?d00001 diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll.meta b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll.meta new file mode 100644 index 0000000..c34b382 --- /dev/null +++ b/Packages/com.voidbotz.fonepayunity/Runtime/Plugins/QRCoder.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: ecb337d209ad74a598de572b4e034307 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs deleted file mode 100644 index 4a8ddb3..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace Darkmatter.Fonepay -{ - public static partial class FonepayQRGenerator - { - // [version-1][eccLevel] = (totalCodewords, ecCodewordsPerBlock, blocks) - static readonly (int total, int ecPerBlock, int blocks)[,] _caps = - { - { (19, 7, 1), (16, 10, 1), (13, 13, 1), (9, 17, 1) }, - { (34, 10, 1), (28, 16, 1), (22, 22, 1), (16, 28, 1) }, - { (55, 15, 1), (44, 26, 1), (34, 18, 2), (26, 22, 2) }, - { (80, 20, 2), (64, 18, 2), (48, 26, 4), (36, 16, 4) }, - { (108, 26, 2), (86, 24, 2), (62, 18, 2), (46, 22, 2) }, - { (136, 18, 4), (108, 16, 4), (76, 24, 4), (60, 28, 4) }, - { (156, 20, 4), (124, 18, 4), (88, 18, 6), (66, 26, 4) }, - { (194, 24, 4), (154, 22, 4), (110, 22, 6), (86, 26, 4) }, - { (232, 30, 4), (182, 22, 5), (132, 20, 8), (100, 24, 4) }, - { (274, 18, 6), (216, 26, 6), (154, 24, 8), (122, 28, 6) }, - }; - - static int DataCodewords(int ver, EccLevel ecc) - { - var (total, ecPer, blks) = _caps[ver - 1, (int)ecc]; - return total - ecPer * blks; - } - - static (int version, (int total, int ecPerBlock, int blocks) ecBlocks) - ChooseVersion(int byteLen, EccLevel ecc) - { - for (int v = 1; v <= 10; v++) - { - int dc = DataCodewords(v, ecc); - if (dc >= byteLen + 2) - return (v, _caps[v - 1, (int)ecc]); - } - throw new Exception($"Data too large for versions 1-10 (byte mode, ecc={ecc})"); - } - } -} diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs.meta b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs.meta deleted file mode 100644 index a2e8c11..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Capacity.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a611e576dae8b4ff6b15c314c1246cf1 \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs deleted file mode 100644 index 01d3588..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Darkmatter.Fonepay -{ - public static partial class FonepayQRGenerator - { - static byte[] BuildCodewords(byte[] data, int version, EccLevel ecc, - (int total, int ecPerBlock, int blocks) ecBlocks) - { - var bits = new List(); - bits.AddRange(new[] { false, true, false, false }); // byte mode - int len = data.Length; - for (int i = 7; i >= 0; i--) bits.Add(((len >> i) & 1) == 1); - foreach (byte b in data) - for (int i = 7; i >= 0; i--) - bits.Add(((b >> i) & 1) == 1); - - int dcBytes = DataCodewords(version, ecc); - int targetBits = dcBytes * 8; - for (int i = 0; i < 4 && bits.Count < targetBits; i++) bits.Add(false); - while (bits.Count % 8 != 0) bits.Add(false); - - bool[] padA = { true, true, true, false, true, true, false, false }; - bool[] padB = { false, false, false, true, false, false, false, true }; - int pi = 0; - while (bits.Count < targetBits) - { - bits.AddRange(pi % 2 == 0 ? padA : padB); - pi++; - } - - byte[] dc = new byte[dcBytes]; - for (int i = 0; i < dcBytes; i++) - for (int b = 0; b < 8; b++) - if (bits[i * 8 + b]) - dc[i] |= (byte)(1 << (7 - b)); - - int blocks = ecBlocks.blocks; - int ecPer = ecBlocks.ecPerBlock; - int blockSize = dcBytes / blocks; - byte[][] dcBlocks = new byte[blocks][]; - byte[][] ecBlocksArr = new byte[blocks][]; - for (int i = 0; i < blocks; i++) - { - dcBlocks[i] = new byte[blockSize]; - Array.Copy(dc, i * blockSize, dcBlocks[i], 0, blockSize); - ecBlocksArr[i] = ReedSolomon(dcBlocks[i], ecPer); - } - - var result = new List(); - for (int i = 0; i < blockSize; i++) - for (int b = 0; b < blocks; b++) - result.Add(dcBlocks[b][i]); - for (int i = 0; i < ecPer; i++) - for (int b = 0; b < blocks; b++) - result.Add(ecBlocksArr[b][i]); - - return result.ToArray(); - } - } -} diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs.meta b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs.meta deleted file mode 100644 index 97e56eb..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Codewords.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: e67574ccbe68944928d706bd99d785ca \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs deleted file mode 100644 index fba66bd..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; - -namespace Darkmatter.Fonepay -{ - public static partial class FonepayQRGenerator - { - static bool[,] BuildMatrix(int version, byte[] codewords) - { - int size = version * 4 + 17; - var matrix = new bool[size, size]; - var reserved = new bool[size, size]; - - PlaceFinder(matrix, reserved, 0, 0); - PlaceFinder(matrix, reserved, 0, size - 7); - PlaceFinder(matrix, reserved, size - 7, 0); - PlaceTiming(matrix, reserved, size); - PlaceDarkModule(matrix, reserved, version); - if (version >= 2) PlaceAlignment(matrix, reserved, version); - ReserveFormat(reserved, size); - PlaceData(matrix, reserved, codewords, size); - - int bestPenalty = int.MaxValue; - bool[,] bestMatrix = null; - for (int m = 0; m < 8; m++) - { - var candidate = (bool[,])matrix.Clone(); - ApplyMask(candidate, reserved, m, size); - ApplyFormatInfo(candidate, reserved, 1, m, size); - int penalty = CalcPenalty(candidate, size); - if (penalty < bestPenalty) - { - bestPenalty = penalty; - bestMatrix = (bool[,])candidate.Clone(); - } - } - return bestMatrix; - } - - static void PlaceFinder(bool[,] m, bool[,] r, int row, int col) - { - for (int dr = -1; dr <= 7; dr++) - for (int dc = -1; dc <= 7; dc++) - { - int rr = row + dr, cc = col + dc; - if (rr < 0 || cc < 0 || rr >= m.GetLength(0) || cc >= m.GetLength(1)) continue; - r[rr, cc] = true; - bool inOuter = dr >= 0 && dr <= 6 && dc >= 0 && dc <= 6; - bool inBorder = (dr == 0 || dr == 6 || dc == 0 || dc == 6) && inOuter; - bool inInner = dr >= 2 && dr <= 4 && dc >= 2 && dc <= 4; - m[rr, cc] = !(dr == -1 || dc == -1 || dr == 7 || dc == 7) && (inBorder || inInner); - } - } - - static void PlaceTiming(bool[,] m, bool[,] r, int size) - { - for (int i = 8; i < size - 8; i++) - { - bool v = i % 2 == 0; - m[6, i] = v; r[6, i] = true; - m[i, 6] = v; r[i, 6] = true; - } - } - - static void PlaceDarkModule(bool[,] m, bool[,] r, int ver) - { - int row = ver * 4 + 9; - m[row, 8] = true; - r[row, 8] = true; - } - - static readonly int[][] _alignCenters = - { - new int[] { }, - new[] { 6, 18 }, - new[] { 6, 22 }, - new[] { 6, 26 }, - new[] { 6, 30 }, - new[] { 6, 34 }, - new[] { 6, 22, 38 }, - new[] { 6, 24, 42 }, - new[] { 6, 26, 46 }, - new[] { 6, 28, 50 }, - }; - - static void PlaceAlignment(bool[,] m, bool[,] r, int version) - { - int[] centers = _alignCenters[version - 1]; - foreach (int row in centers) - foreach (int col in centers) - { - if (r[row, col]) continue; - for (int dr = -2; dr <= 2; dr++) - for (int dc = -2; dc <= 2; dc++) - { - bool dark = Math.Abs(dr) == 2 || Math.Abs(dc) == 2 || (dr == 0 && dc == 0); - m[row + dr, col + dc] = dark; - r[row + dr, col + dc] = true; - } - } - } - - static void ReserveFormat(bool[,] r, int size) - { - for (int i = 0; i <= 8; i++) - { - r[8, i] = true; - r[i, 8] = true; - } - for (int i = size - 8; i < size; i++) - { - r[8, i] = true; - r[i, 8] = true; - } - } - - static void PlaceData(bool[,] m, bool[,] r, byte[] cw, int size) - { - int cwIdx = 0, bitIdx = 7; - bool upward = true; - int col = size - 1; - - while (col > 0) - { - if (col == 6) col--; - for (int rowStep = 0; rowStep < size; rowStep++) - { - int row = upward ? size - 1 - rowStep : rowStep; - for (int c = 0; c < 2; c++) - { - int cc = col - c; - if (r[row, cc]) continue; - bool bit = cwIdx < cw.Length && ((cw[cwIdx] >> bitIdx) & 1) == 1; - m[row, cc] = bit; - if (--bitIdx < 0) - { - bitIdx = 7; - cwIdx++; - } - } - } - upward = !upward; - col -= 2; - } - } - - static void ApplyMask(bool[,] m, bool[,] r, int mask, int size) - { - for (int row = 0; row < size; row++) - for (int col = 0; col < size; col++) - { - if (r[row, col]) continue; - bool flip = mask switch - { - 0 => (row + col) % 2 == 0, - 1 => row % 2 == 0, - 2 => col % 3 == 0, - 3 => (row + col) % 3 == 0, - 4 => (row / 2 + col / 3) % 2 == 0, - 5 => row * col % 2 + row * col % 3 == 0, - 6 => (row * col % 2 + row * col % 3) % 2 == 0, - 7 => ((row + col) % 2 + row * col % 3) % 2 == 0, - _ => false - }; - if (flip) m[row, col] ^= true; - } - } - - static readonly ushort[] _formatL = { 0x77C4, 0x72F3, 0x7DAA, 0x789D, 0x662F, 0x6318, 0x6C41, 0x6976 }; - static readonly ushort[] _formatM = { 0x5412, 0x5125, 0x5E7C, 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0 }; - static readonly ushort[] _formatQ = { 0x355F, 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA, 0x2BED }; - static readonly ushort[] _formatH = { 0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x0762, 0x0255, 0x0D0C, 0x083B }; - - static void ApplyFormatInfo(bool[,] m, bool[,] r, int eccIndex, int mask, int size) - { - ushort[] table = eccIndex switch { 0 => _formatM, 1 => _formatL, 2 => _formatH, _ => _formatQ }; - ushort fmt = table[mask]; - - int[] seq = { 0, 1, 2, 3, 4, 5, 7, 8 }; - for (int i = 0; i < 8; i++) - { - bool bit = ((fmt >> (14 - i)) & 1) == 1; - m[8, seq[i]] = bit; - m[seq[i < 6 ? i : i + 1 < 8 ? i : i], 8] = bit; - } - - for (int i = 0; i < 7; i++) - { - bool bit = ((fmt >> i) & 1) == 1; - m[size - 1 - i, 8] = bit; - } - for (int i = 7; i < 15; i++) - { - bool bit = ((fmt >> i) & 1) == 1; - m[8, size - 15 + i] = bit; - } - } - - static int CalcPenalty(bool[,] m, int size) - { - int p = 0; - for (int r = 0; r < size; r++) - { - int run = 1; - for (int c = 1; c < size; c++) - { - if (m[r, c] == m[r, c - 1]) - { - run++; - if (run == 5) p += 3; - else if (run > 5) p++; - } - else run = 1; - } - run = 1; - for (int c = 1; c < size; c++) - { - if (m[c, r] == m[c - 1, r]) - { - run++; - if (run == 5) p += 3; - else if (run > 5) p++; - } - else run = 1; - } - } - - for (int r = 0; r < size - 1; r++) - for (int c = 0; c < size - 1; c++) - if (m[r, c] == m[r, c + 1] && m[r, c] == m[r + 1, c] && m[r, c] == m[r + 1, c + 1]) - p += 3; - return p; - } - } -} diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs.meta b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs.meta deleted file mode 100644 index 5976f5c..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.Matrix.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6510d029572264a5b8aea6d31e302686 \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs deleted file mode 100644 index 7c1b938..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; - -namespace Darkmatter.Fonepay -{ - public static partial class FonepayQRGenerator - { - static readonly byte[] _exp = new byte[512]; - static readonly byte[] _log = new byte[256]; - - static FonepayQRGenerator() - { - int x = 1; - for (int i = 0; i < 255; i++) - { - _exp[i] = (byte)x; - _log[x] = (byte)i; - x <<= 1; - if (x >= 256) x ^= 0x11d; - } - for (int i = 255; i < 512; i++) _exp[i] = _exp[i - 255]; - } - - static byte GfMul(byte a, byte b) - { - if (a == 0 || b == 0) return 0; - return _exp[(_log[a] + _log[b]) % 255]; - } - - static byte GfPow(int b, int e) => _exp[(_log[(byte)b] * e) % 255]; - - static byte[] ReedSolomon(byte[] data, int ecCount) - { - byte[] gen = RsGenerator(ecCount); - byte[] msg = new byte[data.Length + ecCount]; - Array.Copy(data, msg, data.Length); - - for (int i = 0; i < data.Length; i++) - { - byte coef = msg[i]; - if (coef == 0) continue; - for (int j = 1; j < gen.Length; j++) - msg[i + j] ^= GfMul(gen[j], coef); - } - - byte[] ec = new byte[ecCount]; - Array.Copy(msg, data.Length, ec, 0, ecCount); - return ec; - } - - static byte[] RsGenerator(int degree) - { - byte[] g = { 1 }; - for (int i = 0; i < degree; i++) - { - byte[] ng = new byte[g.Length + 1]; - byte root = GfPow(2, i); - for (int j = 0; j < g.Length; j++) - { - ng[j] ^= GfMul(g[j], root); - ng[j + 1] ^= g[j]; - } - g = ng; - } - return g; - } - } -} diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs.meta b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs.meta deleted file mode 100644 index 083228a..0000000 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.ReedSolomon.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 049bdafac777b4e58bafafb2224e88a8 \ No newline at end of file diff --git a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.cs b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.cs index 4fd6d54..c64d4b5 100644 --- a/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.cs +++ b/Packages/com.voidbotz.fonepayunity/Runtime/QR/FonepayQRGenerator.cs @@ -1,11 +1,13 @@ +using System.Collections; +using QRCoder; using UnityEngine; namespace Darkmatter.Fonepay { /// - /// Pure C# QR Code generator. Byte mode, ECC L/M/Q/H, versions 1–10. + /// QR code generator backed by QRCoder (MIT). See Plugins/QRCoder-LICENSE.txt. /// - public static partial class FonepayQRGenerator + public static class FonepayQRGenerator { public enum EccLevel { L, M, Q, H } @@ -25,16 +27,21 @@ namespace Darkmatter.Fonepay Color dark = darkColor ?? Color.black; Color light = lightColor ?? Color.white; + var pixels = new Color[texSize * texSize]; for (int row = 0; row < size; row++) for (int col = 0; col < size; col++) { Color c = matrix[row, col] ? dark : light; + int yBase = (size - 1 - row) * pixelSize; + int xBase = col * pixelSize; for (int py = 0; py < pixelSize; py++) - for (int px = 0; px < pixelSize; px++) - tex.SetPixel(col * pixelSize + px, - (size - 1 - row) * pixelSize + py, c); + { + int rowStart = (yBase + py) * texSize + xBase; + for (int px = 0; px < pixelSize; px++) + pixels[rowStart + px] = c; + } } - + tex.SetPixels(pixels); tex.Apply(); return tex; } @@ -57,10 +64,26 @@ namespace Darkmatter.Fonepay { if (string.IsNullOrEmpty(text)) throw new System.ArgumentException("QR text must be non-empty", nameof(text)); - byte[] data = System.Text.Encoding.UTF8.GetBytes(text); - var (version, ecBlocks) = ChooseVersion(data.Length, ecc); - byte[] codewords = BuildCodewords(data, version, ecc, ecBlocks); - return BuildMatrix(version, codewords); + + using var data = new QRCodeGenerator().CreateQrCode(text, MapEcc(ecc), forceUtf8: true); + int size = data.ModuleMatrix.Count; + var matrix = new bool[size, size]; + for (int row = 0; row < size; row++) + { + BitArray bits = data.ModuleMatrix[row]; + for (int col = 0; col < size; col++) + matrix[row, col] = bits[col]; + } + return matrix; } + + static QRCodeGenerator.ECCLevel MapEcc(EccLevel e) => e switch + { + EccLevel.L => QRCodeGenerator.ECCLevel.L, + EccLevel.M => QRCodeGenerator.ECCLevel.M, + EccLevel.Q => QRCodeGenerator.ECCLevel.Q, + EccLevel.H => QRCodeGenerator.ECCLevel.H, + _ => QRCodeGenerator.ECCLevel.M + }; } }