阻止多个用户同时访问相同的云功能

时间:2017-05-09 18:51:40

标签: firebase google-cloud-functions

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

  1. 玩家点击“加入房间” - 按钮
  2. 在“搜索房间的玩家”下将唯一设备ID发送到实时数据库,并将事件侦听器添加到该ID
  3. 当'onWrite'事件发生时,将触发云功能。然后函数将检查房间阵列是否为空。如果房间阵列为空,则Cloud功能会将新房间推送到实时数据库。
  4. 云功能会将“房间ID”推送到“玩家搜索房间”
  5. 中的玩家ID下
  6. 因为玩家已经在“玩家搜索房间”下收听了他自己的ID,所以当房间ID按照他自己的ID推送时,将运行一个功能。这将告诉玩家Cloud功能为他成功找到了一个房间。
  7. 以下是云功能:

    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似乎每次都有效,但有时云功能从不将房间ID附加到玩家ID,有时云功能会创建比应有的更多的房间。我只是通过在每次单击时在“Players Searching For Room”下附加随机ID的按钮来测试这个。然后我快速点击该按钮10次。这应该为这10个随机ID附加5个不同的房间ID,并生成5个新房间。相反,它生成了7个房间,并且只为8个随机ID添加了房间ID,而不是10个。

    问题是,我认为:

    1. Abe点击12.00.00
    2. 加入游戏按钮
    3. 云功能启动(执行需要5秒)
    4. Rob点击12.00.02
    5. 加入游戏按钮
    6. 云功能在完成Abe的请求之前再次触发
    7. Eveything变得混乱
    8. 是否可以使用firebase来改变这一点,以便如果Rob在Abe的请求完成之前触发Cloud功能,Rob将在Abe完成时被搁置。当安倍晋三完成而不是罗伯的回合。唉,非常长的解释希望有人会读到这个:)

1 个答案:

答案 0 :(得分:1)

在Google I / O 2017上,我发表了关于在后端仅使用Firebase构建多人游戏的演讲。云功能几乎实现了游戏的所有逻辑。它还具有简单的匹配功能,您可以扩展该方案以执行更复杂的操作。您可以观看演讲here,该项目的源代码即将推出。