How to get information from the outside world
Introduction
Most mscapes use a persons own private sensors (such as GPS and RFiD? ) and history (i.e. where they have been) to deliver the right thing in the right place and moment. You can now also use other sources of information to do this, such as the local weather, or someone else's position. You could even store information online and change it every day without having to change the mscape. This help page wil guide you through hooking up your mscape to a network. I.e. getting information from the internet and using it within a mscape. You can also download content such as images but that will be covered in a separate help page. In this example we will build a very simple mscape that finds the name of the nearest town or city.HttpRequester Object
This is the object that is used to download things from the internet. You can make as many of these as you need. It is best to make one object for each type of request you are going to make. So for example you might make one to get the local traffic information and another to get the location of other players. For this example we will just use one Http Requester object. To make a Http Requester object right click on tools and add the Http object. Then right click on that object and select add Http Requester. You will now have an object that can fetch things from the Internet.Making a simple request
The Http Requester object has a number of methods, most of them will cause it to query a web server and then return the requested data at some point. For this example we will use the most simple of those methods with is Get. For this example we will wait until the GPS has a fix and then use its first location to send a request for the nearest town or city name. To do this, start the mscape maker and then add the Http Requester object by adding Http to the tools section and then a Http Requester. Rename the Http Requester object to NameGetter. We will also need a TrueFalse called madeRequest, this can be added by right clicking on the State object in the left hand pane of the maker, make sure that MadeRequest starts false. All the other objects that we need are already there. We now need to wait until there is a valid GPS location that we can use to look up the place name. On the GPS'sOnLocation Event add the following code:if(MadeRequest.Value == false)
{
MadeRequest.Value = true;
NameGetter.Get("http://ws.geonames.org/findNearbyPlaceName?lat=" + GPS.Latitude + "&lng=" + GPS.Longitude);
// You will * NOT* have the result by now.
}
This will only be run once, since once we get our first OnLocation event then we change the TrueFalse to true and it will not run again. The line NameGetter.get..... is the line that causes the player to go off and make the request.
The actual request is made up out of two things, the URL of the web service that we want to talk to and some extra information about where we are. This is done by adding some text together to make a single longer bit of text that forms the final URL that goes out to the server. This request might take some time to complete, it could take several seconds. The rest of the mscape will keep runnin while this happens. So you should not assume in any line of script after this that you have automatically got the result. We will deal with the result in the next section of this example.
Dealing with the response from a request
Once we have made the initial request, the system will go off and talk to the outside world and wait for it to respond. Once it does respond one of two events will be triggered, either OnResponse or OnResponseFailed. If the system can not recover the data that was requested then the OnResponseFailed event will be triggered. If the request succedded then the OnResponse event will be triggered. For this example we will assume that the request works. The OnResponse event has two parameters, these are extra bits of information that can only be used durring that event handler. One of these parameters is called IncomingData. This parameter is an object with all the information that came back from the request. To read the data that has come back from the request we call methods on the IncommingData object. In this example we are after the place name for this location. A good place to start in understanding how to make sense of the data you have received and how to use it, is to look at the data that you get back in a web browser. For this example I will use a known location and just type the URL into a web browser to see what the data looks like. I will use this URL:http://ws.geonames.org/findNearbyPlaceName?lat=51.45&lng=-2.6The response from the server looks like this:
<geonames>
<geoname>
<name>Bristol</name>
<lat>51.45</lat>
<lng>-2.5833333</lng>
<geonameId>2654675</geonameId>
<countryCode>GB</countryCode>
<countryName>United Kingdom</countryName>
<fcl>P</fcl>
<fcode>PPL</fcode>
<distance>1.1549</distance>
</geoname>
</geonames>
From this we only actually want the country name which, in this case, is "United Kingdom". The IncommingData parameter has the full result but there are a number of ways of getting just the bit we want.
The system can read three different types of data XML, JSON and URL encoded form data. They are all treated the same in the rest of this example unless it's specifically mentioned that they are different.
Using IncommingData.FindTextNamed
The IncomingData paramter from the OnResponse event has a method called FindTextNamed this allows you to specify what you want and the method will make its best guess at your request and return it to you as a text. The response has to have some data that exactly matches the name you have supplied but capitalisation does not matter. The exact way the data is represented is not fixed for example if you use the line:IncomingData.FindTextNamed("countryName");
Then it will match all of the follow situations, if more than one is found it will use the first one:
<anything name="countryName" value="United Kingdom"/>
<anything name="countryName">
United Kingdom
</anything>
<countryName>
United Kingdom
</countryName>
If the data you want to read is relatively simple and you are sure it will not change in order then this is probably the easiest way to read and make sense of the incoming data. But it is not very processor efficiecent and therefore if you want to read lots of data from a very big response this might not be the best option. There are also methods for getting numbers and TrueFalse from the Incoming data in the same way. It will do the same level of matching but instead of returning some text it will return the correct type of information.<anything countryName="United Kingdom"/>
Using IncomingData.ConvertDataTo
As well as reading a single item at a time as we did in the section above, it is also possible to read the entire response in one go and convert it into a group or list of state objects. For example, create a Group in the State section called geoname or geonames and add to that group a text object called name, another called countryName and finally a number called distance. Note that the group can be called anything you like but the state objects must match the terms used in the HTTP response. We can then call:And all the values will be read in one go. Sometimes, HTTP responses will contain lists of data rather than, say, a single geoname. Look at the URL http://ws.geonames.org/postalCodeSearch?postalcode=9011&maxRows=10 for example, and notice that there are ten elements starting with the tag code. Using a StateList, we can read items from all ten elements in a single call. Create a StateList object called code (note that the name does matter here - it must match the name of the repeated element in the response) and add a text object called postalcode. CallIncomingData.ConvertDataTo(geoname);
and notice that the StateList now contains ten items each with a different postcode. You can find out more about making a list of state objects here: StateList. Note that the player is making a best-guess effort to match the structure of the StateList in the incoming data. Be careful - it is easy to get the structure slightly wrong and miss data. Also note that converting incoming data again will append any new values to the StateList. If you want to replace existing values, then simply clear the StateList first. Finally, it is worth noting that if the original data is url encoded form data then converting to a StateList will not work.IncomingData.ConvertDataTo(code);
Using IncomingData.FindTextByPath
This method uses technology called XPath to find the right thing within a response from a server. It is a very powerful but also rather complicated way to find what you want. If you think that the above two methods will not be sufficent for your requirements then you should do some indpendent reading about XPath and try that as a technique. There are a few changes to normal XPath in the mscape system:-
Default namespaces are completely ignored.
-
Other namespaces are not yet supported.
-
You can do XPath on JSON data but you need to start any full paths with "/json/".
-
If you want to navigate with a json list you will need to add another step in the path, each node within the list will be called the same name as the name of the list.
-
You can do XPath on form data but any full paths will have to start "/form/".