OpenSpace & NPCs

Post here your questions about the OpenSpace 1.x or notify bugs and suggestions.

Moderators: Lapo, Bax

User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

OpenSpace & NPCs

Postby Bax » 05 Feb 2009, 18:26

A recurring question about OpenSpace is related to NPCs (Non-Player Characters): can NPCs implemented in OpenSpace?

First of all we have to differentiate between NPCs which simply stand on a tile, and NPCs which are able to walk around.
The first kind of NPCs can easily be implemented in OpenSpace. In this case the NPC is just a "skin" assigned to a tile, and it can have its own logic in an associated custom class.

For the second kind of NPCs the answer is more complex. SmartFoxServer has a server-side API which allows you to create NPCs. In order to make this "fake users" appear on the map as avatars, some special user variables must be set (see below). What about making them move around?
When a user clicks on a tile on the client, OpenSpace calculates the path and sends it to the other clients, instead of sending the destination coordinates only (otherwise each client would have to calculate the paths of all the moving avatars, making the Flash Player performance drop).
So if we talk about NPCs, to move them around a pathfinding algorithm should be executed in a server-side extension and the whole path should be sent to all the clients. This means that the map xml must be parsed on the server-side.

The following post describes which data should be sent to the clients to make the NPCs' avatars appear and move around.
Last edited by Bax on 05 Feb 2009, 19:00, edited 1 time in total.
Paolo Bax
The SmartFoxServer Team
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 05 Feb 2009, 18:37

In order to make an avatar appear in OpenSpace the following user variables must be set:
_os_px: the x coordinate of the tile on which the avatar must appear
_os_py: the y coordinate of the tile on which the avatar must appear
_os_pz: the z coordinate of the tile on which the avatar must appear
_os_type: the avatar identifier (the same string that must be passed to the OpenSpace.createMyAvatar method to generate the proper avatar - see the OpenSpace configuration description)

The following code shows a simple server-side zone extension which creates an NPC and makes it appear in OpenSpace. For sake of simplicity the NPC is created upon receiving a client request containing the x and y coordinates of the tile on which the NPC's avatar should appear.

Code: Select all

package com.smartfoxserver.openspace;

import java.util.HashMap;

import it.gotoandplay.smartfoxserver.data.User;
import it.gotoandplay.smartfoxserver.data.UserVariable;
import it.gotoandplay.smartfoxserver.events.InternalEventObject;
import it.gotoandplay.smartfoxserver.exceptions.ExtensionHelperException;
import it.gotoandplay.smartfoxserver.extensions.AbstractExtension;
import it.gotoandplay.smartfoxserver.extensions.ExtensionHelper;
import it.gotoandplay.smartfoxserver.lib.ActionscriptObject;

public class NPCTestExtension extends AbstractExtension
{
   User npcUser;
   ExtensionHelper api;

   String serverIp = "127.0.0.1";
   int serverPort = 9339;
   
   public void init()
   {
      api = ExtensionHelper.instance();
   }

   public void handleRequest(String cmd, ActionscriptObject params, User sender, int roomId)
   {
      if (cmd.equals("createNpc"))
      {
         // Retrieve NPC coordinates from client request
         String npcPx = params.getString("px");
         String npcPy = params.getString("py");
         
         // Create NPC
         npcUser = api.createNPC("", serverIp, serverPort, getOwnerZone());
         
         // Make the NPC join a room
         Boolean joined = true;
         try
         {
            api.joinRoom(npcUser, -1, roomId, true, null, false, true);
         }
         catch (ExtensionHelperException e)
         {
            joined = false;
         }
         
         if (joined)
         {
            // Set NPC user variables to make it appear on the OpenSpace map
            setupNpc(npcUser, npcPx, npcPy);
         }
      }
   }

   private void setupNpc(User u, String px, String py)
   {
      HashMap<String, UserVariable> vars = new HashMap<String, UserVariable>();
      
      vars.put("_os_type", new UserVariable("dummy", UserVariable.TYPE_STRING));
      vars.put("_os_px", new UserVariable(String.valueOf(px), UserVariable.TYPE_NUMBER));
      vars.put("_os_py", new UserVariable(String.valueOf(py), UserVariable.TYPE_NUMBER));
      vars.put("_os_pz", new UserVariable(String.valueOf(0), UserVariable.TYPE_NUMBER));

      api.setUserVariables(u, vars, true);
   }

   public void handleRequest(String cmd, String[] params, User u, int fromRoom)
   {
      
   }
   
   public void handleInternalEvent(InternalEventObject evt)
   {
      
   }
}


Please notice that the user variables which are significant to OpenSpace are set AFTER the NPC joins the room.
Last edited by Bax on 19 Feb 2009, 14:47, edited 2 times in total.
Paolo Bax
The SmartFoxServer Team
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 05 Feb 2009, 18:59

