สร้างเกมบน Telegram Mini App และเชื่อมต่อกระเป๋า Telegram Wallet ด้วย Unity3D แบบไม่รุงรัง (ภาค2)

ว่าด้วยเรื่องของ Telegram Wallet และเหรียญ TON คือในโลกนี้มี Chain ที่ชื่อ Ton นะครับ โดยสกุลเงินหลักคือ TON ครับ ซึ่งเป็นสกุลหลักที่ใช้จ่ายกันใน Telegram ไม่ว่าจะเป็นบริการหรือซื้อของในเกม หรือบริการต่างๆ

หาเราต้องการเชื่อมต่อกับ TON เพื่อใช้เป็นแหล่งรับ ส่งเงิน หรือเพื่อสร้างรายได้ให้ เกมของเรา เราสามารถทำได้โดยใช้ TON Connect SDK ที่มีให้ใช้หลากหลาย platform มาก รวมทั้ง Unity ด้วยซึ่งสามารถดูรายละเอียดได้ที่
https://docs.ton.org/develop/dapps/ton-connect/developers

แต่เมื่อคุณไปดาวน์โหลด lib ของ Unity มาคุณจะพบว่า ข้างในจะประกอบด้วย Asset มากมายมหาศาลรวมทั้ง WebGL Template มาด้วย และเมื่อเปิด SampleScene ขึ้นมานั่นคือไม่มีการจัดวาง UI แต่ใช้ UI Script เฉพาะอีก (ปัญหามาแระ) และเมื่อเราไปดูใน script ของเขาบอกเลยว่านรกมาก ใครอ่านแล้วเข้าใจฝากบอกด้วย อะพอเลิกบ่นครับ มาดูวิธีง่ายๆ ฉบับไม่รุงรังของผมกัน

ใช้ TonConnect SDK ของ JS ครับ ใช้ได้ 2 วิธีคือโหลดผ่าน scr ของ html เหมือน Telegram หรือจะไป โหลดโดยใช้ npm หรือ node แล้ว compile ออกมาเป็น bundle.js เองเลย ซึ่งผมแนะนำวิธีที่ 2 เพราะมันจะไม่ติดเมื่อมี่การอัพเวอร์ชั่นของ lib นะครับ
วิธีแรก ใช้ใส่ใน HTML แล้วเขียน .jslib เหมือนตอนทำกับ Telegram เลยครับ โดยใส่ code ตรงนี้ใน Header

<script src="https://unpkg.com/@tonconnect/ui@latest/dist/tonconnect-ui.min.js"></script>

หรือเข้าไปใน floder ที่ index.html วางอยู่แล้วลง node ตัวนี้ (ผมแนะนำวิธีนี้เพราะโหลดเร็วกว่า)

npm install @tonconnect/ui
npm install @tonconnect/sdk

แล้วสร้าง file index.js ขึ้นมาโดยในไฟล์จะเขียนดังนี้

import { TonConnectUI } from '@tonconnect/ui';
import { toUserFriendlyAddress } from '@tonconnect/sdk';

const tonConnectUI = new TonConnectUI({
    manifestUrl: 'https://<Your WebGL URL>/tonconnect-manifest.json',
    buttonRootId: 'ton-connect-button'
});
tonConnectUI.uiOptions = {
    twaReturnUrl: 'https://t.me/<your bot name>'
};

var unityCallback = 'TonConnect';
var currentAddress = '';

// ดักจับว่า wallet ที่ีต่อเป็นของใคร
tonConnectUI.onStatusChange(
    walletAndWalletInfo => {
        const rawaddress = walletAndWalletInfo.account.address;
        const readableAddress = toUserFriendlyAddress(rawaddress);
        console.log('Wallet Address : ',readableAddress);
        currentAddress = readableAddress;
        window.unityInstance.SendMessage(unityCallback, 'OnWalletConnected', readableAddress);
    }
);
// Function เอาไว้สั่งให้แอ็ปต่อ wallet
export async function connectTelegramWallet(callbackObjectName) {
    unityCallback = callbackObjectName;
    if(tonConnectUI.connected){
        window.unityInstance.SendMessage(unityCallback, 'OnWalletConnected', currentAddress);
    }else{
        await tonConnectUI.openSingleWalletModal('telegram-wallet');
    }
}

