Duplicate MMOItem

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

Moderators: Lapo, Bax

trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Duplicate MMOItem

Postby trianglehead » 03 Jul 2022, 23:05

Hi. I have no idea how this happens, but it happens every few times a day. I have a car that is an MMOItem, and once in a while the client would receive duplicate MMOItem in the onProxUpdate callback. In the screenshot I show an ID of 0, which occurred 2 times which causes problems.

I create MMO Items on the server like this

Code: Select all

      
      BaseMMOItem item = new MMOItem();
      ...
      mmoApi.setMMOItemPosition(item, new Vec3D(x, y, z), room);
      mmoApi.setMMOItemVariables(item, vars);


And as far as I know, the MMOItem.id is autogenerate so I don't know how it can have a duplicate id...

My smartfox version is
SFS2X-Patch-2.16.0
Attachments
Screenshot 2022-07-03 170845.jpg
(193.84 KiB) Not downloaded yet
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 04 Jul 2022, 08:40

Hi,
is there any specific action/request that seems to trigger this issue in your game?
Version 2.16.0 is already 2 years old, it would be interesting to see if the issue can be reproduced on a recent release, such as 2.18.x

We've done a significant amount of work with the MMOApi, in terms of demos and stress tests and we don't have a record of similar issues happening, so there might be something special in your use case. Can you describe a bit more in detail how your game works? In particular how MMOItems are created and updated during the game.
If you prefer to keep it confidential you can get in touch with us via our support@... email, adding a reference to this thread.

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 18 Jul 2022, 19:29

Let me upgrade to latest and see what happens. Can I just copy my old Server.xml over to new version?

Thanks
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 19 Jul 2022, 09:11

It might work, but the proper way is to reconfigure the settings from scratch.
You can speed up the process if you open the two server.xml files (old and new) side by side and modify what is needed.

Cheers
Lapo

--

gotoAndPlay()

...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 20 Jul 2022, 17:31

Unfortunately v2.18.3 and latest client still has the same issue. But please note that while on the client in the screenshot you can see duplicated "addedItems" on the server, I have also debugged it by looking at room.getAllMMOItems(), in that list on the server, it does not have any duplicate items.

I also noted that this starts to happen when
List<IMMOItem> removedMMOItems = (List<IMMOItem>)evt.Params["removedItems"];
gets invoked, even though the MMOItem is right next to me, e.g. I'm driving the car, and randomly the onProxUpdate() event would fire and the mmoItem that I'm driving is in the "removedItems" list. So the car would just get destroyed, and the duplicate ID issue starts. Once that happens, it's very strange. I would walk a few steps away from the vehicle and it would re-appear, and when I get close to it, it would dissappear. Almost as if the server is confused where my AOI is.

Screenshot 2022-07-20 110140.jpg
(93.39 KiB) Not downloaded yet


This single server side method below is all I use for creating and updating MMOItems. The server will call this one time to create a new car. Then the client will call this anytime the player is driving the car by passing in the MMOItem ID.

Code: Select all

   public int setMMOItem(boolean isCreate, int id, String prefabName, Collection<Float> pos, Collection<Float> rot, MMORoom room, ISFSObject extraVars, String hc) {
      BaseMMOItem item = null;
      if (isCreate) {
         // Create the item
         item = new MMOItem();
      } else {
         // Get existing item
         item = room.getMMOItemById(id);
         if (item == null) {
            return -1;
         }
      }
      // Default variables
      List<IMMOItemVariable> vars = new LinkedList<IMMOItemVariable>();
      if (prefabName != null) {
         vars.add(new MMOItemVariable("prefabName", prefabName));
      }
      if(pos!=null) {
         SFSObject posRotObj = SFSObject.newInstance();
         posRotObj.putFloatArray("pos", pos);
         if (rot != null) {
            posRotObj.putFloatArray("rot", rot);
         }
         vars.add(new MMOItemVariable("pr", posRotObj));
      }else {
         if(isCreate) {// if creating an mmoitem, the position should not be null, or else where is it gonna be?
            throw new RuntimeException("setMMOItem isCreate but null position: " + id + " - " + prefabName);
         }
      }
      // Extra variables
      vars = sfsObjectToMMOItemVariables(extraVars, vars);
      

      // Set the variables
      item.setVariables(vars);

      // Access the MMO API
      ISFSMMOApi mmoApi = SmartFoxServer.getInstance().getAPIManager().getMMOApi();

      // Set the Item in the room at specific coordinates
      if(pos!=null) {
         Float[] attackerPos = pos.toArray(new Float[3]);
         float x = attackerPos[0];
         float y = attackerPos[1];
         float z = attackerPos[2];
         mmoApi.setMMOItemPosition(item, new Vec3D(x, y, z), room);
      }
      mmoApi.setMMOItemVariables(item, vars);

      
      return item.getId();

   }