In order to make the avatar move, first of all you have to check the messages exchanged between clients. If you turn on the debugging in the SmartFoxClient instance, when the avatars of the other users move your client will receive the following message:

Code: Select all

[ RECEIVED ]: <msg t='sys'><body action='dataObj' r='11'>
<user id='1' /><dataObj><![CDATA[<dataObj><var n='cmd' t='s'>_os_move</var><var n='data' t='s'>{&quot;rmv&quot;:0,&quot;ipy&quot;:25,&quot;ipz&quot;:0,&quot;fpz&quot;:0,
&quot;path&quot;:[0,0,7,7,0,0,0,1,2,2,2,0,0,1],&quot;fpy&quot;:22,&quot;ipx&quot;:22,
&quot;fpx&quot;:11}</var></dataObj>]]></dataObj></body></msg>


This message is sent through a call to the client-side SmartFoxClient.sendObject method. The parameters' object passed to the method contains two properties, "cmd" and "data".
cmd contains the string _os_move, while data contains the json representation (you have to encode it) of an object containing the following properties:
ipx, ipy and ipz: the map coordinates of the path starting tile;
fpx, fpy and fpz: the map coordinates of the path ending tile;
rmv: in case the current movement interrupts a previous movement before it is completed, rmv contains the number of "steps" that the clients should discard from the previous path (you can probably set it to 0 always);
path: an array containing the list of steps that the avatar must do to go from the starting tile to the ending tile; each step is represented by a direction (from 0 to 7) where:
Image
OpenSpace makes use of the Breadth-first algorithm: http://en.wikipedia.org/wiki/Breadth-first_search
The above described data must be sent to all the clients in the same room of the NPC, through the server-side API. As the sendObject method is not available on the server-side, you will have to use the sendGenericMessage method replicating the same xml structure shown above.

At the same time, the user variables storing the avatar position (see previous post) must be updated with the path's final coordinates, so that new users entering the same room will see the NPC in its final position.
Paolo Bax
The SmartFoxServer Team
dalanchoo
Posts: 5
Joined: 29 Jan 2009, 19:51

Server Pathfinding

Postby dalanchoo » 05 Feb 2009, 20:28

Thanks for posting this thread. It is quite useful. However, there are a few questions that I still have.

The main reason for wanting to use OpenSpace for an NPC is to have it calculate the path for you. It sounds like in order to make an NPC move, the server will have implement its own A* or depth first search, and then send the appropriate variables to the clients telling them how to move the avatar. This negates a lot of the purpose of having OpenSpace, if you have to implement your own pathfinding.

In addition, I don't know how you would do pathfinding on the server, since the server does not know the layout of the terrain. If OpenSpace is solely a client side component, how does the server know not to walk an NPC through a wall or lake? I don't see how the server would even know the size and number of tiles, or their aspect ratio etc.

You hinted that the programmer should implement his own logic to parse the MXL file on the server:

So if we talk about NPCs, to move them around a pathfinding algorithm should be executed in a server-side extension and the whole path should be sent to all the clients. This means that the map xml must be parsed on the server-side.


Are you suggesting that the server essentially have its own copy of the xml file (which seems reasonable), and that the server side extension programmer write code to parse this XML file, and then use the parsed data in his own custom pathfinder? This seems like a lot of work, and I don't see how the custom server pathfinding solution would necessarily generate the same path as the client. The client already has a perfectly good routine for doing all of this stuff. I just want to be able to access the same logic!

In my mind, the way I expect the pathfinding to work would require a client and a server component. The client component could be exactly the same as OpenSpace is now. The server component would contain the pathfinding logic and logic to parse the XML file.

So all of the logic for doing the pathfinding would be extracted out of OpenSpace and put into its own library. This library would be included into the OpenSpace client, but could also be available to the server (probably needs to be ported to java). The server could then run the exact same logic that clients do to determine paths. After the path has been computed, it is sent to each client, which then makes the NPC follow the received path.

The general flow I envision:
1.) First user logs into a room. The server spawns and NPC and replicates it to the client.
2.) The server figures out where it wants to move the NPC to.
3.) The server runs the cool OpenSpace pathfinding routine, which is now has access to. It then the resulting path to the client for the client to follow.

I hope this makes sense. This is how I'm used to doing things, coming from a game development background. I know we want to run as much as possible on the client, but I don't see how we can get away from having the server compute the path of NPCs.

Thanks for all the info
John Lawrie
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 05 Feb 2009, 21:41

Are you suggesting that the server essentially have its own copy of the xml file (which seems reasonable), and that the server side extension programmer write code to parse this XML file, and then use the parsed data in his own custom pathfinder? This seems like a lot of work, and I don't see how the custom server pathfinding solution would necessarily generate the same path as the client. The client already has a perfectly good routine for doing all of this stuff. I just want to be able to access the same logic!

