Sending extension request right after ROOM_JOIN event error

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

pedroplaykids
Posts: 9
Joined: 27 Feb 2019, 19:58

Sending extension request right after ROOM_JOIN event error

Postby pedroplaykids » 21 Mar 2019, 17:23

Hello,

I'm having an error when I send an extension request on my client ROOM_JOIN event, saying that this user can't send an extension request because he's not at that room, but I've received the ROOM_JOIN event.

Which event can I use to determine when the server is ready to receive player extension requests?

Best regards,
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Sending extension request right after ROOM_JOIN event error

Postby Lapo » 22 Mar 2019, 09:17

Hi,
can you show me the code you're using for the ROOM_JOIN event?
Also can you specify which client you're using, version of the API and version of SFS2X in use?

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
pedroplaykids
Posts: 9
Joined: 27 Feb 2019, 19:58

Re: Sending extension request right after ROOM_JOIN event error

Postby pedroplaykids » 22 Mar 2019, 14:37

Hi Lapo,

Yep! I have two separate clients:

- Unity client -> used by players (Unity, SFS2x 1.7.9.0)
- Stress Test client -> used internally to create a lot of CCU (Kotlin, I don't know the SFS2x client API version, is the same as your stress test. I'll update to the latest)

The problems happen on both clients, so I'll talk about the Stress Test since it's code is smaller. This excerpt (based on the stress test article found on SFS2x blog) initializes the SmartFox object and attaches to the ROOM_JOIN event:

Code: Select all

override fun startUp(userName : String) {
        sfs = SmartFox()
        cfg = ConfigData()
        evtListener = SFSEventListener()

        cfg!!.host = "127.0.0.1"
        cfg!!.port = 9933
        cfg!!.zone = "PlayKidsXD"

        this.userName = userName

        sfs!!.addEventListener(SFSEvent.CONNECTION, evtListener)
        sfs!!.addEventListener(SFSEvent.CONNECTION_LOST, evtListener)
        sfs!!.addEventListener(SFSEvent.LOGIN, evtListener)
        sfs!!.addEventListener(SFSEvent.ROOM_JOIN, evtListener)
        sfs!!.addEventListener(SFSEvent.PUBLIC_MESSAGE, evtListener)

        sfs!!.connect(cfg!!)
}


In the same class we have the following method that listens to the requests:

Code: Select all

inner class SFSEventListener : IEventListener {
        @Throws(SFSException::class)
        override fun dispatch(evt: BaseEvent) {
            val type = evt.type
            val params = evt.arguments

            println("Event received " + type)

            if (type == SFSEvent.CONNECTION) {
                val success = params["success"] as Boolean

                if (success)
                    sfs!!.send(LoginRequest(userName))
                else {
                    System.err.println("Connection failed")
                    cleanUp()
                }
            } else if (type == SFSEvent.CONNECTION_LOST) {
                println("Client disconnected. ")
                cleanUp()
            } else if (type == SFSEvent.ROOM_JOIN) {
                println("parameters: " + params)
                userVariableTask = sched.scheduleAtFixedRate(
                    UserVariableTask(sfs!!, userName),
                    INITIAL_DELAY.toLong(),
                    USER_VARIABLES_MESSAGE_PERIOD.toLong(),
                    TimeUnit.MILLISECONDS)

                keepAliveTask = sched.scheduleAtFixedRate(
                    KeepAliveTask(sfs!!, userName),
                    INITIAL_DELAY.toLong(),
                    KEEP_ALIVE_MESSAGE_PERIOD.toLong(),
                    TimeUnit.MILLISECONDS)

                equipItemsTask = sched.scheduleAtFixedRate(
                    EquipItemsTask(sfs!!, userName),
                    INITIAL_DELAY.toLong(),
                    EQUIP_MESSAGE_PERIOD.toLong(),
                    TimeUnit.MILLISECONDS)

                buyItemsTask = sched.scheduleAtFixedRate(
                    BuyItemsTask(sfs!!, userName),
                    INITIAL_DELAY.toLong(),
                    BUY_MESSAGE_PERIOD.toLong(),
                    TimeUnit.MILLISECONDS)

                sched.schedule(
                    ResetInventoryTask(sfs!!, userName),
                    INITIAL_DELAY.toLong() - 2000,
                    TimeUnit.MILLISECONDS)

            } else if (type == SFSEvent.ROOM_REMOVE) {
                println("Client " + userName + " removed from room.")
            }
        }
    }