On the client, there is the callback for creating

Code: Select all

    private void onProxUpdate(BaseEvent evt){
      // Deal with MMOItem removal when out of proximity range
      List<IMMOItem> removedMMOItems = (List<IMMOItem>)evt.Params["removedItems"];
      foreach (IMMOItem mmoItem in removedMMOItems) {
         if (MyMMOItem.mmoItemMap.ContainsKey(mmoItem.Id)) {
            MyMMOItem myMMOItem = MyMMOItem.mmoItemMap[mmoItem.Id];
            if (myMMOItem != null) {
               GameObject.Destroy(myMMOItem.gameObject);
            }
         }
      }

      // deal with MMO Items being in range of proximity
      List<IMMOItem> addedMMOItems = (List<IMMOItem>)evt.Params["addedItems"];
      foreach (IMMOItem mmoItem in addedMMOItems) {
         if (MyMMOItem.mmoItemMap.ContainsKey(mmoItem.Id)) {
            Debug.LogError("DUPLICATE MMOItem: " + mmoItem.Id);// this just should never happen, but it is.  addedMMOItems has multiple entries of same ID
         }

         // create the item
         MyMMOItem myMMOItem = createMMOItem(mmoItem);

         // process the item variables
         foreach (IMMOItemVariable mmoItemVariable in mmoItem.GetVariables()) {
            myMMOItem.processMMOItemVar(mmoItemVariable);
         }
      }
      ...
}


And this is how MMOItems are instantiated

Code: Select all

    private static MyMMOItem createMMOItem(IMMOItem mmoItem)
    {
        string itemName = mmoItem.GetVariable("prefabName").GetStringValue();
        GameObject go = MyUtil.instantiate(itemName);
        MyMMOItem myMMOItem = go.GetComponent<MyMMOItem>();
        myMMOItem.id = mmoItem.Id;

        //set initial position of creation
        Vec3D v = mmoItem.AOIEntryPoint;
        Vector3 pos = new Vector3(v.FloatX, v.FloatY, v.FloatZ);
        myMMOItem.transform.position = pos;

      // add to mmoItem Map so I can find the item by ID
      MyMMOItem.mmoItemMap.Add(myMMOItem.id, myMMOItem);

      return myMMOItem;
    }


this is how updates are handled

Code: Select all

    private void onMMOItemUpdate(BaseEvent evt)
    {
        List<string> changedVars = (List<string>)evt.Params["changedVars"];

        IMMOItem mmoItem = (IMMOItem)evt.Params["mmoItem"];
      MyMMOItem myMMOItem = null;
      if (MyMMOItem.mmoItemMap.ContainsKey(mmoItem.Id)) {
         myMMOItem = MyMMOItem.mmoItemMap[mmoItem.Id];
      } else {// if for any reason an mmoitem that exist on server but in my client does not exist, I need to instantiate the MMOItem object on the client side, just like how we do players
         myMMOItem = createMMOItem(mmoItem);
      }

      foreach (string changedVar in changedVars) {
         myMMOItem.processMMOItemVar(mmoItem.GetVariable(changedVar));// this just does what it needs to do with the vars
        }
    }
   
 
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 21 Jul 2022, 03:18

I don't have a small enough project to reproduce this. But I think this might be how you can reproduce it.

1.) Create an MMORoom that is this size:
new Vec3D(-11313, -2073, -10749), new Vec3D(14250, 4560, 12980)

2.) Make the room to have a small enough AOI like this size:
new Vec3D(220f, 220f, 220f)

3.) Then create an MMOItem

4.) Create a player