Yes, you have to parse the map XML file and create your own pathfinding routine. If you implement the Breadth-first algorithm, you will obtain the same path. And even if you generate a different one, this is not an issue as long as it is a valid one.
OpenSpace is a client-side application, you can't use it on the server-side. The only way to reproduce the same features is to implement them in your server-side extension.

In my mind, the way I expect the pathfinding to work would require a client and a server component. The client component could be exactly the same as OpenSpace is now. The server component would contain the pathfinding logic and logic to parse the XML file.

The flow you envision is perfect... but OpenSpace was created to be compatible with both SmartFoxServer Pro and Basic. SFS Basic doesn't support server-side extensions.
Paolo Bax
The SmartFoxServer Team
aniche
Posts: 4
Joined: 07 Dec 2009, 14:07

sendGenericMessage

Postby aniche » 07 Dec 2009, 14:10

hi
thanks for your helpful post
i managed to show the npc on openspace
and trying to move it around

the sendGenericMessage is definedL

public void sendGenericMessage(java.lang.String message,
java.nio.channels.SocketChannel sender,
java.util.LinkedList channelList)

how do i populate the channelList with users in the room?
thanks
uri
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 07 Dec 2009, 14:29

Each User object has the getChannel() method.
Paolo Bax
The SmartFoxServer Team
mikih
Posts: 11
Joined: 17 Jan 2008, 19:30

sending path does not move npc

Postby mikih » 11 Dec 2009, 12:48

Hi there,

we are currently creating a prototype were we want to simulate npc's that can be selected to follow the avatar.

I tried to send a self made _os_move like that one above and do send it as a generic message to all users in the zone... ( we are not going to implement a breadth first technic on the server site)

NPC's still dont move on the openspace tiles :)


@aniche: Did you got it running probably? I would appreciate if you can help us. Maybe we can share some testcases.


Thanks a lot!

Florian
aniche
Posts: 4
Joined: 07 Dec 2009, 14:07

Path

Postby aniche » 14 Dec 2009, 09:20

bax, thanks for answering
i got my npc moving fine,
for now i would just like it to follow an active player
so i would need a way to get the path that is already generated to that player,
is there a way to get it?
besides that it could be nice if the generate path function of openspace client could be used to send the path back to the server inside the object sent in sendXtMessage.

@mikih, be happy if we can help each other, where are you stuck?
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 17 Dec 2009, 08:31

so i would need a way to get the path that is already generated to that player, is there a way to get it?

The path is sent by the user client through the sendObject method. Your NPC client receives the onObjectReceived event containing the path data, so you should be able to access it.
Paolo Bax
The SmartFoxServer Team
brian.heylin
Posts: 2
Joined: 18 Dec 2009, 07:24
Location: Amsterdam
Contact:

NPC using a mock SmarkFoxClient

Postby brian.heylin » 18 Dec 2009, 14:57

Hi i've gone a little further here. I needed to mock the SmartFoxClient as Im using OS to make an offline demo for a client, that should not depend on starting a SmarFoxServer.

So the mocking is fine I extended SmartFoxClient and override all methods.

This means I now have to act like the server. In This case what to I need to do to emulate the server?

When I dispatch a join room event OpenSpaces resets itself. What events does OpenSpaces receive when an NPC joins?
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Postby Bax » 19 Dec 2009, 13:42

Sorry, but this is far beyond the support we can give on OpenSpace. I can only say that OS handles the following SmartFoxServer events:
SFSEvent.onJoinRoom
SFSEvent.onUserVariablesUpdate
SFSEvent.onUserLeaveRoom
SFSEvent.onObjectReceived
SFSEvent.onPublicMessage
SFSEvent.onPrivateMessage
Paolo Bax
The SmartFoxServer Team
aniche
Posts: 4
Joined: 07 Dec 2009, 14:07

onObjectReceived return object

Postby aniche » 21 Dec 2009, 09:55

hi bax

Your NPC client receives the onObjectReceived event containing the path data


i can't find documentation on how to get the path from this object

also it seems that the same client who generated this object with the path, can't get this path because onObjectReceived isnt called
User avatar
Bax
Site Admin
Posts: 4609
Joined: 29 Mar 2005, 09:50
Location: Italy
Contact:

Re: onObjectReceived return object

Postby Bax » 24 Dec 2009, 09:03

aniche wrote:also it seems that the same client who generated this object with the path, can't get this path because onObjectReceived isnt called

That's right. That event is fired on the other clients only.
Paolo Bax
The SmartFoxServer Team
laxersaz
Posts: 50
Joined: 30 Nov 2009, 16:19
Contact:

Postby laxersaz » 05 Jan 2010, 16:24

Is there any way for a client to get the calculated path for himself? That would be the easiest way to let map elements follow the player's avatar - which we want to achieve.

Return to “OpenSpace v1 discussions and help”

Who is online

Users browsing this forum: No registered users and 30 guests