【问题标题】:Preventing multiple users accessing same Cloud Function simultaneously防止多个用户同时访问同一个云功能
【发布时间】:2017-10-08 05:34:37
【问题描述】:

我正在使用 Unity 创建一个简单的 2D 多人游戏,我选择使用 Firebase 作为后端。在尝试使用 Firebase Cloud 功能填满房间时,我遇到了一些问题。我计划它的工作方式如下:

  1. 玩家点击“加入房间”按钮
  2. 唯一的设备 ID 被发送到“玩家搜索房间”下的实时数据库,并且事件监听器被添加到该 ID
  3. “onWrite”事件发生时将触发云函数。然后函数将检查房间数组是否为空。如果房间数组为空,云函数会将新房间推送到实时数据库。
  4. 云功能在“玩家搜索房间”中将房间ID推送到玩家ID下
  5. 由于玩家已经在“玩家搜索房间”下监听自己的ID,当房间ID被推到自己的ID下时会运行一个函数。这将告诉玩家云功能已成功为他找到了房间。

下面是云功能:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions

var room = [];

// ID for the room we are filling at the moment
var room_currentID;

// This functions triggers each time something is added or deleted to "Players Searching For Room"

exports.findRoom = functions.database
    .ref('/Players Searching For Room/{pushId}')
    .onWrite(event => {

        // Check if data exists (if not, this was triggered by delete -> return)

        if(!event.data.exists())
        {
            return;
        } 

        // If this player already has a room, we want to return
        if(event.data.val().inRoom != "none")
            return;

        // Store data under changed pushId (if player was added to waiting players then data is -> "size" : 4)
        const data = event.data.val();
        // Name of the player. We get this from the pushId of the item we pushed ("container" for data pushed).
        var name = event.params.pushId;
        // Size of the room the player wants to join
        var size = data.size;

        // With IF-statements check which room_size_n object array we want to loop through

        console.log("Player called " + name + " is waiting for room that has maxium of " + size + " players")

        // We can push the user to the room array since it can never be full 
        // (we clear the array before allowing next guy to join)
        room.push(name);

        // If this was the first guy
        // we need to create new room
        if(room.length == 1) 
        {
            admin.database().ref('/Rooms').push({
                onGoing: false // We need to set something, might aswell set something usefull
            }).then(snapshot => {
                // because this function is triggered by changes in firebase realtime database
                // we can't return anything to the player. BUT we can inform player about the room
                // he's been attached to by adding roomID to the playername in the "Players Searching For Room"
                // then players device will handle removing 

                // Store ID of the room so that we can send it to later joiners in this room
                room_currentID = snapshot.key;

                data.inRoom = room_currentID;

                return event.data.ref.set(data);
            });
        }
        // If there already exists a suitable room with space on it
        else if(room.length > 1)
        {
            // We can attach the stored roomID to the player so he knows which rooms onGoing flag to watch for.
            data.inRoom = room_currentID;

            // Attach roomID to the player and then check if room is full
            // waiting roomID to attach to player before setting onGoing TRUE
            // prevents other player to get a head start
            event.data.ref.set(data).then(snapshot => {
                // If roomId was attached to the player we can check the room size
                if(room.length == size)
                {
                    // ...and if the room became full we need to set onGoing to true
                    admin.database().ref('/Rooms/'+room_currentID).set({
                        onGoing: true
                    }).then(snapshot => {
                        room = [];
                    });
                }
            });
        }
    });

问题是,如果多个用户在短时间内点击Join Game-button,则会导致系统混乱。在“搜索房间的玩家”下添加玩家 ID 似乎每次都有效,但有时 Cloud 功能从不将房间 ID 附加到玩家 ID,有时 Cloud 功能会创建比应有的更多房间。我只是通过在每次单击“玩家搜索房间”下附加随机 ID 的按钮来测试这一点。然后我迅速点击了那个按钮 10 次。那应该将 5 个不同的房间 ID 附加到这 10 个随机 ID 上,并生成 5 个新房间。相反,它生成了 7 个房间并将房间 ID 添加到仅 8 个随机 ID 而不是 10 个。

问题是,我认为:

  1. Abe 在 12.00.00 点击加入游戏按钮
  2. 云功能启动(执行需要 5 秒)
  3. Rob 在 12.00.02 点击加入游戏按钮
  4. 在完成 Abe 的请求之前再次触发云功能
  5. 一切都搞砸了

firebase 是否可以更改此设置,以便如果 Rob 在 Abe 的请求完成之前触发 Cloud 功能,Rob 将在 Abe 完成时被搁置。当安倍完成时,轮到罗布了。呃,非常长的解释希望有人会读到这个:)

【问题讨论】:

  • 您需要使用事务来维护数据库中游戏的一致状态。详细说明这一点可能比这里的答案更复杂。
  • 你能给我一些教程视频或API链接吗?我似乎无法找到有关交易的任何信息,甚至从 Firebase API 也找不到(或者我可能只是错过了它)。

标签: firebase google-cloud-functions


【解决方案1】:

在 2017 年 Google I/O 上,我发表了关于仅在后端使用 Firebase 构建多人游戏的演讲。 Cloud Functions 几乎实现了游戏的所有逻辑。它还有一个简单的匹配功能,您可以扩展该方案来做更复杂的事情。大家可以观看here的讲座,项目的源代码即将发布。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 2022-09-24
    • 2012-05-05
    • 1970-01-01
    • 2011-03-14
    • 2015-06-02
    • 2012-11-18
    相关资源
    最近更新 更多