5.) Code it so that when the player is out of the AOI of the MMOItem or vise versa, the MMOItem will be destroyed.
Parent the player to the MMOItem so that whereever the MMOItem moves to, so will the player.
On the server when the mmoItem is moving
setMMOItemPosition( thePosition);
and
mmoAPi.setUserPosition( thePosition)
This is to ensure the player is always going to be in the same AOI as the MMOItem, as the player is riding the "car" the car should never dissappear.

6.)
Now make the MMOItem move across several "sectors" so that is it in different AOI. Move it quick enough a few times and the MMOItem will get destroyed as if it is out of the player's AOI.
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 23 Jul 2022, 08:25

Thanks.
Points #5 and #6 are not very clear to us.

Parent the player to the MMOItem so that whereever the MMOItem moves to, so will the player.

Maybe you mean the opposite? Because it's the player that is moving around, I'd expect.
But in any case I still don't understand the logic behind this particular MMOItem:

Code it so that when the player is out of the AOI of the MMOItem or vise versa, the MMOItem will be destroyed.

Here you say that the MMOItem should be destroyed when it goes out of the AOI but two lines later you write:
This is to ensure the player is always going to be in the same AOI as the MMOItem, as the player is riding the "car" the car should never dissappear.

If player and MMOItem are locked in the same AOI what's the point of the first statement?

Another question:
Now make the MMOItem move across several "sectors" so that is it in different AOI. Move it quick enough a few times and the MMOItem will get destroyed as if it is out of the player's AOI.

What do you mean by "quick enough"?
Can the MMOItem jump from place to another in a "discontinuous" way (i.e. be teleported) rather than moving across the map at a certain speed?

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 23 Jul 2022, 17:26

Lapo wrote:Thanks.
Points #5 and #6 are not very clear to us.

Parent the player to the MMOItem so that whereever the MMOItem moves to, so will the player.

Maybe you mean the opposite? Because it's the player that is moving around, I'd expect.
But in any case I still don't understand the logic behind this particular MMOItem:



Code it so that when the player is out of the AOI of the MMOItem or vise versa, the MMOItem will be destroyed.

Here you say that the MMOItem should be destroyed when it goes out of the AOI but two lines later you write:
This is to ensure the player is always going to be in the same AOI as the MMOItem, as the player is riding the "car" the car should never dissappear.

If player and MMOItem are locked in the same AOI what's the point of the first statement?



Another question:
Now make the MMOItem move across several "sectors" so that is it in different AOI. Move it quick enough a few times and the MMOItem will get destroyed as if it is out of the player's AOI.

What do you mean by "quick enough"?
Can the MMOItem jump from place to another in a "discontinuous" way (i.e. be teleported) rather than moving across the map at a certain speed?

Thanks

The way the game works is that normally the player will walk around, but when they enter the vehicle, the vehicle which is an MMOItem will be the thing that moves, and the players who are sitting in the vehicle are children of the vehicle. So as the vehicle moves, the players will as in real life move at the same speed as the vehicle that is moving. The player is no longer walking, they are just sitting in the vehicle and riding it.

The players riding the car should always be in the AOI, but players who are not in the car, on their screen the car will be destroyed when the car exits the AOI. This first statement is simply talking about setting up the callback so vehicle/mmoitems that exit the AOI will get destroyed. This is how it should behave.

The later statement is talking about as the vehicle moves, the MMOitem position is set, that's why it's broadcasted to the world so everyone sees the vehicle moving, but we also need to remember that the players are moving on the client side with the vehicle simply because they player.transform.parent is locked on the vehicle, but the server does not know the players position is moving, so we need to ensure the players riding on the vehicle is setting their positions on the server side, or else even tho on the client side, you see the player at the same position as the vehicle, on the server the mmoitem(vehicle) has a position of e.g. 100,100,100. But the player's position is still at 0,100,00, which would cause the player to be out of range from the vehicle's AOI.

No the car should never teleport, but I manage to reproduce this issue by moving the vehicle in the editor really fast b/t several "sectors".

If I'm not explaining this properly please let me know, I'll try to setup a sample project that reproduces this issue.
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 25 Jul 2022, 08:59