When I receive the ROOM_JOIN event if I sent the extension requests without delay I get the described error on the server side.

The delay solution is very unreliable and inefficient, so how can I deterministically ensure that the server considers that this user is ready to send extension requests if I already received the ROOM_JOIN event?

Best regards,
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Sending extension request right after ROOM_JOIN event error

Postby Lapo » 22 Mar 2019, 15:05

Hi,
the code seems incomplete.
I don't see a handler for the LOGIN and LOGIN_ERROR event. Did you remove them?

Also I don't see the actual code that sends an Extension request.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
pedroplaykids
Posts: 9
Joined: 27 Feb 2019, 19:58

Re: Sending extension request right after ROOM_JOIN event error

Postby pedroplaykids » 22 Mar 2019, 19:20

Hi Lapo,

yes, it is incomplete. The code contains the relevant parts. Why do you need the LOGIN/LOGIN_ERROR events? The user in question is logged in if not the error wouldn't be that he isn't able to send extension requests to the room.

The extension request is encapsulated in these classes, here is a simple one:

Code: Select all

package sfs2x.example.stresstest.tasks

import com.smartfoxserver.v2.entities.data.SFSObject
import sfs2x.client.SmartFox
import sfs2x.client.requests.ExtensionRequest
import java.lang.Exception

class ResetInventoryTask(smartFox: SmartFox, clientName: String) : BaseTask(smartFox, clientName) {
    override fun run() {
        try {
            sfs.send(ExtensionRequest(command, SFSObject(), sfs.lastJoinedRoom))
        }
        catch (e: Exception) {
            println("ERROR sending client keep alive: " + e.message)
        }
    }

    companion object {
        val command = "reset_inventory"
    }
}


If I remove the delay the problems occur. The question is:

Why can't I send extension requests as soon as I receive the ROOM_JOIN event? The delay solution is very unreliable and inefficient, so how can I deterministically ensure that the server considers that this user is ready to send extension requests if I already received the ROOM_JOIN event?

Best regards,
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Sending extension request right after ROOM_JOIN event error

Postby Lapo » 23 Mar 2019, 13:26

Hi,
pedroplaykids wrote:Hi Lapo,
Why can't I send extension requests as soon as I receive the ROOM_JOIN event?

There is no such limitation. You can call an Extension at any time once you have joined the Room, in fact a few of our examples do it.
I also did a quick test with e Java client to tripe-check and it works as expected. No errors.

Unless this is some strange behavior in Kotlin I have no idea why this would happen.
In the opening post you said this:
"I'm having an error when I send an extension request on my client ROOM_JOIN event, saying that this user can't send an extension request because he's not at that room, but I've received the ROOM_JOIN event."

1) can you double check via the AdminTool > Zone Monitor that the User is indeed joined in the Room?
2) can you copy/paste here the full stack trace of the error you're receiving?

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Sending extension request right after ROOM_JOIN event error

Postby Lapo » 25 Mar 2019, 08:35

As a small update to my previous post I have found a simple test client made in Kotlin that I made a while ago.
You can test it and see that there's no problem with regards to calling a Room Extension as soon as you join such Room.

Code: Select all

import com.smartfoxserver.v2.entities.data.SFSObject
import sfs2x.client.SmartFox
import sfs2x.client.core.BaseEvent
import sfs2x.client.core.IEventListener
import sfs2x.client.core.SFSEvent
import sfs2x.client.entities.Room
import sfs2x.client.requests.ExtensionRequest
import sfs2x.client.requests.JoinRoomRequest
import sfs2x.client.requests.LoginRequest
import sfs2x.client.util.ConfigData

class SFSEventListener : IEventListener
{
    override fun dispatch(evt: BaseEvent?)
    {

        when (evt?.type)
        {
            SFSEvent.CONNECTION -> onConnection(evt)
            SFSEvent.CONNECTION_LOST -> println("Connection lost")
            SFSEvent.LOGIN -> onLogin(evt)
            SFSEvent.LOGIN_ERROR ->onLoginError(evt)
            SFSEvent.ROOM_JOIN -> onRoomJoin(evt)
            SFSEvent.EXTENSION_RESPONSE ->onExtensionResp(evt)
        }
    }

