🍜

【VRChat】AWSを使ったアクセスカウンター制作手順

2025/02/27に公開

概要

AWSのLambdaとDynamoDBを利用したVRChatのワールドのアクセスカウンターを作る手順を覚書レベルで記します。

初めて作ったVRChatのワールドとサーバーを連携させるギミックなので間違いもあると思います。予めご容赦ください。

自分が初めてAWSを使った際に、どこに何があるかわからないことが多かったので、AWSのスクリーンショットが多めです。

環境

  • AWS Lambda: Python 3.13

  • Unity 2022.3.22f1

  • VRChat SDK - Base 3.6.1

  • VRChat SDK - Worlds 3.6.1

手順

AWSのリージョン設定

東京に設定する

アクセス数を保存するデータベースの作成(DynamoDB)

DynamoDBを選択


テーブルを作成


テーブル名(Table1)とパーティションキー(PartitionKey)を設定


項目を作成


PartitionKeyをPlayerCountとし、アクセス数を保存する数値タイプのCountValueというデータを登録する。

アクセス数をカウントアップする関数の作成(Lambda)

Lambdaを選択


関数を作成


関数名をCountUpとし、ランタイムでPythonを指定する


関数URLを有効化にチェックを入れ、認証タイプでNONEを指定し、関数を作成


タイムアウト時間を3秒から10秒に変更しておく


Lambda関数のコードを貼り付けてDeploy(保存)する

import json
import boto3

def lambda_handler(event, context):

    """ VRChat以外からの通信だったら弾く処理 (user-agentは偽装可能なので気持ち程度)
    try:
        UserAgent = event["headers"]["user-agent"]
    except:
        return "Error"
    if False == ("UnityPlayer" in UserAgent):
        return "Error"
    """

    dynamodb = boto3.resource("dynamodb")
    table = dynamodb.Table("Table1")

    # CountValueの値をカウントアップ
    table.update_item(
        Key = {"PartitionKey" : "PlayerCount"},                 # PartitionKey選択
        UpdateExpression = "SET #Para = #Para + :Value",        # 更新式 (i = i + 1と同じことを書いてある)
        ExpressionAttributeNames = {"#Para" : "CountValue"},    # 更新式の変数名
        ExpressionAttributeValues = {":Value" : 1}              # 更新式の値
    )

    # CountValueの値を返す
    DataDict = table.get_item(Key={"PartitionKey" : "PlayerCount"}).get("Item")
    return DataDict["CountValue"]

LambdaからDynamoDBへのアクセス権限設定

IAMを選択


Lambda関数の名前(CountUp)がついているロールをクリック


インラインポリシーを作成をクリック


サービスの選択でDynamoDBを選択


Lambda関数のコード内で使用しているメソッドのGetItemUpdateItemにチェックを入れる


別タブでDynamoDBを開き、Table1のARNをコピーする


IAMに戻り、リソースARN欄に貼り付けてARNを追加し、次へをクリック


好きなポリシー名をつけてポリシーを作成する (PlayerCountPolicyとした)

Lambda関数を実行するUdonSharpの作成

Lambda関数の関数URLをコピーしておく


Lambda関数の関数URLを以下のUdonSharpのVRCUrlにコピペする

AccessCounter.cs
using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;
using VRC.Udon;
using VRC.SDK3.StringLoading;
using VRC.Udon.Common.Interfaces;

public class AccessCounter : UdonSharpBehaviour
{
    [SerializeField] private Text TextObj;
    private VRCUrl URL = new VRCUrl("Lambda関数の関数URLをここにコピペ");

    void Start()
    {
        VRCStringDownloader.LoadUrl(URL, (IUdonEventReceiver)this);
        TextObj.text = "Loading...";
    }

    // 成功
    public override void OnStringLoadSuccess(IVRCStringDownload Result)
    {
        TextObj.text = Result.Result;
    }

    // 失敗
    public override void OnStringLoadError(IVRCStringDownload Result)
    {
        TextObj.text = "Error";
    }
}

実行結果

UdonSharpスクリプトを適当なオブジェクトにアタッチし、InspectorでTextオブジェクトを設定してください


アップロードしたワールドにJoin後、1回Rejoinしてアクセス数が2に増えた

おまけ (Lambdaに引数を渡す)

アクセスカウンターが作れたら、次はUdonSharpからLambdaに引数を渡して、その引数に応じてサーバー側で様々な処理をさせたくなると思います。

そういった場合は、URLクエリパラメータ(クエリストリング)というものを使ってLambdaに好きな情報を渡すことができます。

クエリパラメータはURL末尾の?以降に記述することができます。例えばa=0、b=1、c=ABCという情報を渡したい場合、以下のようなURLになります。

https://~.on.aws/?a=0&b=1&c=ABC

このURLを以下のようなクエリパラメータを返すだけのLambda関数に送ってみます

import json
import boto3

def lambda_handler(event, context):
    return event["queryStringParameters"]

すると以下のようなjsonデータが返ってきます。

{"a":"0","b":"1","c":"ABC"}

このような感じで、クエリパラメータを使ってLambdaに好きな情報を渡すことができます。


ただし、UdonSharpではVRCUrlの内容をユーザーからの入力無しに動的に変更できないため、例えばa=0,a=1,a=2,...a=9の10種類のクエリパラメータをLambda関数に渡したい場合、以下のようにあらかじめ10種類のVRCUrlを用意しておく必要があります。

private VRCUrl[] UrlArray = {
    new VRCUrl("https://~.on.aws/?a=0"), 
    new VRCUrl("https://~.on.aws/?a=1"),
    new VRCUrl("https://~.on.aws/?a=2"),
    new VRCUrl("https://~.on.aws/?a=3"),
    new VRCUrl("https://~.on.aws/?a=4"),
    new VRCUrl("https://~.on.aws/?a=5"),
    new VRCUrl("https://~.on.aws/?a=6"),
    new VRCUrl("https://~.on.aws/?a=7"),
    new VRCUrl("https://~.on.aws/?a=8"),
    new VRCUrl("https://~.on.aws/?a=9")};

例として、2025年2月にVRChatユーザーのPCスペックを集計するワールドを作ったのですが、このワールドでは、CPU、GPU、RAM、OSをPCVRとDesktop別に集計するためにクエリパラメータ別に1198個のVRCUrlを使っています。

Discussion