Thanks, this clarifies the use case.
Just as a side note, I was wondering if this could be simplified. As you said when the player is in the vehicle you use a different approach on the client side (where player is locked on the parent) than the server side where there is no such auto lock-on.

I am wondering if from the server side perspective there's a need to move two entities (car + player) rather than one. Wouldn't it be better to just remove the MMOItem (i,e. the car) from the server-side view and just use the player as the single entity representing Player-in-the-car?

On client side you will still render both things as you're already doing, but this would save extra calls (and entities) on the SFS side instead of keeping the two objects in synch at all times.
When the player enters the car you remove the car from the server side but you also set a UserVariable on the Player that says "player is driving a car", so that clients will keep showing both.
When the player leaves the vehicle you reset the variable and place the MMOItem to represent the parked car.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 25 Jul 2022, 13:21

Hi thx for writing back. Your idea is what we did with a other type of vehicle, e.g. skateboard. However, we opted to use mmoitem for the latest vehicle because the new vehicles have many states, e.g. players can customize the vehicle to have attachments like rams, tails, wings, turrets, these attachments can have different positions and states, and stats, like durability, damage, speed enhancement, etc. the vehicles also have stats like damage, life, etc. All of that is stored in the mmoitem variables, so when State changes, all players can see the change and mmoitem does this job really well. So if we remove the mmoitem when a player enters, we would have to transfer the variables to user variable and if player disconnects we would have to handle it too by recreating the mmoitem and transfering the states back, it almost defeats the point of using mmoitem. We are so close, everything about mmoitem is working so well for our use case. Except the issue where the mmoitem intermittently gets destroyed while player is driving because the callback gets triggered with "removedItems" containing the vehicle the player is driving. Which I can't figure out why, because the player is just a few coordinates next to the vehicle at all times.

I just want to add, when thus anomaly occurs, it is some times so strange that this is the scenario

1. Player is driving normally, everything is fine
2. Vehicle dissappear
3. Player walks away x distance.
4 vehicle reappears
5. Player walks towards vehicle
6. Vehicle dissappear

It is almost as if the AOI got confused. When this happens i tried setting the mmoitem.setposition(), just to make sure it is at the correct position, but it doesnt help. Once this happens to an mmoitem, it stays in this broken state. Current workaround is to remove the mmoitem and recreate it. Which is not ideal.
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 26 Jul 2022, 07:45

Thanks, this allows us to better understand the use case.
As regards the vehicle state being transferred to the Player, I see what you mean. I think it could be implemented fairly easily as all of the car's properties could be copied to the Player's variables as a single SFSObject, but in any case that's not the point of this discussion.

We'll try to setup a use case similar to what you have described and see if we can reproduce it.

Last questions:
Are the positional updates for the player and vehicle (i.e. the setUserPos./setMMOItemPos. calls) invoked from client or server side?
What's the update rate (from client to server) of the vehicle movement?
Finally, is there a minimum amount of players in the AOI necessary for this issue to occur? Or, say, two players is enough?

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 26 Jul 2022, 13:14

Thanks for the help. Yes what you suggest might work, but it seems more like a workaround than using mmoitem as intended IMO.

I do find it alot easier to reproduce in production than locally. But I think 2 players can be done too. I have tried setting mmoitem position and player position on server, e.g. anytime the mmoitem position is set, I would set the position of player to same position. That didn't seem to solve it. I need to look into that today once more as I was getting tired when I tried that, so could have done it wrong. But currently we have it set on client. The update rate is every 250ms max.
User avatar
Lapo
Site Admin
Posts: 22516
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Duplicate MMOItem

Postby Lapo » 02 Aug 2022, 14:06

Quick update:
We have setup a test as per your description where we can run around the map with the player connected to an MMOItem that follows at the same position but we have not seen any strange behaviors or disappearances.
We have tested locally and online with different AOIs to see if it mattered but it doesn't seem to make a difference.

I think it'd be best if you could provide a repro-case that can trigger the issue.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
trianglehead
Posts: 85
Joined: 13 Aug 2016, 04:28

Re: Duplicate MMOItem

Postby trianglehead » 02 Aug 2022, 14:53

Thanks so much for the effort. Once I get the time I will do that.

Return to “SFS2X Questions”

Who is online

Users browsing this forum: No registered users and 44 guests