    fun onConnection(evt:BaseEvent)
    {
        val success = evt.arguments.get("success") as Boolean

        if (success)
        {
            println("Connected to server...")
            sfs.send(LoginRequest("", "", cfg.zone))
        }

        else println("Connection failed!")
    }

    fun onLogin(evt:BaseEvent)
    {
        println("Logged in as: " + sfs.mySelf.name)
        sfs.send(JoinRoomRequest("The Lobby"));
    }

    fun onLoginError(evt:BaseEvent)
    {
        val errorMsg = evt.arguments.get("errorMessage");
        println("Login failed: ${errorMsg}")
    }

    fun onRoomJoin(evt:BaseEvent)
    {
        val room:Room = evt.arguments.get("room") as Room;
        println("Joined in Room: ${room.name}");

        callExtension();
    }

    fun onExtensionResp(evt:BaseEvent)
    {
        val params = evt.arguments.get("params") as SFSObject
        println("Result = " + params.getInt("res"))
    }

    fun callExtension()
    {
        val sfso = SFSObject()
        sfso.putInt("n1", 15)
        sfso.putInt("n2", 50)

        sfs.send( ExtensionRequest("sum", sfso, sfs.lastJoinedRoom) )
    }
}

val sfs = SmartFox()
val cfg = ConfigData()
val listener = SFSEventListener()

fun main(args: Array<String>)
{
    println("SFS2X API Version: ${sfs.version}")

    cfg.host = "127.0.0.1"
    cfg.port = 9933
    cfg.zone = "BasicExamples"
    cfg.isDebug = false

    sfs.setClientDetails("Kotlin", "")
    sfs.addEventListener(SFSEvent.CONNECTION, listener)
    sfs.addEventListener(SFSEvent.CONNECTION_LOST, listener)
    sfs.addEventListener(SFSEvent.LOGIN, listener)
    sfs.addEventListener(SFSEvent.LOGIN_ERROR, listener)
    sfs.addEventListener(SFSEvent.ROOM_JOIN, listener)
    sfs.addEventListener(SFSEvent.EXTENSION_RESPONSE, listener)

    // Start connection
    sfs.connect(cfg)
}
Lapo

--

gotoAndPlay()

...addicted to flash games
pedroplaykids
Posts: 9
Joined: 27 Feb 2019, 19:58

Re: Sending extension request right after ROOM_JOIN event error

Postby pedroplaykids » 25 Mar 2019, 20:48

Hi Lapo,

thanks for the reply. I didn't check the AdminTool > Zone Monitor to see if the User indeed joined the room, but please check the following stack trace/logs from the server where I'm able to reproduce the problem:

20:42:47,682 INFO [SFSWorker:Ext:4] com.smartfoxserver.v2.api.SFSApi - User login: { Zone: PlayKidsXD }, ( User Name: StressUser47, Id: 887, Priv: 0, Sess: 172.17.0.1:58674 ) , Type: Android
20:42:47,682 INFO [SFSWorker:Ext:4] Extensions - {PlayKidsXDZone}: StressUser47 joined zone.
20:42:47,822 INFO [SFSWorker:Ext:4] Extensions - {PlayKidsXDZone}: Creating a new room
20:42:47,823 INFO [SFSWorker:Ext:4] Extensions - {PlayKidsXDZone}: createNewRoom call:
20:42:48,045 INFO [SocketReader] com.smartfoxserver.bitswarm.sessions.DefaultSessionManager - Session created: { Id: 890, Type: DEFAULT, Logged: No, IP: 172.17.0.1:58676 } on Server port: 9933 <---> 58676
20:42:49,773 INFO [SFSWorker:Ext:4] com.playkids.xd.smartfox.extensions.room.RoomExtension - RoomExtension { Ext: PlayKidsXDRoom, Type: JAVA, Lev: ROOM, { Zone: PlayKidsXD }, [ MMORoom: XDRoom-169b697608f, Id: 36, Group: default, AOI: (100.0, 40.0, 100.0) ] } initialized
20:42:49,773 INFO [SFSWorker:Ext:4] com.smartfoxserver.v2.entities.managers.SFSRoomManager - Room created: { Zone: PlayKidsXD }, [ MMORoom: XDRoom-169b697608f, Id: 36, Group: default, AOI: (100.0, 40.0, 100.0) ], type = MMORoom
20:42:49,773 INFO [SFSWorker:Ext:4] Extensions - {PlayKidsXDZone}: room created!
20:42:49,773 INFO [SFSWorker:Ext:4] Extensions - {PlayKidsXDZone}: Room available, joining Room!
20:42:49,774 INFO [SFSWorker:Ext:4] com.smartfoxserver.v2.api.SFSApi - Room joined: [ MMORoom: XDRoom-169b697608f, Id: 36, Group: default, AOI: (100.0, 40.0, 100.0) ], { Zone: PlayKidsXD }, ( User Name: StressUser47, Id: 887, Priv: 0, Sess: 172.17.0.1:58674 ) , asSpect: false