// Function เอาไว้โอนเงินให้กระเป๋าของเกมอาจเอาไว้ซื้อ item ที่เราจะขาย
export async function payWithTon(targetAddress, amount, callbackObjectName) {
    const transaction = {
        validUntil: Math.floor(Date.now() / 1000) + 60, // 60 sec
        messages: [
            {
                address: targetAddress,
                amount: amount // TON in nanoton
            }
        ]
    };

    const result = await tonConnectUI.sendTransaction(transaction).then(tx=>{
        window.unityInstance.SendMessage(callbackObjectName, 'OnPayWithTonSuccess', JSON.stringify(tx));
    }).catch(error=>{
        window.unityInstance.SendMessage(callbackObjectName, 'OnPayWithTonError', error.message);
    });
    console.log('Transacton :',result);
}

// ใส่เพื่อให้ Unity เรียกได้ผ่าน jslib
window.connectTelegramWallet = connectTelegramWallet;
window.payWithTon = payWithTon;

Address ที่ได้จาก Ton มันจะอยู่ในฟอร์ม 0:4578855…. แบบนี้ซึ่งเรียกว่า raw address ซึ่งจะไม่เหมือน Wallet ที่เราเห็นใน Telegram Wallet นะครับ เราต้องแปลงอีกครั้งโดยใช้ toUserFriendlyAddress

ส่วนใน function SendTon เราจะใช้ readable address นะครับ เลยแปลงไปเลยดีกว่า

จากนั้นแก้ไขไฟล์ webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',  // Entry point for your JavaScript code
    output: {
        filename: 'bundle.js',  // The output file name
        path: path.resolve(__dirname, 'dist'),  // The output directory
        library: 'TonConnectLibrary',  // Library name
        libraryTarget: 'window',  // Attach to the window object
    },
    mode: 'production',  // Minified production build
};

จากนั้นรัน npx webpack ใน Terminal เพื่อ compile ให้ออกมาเป็น bundle.js และนำไปแทรกใน header ดังนี้

<script src="dist/bundle.js" defer></script>

จากนั้นให้สร้าง TonConnectInterface.jslib

mergeInto(LibraryManager.library, {
    ConnectTelegramWallet: function (callbackObjectNamePtr) {
        var callbackObjectName = UTF8ToString(callbackObjectNamePtr);

        // Call the globally exposed function from bundle.js
        if (typeof window.connectTelegramWallet !== 'undefined') {
            window.connectTelegramWallet(callbackObjectName);
        } else {
            console.error("connectTelegramWallet function not defined in bundle.js");
        }
    },

    PayWithTon: function (targetAddressPtr, amountPtr, callbackObjectNamePtr) {
        var targetAddress = UTF8ToString(targetAddressPtr);
        var amount = UTF8ToString(amountPtr);
        var callbackObjectName = UTF8ToString(callbackObjectNamePtr);

        // Call the globally exposed function from bundle.js
        if (typeof window.payWithTon !== 'undefined') {
            window.payWithTon(targetAddress, amount, callbackObjectName);
        } else {
            console.error("payWithTon function not defined in bundle.js");
        }
    }
});

สุดท้ายแล้วครับ เขียน C# interface

using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class TonConnectIntegration : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void ConnectTelegramWallet(string callbackObjectName);

    [DllImport("__Internal")]
    private static extern void PayWithTon(string targetAddress, string amount, string callbackObjectName);

    public Text walletAddressText;
    public Text transactionStatusText;

    public void ConnectWallet()
    {
        ConnectTelegramWallet(gameObject.name);  // Call the JavaScript function to connect the wallet
    }

    public void PayWithTon(string targetAddress, string amount)
    {
        PayWithTon(targetAddress, amount, gameObject.name);  // Call the JavaScript function to send a custom amount of TON
    }

    public void OnWalletConnected(string walletAddress)
    {
        walletAddressText.text = "Wallet Address: " + walletAddress;
    }

    public void OnWalletConnectionError(string errorMessage)
    {
        walletAddressText.text = "Error: " + errorMessage;
    }

    public void OnPayWithTonSuccess(string transactionData)
    {
        transactionStatusText.text = "Transaction Success: " + transactionData;
    }

    public void OnPayWithTonError(string errorMessage)
    {
        transactionStatusText.text = "Transaction Error: " + errorMessage;
    }
}

หากรันแล้วเกิด error ว่าหา unityInstance ไม่เจอ ให้ไปดูที่ Template ของเราครับ หาว่า unityInstance ของเราถูกสร้างที่ไหนแล้ว ใส่

window.unityInstance = unityInstance; ลงไปในช่วงนั้นครับ

เท่านี้ก็จะได้ Telegram Mini App ที่เชื่อมต่อกับ Telegram Wallet ได้แล้วครับ แถมยังเอาไปขายของได้ด้วย โดยใช้ PayWithTON แล้วถ้า Success ก็เพิ่ม item หรือ asset อะไรให้ลูกค้าก็ว่าไปครับ

By admin

Leave a Reply

Your email address will not be published. Required fields are marked *