20:42:52,218 WARN [SFSWorker:Ext:4] com.smartfoxserver.v2.controllers.v290.ExtensionReqController - com.smartfoxserver.v2.exceptions.SFSExtensionException: User cannot invoke Room extension if he's not joined in that Room. ( User Name: StressUser47, Id: 887, Priv: 0, Sess: 172.17.0.1:58674 ) , [ MMORoom: XDRoom-169b697608f, Id: 36, Group: default, AOI: (100.0, 40.0, 100.0) ]
com.smartfoxserver.v2.controllers.v290.ExtensionReqController.processRequest(ExtensionReqController.java:145)
com.smartfoxserver.v2.controllers.v290.ExtensionReqController$1.run(ExtensionReqController.java:68)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)


The exception occurs when the user receives the ROOM_JOIN event and I send an extension request without any delay. I don't think it's a language issue with Kotlin, this also occurs with our Unity C# client.

Best regards,
pedroplaykids
Posts: 9
Joined: 27 Feb 2019, 19:58

Re: Sending extension request right after ROOM_JOIN event error

Postby pedroplaykids » 25 Mar 2019, 21:32

Lapo,

the same problem occurs with NPCs in a different context:

20:42:37,168 INFO [DefaultDispatcher-worker-1] Extensions - {PlayKidsXDRoom}: NPC Joining Room: Laura Kinney
20:42:37,171 INFO [DefaultDispatcher-worker-1] com.smartfoxserver.v2.api.SFSApi - Room joined: [ MMORoom: XDRoom-169b69731ba, Id: 35, Group: default, AOI: (100.0, 40.0, 100.0) ], { Zone: PlayKidsXD }, ( User Name: Laura Kinney, Id: 859, Priv: 0, Sess: NO_IP ) , asSpect: false

20:42:37,172 INFO [SFSWorker:Ext:1] com.smartfoxserver.v2.entities.managers.SFSRoomManager - Room created: { Zone: PlayKidsXD }, [ MMORoom: XDRoom-169b69731ba, Id: 35, Group: default, AOI: (100.0, 40.0, 100.0) ], type = MMORoom
20:42:39,343 WARN [SFSWorker:Ext:4] com.smartfoxserver.v2.entities.managers.SFSExtensionManager - com.smartfoxserver.v2.exceptions.SFSRuntimeException:
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Exception: com.smartfoxserver.v2.exceptions.SFSRuntimeException
Message: ( User Name: Laura Kinney, Id: 859, Priv: 0, Sess: NO_IP ) is not joined in [ MMORoom: XDRoom-169b69731ba, Id: 35, Group: default, AOI: (100.0, 40.0, 100.0) ]
Description: Error during event handling: com.smartfoxserver.v2.exceptions.SFSRuntimeException: ( User Name: Laura Kinney, Id: 859, Priv: 0, Sess: NO_IP ) is not joined in [ MMORoom: XDRoom-169b69731ba, Id: 35, Group: default, AOI: (100.0, 40.0, 100.0) ] , Listener: { Ext: PlayKidsXDRoom, Type: JAVA, Lev: ROOM, { Zone: PlayKidsXD }, [ MMORoom: XDRoom-169b69731ba, Id: 35, Group: default, AOI: (100.0, 40.0, 100.0) ] }
+--- --- ---+
Stack Trace:
+--- --- ---+
com.smartfoxserver.v2.api.SFSMMOApi.setUserPosition(SFSMMOApi.java:93)
com.playkids.xd.smartfox.extensions.room.handlers.UserVariablesUpdateEventHandler$handleServerEvent$1.invokeSuspend(UserVariablesUpdateEventHandler.kt:48)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.kt:116)
kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:76)
kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:53)
kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:35)
kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
com.playkids.xd.smartfox.extensions.room.handlers.UserVariablesUpdateEventHandler.handleServerEvent(UserVariablesUpdateEventHandler.kt:26)
com.smartfoxserver.v2.extensions.SFSExtension.handleServerEvent(SFSExtension.java:259)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.dispatchEvent(SFSExtensionManager.java:768)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.dispatchRoomLevelEvent(SFSExtensionManager.java:710)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.dispatchRoomLevelEvent(SFSExtensionManager.java:723)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.handleServerEvent(SFSExtensionManager.java:898)
com.smartfoxserver.v2.core.SFSEventManager$SFSEventRunner.run(SFSEventManager.java:65)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

The update is question was this (exception is caused by mmoApi.setUserPosition(sfsUser, position, roomExtension.parentRoom) on SFSEventType.USER_JOIN_ROOM event if):

Code: Select all

class UserVariablesUpdateEventHandler(private val roomExtension: RoomExtension,
                                      private val mmoApi: ISFSMMOApi,
                                      private val profileService: ProfileService) : BaseServerEventHandler() {

  override fun handleServerEvent(event: ISFSEvent) { runBlocking {
    val sfsUser = event.getUser()

    if (event.type == SFSEventType.USER_VARIABLES_UPDATE) {
      val variables = event.getVariables().associateBy { it.name }

      if (variables.containsKey("x") && variables.containsKey("z")) {
        val position =
          Vec3D(
            variables["x"]?.doubleValue?.toFloat() ?: 0.0f,
            variables["y"]?.doubleValue?.toFloat() ?: 0.0f,
            variables["z"]?.doubleValue?.toFloat() ?: 0.0f)
        mmoApi.setUserPosition(sfsUser, position, roomExtension.parentRoom)
      }
    } else if (event.type == SFSEventType.USER_JOIN_ROOM) {

      if (sfsUser.isNpc){
        val variables = sfsUser.variables.associateBy { it.name }
          val position = Vec3D(
            variables["x"]?.doubleValue?.toFloat() ?: 0.0f,
            variables["y"]?.doubleValue?.toFloat() ?: 0.0f,
            variables["z"]?.doubleValue?.toFloat() ?: 0.0f)
        mmoApi.setUserPosition(sfsUser, position, roomExtension.parentRoom)

      } else {
        val username = sfsUser.name
        val context = UserRequestContext(username)

        val profile =
          profileService.find(context, username) ?:
          profileService.create(context, CreateProfileRequest(username = username, name = username))

        api.setUserVariables(sfsUser, profile.toUserVariables())
      }
    }
  } }

}


Notice that again, at the USER_JOIN_ROOM event (this time at server side) that the server throws an exception saying that the user haven't joined the room.

This problem is even worse because this NPC stays a zombie on the zone:

zone_capture.png
(22.86 KiB) Not downloaded yet


Best regards,
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Sending extension request right after ROOM_JOIN event error

Postby Lapo » 26 Mar 2019, 10:06

Hmm, this is a little confusing.
In your first post you showed us client side Kotlin code, and you said that you could not invoke a Room Extension as soon as the client joined the Room (via client calls).

I replied offering a Kotlin examples that does exactly what you asked for, and works as expected (i.e. no errors)

Now you're showing a pretty different scenario with server side generated NPCs and server side Kotlin code ... so before we proceed onto a new topic, can make sure that the original issue can be closed?

Did you check my example? It should work just fine for you as well.

As regards this:
The exception occurs when the user receives the ROOM_JOIN event and I send an extension request without any delay. I don't think it's a language issue with Kotlin, this also occurs with our Unity C# client.


Can you please provide the entire C# client code that causes the issue?
Alongside with the C# API version and SFS2X version?

Finally as regards the NPC issue, can we keep it on hold and deal with the C# problem first? Otherwise It's going to be difficult to discuss multiple issues in the same thread.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games

Return to “SFS2X Questions”

Who is online

Users browsing this forum: No registered users and 114 guests