https://www.sirikata.com/wiki/index.php?title=Special:NewPages&feed=atom&hidebots=1&hideredirs=1&limit=50&offset=&namespace=0&username=&tagfilter=Sirikata Wiki - New pages [en]2024-03-28T18:08:18ZFrom Sirikata WikiMediaWiki 1.35.7https://www.sirikata.com/wiki/index.php?title=InstallationInstallation2012-05-26T02:10:23Z<p>Ewencp: Add note that installers are preferred</p>
<hr />
<div>== Downloading and Installing Sirikata ==<br />
<br />
Start by downloading the binary packages from the [http://sirikata.com/blog/download/ download page]. The installers are preferred and should just work. If you're having trouble with the installers or prefer installing manually, then follow the instructions below for your platform.<br />
<br />
=== Windows ===<br />
To run Sirikata, including the graphical client, you'll need to install two additional packages:<br />
*[http://www.microsoft.com/downloads/details.aspx?familyid=2DA43D38-DB71-4C1B-BC6A-9B6652CD92A3 DirectX End-User Runtime Web Installer]<br />
*[http://www.microsoft.com/downloads/details.aspx?FamilyID=a5c84275-3b97-4ab7-a40d-3802b2af5fc2 Microsoft Visual C++ 2008 SP1 Redistributable Package (x86)]<br />
<br />
With these installed, simply download the [http://sirikata.com/blog/download/ latest package]. Unzip it anywhere on your computer. You should then have directories that look like this:<br />
<br />
* sirikata_win32/<br />
* bin/<br />
* include/<br />
* lib/<br />
* share/<br />
<br />
Go into sirikata_win32/bin/ and run space.exe, then cppoh.exe. space.exe starts a space locally. It is private and will only use the objects you start. cppoh.exe is the client. By default, it loads up a few objects as well as your avatar. If everything worked, you should see a window pop up and start displaying the world.<br />
<br />
=== Mac OS X ===<br />
<br />
Download the [http://sirikata.com/blog/download/ latest package]. Unzip it anywhere on your computer. You should then have directories that look like this:<br />
<br />
* sirikata_mac/<br />
* Frameworks/<br />
* bin/<br />
* include/<br />
* lib/<br />
* share/<br />
<br />
Go into sirikata_mac/bin/ and run space, then cppoh.app. To run these, you likely need to set DYLD_LIBRARY_PATH, e.g.:<br />
<br />
cd sirikata_mac/bin<br />
./space<br />
<br />
space starts a space (world) locally. It is private and will only use the objects you start. cppoh.app is the client. By default, it loads up a few objects as well as your avatar. If everything worked, you should see a window pop up and start displaying the world.<br />
<br />
To run cppoh.app from the command line and add parameters, run it as<br />
<br />
./cppoh.app/Contents/MacOS/cppoh [--option=value]<br />
<br />
=== Linux ===<br />
<br />
==== Ubuntu ====<br />
<br />
Follow the link on the [http://sirikata.com/blog/download/ download page] and follow the instructions to install the packages from the PPA. The binaries (e.g. space, cppoh) will be installed in your PATH.<br />
<br />
==== Other Distributions ====<br />
<br />
Linux users on other distributions should [[GetTheCode|check out]] and [[BuildTheCode|build]] the code themselves. This process is scripted, so it should be simple even though it takes awhile.<br />
<br />
==== Configuration ====<br />
<br />
See the [[Keybindings]] page for information about how to control your object.<br />
<br />
When you first start the client, a window will pop up with the Ogre logo asking for some settings. Usually you only need to change two settings: from the top drop down, select 'OpenGL Renderer' and in the resulting option list chnage 'Fullscreen' to off. OpenGL is the more reliable default, but you may also try the Direct3D renderer (see 'Troubleshooting' below for more details).<br />
<br />
=== Troubleshooting ===<br />
<br />
* I'm getting the message 'This application has failed to start because d3dx9_42.dll was not found. Re-installing the application may fix this problem.'<br />
** You need to install the DirectX End-User Runtime. Make sure you've followed the instructions above.<br />
* Nothing is showing up.<br />
** Give it a minute or two on the first run. The default scene isn't small and the meshes need to be downloaded. On future runs, the content will be loaded from your local disk if possible, making it start up much more quickly. If, after a few minutes, still nothing shows up, get in touch with the developers as described below.<br />
* I'm getting a message that I don't have permissions to access a file when I try to run the space server.<br />
** Chances are you unzipped the sirikata package using Cygwin, which doesn't handle file permissions properly. Try unzipping using Windows' standard utilities.<br />
* The settings I chose for Ogre don't work and it doesn't pop up the configuration screen anymore.<br />
** You need to clear out your ogre.cfg file. On Windows you can find this under, e.g., C:\Users\Username\AppData\Local\Sirikata. Under Linux and Mac it should be under ~/.sirikata. Delete the file ogre. and the next time you run the configuration will pop up again.<br />
* I'm having another problem not covered here.<br />
** Get in touch with the developers on the [http://groups.google.com/group/platformtalk developer mailing list] or via IRC (#sirikata on irc.freenode.net).<br />
<br />
<br />
== Scripting Objects ==<br />
<br />
Once you've connected, you might want to try scripting some objects. Check out the [[Guides/Scripting Guide|Scripting Guide]] for more details.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/TOCGuides/TOC2012-05-25T23:14:26Z<p>Ewencp: Add basic TOC</p>
<hr />
<div>* [[Guides/Scripting Guide|Scripting Guide]]<br />
* [[Guides/Architecture|Sirikata's Architecture]]<br />
* [[Guides/Platform Development|Platform Development]]</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/TOCGuides/Scripting Guide/TOC2012-05-25T23:09:17Z<p>Ewencp: Add TOC for scripting guide</p>
<hr />
<div>* [[Guides/Scripting Guide/Terminology|Terminology]] <br />
* [[Guides/Scripting Guide/Tutorials|Tutorials]]<br />
{{:Guides/Scripting Guide/Tutorials/TOC}}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/Send_MessageGuides/Scripting Guide/Tutorials/Send Message2012-05-25T22:52:13Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Communicating with Other Entities =<br />
<br />
The primary way that a presence associated with one entity interacts with a presence associated with another entity is for the presences to send messages between each other. This tutorial will show you how to send and receive messages between presences.<br />
<br />
In the real world, if you were going to email your friend, you would first need your friend's email address. Similarly, before Presence A can send a message to Presence B in the virtual world, Presence A must be have Presence A's &quot;address&quot;. This tutorial will first describe how to get a presence's address, then it will explain how to send messages, and, finally, it will describe how to receive messages. It will use the example of one presence's sending another presence a request to move, and the other presence's responding to that message by moving.<br />
<br />
== Register proximity queries/discover presences ==<br />
<br />
=== Theory ===<br />
<br />
By default an entity only knows about its own presences. For an entity to discover other presences in the virtual world, it registers a query through one of its presences with the Meru system. Here's an example of such a query:<br />
<br />
system.self.onProxAdded( userAddedCallback );<br />
system.self.setQueryAngle(.4);<br />
<br />
These queries take a little thinking about. Roughly translated, the first line of the above code reads: &quot;When a presence gets near to be important to me, execute the function <tt>userAddedCallback</tt>, which the scripter has defined somewhere earlier in the program.&quot; (We will show an example of <tt>userAddedCallback</tt> that sends messages in the next section.)<br />
<br />
The second line of the above code actually defines what it means to be &quot;important&quot;. Meru uses the amount of Presence A's field of view taken up by Presence B as a measure of B's importance to A. Maybe a more concrete way to think about the above is through pixels. If Presence B takes a large number of pixels on a computer monitor showing Presence A's view of the world, it is more important than if it takes only a small number of pixels to render B. In this way, presences that are nearer to A or larger are more important to A than those that are more distant and smaller. The below figures highlight relative importance. The lower figures are more &quot;important&quot; than the upper figures.<br />
<br />
[[Image:scripting_tutorial_messaging_leastimportant.png|512px]]<br />
<br />
The bug in the above picture is less &quot;important&quot; than the bug in the picture below.<br />
<br />
[[Image:scripting_tutorial_messaging_mediumimportant.png|512px]]<br />
<br />
The bug in the above picture is less &quot;important&quot; than the bug in the picture below.<br />
<br />
[[Image:scripting_tutorial_messaging_mostimportant.png|512px]]<br />
<br />
The bug in the above figure would be more &quot;important&quot; than the bugs in either of the previous two figures.<br />
<br />
However, because of discretization and other errors caused by pixels, we don't use pixels directly. Instead we use steradians. The second line of the above code therefore reads, &quot;A presence is important to me if it takes up at least .4 steradians of my field of view&quot;. (steradians are a measure of solid angle. You can read more about them here [http://en.wikipedia.org/wiki/Steradian. http://en.wikipedia.org/wiki/Steradian.] All we really want you to know is that a large steradian means that a presence would take up many pixels on your monitor; a small steradian would take up very few pixels on your monitor.)<br />
<br />
Before moving on to the next section, it should be noted that in addition to the <tt>onProxAdded</tt> function shown above, Emerson has a complementary <tt>onProxRemoved</tt> function for presences. It looks something like this in practice:<br />
<br />
system.self.onProxRemoved(userRemovedCallback);<br />
<br />
Essentially, when an external presence no longer satisfies a solid angle query, the system notifies you that that presence has left the result set by calling userRemoveCallback.<br />
<br />
=== Try it yourself ===<br />
<br />
Enter the virtual world as an avatar. You should have just one presence associated that is connected to the space. From here, script yourself. Enter the following code into your own scripting terminal (hit <tt>ctrl</tt> + <tt>s</tt> to bring up a scripting window for yourself):<br />
<br />
function userAddedCallback(nowImportantPresence) {<br />
system.print(&quot;nnPresence with address &quot; + nowImportantPresence.toString() + &quot; is now important!nn&quot;);<br />
}<br />
<br />
function userRemovedCallback(nowUnimportantPresence) {<br />
system.print(&quot;nnPresence with address &quot; + nowUnimportantPresence.toString() + &quot; is now unimportant!nn&quot;);<br />
}<br />
<br />
system.self.onProxAdded( userAddedCallback );<br />
system.self.setQueryAngle(.4);<br />
<br />
Now, move closer and farther from other presences in the virtual world. You should see the print message associated with <tt>userAddedCallback</tt> when you get very close to an presence, and you should see <tt>userRemovedCallback</tt> when you move away from that presence after being more distant.<br />
<br />
You can monkey around by changing <tt>userAddedCallback</tt> and <tt>userRemovedCallback</tt> to do more elaborate things, for instance, rotating your avatar in a circle on each message.<br />
<br />
== Send message ==<br />
The previous section should have explained to you how to discover presences in the virtual world. However, even if you know the address and existence of a presence how can you interact with it?<br />
<br />
The way that presences on distinct entities interact in Emerson is through ''messages''. This section explains how a scripter would create and send a message to another presence. To do so, let's start by re-using a little code from the previous section:<br />
<br />
function userAddedCallback(nowImportantPresence) {<br />
system.print(&quot;nnPresence with address &quot; + nowImportantPresence.toString() + &quot; is now important!nn&quot;);<br />
...<br />
We will be changing the contents of this function.<br />
...<br />
}<br />
<br />
function userRemovedCallback(nowUnimportantPresence) {<br />
system.print(&quot;nnPresence with address &quot; + nowUnimportantPresence.toString() + &quot; is now unimportant!nn&quot;);<br />
}<br />
<br />
system.self.onProxAdded( userAddedCallback );<br />
system.self.setQueryAngle(.4);<br />
<br />
As mentioned in the previous section, the Emerson runtime system will automatically execute <tt>userAddedCallback</tt> when a new presence consumes more than .4 steradians of <tt>presence[0]</tt>'s field of view. What we didn't mention before was what the runtime binds to <tt>nowImportantPresence</tt> (the argument of <tt>userAddedCallback</tt>) how it can be used. <tt>nowImportantPresence</tt> corresponds to an Emerson ''visible'' object.<br />
<br />
To simplify sending messages, Emerson provides &quot;angle-angle&quot; syntax below.<br />
<br />
function userAddedCallback(nowImportantPresence) {<br />
system.print(&quot;nnPresence with address &quot; + nowImportantPresence.toString() + &quot; is now important!nn&quot;);<br />
<br />
//create a new message<br />
var moveMsg = new Object();<br />
moveMsg.action = &quot;forward&quot;;<br />
<br />
moveMsg &gt;&gt; nowImportantPresence &gt;&gt; [];<br />
<br />
}<br />
<br />
The line <tt>moveMsg &gt;&gt; nowImportantPresence &gt;&gt; []</tt>, handles message-sending, where <tt>moveMsg</tt> is an Emerson object (that does not have data written into the reserved fields <tt>seqNo</tt>, <tt>streamID</tt>, and <tt>makeReply</tt>), <tt>nowImportantPresence</tt> is the intended recipient of the message, and <tt>[]</tt> will be described in section :ref:`msgResponse`. That's all there is to it. You can now send messages. The next section will describe how to react to messages that you receive.<br />
<br />
== Receive Message ==<br />
<br />
In general, a scripter may want to perform different actions depending on the type of message that his/her presence receives and who that message is from.<br />
<br />
Emerson provides custom &quot;angle-angle&quot; syntax to make this process easier.<br />
<br />
For instance, examine the following code snippet:<br />
<br />
function actionMsgCallback(msg,sender) {<br />
system.print(&quot;I got a message with action: &quot; + msg.action);<br />
}<br />
<br />
actionMsgCallback &lt;&lt; [{'action'::}];<br />
<br />
In English, the last line of the above code states, &quot;If any presence connected to this entity receives a message that has a field entitled action in it, then call the function actionMsgCallback.&quot;<br />
<br />
One can also create more elaborate patterns for matching. For instance,<br />
<br />
actionMsgCallback &lt;&lt; [{'action'::}] &lt;&lt; someSender;<br />
<br />
the above line of code transalates to &quot;Call actionMsgCallback if any of my presences receive a message from someSender that has an action field.&quot;<br />
<br />
actionMsgCallback &lt;&lt; [{'action':'forward':}] &lt;&lt; someSender;<br />
<br />
And the above line of code transalates to &quot;Call actionMsgCallback if any of my presences receive a message from someSender that has an action field that has the value 'forward'.&quot;<br />
<br />
actionMsgCallback &lt;&lt; [{'action':'forward':}, {'seqno':3:}] &lt;&lt; someSender;<br />
<br />
And the above line of code translates to &quot;Call actionMsgCallback if any of my presences receive a message from someSender that has an action field that has the value 'forward' ''and'' has a field named 'seqno' with value 3.&quot;<br />
<br />
To match any message, with any fields, scripters currently, must enter:<br />
<br />
actionMsgCallback &lt;&lt; [new util.Pattern()] &lt;&lt; someSender;<br />
<br />
This is because of a compiler bug, which will be fixed in the next released version of the code.<br />
<br />
== Message Responses ==<br />
<br />
In section :ref:`secSendMsg`, you may have noticed the funny <tt>[]</tt> at the end of message send statements. This section describes how you can use this final statement in the angle-angle pipeline to to support message-response pattern of communication (A sends a message to B, B responds to that message, A responds to B's response, etc.).<br />
<br />
The array at the end of the message sending statement can have zero to three fields. The first field is a function that describes what to do if a message sender receives a response to his/her message. For instance, if you simply want to print &quot;I got a response&quot;, whenever you receive a response to one of your messages, you would do the following:<br />
<br />
<pre>function printOnRespFunc(msgResp,msgRespSender)<br />
{<br />
system.print('\n\nI got a response\n');<br />
}<br />
<br />
msgToSend &gt;&gt; receiver &gt;&gt; [printOnRespFunc];</pre><br />
By default, the system executes the <tt>printOnRespFunc</tt> when a receiver replies to your message. The receiver's reply is placed in the argument <tt>msgResp</tt> and the receiver (as a visible object) is placed in the argument <tt>msgRespSender</tt>.<br />
<br />
The system automatically stops waiting for a response after 5 seconds pass. Any response that you receive after this time will not trigger <tt>printOnRespFunc</tt> to execute. If you want to listen for a response for a longer or shorter time, you can provide a second argument to the sending array. For instance, if you instead want to listen for a response to your message for a full 10 seconds after your message has been sent, you would change the last statement to:<br />
<br />
msgToSend &gt;&gt; receiver &gt;&gt; [printOnRespFunc,10];<br />
<br />
Finally, if you want to print &quot;No response&quot; if you do not receive a response within 10 seconds, the send array takes a third parameter:<br />
<br />
function printOnRespFunc(msgResp,msgRespSender) {<br />
system.print('nnI got a responsen');<br />
}<br />
<br />
function printOnNoRespFunc() { system.print('nNo responsen'); }<br />
<br />
msgToSend &gt;&gt; receiver &gt;&gt; [printOnRespFunc,10,printOnNoRespFunc];<br />
<br />
The above code describes how one would catch a response, but does not explain how one would actually generate a response. Consider a new example where instead of printing &quot;I got a response&quot;, you want to instead echo back any responses that you receive to your first message. This is simply done through the <tt>makeReply</tt> function that the system appends to each message: <br />
<br />
function echoOnRespFunc(msgResp,msgRespSender) {<br />
msgResp.makeReply(msgResp) &gt;&gt; [echoOnRespFunc, 10, printOnNoRespFunc];<br />
}<br />
<br />
function printOnNoRespFunc() { system.print('nNo responsen'); }<br />
<br />
msgToSend &gt;&gt; receiver &gt;&gt; [printOnRespFunc,10,printOnNoRespFunc];<br />
<br />
<tt>makeReply</tt> takes a single argument, an object that you want to send to whoever sent you a message in response to the message that that presence sent you. If for instance, you wanted to send an empty object in response to any message that you received, you would change the body of <tt>echoOnRespFunc</tt> to state: <tt>msgResp.makeReply({}) &gt;&gt; [echoOnRespFunc, 10, printOnNoRespFunc];</tt>.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/GUIGuides/Scripting Guide/Tutorials/GUI2012-05-25T22:38:57Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Adding Graphical User Interfaces =<br />
<br />
Sometimes 2D user interface widgets are a better way to interact with a user than 3D interactions. For example, you might use a 2D widget to request that a user execute a script locally in a sandbox or provide a simpler interface to some interaction, like completing a purchase in a store.<br />
<br />
In Sirikata, 2D UIs are presented via small Javascript and HTML based widgets. You can find examples in the UI you get with the default client: both the scripting window and chat use these simple widgets to allow the user to take action in the world through a 2D interface.<br />
<br />
== Components ==<br />
<br />
There are 3 components involved in making a UI that can perform actions in the world.<br />
<br />
* The graphics object -- manages the UI widget and is required to allocate a widget.<br />
* The UI widget code -- Javascript and embedded HTML, just like the code in a web page.<br />
* Emerson driver code -- requests allocation of the UI widget and mediates interaction between the UI and the world, sending and receiving events in both directions.<br />
<br />
Generally you will be adding the UI to an avatar which already has the graphics object allocated. Your driver code is loaded somehow (as part of the user's default avatar script, or dynamically by sending a request to the user), asks the graphics object to allocate the UI widget, and then interacts with it, possibly sending events to the UI and receiving events back.<br />
<br />
In this tutorial, we'll construct a simple UI with a single button that sets your mesh to a predefined value when clicked. This is a simple but complete example of constructing a 2D UI.<br />
<br />
== Graphics Object ==<br />
<br />
In order to load a UI, you need a graphics object to allocate it within. The graphics object manages everything that occurs within the window that displays the world.<br />
<br />
In the current default avatar script (<tt>js/scripts/std/defaultAvatar.em</tt>) you can find it in the global variable <tt>simulator</tt> and it is an instance of the <tt>std.graphics.DefaultGraphics</tt> class. Because you need the graphics and GUI systems to be completely initialized before executing your code, we'll place our code inside the callback it provides:<br />
<br />
<pre>simulator = new std.graphics.DefaultGraphics(<br />
system.self, 'ogregraphics',<br />
function() {<br />
// Invoked when DefaultGraphics is done initializing,<br />
// we'll put our new code in here<br />
}<br />
);</pre><br />
== Emerson Driver Code and Allocating a UI Widget ==<br />
<br />
On disk, a UI widget is just a Javascript file that lives somewhere under <tt>ogre/data/</tt>). We'll get to the exact code later, but let's assume we have the code in the files <tt>setmesh.js</tt>. To load the GUI module, we call the <tt>addGUIModule</tt> method on the graphics object to load the UI:<br />
<br />
<pre>simulator.addGUIModule(<br />
&quot;SetMesh&quot;, &quot;setmesh.js&quot;,<br />
function(gui) {<br />
// gui is the new GUI object<br />
}<br />
);</pre><br />
The third parameter is a callback function. UI loading is asynchronous because it might involve downloading resources. To avoid blocking for a long time, a callback is invoked and provides you with the newly created GUI object only after it is safe to start interacting with it. A common pattern is to store the resulting GUI object in a field of the object that created it:<br />
<br />
<pre>simulator.addGUIModule(<br />
&quot;SetMesh&quot;, &quot;setmesh.js&quot;,<br />
std.core.bind(<br />
function(gui) {<br />
this._gui = gui;<br />
},<br />
this<br />
)<br />
);</pre><br />
In this approach, we use <tt>std.core.bind</tt> to make the <tt>this</tt> object the same in the callback as it is for the constructor. Any additional initialization for the GUI, such as calling an initialization function in the GUI with parameters from your Emerson script, should also occur in this callback function.<br />
<br />
Next, we know that our UI is going to generate some events we need to handle. In particular, it is going to send a request to change mesh. Events from the UI are specified by a string and a series of Javascript arguments (basic types such as strings and numbers only). To handle this event, we'll ''bind'' a handler for the event <tt>&quot;setmesh&quot;</tt>. Extending our previous code, we get:<br />
<br />
<pre>simulator.addGUIModule(<br />
&quot;SetMesh&quot;, &quot;setmesh.js&quot;,<br />
std.core.bind(<br />
function(gui) {<br />
this._gui = gui;<br />
<br />
var setmesh_pres = system.self;<br />
handleSetMesh = function(meshurl) {<br />
setmesh_pres.mesh = meshurl;<br />
};<br />
this._gui.bind(&quot;setmesh&quot;, handleSetMesh);<br />
},<br />
this<br />
)<br />
);</pre><br />
And that's it. When the UI sends a setmesh event, handleSetMesh will be invoked. It uses the reference <tt>setmesh_pres</tt>, the presence active when the GUI was loaded, to set the mesh. Because we know the arguments (and types!) that will be provided, we put a named argument for <tt>meshurl</tt>. However, if we don't know the exact form or number of arguments, we can use the <tt>arguments</tt> keyword to extract them dynamically.<br />
<br />
Finally, we have all the code we need to setup the GUI from the Emerson script. You can replace a line like<br />
<br />
<pre>simulator = new std.graphics.DefaultGraphics(system.self, 'ogregraphics');</pre><br />
in <tt>std/defaultAvatar.em</tt> with our updated code<br />
<br />
<pre>simulator = new std.graphics.DefaultGraphics(<br />
system.self, 'ogregraphics',<br />
function() {<br />
<br />
simulator.addGUIModule(<br />
&quot;SetMesh&quot;, &quot;setmesh.js&quot;,<br />
std.core.bind(<br />
function(gui) {<br />
this._gui = gui;<br />
<br />
var setmesh_pres = system.self;<br />
handleSetMesh = function(meshurl) {<br />
setmesh_pres.mesh = meshurl;<br />
};<br />
this._gui.bind(&quot;setmesh&quot;, handleSetMesh);<br />
},<br />
this<br />
)<br />
);<br />
}<br />
);</pre><br />
== UI Widget Code ==<br />
<br />
As discussed earlier, the UI code lives in a single Javascript file. The UI code is similar to Emerson code: it will be fully executed as soon as it is loaded. To continue taking actions, it sets up HTML elements that trigger events or uses timers to periodically take actions.<br />
<br />
Here's our entire script, <tt>setmesh.js</tt>:<br />
<br />
<pre>sirikata.ui(<br />
'SetMesh',<br />
function() {<br />
$('&lt;div id=&quot;set-mesh-ui&quot; title=&quot;SetMesh&quot;&gt;' + // (1)<br />
' &lt;button id=&quot;set-mesh-button&quot;&gt;Set Mesh!&lt;/button&gt;' +<br />
'&lt;/div&gt;').appendTo('body');<br />
<br />
var window = new sirikata.ui.window( // (2)<br />
&quot;#set-mesh-ui&quot;,<br />
{<br />
width: 100,<br />
height: 'auto'<br />
}<br />
);<br />
window.show();<br />
<br />
sirikata.ui.button('#set-mesh-button').click(setMesh); // (3)<br />
<br />
function setMesh() { // (4)<br />
sirikata.event(&quot;setmesh&quot;, &quot;meerkat:///test/cube.dae/original/0/cube.dae&quot;);<br />
}<br />
}<br />
);</pre><br />
Our entire UI script is wrapped in a <tt>sirikata.ui</tt> call, which also takes a name for our UI. This allows Sirikata to set up some helpers and try to isolate us from other UIs. It also automatically wraps your script that gets rid of some quirks with the way web pages load. You should always wrap your UI code in <tt>sirikata.ui</tt>.<br />
<br />
The first statement (1) injects our UI into the page by creating a <tt>div</tt> containing all our UI elements and appending it to <tt>body</tt>. This example was very simple, but complete examples may require a few lines to get all the components put together. Our UI just consists of a single button. Note that we've labeled each element with an ID.<br />
<br />
The second line (2) uses the ID we assigned to the <tt>div</tt>, <tt>set-mesh-ui</tt> to create a window out of it using <tt>sirikata.ui.window</tt>. The second parameter is a dictionary of parameters. In this case, we just set the size of the window.<br />
<br />
The third line (3) sets up the action that should be taken when the <tt>set-mesh-button</tt> is clicked. We simply tell it to execute a callback <tt>setMesh</tt>. Many other types of actions can be bound as callbacks --mouse over, mouse move, click, keypresses, etc.<br />
<br />
Of course, to invoke <tt>setMesh</tt> it must be defined. The fourth statement (4) does just that. However, the callback can't set the mesh itself -- it doesn't have a presence to act upon. Instead, it relays this information back to the Emerson script. Recall that we decided to use the string <tt>&quot;setmesh&quot;</tt> to filter events from the UI (other elements may also be sending events, e.g., &quot;chat&quot; or &quot;scripting&quot;). The special <tt>sirikata.event</tt> method allows you to send events out of the browser and back into the underlying system, getting them back to your Emerson script. The first parameter is our filter string. The remaining arguments are passed as the arguments to the callback registered for this event. In this case, we specify the URL for the mesh we want to use.<br />
<br />
And that's it, with the UI loaded and the callback setup, clicking on the button will trigger a message back to Emerson code, which will be handled by the Emerson <tt>handleSetMesh</tt> method. This, in turn, results in a request to the space to set the presence's mesh.<br />
<br />
== Manipulating Widgets from Emerson ==<br />
<br />
This simple example only required the UI to be setup and then listen for events, but didn't require any further manipulation of the UI from Emerson. To further interact or update the UI from Emerson, you use the <tt>std.graphics.GUI</tt> object returned by <tt>addGUIModule</tt>. This object has a few simple methods like <tt>show</tt>, <tt>hide</tt>, and <tt>bind</tt> (as used earlier). It also includes <tt>GUI.eval</tt>, which is the generic way of interacting with the code in the UI widget. <tt>GUI.eval</tt> takes a single string argument containing Javascript to execute in the page. In our example, if we instead used the function:<br />
<br />
<pre>var setMeshURL = &quot;meerkat:///test/cube.dae/original/0/cube.dae&quot;<br />
function setMesh() {<br />
sirikata.event(&quot;setmesh&quot;, setMeshURL);<br />
}</pre><br />
we could change the URL we'd request by executing the following:<br />
<br />
<pre>this._gui.eval(&quot;setMeshURL = 'meerkat:///test/multimtl.dae/original/0/multimtl.dae'&quot;);</pre><br />
which overwrites the value of <tt>setMeshURL</tt>. The next time the button is pressed and setMesh is invoked, the new value is passed back to the script. This approach is convoluted, but it demonstrates how additional actions can be taken by Emerson code on the GUI well after the GUI is created.<br />
<br />
GUI objects also provide a few methods to make the most common interactions with GUIs simpler: <tt>GUI.call</tt>, <tt>GUI.set</tt>, <tt>GUI.variable</tt>. <tt>GUI.call</tt> invokes a method in the context of the GUI, making sure all variables passed through are substituted for their values and properly escaped if necessary. For example:<br />
<br />
<pre>var x = 7;<br />
var st = 'hello &quot;Bob&quot;';<br />
this._gui.call('myfunc', x, st);</pre><br />
is equivalent to<br />
<br />
<pre>this._gui.eval( &quot;myfunc(7, 'hello \&quot;Bob\&quot;');&quot; );</pre><br />
and is much simpler and more readable than the normal approach:<br />
<br />
<pre>this._gui.eval( 'myfunc(' + x + ',' + escape(st) + ');' );</pre><br />
It looks more natural, is closer to a normal function call, and is less error-prone since escaping is performed automatically.<br />
<br />
<tt>GUI.set</tt> sets the value of a variable in the script's context. The above example of setting the mesh URL could be written as:<br />
<br />
<pre>this._gui.set('setMeshURL', 'meerkat:///test/multimtl.dae/original/0/multimtl.dae');</pre><br />
Of course this isn't much shorter, but the <tt>GUI.eval</tt> string is generated automatically, escaping of strings is automatic, and you can easily substitute variables:<br />
<br />
<pre>this._gui.set('setMeshURL', new_mesh_url);</pre><br />
Sometimes you want to be able to specify variable names in the GUI's context in other expressions, but any strings you pass in are converted to literals. <tt>GUI.variable</tt> solves this by producing a special object which will be interpreted as a variable name. For example, to use an existing JavaScript variable <tt>name</tt> when evaluating a function we would say<br />
<br />
<pre>this._gui.call('printname', this._gui.variable('name'));</pre><br />
Note that because <tt>GUI.set</tt> has a fixed format for parameters, you don't need to use <tt>GUI.variable</tt> on its first argument.<br />
<br />
== Debugging GUI Code ==<br />
<br />
The <tt>sirikata</tt> object provides utilities besides the ability to notify the owning script of events. In particular, <tt>sirikata.log</tt> allows you to log information to the console:<br />
<br />
<pre>sirikata.log('info', 'Value: ', myvalue);</pre><br />
This will log the message and value of <tt>myvalue</tt> to the console. The first parameter should always be a string and indicates the ''log level''. These levels let you control the amount of information that is reported ('fatal', 'error', 'warn' or 'warning', 'info', 'debug', 'detailed', 'insane'). You might put a lot of logging at the 'debug' level, which is off by default, and more important messages at 'warn', 'info', or 'fatal'.<br />
<br />
To control the level of messages reported, start the client with a different level for the `ui` module:<br />
<br />
<pre>cppoh --moduleloglevel=ui=debug</pre><br />
If you need messages provided by other components that may use the standard logging mechanisms in browsers, you can also enable these with the <tt>webview</tt> module:<br />
<br />
<pre>cppoh --moduleloglevel=ui=debug,webview=debug</pre><br />
Note that this also turns on other logging from this module besides that generated by <tt>console.log</tt> calls from scripts, so using <tt>sirikata.log</tt> is the preferred method for logging.<br />
<br />
Another approach to debugging UI code is to develop much of it in a normal browser and use the debugging tools there. You can't test any code which interacts with the rest of Sirikata (e.g. the <tt>sirikata.event()</tt> calls), but this can be helpful for the initial development of the UI and workflow.<br />
<br />
To do this, there are just 2 steps. First, you need to force the system to load your GUI as a builtin. In <tt>ogre/data/chrome/ui.html</tt>, find the section where a bunch of modules are loaded by <tt>$LAB</tt>. Add a line for your own file ''after'' all the other <tt>.js</tt> files. For example, given the placement described earlier, <tt>setmesh.js</tt> would be loaded as:<br />
<br />
<pre>.script(&quot;../setmesh.js&quot;).wait()</pre><br />
Next, you'll just load up <tt>ui.html</tt> directly in a browser. You should see at least the menu system and be able to click and select them. If your UI doesn't pop up by default, you'll need to force it to since the Emerson code cannot initialize it for you. In this mode, certain functions (like sirikata.log and sirikata.event) cannot function normally. They should just end up getting logged to the JavaScript console in the browser and ignored.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/Create_EntityGuides/Scripting Guide/Tutorials/Create Entity2012-05-25T22:37:25Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Creating entities =<br />
<br />
By now, you should know how to add presences to an entity. This tutorial describes how you would go about creating a '''new''' entity. We'll use an example in which we create a new entity, and then have that entity's presence move through the world.<br />
<br />
==The create entity call ==<br />
All a scripter does to create a new entity is to execute the <tt>create_entity</tt> call. The call:<br />
<br />
* creates a new entity on the same entity host that processed the <tt>create_entity</tt> call and<br />
* automatically connects a presence for that entity to the world.<br />
<br />
The second task requires some additional information, and requires that the <tt>create_entity</tt> call takes several parameters. In order, these parameters are:<br />
<br />
* The position the entity's presence should occupy in the world (Vec3).<br />
* The type of script to import. (For emerson scripts, include &quot;js&quot;.).<br />
* The filename of the script to import.<br />
* A URI to the mesh the entity's automatically-connected presence should take.<br />
* A scaling factor for that mesh.<br />
* A steradian value for the solid angle query the entity's automatically-connected presence should issue.<br />
<br />
== Example ==<br />
<br />
Now that you know the structure of a <tt>create_entity</tt> call, consider the following code:<br />
<br />
//new entity's presence has the mesh of a sphere<br />
var meshToChangeTo = &quot;meerkat:///test/sphere.dae/original/0/sphere.dae&quot;;<br />
<br />
//new entity's presence will be located two units away from creating<br />
//presence's position<br />
var newPos = system.self.getPosition(); newPos.x = newPos.x + 2;<br />
<br />
//First thing that the new entity will do after its presence connects<br />
//to space is import the following file.<br />
var scriptToImport = &quot;test/testMove.em&quot;;<br />
<br />
system.create_entity(newPos,<br />
&quot;js&quot;, //this arg will almost always be 'js'<br />
scriptToImport, meshToChangeTo,<br />
1.0, //how do you want to scale the mesh of<br />
//the entity's new presence<br />
3 //what is the solid angle query that<br />
//the entity's initial presence <br />
//queries with.<br />
);<br />
<br />
This code would be executed on an already-existing entity to create a new entity. The new entity's automatically-connected presence would have a mesh of <tt>meshToChangeTo</tt> (a sphere), be positioned a the x,y,z coordinates contained in <tt>newPos</tt> (2 meters away from the previous entity's first presence), import a script from <tt>scriptToImport</tt> (in filename 'test/testMove.em'), and set a solid angle query of 3 steradians.<br />
<br />
The actual structure in the script 'test/testMove.em' may be a little different than scripters are used to. Most of the scripts that we have discussed to this point operated on entities that already had presences connected to the world: scripters were able to assume <tt>system.self</tt> existed, and was connected to the world. In contrast, the imported script executes '''before''' its first presence is automatically connected. This means that 'test/testMove.em' must actually catch the first presence's connection before operating on it.<br />
<br />
This is easy, and is accomplished through the <tt>onPresenceConnected</tt> system call. Below is the 'test/testMove.em' script, which uses the <tt>onPresenceConnected</tt> call.<br />
<br />
//whenever a presence in the system connects to the world,<br />
//execute the argument of onPresenceConnected<br />
system.onPresenceConnected(moveFunc);<br />
<br />
function moveFunc(newPres) {<br />
//set a unit velocity for the first presence in the x direction.<br />
system.self.setVelocity(&lt;1,0,0&gt;);<br />
}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/Create_PresenceGuides/Scripting Guide/Tutorials/Create Presence2012-05-25T22:32:02Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Creating presences =<br />
<br />
The previous tutorials explained how to move an entity's presence. This tutorial describes how to create new presences for an entity.<br />
<br />
== The create presence call ==<br />
All a scripter does to create a new entity is to execute the <tt>createPresence</tt> call.<br />
<br />
<tt>createPresence</tt> requires two arguments: a uri for the mesh to load for the newly created presence (as a string) and a callback function to execute once the presence connects.<br />
<br />
The <tt>createPresence</tt> call is ''non-blocking''. What this means is that a presence is not created as soon as the call returns. Instead, a presence is connected to the world and appears some time (usually less than one second) after the call has been made. When the presence does get connected, the system automatically executes the callback, passing in the newly-created presence as an argument to this callback.<br />
<br />
Let's combine this information with the previous example on moving presences to create a new presence, and then have it move forever in one direction:<br />
<br />
function presCreatedCallback(presCreated) {<br />
//the new presence's velocity is set to<br />
//1 m/s in the x direction.<br />
presCreated.setVelocity(&lt;1,0,0&gt;);<br />
}<br />
<br />
//the new presence will have the mesh of a kiosk.<br />
var newPresMesh = 'meerkat:///kittyvision/kiosk/flyers.dae/optimized/0/flyers.dae';<br />
system.createPresence(newPresMesh,presCreatedCallback);<br />
<br />
== Managing presences: <tt>system.presences</tt> and <tt>system.self</tt> ==<br />
As you can imagine, an entity with very many presences can become difficult to manage. To address this, Emerson automatically manages two global variables: <tt>system.presences</tt> and <tt>system.self</tt>. Any time a new presence is created, it gets loaded into <tt>system.presences</tt>, an array that contains all the presences connected to an entity. If, for instance, a scripter wanted to set the velocity for all of his/her presences, he/she could enter the following code:<br />
<br />
for (var s in system.presences) {<br />
system.presences[s].setVelocity(&lt;1,0,0&gt;);<br />
}<br />
<br />
While, <tt>system.presences</tt> allows a scripter to track ''all'' the presences he/she has connected, <tt>system.self</tt> is intended to automatically track the most &quot;relevant&quot; presence for an event.<br />
<br />
Emerson is event-based, and the majority of events in the virtual world are associated with a single presence. <tt>system.self</tt> gets set to the presence associated with that event. This may seem a little confusing, and may make more sense through a series of examples:<br />
<br />
* If an entity's presence receives a message, <tt>system.self</tt> is automatically set to the presence that received the message.<br />
* If an entity receives a timeout event, <tt>system.self</tt> is automatically set to the presence that originally set the timeout.<br />
* If an entity receives a presence connected event, <tt>system.self</tt> is automatically set to the presence that was connected.<br />
<br />
To provide an example of <tt>system.self</tt> in action, recall our earlier task of creating a new presence and setting its velocity to be 1 m/s. We can re-write <tt>presCreatedCallback</tt> to use <tt>system.self</tt> instead of <tt>presCreated</tt>:<br />
<br />
function presCreatedCallback(presCreated) {<br />
//the new presence's velocity is set to<br />
//1 m/s in the x direction.<br />
system.self.setVelocity(&lt;1,0,0&gt;);<br />
//now using system.self<br />
}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/Move_PresenceGuides/Scripting Guide/Tutorials/Move Presence2012-05-25T22:27:24Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Moving in the World =<br />
<br />
It would be a pretty boring world if all presences just stayed in one place. This tutorial explains how a scripter can move presences throughout the world.<br />
<br />
There are two basic types of movement in the system: translational and rotational. In translational movement, every point of the presence's mesh moves the same distance; in rotational movement, a presence's mesh spins around a fixed axis. A useful way of understanding the difference between translational and rotational movement is to think about a wheeled office chair. A person wanting to translate his/her office chair would roll it from one point in a room to another. A person wanting to rotate his/her office chair would spin in place on the office chair.<br />
<br />
Translational and rotational movement can be combined (ie, one can use Emerson to translate and rotate a presence simultaneously). For the simplicity of this tutorial, we instead focus on each separately.<br />
<br />
Before we begin, a quick note on code in the following examples: the Emerson run-time keeps track of all of an entity's connected presences in an array available to the scripter as <tt>system.presences</tt>. For the example code used in this tutorial, we'll assume that the presence being moved is named by <tt>system.self</tt>.<br />
<br />
== Translational motion ==<br />
Emerson allows a scripter to either instantly teleport a presence to a new position or to assign a velocity to the presence. A presence with an assigned velocity automatically moves through the world in the assigned direction and rate. For both position and velocity, Emerson uses standard Cartesian coordinates, and represents each using 3-dimensional vectors. We'll talk about position and velocity separately below, but it may be useful for the reader to refer to the Vec3 type described here&lt;lkjs&gt; before beginning.<br />
<br />
=== Teleport/SetPosition ===<br />
Assume that you have a presence that you want to instantly translate from its current position to a position 100m away in the x direction.<br />
<br />
We'll break such a script into 3 pieces:<br />
<br />
<blockquote>* Getting the presence's current x, y, and z coordinates in the space.<br />
* Specifying a new 3-dimensional position based on the presence's current x, y, and z coordinates in the space.<br />
* Requesting the system to move your object to this new position.<br />
</blockquote><br />
Here's the entire script to perform the above.<br />
<br />
var pos = system.self.getPosition();<br />
pos.x = pos.x + 100;<br />
system.self.setPosition(pos);<br />
<br />
The above is explained more methodically below.<br />
<br />
==== Getting the presence's current coordinates in the space ====<br />
<br />
To get a 3-dimensional vector representing the current position of a presence in space, simply use the <tt>getPosition()</tt> function. As an example, open a scripting window and enter:<br />
<br />
var pos = system.self.getPosition(); system.print(pos);<br />
<br />
You should see the position of a presence printed in the following form: &lt;x,y,z&gt;. You can access the individual x, y, and z fields of this position with the accessors `.x`, `.y`, and `.z`, respectively. That is, if you wanted to just print the x position of a presence, you would replace the second line of the above function as shown below:<br />
<br />
var pos = system.self.getPosition(); system.print(pos.x);<br />
<br />
====Specifying a new 3-dimensional position based on <tt>pos</tt>====<br />
After the previous section, the variable <tt>pos</tt> stores the current position associated with <tt>system.self</tt>. We need to specify a new target position. Doing so is simple:<br />
<br />
pos.x = pos.x + 100;<br />
<br />
It is important to note, the above line does ''not'' move the presence by itself. It instead changes the value stored in <tt>pos</tt>. <tt>pos</tt> now describes the position that we want to move our presence to.<br />
<br />
====Requesting the system to move your object to <tt>pos</tt>====<br />
To actually set the position of <tt>system.self</tt> to <tt>pos</tt>, one simply uses the <tt>setPosition</tt> function:<br />
<br />
system.self.setPosition(pos);<br />
<br />
The <tt>setPosition</tt> function takes in a single argument, a 3-dimensional vector, and instantly moves the associated presence to that point in the space.<br />
<br />
=== SetVelocity ===<br />
<br />
The above example instantly moved a presence from one point to another. While such an operation is possible in a virtual world, it certainly does not agree with (most of) the real world: one wouldn't see a train teleport from one station to another -- instead, the train acquires a velocity and moves from point to point non-instantaneously.<br />
<br />
Emerson provides similar capabilities for presences by allowing a scripter to set a presence's velocity (both magnitude and direction). (Note: in Emerson, a scripter ''cannot'' set higher order movement properties for presences such as acceleration or jerk.)<br />
<br />
Consider the simple task of moving a stationary presence 30m in the y direction. To do so, a scripter would use the <tt>setVelocity</tt> command. Like the <tt>setPosition</tt> command described in the previous section, <tt>setVelocity</tt> takes in a single argument: a 3-dimensional vector. The x, y, and z components of this argument 3-dimensional vector specifies the velocity that the presence should move in meters per second (in the x, y, and z directions respectively). You can experiment with the <tt>setPosition</tt> function pretty easily. For instance, at a scripting prompty, enter the following code:<br />
<br />
var zeroVelocity = new util.Vec3(0,0,0);<br />
var posYVelocity = new util.Vec3(0,1,0);<br />
var negYVelocity = new util.Vec3(0,-1,0);<br />
<br />
Now, to get a presence to stop moving, just enter:<br />
<br />
system.self.setVelocity(zeroVelocity);<br />
<br />
To get a presence to start moving in the positive y direction, enter:<br />
<br />
system.self.setVelocity(posYVelocity);<br />
<br />
And, to get a presence to start moving in the negative y direction, enter:<br />
<br />
system.self.setVelocity(negYVelocity);<br />
<br />
To complete the simple task of moving a stationary presence 30m in the y direction, enter into the command prompt:<br />
<br />
system.self.setVelocity(posYVelocity);<br />
<br />
and then 30 seconds later:<br />
<br />
system.self.setVelocity(zeroVelocity);<br />
<br />
The first command should start the presence moving in the y direction at 1 m/s. The second command should stop the presence. Manually entering such commands obviously leaves something to be desired. For a more robust solution, read about <tt>timeout</tt>s in the tutorial.<br />
<br />
== Rotational motion ==<br />
Ugh. I hate quaternions.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/ResetGuides/Scripting Guide/Tutorials/Reset2012-05-25T22:21:59Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Resetting Scripts =<br />
<br />
Using the in-world scripting prompt may not be the best way for you to build your virtual world application. This tutorial talks about:<br />
<br />
<blockquote>* Writing a script file.<br />
* Loading that script on an entity.<br />
* Resetting an entity to an initial script.<br />
</blockquote><br />
<br />
== Writing a script file ==<br />
If you are running the entire system locally, look for the &quot;std&quot; and &quot;test&quot; scripts directories. (If you're on the windows build, go to the sirikata folder you unzipped, open the &quot;share&quot; folder, then, open the &quot;js&quot; folder; if you're on Mac or Linux, then go to &quot;liboh&quot;, then &quot;plugins&quot;, then &quot;js&quot;, then &quot;scripts&quot;.) Once in this folder, create a new file, and name it &quot;myScript.em&quot;.<br />
<br />
The script that we're going to write is going to print the text &quot;timer fired!&quot; every 3 seconds. Think about how you would do this in an in-world command prompt. You'd probably enter the following commands into the prompt: :: system.import('std/core/repeatingTimer.em');<br />
<br />
<blockquote>function testCallback() { system.print(&quot;ntimer fired!n&quot;); }<br />
<br />
var repTimer = new std.core.RepeatingTimer(3,testCallback);<br />
</blockquote><br />
Your script should look exactly the same. All that executing a script does is sequentially evaluate all the commands in a script file as if they had been individually entered at an in-world scripting terminal.<br />
<br />
== Loading a script ==<br />
By the end of the previous section, you should have your script in 'myScript.em'. How do you get an in-world entity to execute it? Approach a presence in the world, and open a scripting point associated with it. To execute the script you just wrote, all you need to do is call import: :: system.import('myScript.em');<br />
<br />
The first argument of the import call should be the name of your script. (If you had put your script in the &quot;test&quot; folder, then you would have entered 'test/myScript.em' as the first argument.)<br />
<br />
At this point, every 3 seconds, you should see, printed into your scripting console, 'timer fired!'. At this point, you should know how to write a script in an external file and get it<br />
<br />
== Resetting ==<br />
<br />
Let's say that you don't want to print 'timer fired!' every 3 seconds. Instead, you want to print 'timer REALLY fired!' every 5 seconds. You can certainly, by hand, call `repTimer.clear()`, and then create a new timer. In practice, this process may be a little cumbersome. A better approach would be to modify myScript.em, clear the entity's current script, and then import the now-modified myScript.em. Emerson makes this easy.<br />
<br />
Before showing you how to do this, it's worth a little explanation. Emerson has a special &quot;reset&quot; call that can only be executed from your root sandbox. When a scripter executes this call, almost everything that he/she scripted is wiped away. The two things that remain:<br />
<br />
<blockquote>* The root sandbox's presences (and their associated state)<br />
* A special `script` string associated with each entity.<br />
</blockquote><br />
You should know about the first of these by now, so let's focus on the second part. A user can set the `script` string by calling: :: system.set_script(someString);<br />
<br />
where `someString` is a string the scripter provides. When an Emerson entity is reset, the Emerson runtime explicitly executes whatever is contained in that string after wiping away all other data.<br />
<br />
A really useful thing to put into strings like this is a simple import call. Let's think about how that would work for our simple timer fired script. After making the changes to myScript.em so that the timer fires every 5 seconds (instead of 3) and displays a different message, enter: :: system.set_script(&quot;system.import('std/default.em'); system.import('std/shim.em'); system.import('myScript.em');&quot;);<br />
<br />
into your in-world scripting console, then wehenever you call `system.reset()`, the first thing that happens after reset is that your entity re-imports myScript.em. You can now change your script files, and automatically incorporate those changes. You may be a little confused by the two imports that precede importing from &quot;myScript.em&quot;. For entities that exist in the world before you bring them up, the system automatically imports these libraries (they do things like allowing entities in the world to respond to scripting messages, move events, etc.). Because you're resetting the entire entity state, you must include these explicitly.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/ConnectingGuides/Scripting Guide/Tutorials/Connecting2012-05-25T22:19:46Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Connecting to a Sirikata World =<br />
<br />
Before you can start scripting, you need to be connected to a world. Currently, the connection procedure isn't very user friendly -- there isn't a UI for it -- but its also not too challenging to customize.<br />
<br />
First, you'll need to know what server you are connecting to. You'll need to know both the hostname (e.g `sample.sirikata.com`) and the port (e.g. `7777`). If you are running your own space server, these values will be `localhost` and `7777` by default.<br />
<br />
To run, find the object host binary, called `cppoh` (or `cppoh_d`). If you're using a prepackaged version then it should be under `sirikata/bin/`. If you've built from scratch, it is under `sirikata/build/cmake/`. Then, we just run the binary, specifying the hostname and port:<br />
<br />
<pre>./cppoh_d &quot;--servermap-options=--host=sample.sirikata.com --port=7777&quot;</pre><br />
Note the quotes around the one option string -- because we need to specify both the host and port as '''suboptions''' to `servermap-options`, we need to put quotes around the entire `servermap-options` string.<br />
<br />
If everything went right, a window should have popped up and started displaying the world.<br />
<br />
== Client Configuration ==<br />
<br />
The default scene should provide you with a configuration . If you want to use a customized client script (for instance, providing different features or key bindings) you need to specify.<br />
<br />
In Sirikata, the client is not special in anyway -- it is just a normal object that connects to and interacts with the world just as any other object and it just happens to also display the world in a window and handle user input. Because of this, the program being executed is just the normal `object host`. Generally, when running as the client, the configuration specifies only one object -- your avatar -- to be loaded. To control the set of objects that are loaded, you can specify a scene file instead of using the default of `scene.db`:<br />
<br />
<pre>./cppoh_d --object-factory-opts=--db=my.db</pre><br />
Within the database file, each object can specify a `script_type` and `script_options`. By setting these for your avatar object, you can alter the behavior of the client. The defaults for the client are `js`, which specifies the JavaScript/Emerson scripting plugin, and `--init-script=std/defaultAvatar.em`, which is a script that turns on graphics and sets up many useful default interactions such as using the mouse for manipulating objects and key bindings for bringing up a scripting window for objects.<br />
<br />
== Additional Configuration ==<br />
<br />
If you need to specify additional options, or you always want to connect to the same server, it can be more convenient to create a configuration file which specifies all your options. A configuration file has one option per line, formatted as:<br />
<br />
<pre>--option=optionvalue</pre><br />
From the example above, we might specify the following in our configuration [file: file:]<br />
<br />
<pre>--servermap-options=--host=sample.sirikata.com --port=7777</pre><br />
to avoid typing it every time we want to start the client. To run with the configuration file, you specify it as an option to the client:<br />
<br />
<pre>./cppoh_d --cfg=my.cfg</pre><br />
Now, if you have many options in `my.cfg`, they will all be included when you specify the configuration file.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/Hello_WorldGuides/Scripting Guide/Tutorials/Hello World2012-05-25T22:19:16Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Hello World -- Your First Script =<br />
<br />
== Hello World! ==<br />
<br />
Let's put together a quick hello world script. One can do this in one of two ways: by printing from a running entity's presence or by creating a new entity, connecting that entity to the world, and then telling that entity to print your message.<br />
<br />
We'll talk about each separately below.<br />
<br />
=== Print from running object ===<br />
<br />
Presumably, you're connected to a world with already-existing entities connected through presences. Move close towards one (you can use the arrow keys to navigate in flat space and 'q' and 'z' to adjust your height). Click on it. A white cube should appear around the presence's mesh as seen in the following figures:<br />
<br />
; Before clicking on object:<br />
[[Image:scripting_tutorial_helloworld_0.png|512px]]<br />
; After clicking on object:<br />
[[Image:scripting_tutorial_helloworld_1.png|512px]]<br />
<br />
This white cube means that the presence is &quot;selected&quot;. Type <tt>alt</tt>+<tt>s</tt> to bring up a scripting window for the entity connected. Note that although the presence is highlighted, you will be scripting the '''entity''' associated with the presence, '''not''' the presence itself. The scripting window appears as the white rectangle in the following example image:<br />
<br />
[[Image:scripting_tutorial_helloworld_2.png|512px]]<br />
<br />
In the window, type <tt>system.print(&quot;\n\nHello, World!\n\n&quot;);</tt>. Hit <tt>ctrl</tt>+<tt>enter</tt> to execute this script (or, hit the button marked &quot;run&quot;). You should see &quot;Hello, World!&quot; appear in the scripting window. That should be it. You've created your first program! If you want, you can enter other commands into the scripting window to do basic math, :ref:`movepresence`, print more messages, etc.<br />
<br />
; Typing in command at prompt.<br />
[[Image:scripting_tutorial_helloworld_3.png|512px]]<br />
; Result of running hello, world command.<br />
[[Image:scripting_tutorial_helloworld_4.png|512px]]<br />
<br />
=== Bring up entity and print when first presence is connected ===<br />
<br />
There are a variety of ways to create new entities in the world. The simplest is to approach an object in the world, and ask it to create a new entity for you. The tutorial on :ref:`createent` explains how a scripter can create a new entity. This subsection focuses on writing a script that a newly created entity would use to print &quot;Hello, World!&quot; after it has connected to a new space.<br />
<br />
Conceptually, there are several ways to approach such a task. For instance, one could send a request to connect to the space and frequently check an indicator to see when that request has been accepted, performing some action on acceptance. Such an approach is called &quot;polling&quot;. As an alternate strategy, one could instead request a connection to the space and register a ''callback'' with the underlying run-time environment so that the script is notified when the connection request is successful. This is called an &quot;event-based approach&quot;. Emerson, for the most part, encourages event-based scripting, and therefore uses the second strategy.<br />
<br />
Consider the simple following script:<br />
<br />
function printHelloWorld(newPres) {<br />
system.print(&quot;nnHello, World!nn&quot;);<br />
}<br />
system.onPresenceConnected(printHelloWorld);<br />
<br />
Let's break it into pieces:<br />
<br />
function printHelloWorld(newPres) {<br />
system.print(&quot;nnHello, World!nn&quot;);<br />
}<br />
<br />
As one might guess from the print from running object section of this tutorial, when the above function is called, it simply prints &quot;Hello, World!&quot;. No surprises here. Let's look at the next bit:<br />
<br />
system.onPresenceConnected(printHelloWorld);<br />
<br />
The above <tt>system.onPresenceConnected</tt> function takes in a single argument: a function that specifies what to do when a presence is newly connected. When a new presence is connected, the Emerson run-time automatically executes this function for the scripter.<br />
<br />
In general, a scripter might write presence initialization code in such a function, but, for our purposes, printing &quot;Hello, World!&quot; suffices.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/TutorialsGuides/Scripting Guide/Tutorials2012-05-25T22:08:51Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Emerson Tutorials =<br />
<br />
The best way to get started is to jump right in and write a simple script. The first few tutorials step through the necessary basics: connecting to the world, writing a simple script, controlling an object, and communicating with other objects. Everyone should start by working through these tutorials in order. After these, follow additional tutorials or just experiment, using the [http://sirikata.com/docs/emersonapi/ API] for additional details.<br />
<br />
== Table of Contents ==<br />
<br />
{{:Guides/Scripting_Guide/Tutorials/TOC}}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/Tutorials/TOCGuides/Scripting Guide/Tutorials/TOC2012-05-25T22:07:03Z<p>Ewencp: Clean up names</p>
<hr />
<div>* [[Guides/Scripting_Guide/Tutorials/Connecting|Tutorial: Connecting]]<br />
* [[Guides/Scripting_Guide/Tutorials/Hello World|Tutorial: Hello World]]<br />
* [[Guides/Scripting_Guide/Tutorials/Reset|Tutorial: Reset]]<br />
* [[Guides/Scripting_Guide/Tutorials/Move Presence|Tutorial: Move Presence]]<br />
* [[Guides/Scripting_Guide/Tutorials/Create Presence|Tutorial: Create Presence]]<br />
* [[Guides/Scripting_Guide/Tutorials/Create Entity|Tutorial: Create Entity]]<br />
* [[Guides/Scripting_Guide/Tutorials/Send Message|Tutorial: Send Message]]<br />
* [[Guides/Scripting_Guide/Tutorials/GUI|Tutorial: GUI]]</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_Guide/TerminologyGuides/Scripting Guide/Terminology2012-05-25T22:04:59Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Basic Emerson Terminology =<br />
<br />
The tutorials and documentations throw around two terms that are unusual, and should be defined. These are entity and presence. Here's a quick description of the relation between entities and presences.<br />
<br />
An ''entity'' has an associated Emerson script. It has zero, one, or many ''presences'' through which it connects to a virtual world. Each presence has a physical manifestation in the virtual world, and has properties such as velocity, mesh, bounding volume, etc. that are managed by the virtual world.<br />
<br />
As a concrete and visual example of entities and presences, consider the following figure<br />
<br />
[[Image:FishEntityPresence.png|512px]]<br />
<br />
In it, Entity A has two presences associated with the world, both fish. Each of these fish can move independently of the other in the virtual world. In contrast, all the other entities only connect to this virtual world through one presence. (In case you're wondering those presences are seaweed, a starfish, and another fish for Entities B, C, and D, respectively.)</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Scripting_GuideGuides/Scripting Guide2012-05-25T22:01:25Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Introduction Scripting =<br />
<br />
Welcome to the application developer's guide. If you want to connect to a Sirikata world and script objects, this is where you should start.<br />
<br />
Currently, the primary scripting language for Sirikata worlds is '''Emerson''', a derivative of JavaScript with features designed specifically for virtual worlds. This guide will teach you how to connect to a Sirikata world and script objects in Emerson.<br />
<br />
== Navigating the Guide ==<br />
<br />
This guide is broken down into two major components: :ref:`emerson-tutorials` and the [http://sirikata.com/docs/head/emersonapi/ Emerson api]. The tutorials will get you started, letting you start writing code with no previous experience with the system. The language reference is useful once you know your way around the system but need to know specifics -- what is the exact syntax and options for sending messages? or how do I dynamically create new objects?<br />
<br />
For a beginner, we recommend starting with the :ref:`emerson-introductory-tutorials` to get a feel for how the system works. Then, to better understand the system and the language, learn the :ref:`terminology` used throughout this documentation, as well as basic JavaScript syntax, most of which Emerson borrows directly (e.g. expressions, conditionals, loops, functions, object and array literals; some good references, ignoring web-specific features such as DOM access, are these [http://www.cs.brown.edu/courses/bridge/1998/res/javascript/javascript-tutorial.html tutorials] and a description of how to use [http://www.crockford.com/javascript/inheritance.html classical inheritance])<br />
<br />
At that point, you should be familiar enough to start writing your own, novel applications. Of course, through additional tutorials and the language reference, you can learn about more features of Emerson and the system.<br />
<br />
If you get stuck or are unable to find the answer to a question in these guides, try the [http://groups.google.com/group/emerson-users emerson-users mailing list]. Be sure to search before posting a new question.<br />
<br />
Head over to the :ref:`emerson-tutorials` to get started.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Tutorials/Adding_OptionsGuides/Platform Development/Tutorials/Adding Options2012-05-25T21:49:59Z<p>Ewencp: Initial import from sirikata-docs</p>
<hr />
<div>= Adding Options using Sirikata's Option Library =<br />
<br />
The primary method of customizing Sirikata's behavior is through plugins: different implementations of a particular service or interface are stored in and loaded from different plugins. To further customize behavior, Sirikata has an options system.<br />
<br />
== Option Parsing ==<br />
<br />
Options are generally specified in two places: the command line and configuration files. Command line options are specified in the standard format<br />
<br />
<pre>sirikata-binary --config.option.first=value1 --config.option.second=value2</pre><br />
Note that if you need to include special characters in an option (spaces, <tt>\</tt>, <tt>&quot;</tt>, etc), you'll need to quote and escape them:<br />
<br />
<pre>sirikata-binary &quot;--config.option.first=value with spaces&quot;</pre><br />
Configuration files are loaded by specifying them in the command line opion <tt>--cfg=file.cfg</tt>. They are formatted as a list of option-value pairs<br />
<br />
<pre>config.option.first=value1<br />
config.option.second=value2</pre><br />
== Recursive Options ==<br />
<br />
A key property of Sirikata's option system is that it will not allow unknown options. In order to accomplish this when there are options being added dynamically (e.g. by plugins) it uses recursive options.<br />
<br />
For instance, consider a the interface <tt>LocationService</tt> and two implementations, <tt>LocalLocationService</tt> and <tt>DistributedLocationService</tt>. The <tt>LocalLocationService</tt> may have no special options, but <tt>DistributedLocationService</tt> might need to allocate a network socket to communicate with neighboring servers. In this case, it needs a <tt>--port</tt> option. We can't add the option globally because the different plugins need different options and we don't want implementation details of the plugin to leak into the main binary using them. (Further the option name could easily conflict with the name used by many other plugins).<br />
<br />
Instead, we define only two options: <tt>loc</tt> and <tt>loc-options</tt>. The first specifies which plugin we use (e.g. <tt>local</tt> or <tt>distributed</tt>) and the second is just a string which gets passed along to the plugin as options. The plugin is then responsible for parsing them. Of course the plugin may parse them however it likes (it just receives them as a String), but using the Sirikata options system is highly encouraged to simplify the implementation, avoid redundancy, and for consistency.<br />
<br />
Note that these recursive options often require quoting:<br />
<br />
<pre>sirikata-binary --loc=distributed &quot;--loc-options=--port=1234 --max-dist=1000&quot;</pre><br />
== Options Basics ==<br />
<br />
Options are always provided initially as Strings, read from either the command line or a configuration file. The option system takes care of parsing these options, verifying their formatting, and converting them to the desired type.<br />
<br />
This entire process should be transparent to you: you just need to specify a set of '''options''', with their types, defaults, and descriptions, which you store in a '''module'''. You then request that the options are parsed and extract and convert the actual option values.<br />
<br />
In the following example, we'll create options for a simple <tt>comm</tt> plugin. First, we need the options library itself:<br />
<br />
<pre>#include &lt;sirikata/core/options/Options.hpp&gt;</pre><br />
Next, we need to specify our set of options. We'll create them under the module <tt>&quot;comm&quot;</tt> and add two options, `host` and `port`:<br />
<br />
<pre>Sirikata::InitializeClassOptions ico(&quot;comm&quot;,NULL,<br />
new Sirikata::OptionValue(&quot;host&quot;, &quot;127.0.0.1&quot;, Sirikata::OptionValueType&lt;String&gt;(), &quot;The host to connect to.&quot;),<br />
new Sirikata::OptionValue(&quot;port&quot;, &quot;7777&quot;, Sirikata::OptionValueType&lt;uint16&gt;(), &quot;The port to connect to.&quot;),<br />
NULL);</pre><br />
Make sure that your module is unique: while a conflict isn't a problem so long as types match up, you could allow options that shouldn't be permitted due to somebody else's options being permitted along with yours.<br />
<br />
<tt>InitializeClassOptions</tt> can accept an arbitrarily long list of <tt>OptionValue</tt>'s, terminated by a <tt>NULL</tt>. This registration process should be performed once. Usually this means registering them during plugin initialization. (If you need per-instance options, then you should generate a module for each of instance. Usually this is only necessary when you could be creating multiple instances simultaneously.)<br />
<br />
Next, when you actually have some options to parse (for instance, when a new instance of your implementation is requested), you can retrieve the <tt>OptionSet</tt>, parse, and extract options:<br />
<br />
<pre>OptionSet* optionsSet = OptionSet::getOptions(&quot;comm&quot;,NULL);<br />
optionsSet-&gt;parse(args);<br />
<br />
String server_host = optionsSet-&gt;referenceOption(&quot;host&quot;)-&gt;as&lt;String&gt;();<br />
uint16 server_port = optionsSet-&gt;referenceOption(&quot;port&quot;)-&gt;as&lt;uint16&gt;();</pre><br />
Note that the types requested during conversion match those specified in the registration. The system will throw an exception if you try to convert to the wrong type.<br />
<br />
== Adding Parsing Methods For a New Option Type ==<br />
<br />
Options are not limited to primitive types like integers and Strings. Any type can be used as an option so long as the option system can convert it to and from a String. For instance, Vector3 frequently appears as an option type for specifying properties like locations and bounding regions.<br />
<br />
Suppose you have a new type, <tt>MyStruct</tt>, which you need to use as an option value. While the Option system provides overloads for many types, you need to make sure the template instantiation <tt>OptionValueType&lt;MyStruct&gt;</tt> will be valid in order to use it as an option. In order for this to be valid, there must be an accessible implementation of the &quot;stream&quot; operators (<tt>&lt;&lt;</tt> and <tt>&gt;&gt;</tt>). If you're familiar with <tt>boost::lexical_cast</tt>, the requirements are essentially identical.<br />
<br />
If we have the following definition of <tt>MyStruct</tt>:<br />
<br />
<pre>struct MyStruct {<br />
int32 x;<br />
int32 y;<br />
};</pre><br />
then making the following globally accessible is a simple way to provide the necessary conversions:<br />
<br />
<pre>inline std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const MyStruct&amp; rhs) {<br />
os &lt;&lt; '&lt;' &lt;&lt; rhs.x &lt;&lt; ',' &lt;&lt; rhs.y &lt;&lt; '&gt;';<br />
return os;<br />
}<br />
<br />
inline std::istream&amp; operator&gt;&gt;(std::istream&amp; is, MyStruct&amp; rhs) {<br />
char dummy;<br />
is &gt;&gt; dummy &gt;&gt; rhs.x &gt;&gt; dummy &gt;&gt; rhs.y &gt;&gt; dummy;<br />
return is;<br />
}</pre><br />
Of course the parsing could be more robust, but this minimal example is sufficient to get conversions sufficient to use <tt>MyStruct</tt> as an option value type.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Tutorials/Writing_a_PluginGuides/Platform Development/Tutorials/Writing a Plugin2012-05-25T21:49:35Z<p>Ewencp: Formatting cleanup</p>
<hr />
<div>= Writing a Sirikata Plugin =<br />
<br />
The primary way to extend Sirikata is to provide a new implementation of an interface in one of the libraries. These implementations generally live in plugins and only the plugins required to run the desired world are loaded. For example, the interface <tt>ObjectSegmentation</tt> defines the interface for the component that stores the mapping from objects to the servers managing them. However, we could implement it in different ways. Sirikata already has one implementation called <tt>LocalObjectSegmentation</tt> for spaces which will only ever run on a single server. This implementation is trivial. It also has another, <tt>CraqObjectSegmentation</tt>, which works in the distributed case by using a separate key-value store based on CRAQ.<br />
<br />
Most components in the system can have different implementations. To make these options pluggable and not require all dependencies to build the system, we utilize a plugin-based architecture. This tutorial will explain how to create a new plugin to extend the system. Obviously this approach works for any interface, but this tutorial will focus on a new <tt>ObjectSegmentation</tt> implementation called <tt>TutorialObjectSegmentation</tt>.<br />
<br />
== Skeleton Code ==<br />
<br />
The best way to start a new plugin is to base it on the skeleton plugin for <tt>libcore</tt>, found in <tt>libcore/plugins/skeleton</tt>. The rest of this tutorial will be based on this code, so you can start by copying it into place for your new plugin. It contains only a single file, <tt>PluginInterface.cpp</tt>, since it has no real interface implementation. You will add new files for the implementation later in this tutorial.<br />
<br />
== Adding the Plugin to the Build System ==<br />
<br />
As with the skeleton code, there are some commands for adding the skeleton plugin to the build system. This is a good starting point, especially since the build system is complex. Translating the skeleton commands, we might end up adding something like this to <tt>build/cmake/CMakeLists.txt</tt>.<br />
<br />
<pre class="sourceCode cmake">SET(LIBSPACE_PLUGIN_TUTORIAL_DIR ${LIBSPACE_PLUGIN_DIR}/tutorial)<br />
SET(LIBSPACE_PLUGIN_TUTORIAL_SOURCES ${LIBSPACE_PLUGIN_TUTORIAL_DIR}/PluginInterface.cpp)<br />
<br />
ADD_PLUGIN_TARGET(space-tutorial<br />
SOURCES ${LIBSPACE_PLUGIN_TUTORIAL_SOURCES}<br />
TARGET_LDFLAGS ${sirikata_LDFLAGS}<br />
LIBRARIES ${SIRIKATA_CORE_LIB} ${SIRIKATA_SPACE_LIB}<br />
TARGET_LIBRARIES ${SIRIKATA_CORE_LIB} ${SIRIKATA_SPACE_LIB})<br />
SET(PLUGIN_INSTALL_LIST ${PLUGIN_INSTALL_LIST} space-tutorial)</pre><br />
First, note that we've labelled it appropriately as a space plugin by prefixing everything with <tt>LIBSPACE</tt> . Second, we've made sure all our variables have our plugin name in them, <tt>TUTORIAL</tt> . The utility macro <tt>ADD_PLUGIN_TARGET</tt> takes care of most of the complicated work of setting up a plugin to be built. You specify source files, any linker flags and target libraries, and the macro takes care of the rest. The final line adds the plugin for installation.<br />
<br />
If this plugin has a non-standard dependency, then we should only add the plugin if that dependency is found. This would look like this for a dependency called <tt>tutdep</tt><br />
<br />
<pre class="sourceCode cmake">FIND_PACKAGE(tutdep)<br />
IF(TUTDEP_FOUND)<br />
ADD_PLUGIN_TARGET(space-tutorial<br />
...<br />
)<br />
ENDIF(TUTDEP_FOUND)</pre><br />
If necessary, add the <tt>tutdep</tt> library to the <tt>LIBRARIES</tt> argument of <tt>ADD_PLUGIN_TARGET</tt>.<br />
<br />
== Implementing the Interface ==<br />
<br />
How the interface is implemented obviously depends on the plugin you are writing. Here, we'll present the skeleton for `TutorialObjectSegmentation` , which is enough to explain the basic concepts.<br />
<br />
Following the interface for <tt>ObjectSegmentation</tt> we create a file <tt>TutorialObjectSegmentation.hpp</tt> with the following contents<br />
<br />
<pre>#ifndef _SIRIKATA_TUTORIAL_OBJECT_SEGMENTATION_HPP_<br />
#define _SIRIKATA_TUTORIAL_OBJECT_SEGMENTATION_HPP_<br />
<br />
#include &lt;sirikata/space/ObjectSegmentation.hpp&gt;<br />
<br />
namespace Sirikata {<br />
<br />
class TutorialObjectSegmentation : public ObjectSegmentation {<br />
public:<br />
...<br />
};<br />
<br />
} // namespace Sirikata<br />
<br />
#endif //_SIRIKATA_TUTORIAL_OBJECT_SEGMENTATION_HPP_</pre><br />
and a <tt>TutorialObjectSegmentation.cpp</tt> with the following contents<br />
<br />
<pre>#include &quot;TutorialObjectSegmentation.hpp&quot;<br />
<br />
namespace Sirikata {<br />
<br />
TutorialObjectSegmentation::TutorialObjectSegmentation() {<br />
}<br />
<br />
...<br />
<br />
} // namespace Sirikata</pre><br />
Recall that we had to specify our source files in the build system. Having added the implementation file, we need to add it to the build, changing our source file list:<br />
<br />
<pre class="sourceCode cmake">SET(LIBSPACE_PLUGIN_TUTORIAL_SOURCES<br />
${LIBSPACE_PLUGIN_TUTORIAL_DIR}/PluginInterface.cpp<br />
${LIBSPACE_PLUGIN_TUTORIAL_DIR}/TutorialObjectSegmentation.cpp<br />
)</pre><br />
== Exposing the Implemented Interface from the Plugin ==<br />
<br />
The previous steps got the implementation into the dynamic library, but it isn't exposed to the rest of the system. Sirikata enables you to expose it as an option via a <tt>Factory</tt>. Usually, any interface which could be instantiated from a plugin has a <tt>Factory</tt> associated with it. The factory allows implementations to register a constructor function which can be invoked to create a new instance, and names that constructor with a string. In this way, the library, and its users, only needs to know about the generic interface, the factory, and what strings can be used to identify implementations.<br />
<br />
Back in the <tt>PluginInterface.cpp</tt> we add (or replace) the following code:<br />
<br />
<pre>namespace Sirikata {<br />
<br />
static ObjectSegmentation* createTutorialOSeg(<br />
SpaceContext* ctx, Network::IOStrand* oseg_strand,<br />
CoordinateSegmentation* cseg, OSegCache* cache,<br />
const String&amp; args)<br />
{<br />
return new TutorialObjectSegmentation(ctx, oseg_strand, cseg, cache);<br />
}<br />
<br />
} // namespace Sirikata<br />
<br />
SIRIKATA_PLUGIN_EXPORT_C void init() {<br />
using namespace Sirikata;<br />
if (space_tutorial_plugin_refcount==0) {<br />
using std::tr1::placeholders::_1;<br />
using std::tr1::placeholders::_2;<br />
using std::tr1::placeholders::_3;<br />
using std::tr1::placeholders::_4;<br />
OSegFactory::getSingleton()<br />
.registerConstructor(&quot;tutorial&quot;,<br />
std::tr1::bind(&amp;createTutorialOSeg, _1, _2, _3, _4));<br />
}<br />
space_tutorial_plugin_refcount++;<br />
}<br />
<br />
SIRIKATA_PLUGIN_EXPORT_C void destroy() {<br />
using namespace Sirikata;<br />
if (space_tutorial_plugin_refcount==0) {<br />
OSegFactory::getSingleton().unregisterConstructor(&quot;tutorial&quot;);<br />
}<br />
}</pre><br />
This registers our constructor (indirectly via a wrapper function) to the factory when the plugin is initialized, and unregisters it when the plugin is destroyed. In this case, you can ignore the parameters to the constructor --they are just the parameters all <tt>ObjectSegmentation</tt> implementations must take. While the <tt>createTutorialOSeg</tt> function must match this signature, the constructor could take additional parameters. In fact, a common pattern is to parse arguments from the last parameter and pass them directly into the <tt>TutorialObjectSegmentation</tt> constructor so the parsing of options is isolated from the implementation.<br />
<br />
If you aren't familiar with it, you probably want to learn about boost::bind. It is a generalization of function pointers which is type-safe and allows you to curry arguments. In this case, it is used to turn <tt>createTutorialOSeg</tt> into a type-safe &quot;constructor&quot; which returns an <tt>ObjectSegmentation*</tt>.<br />
<br />
That's all that's required -- no modifications to the core code and no need to export symbols from the plugin.<br />
<br />
== Conclusion ==<br />
<br />
This tutorial should have enabled you to create a new plugin for Sirikata which adds and exposes a new interface implementation to Sirikata. Frequently, after a basic implementation works one of the first needs is to control its behavior with options. See [[Guides/Platform_Development/Tutorials/Adding_Options|the options tutorial]] for details on using options.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Tutorials/Application_StructureGuides/Platform Development/Tutorials/Application Structure2012-05-25T21:49:17Z<p>Ewencp: Cleanup formatting</p>
<hr />
<div>= Structure of a Sirikata Application: Contexts, Services and Plugins =<br />
<br />
In order to add new components to the system, and in some cases when creating a plugin implementing an existing interface, you'll need to understand how a Sirikata application (like <tt>space</tt> or <tt>cppoh</tt>) is structured. This document walks you through the process of setting up a new application. Although this will be unusual -- you would only follow this process directly to add a new binary for a completely new service -- it is useful to provide context for how components you write will fit into an application.<br />
<br />
Sirikata provides a basic framework for constructing applications which provides common infrastructure, for example managing the event loop, managing the lifetime of the application, some simple timing functions, and managing the services running in the application.<br />
<br />
== Definitions ==<br />
<br />
To begin, we start with some definitions. These should give a sense of what each one does, but the rest of the tutorial will fill in the details.<br />
<br />
== A Barebones Application ==<br />
<br />
A barebones application is simple to setup: simply create a Context to run the application and start it. When the application finishes running, it will return and we just need to clean up.<br />
<br />
First, start by including the necessary headers:<br />
<br />
<pre>#include &lt;sirikata/core/service/Context.hpp&gt;<br />
#include &lt;sirikata/core/network/IOServiceFactory.hpp&gt;<br />
#include &lt;sirikata/core/network/IOService.hpp&gt;<br />
#include &lt;sirikata/core/trace/Trace.hpp&gt;</pre><br />
Then create the <tt>main</tt> method and create the <tt>Context</tt> , filling in a few parameters<br />
<br />
<pre>int main(int argc, char** argv) {<br />
<br />
Network::IOService* ios = Network::IOServiceFactory::makeIOService();<br />
Network::IOStrand* mainStrand = ios-&gt;createStrand();<br />
<br />
Trace::Trace* trace = new Trace::Trace(trace_file);<br />
Time epoch = Timer::now();<br />
<br />
Context* ctx = new Context(&quot;OurApplication&quot;, ios, strand, trace, epoch);</pre><br />
The first two lines setup the basic event handling system and these objects are stored in <tt>Context</tt> to make them available throughout the system. The <tt>Trace</tt> and <tt>epoch</tt> values are for collecting statistics and controlling timed applications.<br />
<br />
At this point, the context has almost enough information to run. The <tt>Context</tt> is itself a <tt>Service</tt> that will be added to itself to get notified of the run starting and ending. Then we'll start the application by calling <tt>run</tt>.<br />
<br />
<pre>ctx-&gt;add(ctx);<br />
ctx-&gt;run(1);</pre><br />
The parameter to the run method is how many threads to run with. Sirikata supports running with many threads to exploit as many cores as are available on the system. Events will be dispatched and handled on multiple threads. To ensure serialization of certain event handlers, see <tt>IOStrand</tt> or use locks directly.<br />
<br />
Finally, when everything has stopped running and we just need to clean up and close the main method.<br />
<br />
<pre>ctx-&gt;cleanup();<br />
trace-&gt;prepareShutdown();<br />
<br />
delete ctx;<br />
<br />
trace-&gt;shutdown();<br />
delete trace;<br />
<br />
delete mainStrand;<br />
Network::IOServiceFactory::destroyIOService(ios);<br />
<br />
return 0;<br />
<br />
}</pre><br />
<br />
And that's it. This should be sufficient to get a running application -- but it won't do anything except wait for shutdown to be requested (which you can do via a signal, hit Ctrl-C).<br />
<br />
== Loading Plugins ==<br />
<br />
In order to use implementations of interfaces that are not included in the libraries, you must load a plugin. For example, there is not an implementation of the <tt>ObjectSegmentation</tt> interface provided directly in the <tt>libspace</tt> library. One implementation, <tt>LocalObjectSegmentation</tt> is implemented in the <tt>space-local</tt> plugin and is used to run a single space server system where only a local table is required for the ObjectSegmentation.<br />
<br />
In our hypothetical application, let's assume we need an <tt>ObjectSegmentation</tt> instance and we know ahead of time that we want the <tt>LocalObjectSegmentation</tt> . First, we'll need to add the header that brings in the interface and its factory, <tt>OSegFactory</tt> . Because we'll need to load the appropriate plugin, we'll also need to use the <tt>PluginManager</tt> class.<br />
<br />
<pre>#include &lt;sirikata/space/ObjectSegmentation.hpp&gt;<br />
#include &lt;sirikata/core/util/PluginManager.hpp&gt;</pre><br />
Then, after the creation of our <tt>Context</tt> , we need to first load the plugin to make the implementation available to the <tt>OSegFactory</tt> , and then instantiate a copy through the factory.<br />
<br />
<pre>PluginManager plugins;<br />
assert( ! OSegFactory::getSingleton().hasConstructor(&quot;local&quot;) );<br />
plugins.load(&quot;space-local&quot;);<br />
<br />
assert( OSegFactory::getSingleton().hasConstructor(&quot;local&quot;) );<br />
ObjectSegmentation* oseg = OSegFactory::getSingleton().getConstructor(&quot;local&quot;)(ctx, ctx-&gt;mainStrand);</pre><br />
On the last line, the parameters are not important; the key point is that we retrieved the constructor for the <tt>&quot;local&quot;</tt> implementation of <tt>ObjectSegmentation</tt> . That's it -- we dynamically loaded the plugin, making this local implementation available, and instantiated it. The <tt>assert</tt> statements show what the call to <tt>PluginManager::load()</tt> changed: the <tt>&quot;local&quot;</tt> constructor became available.<br />
<br />
Of course we'll need to clean this up along with the other objects.<br />
<br />
<pre>delete oseg;</pre><br />
== Adding a Service ==<br />
<br />
Of course, the <tt>ObjectSegmentation</tt> we created isn't connected to anything and won't be notified of the start and end of the application. Knowing how to connect the component depends on the particular component, but adding the component to the application's context is easy<br />
<br />
<pre>ctx-&gt;add(oseg);</pre><br />
<tt>ObjectSegmentation</tt> implements the <tt>Service</tt> interface, so it will now be notified with <tt>start()</tt> and <tt>stop()</tt> method invokations.<br />
<br />
== Conclusion ==<br />
<br />
Now that you know the basics of a Sirikata application, you should take a look at the <tt>Context</tt>, <tt>Service</tt>, and <tt>Plugin</tt> classes in the API documentation to see what else they can do. And of course the <tt>main.cpp</tt> files for each Sirikata binary is a good place to start: they are long but readable, will teach you some of the common patterns, and show how these tools are integrated with others such as the options system.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/TutorialsGuides/Platform Development/Tutorials2012-05-25T21:48:25Z<p>Ewencp: /* Platform Development Tutorials */ Make link names more attractive</p>
<hr />
<div>= Platform Development Tutorials =<br />
<br />
The sheer size of complexity of the Sirikata code can be a real barrier to contributing. The other parts of the guide try to help a new developer isolate themselves to a smaller portion of the code, allowing them to quickly understand the components they need to modify or extend. Here, we try to address a number of common tasks that span the entire project, either because they deal with utility code used throughout the project or because they deal with the architecture of the entire system.<br />
<br />
* [[Guides/Platform_Development/Tutorials/Application Structure|Application Structure]]<br />
* [[Guides/Platform_Development/Tutorials/Writing a Plugin|Writing a Plugin]]<br />
* [[Guides/Platform_Development/Tutorials/Adding Options|Adding Options]]</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Tour_of_the_CodeGuides/Platform Development/Tour of the Code2012-05-25T19:27:27Z<p>Ewencp: Clean up, tighten, wiki formatting, and fix missing refs</p>
<hr />
<div>= A Tour of the Sirikata Code =<br />
<br />
In order to extend or modify the Sirikata code, you'll need a basic understanding of the components involved and where to find them in the code base. Make sure you've already familiarized yourself with the [[Guides/Architecture|system architecture]] before moving on.<br />
<br />
== Implementation Approach ==<br />
<br />
The Sirikata implementation is broken down into libraries, binaries, and plugins.<br />
<br />
;Libraries<br />
:hold the bulk of the common functionality and all the exported interfaces in the system. They are organized logically based on high level tasks. By keeping most of the code in libraries it is reusable: they contain all the components or interfaces but don't full connect them.<br />
<br />
;Binaries<br />
:put the pieces together, making sure all the necessary components for a service are available, instantiate them, connect them, and manage the service. They are minimal because they only tie existing components together. Adding new binaries should be unusual -- new functionality is usually added to libraries or plugins.<br />
<br />
;Plugins<br />
:contain the specialized functionality of the system. They usually contain an implementation of an interface from one of the libraries and add it to a factory so a binary can instantiate it. This is probably the most common location for code modifications -- the basic functionality is already defined in libraries and plugins provide different implementations with different features (e.g. different scripting engines).<br />
<br />
== Code Layout Conventions ==<br />
<br />
Navigating the code base is made simpler by following a few conventions.<br />
<br />
# Each library or binary is organized into its own directory. Library directories are prefixed with <tt>lib</tt>, e.g. <tt>libmesh</tt>, and binaries aren't, e.g. <tt>space</tt>.<br />
# Source within each code directory should be broken into a standard set of directories: <tt>include</tt> for public header files, <tt>src</tt> for internal headers and source files, and <tt>plugins</tt> for all code associated with plugins for interfaces in that library.<br />
# Plugins are always associated with a library, not a binary. Plugins implement generic interfaces and these generic interfaces should always be in libraries (binaries should not export any additional symbols).<br />
<br />
Of course there are some additional directories that don't follow these conventions, but they are easily identified. Examples include the <tt>scripts</tt> and <tt>build</tt> directories.<br />
<br />
As an example, here are is the directory layout for a few items in the repository:<br />
<br />
<pre>libcore/<br />
include/<br />
sirikata/core/*.hpp<br />
src/<br />
plugins/<br />
local/<br />
test/<br />
space/<br />
src/</pre><br />
The library has longer include directories to make the directory structure work for both in-tree builds and when the libraries have been installed into system directories. Since only libraries should have headers installed, only libraries require this structure.<br />
<br />
In this example, libcore has a plugin <tt>local</tt> in addition to its <tt>include</tt> and <tt>src</tt> directories. It also has some unit tests associated with it, stored in a separate <tt>test</tt> directory. The space binary only has a source directory.<br />
<br />
== A Tour of the Libraries and Binaries ==<br />
<br />
At a high level, the system is broken down into two binaries which clearly map to the space and object host components:<br />
<br />
* <tt>space</tt> is the space server binary. It can be run in isolation or on many servers to simulate a larger world.<br />
* <tt>cppoh</tt> is the object host binary. It ties together the components for simulating objects -- storage, scripting, display, etc.<br />
<br />
As mentioned earlier, these binaries should be minimal. They should instantiate implementations (in plugins) of interfaces (in libraries). Therefore, they depend on a number of libraries:<br />
<br />
* <tt>libcore</tt> provides '''a lot''' of core utilities across a range of functionality. As you're adding code, this library will be a powerful resource for common functionality -- options, network utilities, CDN access, geometric data types, threads and locking, platform abstractions for dealing with OS interaction like signals, factory and listener patterns, etc.<br />
* <tt>libmesh</tt> provides basic data structures for dealing with meshes and generic interfaces for mesh processing. Plugins for libmesh implement loading and saving for different file formats and &quot;filters&quot; for meshes, e.g. for simplification, computing statistics, or any type of content conditioning.<br />
* <tt>libproxyobject</tt> provides functionality organized around &quot;proxies&quot; or replicated objects. Proxies are objects which you have learned about and may have knowledge of their location, appearance, and messaging identifier, but they are not local. For most developers this library is most relevant when dealing with display since display is focused around these basic properties and a display plugin lives under this library.<br />
* <tt>libspace</tt> contains all the interfaces and generic services for space servers. This include the generic parts of session management, message forwarding, location management, and querying, as well as interfaces for OSeg (routing table), CSeg (region to space server mapping), and PIntO (object queries).<br />
* <tt>liboh</tt> contains all the interfaces and generic services for object hosts. This includes the code for managing connections to space servers and interacting with them, managing collections of objects, and the interface for object scripts.<br />
<br />
This figure shows how the binaries depend on these libraries (and the libraries depend on each other).<br />
<br />
[[Image:code_libraries_and_binaries.png]]<br />
<br />
Since plugins are stored within the directories of the library they are associated with, most code specific to a space is under <tt>libspace</tt> and most code specific to object hosts is under <tt>liboh</tt>. However, code useful to both appears in the other libraries, upon which <tt>libspace</tt> and <tt>liboh</tt> depend. The separation of these core libraries is simply to logically partition the code to make it more manageable. Note that there are direct dependencies that are only implicit transitively in the image. For instance, both <tt>liboh</tt> and <tt>libspace</tt> depend directly on <tt>libcore</tt>, but this is only implied by their dependence on <tt>libmesh</tt> and <tt>libproxyobject</tt>.<br />
<br />
You may also notice that the content distribution network is missing from this description. Currently, the CDN uses stock web servers, so its implementation is separated and not referenced in the remainder of this guide. It can be found in the <tt>cdn</tt> directory. Access to the CDN is provided in the <tt>transfer</tt> directories in <tt>libcore</tt> since it is used throughout the system.<br />
<br />
=== Additional Libraries and Binaries ===<br />
<br />
You'll notice that there are some additional directories for libraries and binaries:<br />
<br />
* <tt>libsqlite</tt> provides access to SQLite databases. It is a library since SQLite is used by plugins associated with multiple libraries.<br />
* <tt>analysis</tt> performs analysis of trace data from measurement experiments of the system. This reports data which helps evaluate the performance and correctness of the system.<br />
* <tt>bench</tt> performs a few low-level benchmarks.<br />
* <tt>cseg</tt> is a service which the CoordinateSegmentation in the space server communicates with. It organizes and coordinates space servers.<br />
* <tt>pinto</tt> is a service which the Proximity service in the space server communicates with. It aids in the query handling process for large deployments with many servers.<br />
* <tt>simoh</tt> is a stripped down simulated object host used for automatic evaluation of the system. It lacks true scripting support, opting for simplicity and minimalism to accurately benchmark the system.<br />
<br />
These won't be discussed further in this guide as they are more would require more detail than this guide aims to give.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Components/SpaceGuides/Platform Development/Components/Space2012-05-25T19:21:19Z<p>Ewencp: Minor clarifcation of terms and cleanup</p>
<hr />
<div>= Space =<br />
<br />
The space provides the actual world: it enforces the physical laws that objects obey. Objects connect to it and it provides the coordinate system, simulates global effects like physics, and enables interaction between objects.<br />
<br />
From the perspective of objects connected to the space (or their object hosts) a space provides these logical service:<br />
<br />
* Presence (also known as space membership, session management, authentication)<br />
* Coordinate System<br />
* Physical Simulation<br />
* Object Discovery<br />
* Interobject Communication<br />
<br />
This image shows the software components of the space at a high level.<br />
<br />
[[Image:space_server_architecture.png]]<br />
<br />
We'll cover each logical service and map it to the software components in the image. This mapping should guide you to the right classes and interfaces to look at when addressing a particular aspect of the system.<br />
<br />
In the image, the <tt>Server</tt> is shown as encompassing all other components but has a dashed border. This shows that the <tt>Server</tt> has references to all these objects but doesn't create or own them all -- it ties them together and helps coordinate them. The <tt>Server</tt> can be thought of as the core service of the space server.<br />
<br />
== Presence ==<br />
<br />
When an object wants to enter the world, the space acts as the guardian. The policy for entrance is pluggable, but most of the machinery is the same regardless of the authentication method -- customization is provided simply by implementing different identify verification methods. In the code, authentication and presence management is driven by the <tt>Server</tt> class, supported by the <tt>ObjectHostConnectionManager</tt> and <tt>ObjectConnection</tt> classes. The <tt>Authenticator</tt> interface abstracts authentication methods.<br />
<br />
In many existing systems, especially games, authentication is only required for clients: a distinction is made between objects in the world and avatars. In Sirikata, all objects require authentication. This may sound costly, but the cost can easily be mitigated by using intelligent <tt>Authenticator</tt> implementations.<br />
<br />
Part of acquiring a presence in a world is providing the space with all the basic information necessary to represent the object in the world. In this respect, the code for presence management interacts with all other components since it provides initial values for them. This explains why it is managed in the central <tt>Server</tt> class, which ties together all the components of the space server.<br />
<br />
== Coordinate System ==<br />
<br />
The unique aspect of virtual worlds is that objects inherit a shared, 3D space. The space provides the coordinate system, controls the extents of the world, and determines whether object's request positions can be set. &quot;Location&quot; in Sirikata refers to a collection of geometric properties in addition to position: velocity, orientation, rotational velocity, bounds, and mesh URL.<br />
<br />
=== Coordinate Segmentation ===<br />
<br />
The <tt>CoordinateSegmentation</tt> is an internal service for spaces which divides the world into regions and maps each region to a space server for simulation. It can map from a position to the space server managing it as well as from a space server to the region managed by it. This is used by many other parts of the system since it lets them discover other servers they might need to communicate with.<br />
<br />
=== LocationService ===<br />
<br />
The <tt>LocationService</tt> is the externally visible service which maintains object locations. A <tt>LocationService</tt> implementation is essentially a large table storing information for each object. As necessary, this information is replicated to the <tt>LocationService</tt> on other space servers.<br />
<br />
<tt>LocationService</tt> also provides a subscription service: objects can be subscribed for updates about other objects positions (currently performed only by <tt>Proximity</tt>). Instead of always sending all updates to all listeners, <tt>LocationUpdatePolicy</tt> determines when updates should be sent to objects. For instance, the update policy might reduce the rate of updates when the messaging system is overloaded or send updates more frequently to nearby objects since changes will be more significant to them.<br />
<br />
== Physical Simulation ==<br />
<br />
Physical simulation is just a set of constraints on the values stored in <tt>LocationService</tt>: requests to change position must be checked for validity and a continuous simulation must be run to update those values according to the laws of physics for the world. This is shown in the figure as the Physics component intercepting requests from objects before they reach the location service.<br />
<br />
== Object Discovery ==<br />
<br />
Once objects are inhabiting the world, they need to be able to interact. Aside from the physical simulation, this occurs through interobject messaging. But to message an object, you must first know how to address it. The process of learning object identifiers is called &quot;object discovery.&quot;<br />
<br />
Sirikata restricts object discovery to simple geometric queries. This enables efficient implementation and objects can filter results further when they receive the results. In Sirikata the query has a single parameter: a solid angle. All with solid angle larger than this value from the perspective of the querying object will be returned.<br />
<br />
Because this interface is fixed and the default implementation is efficient, unlike most other components, object discovery isn't abstracted into an interface and an implementation via plugin. Instead, the class <tt>Proximity</tt> implements query handlers, including hanlding interaction with other servers to return objects connected to other servers.<br />
<br />
<tt>Proximity</tt> interacts heavily with <tt>LocationService</tt>, which provides all the state required to evaluate queries. It also uses <tt>CoordinateSegmentation</tt> to determine which other servers to communicate with. This process is handled by the <tt>PintoServerQuerier</tt> class.<br />
<br />
== Interobject Communication ==<br />
<br />
Once an object has identifiers for other objects, it needs to interact with them. It does so by sending Object Datagram Protocol (ODP) messages. These are formatted and have semantics a lot like UDP or IP packets: they have source and destination addresses and ports and a payload. The system knows nothing more about the format of the packets (unless they are destined for a space service such as <tt>LocationService</tt> or <tt>Proximity</tt>). Packets are best-effort: they may be dropped if the space servers are overwhelmed with traffic.<br />
<br />
The two components responsible for getting messages to their destination are the <tt>ObjectSegmentation</tt> and the <tt>Forwarder</tt>.<br />
<br />
=== ObjectSegmentation ===<br />
<br />
In order to deliver a packet, the space server needs to know ''where'' to deliver it. The first step is to lookup which space server the destination object resides on. The <tt>ObjectSegmentation</tt> class performs this lookup, and externally looks like an asynchronous key-value store. In order to avoid unnecessary lookups (<tt>ObjectSegmentation</tt> storage may be on another node, requiring a network hop), <tt>OSegCache</tt> caches previously retrieved entries. To avoid a backlog, <tt>OSegLookupQueue</tt> manages the total number of outstanding queries, and also allows coalescing of requests for the same destination object's data.<br />
<br />
=== Forwarder ===<br />
<br />
With the destination server in hand, forwarding begins. This is handled by the <tt>Forwarder</tt> class. A supporting class <tt>LocalForwarder</tt> handles checking for and forwarding to local objects. Otherwise, at its simplest, the <tt>Forwarer</tt> just ships the packet to the appropriate server, using the <tt>ServerIDMap</tt> to convert from a server's unique identifier to an IP address.<br />
<br />
In practice, the <tt>Forwarder</tt> is much more complicated: it has to ensure competing flows between objects don't deny service to other flows, also manages communication between space servers and balances it with interobject communication, and make sure messages destined for space server components make it to their appropriate destination. Additional supporting classes include <tt>ODPFlowScheduler</tt> and <tt>ForwarderServiceQueue</tt>.<br />
<br />
=== Transport Protocols ===<br />
<br />
For users, it can be very inconvenient to work with best-effort datagrams. Much of the time, they'd prefer a reliable protocol, possibly stream oriented. The core system provides one such protocol based on Structured Streams (SST). The templated <tt>Stream</tt> class (and templated <tt>Connection</tt> class for support) implement this abstraction. This protocol is used between the space server and object host for services that need reliability or ordering. For instance, because <tt>Proximity</tt> results contain deltas, ordering is important. These updates are sent over SST.<br />
<br />
== Extensions ==<br />
<br />
These are the core set of services provided, but one could extend the space to provide additional services. One example where this might make sense is audio mixing: the space server can more efficiently mix audio for each client as well as collaborate with nearby space servers to generate a more complete mix than a client might be able to.<br />
<br />
If you'd like to add extensions like this, you should structure them as a generic interface which fits into the architecture. A dummy implementation (plugin) should allow spaces to run without the service and your implementation would provide the actual service. Note that usually adding an extension requires modifying both the space and the object host.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Components/Content_Distribution_NetworkGuides/Platform Development/Components/Content Distribution Network2012-05-25T19:18:41Z<p>Ewencp: Remove bogus reference to other page giving more detail.</p>
<hr />
<div>= Content Distribution Network =<br />
<br />
The content distribution network is used to store and distribute large, static, long-lived content. Some examples include meshes, textures, and object scripts. Although we can take advantage of its use in a virtual world to optimize it, the content distribution network looks very similar to existing solutions for other applications. We take advantage of this by leveraging existing solutions.<br />
<br />
The CDN supports two levels: names and content. The inputs to the CDN are always URIs. All URIs can respond with data directly. However, the preferred organization is to use a hash URI for direct data storage. This allows efficient storage, replication, and flexibility in the source of the data (e.g. direct from the provider, via a torrent, etc). Then, when referring to the content, for example when specifying a mesh, a human readable URI is used. This attaches some semantic meaning the URL and allows changes to be made in hierarchical resources without requiring large adjustments (for instance, changing a texture only requires pointing the name URI at a different hash URI; since the mesh refers to the named resource its hash doesn't change and so the content for the mesh remains the same but now points to the new texture).<br />
<br />
The CDN should support additional features that are especially useful in this context -- attaching certain types of standard metadata, range requests, and hashes on partial data to allow for safe use of partial data for lower levels of detail.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/Components/Object_HostGuides/Platform Development/Components/Object Host2012-05-25T19:18:22Z<p>Ewencp: Remove bogus reference to other page giving more detail.</p>
<hr />
<div>= Object Host =<br />
<br />
The object host handles simulation of objects and provides utilities or them to interact with the space, other objects, and the CDN. It is where object scripts (or behaviors) are loaded and run.<br />
<br />
The object host has 3 main duties:<br />
<br />
* Object simulation, including running object scripts, performing any local physical simulation that may be necessary<br />
* Session management for objects, including communication for basic services such as location management, proximity queries, and message routing.<br />
* Expose utilities to objects. Examples might include persistent storage, higher level communication abstractions, timers, an inventory service, animation utilities, and so on.<br />
<br />
In some sense, the choice of scripting language is just an extension of the first and third duties. Because we define a network protocol which the components use to communicate, the choice of scripting language is not fixed -- as long as the language can encode our messages (or connect to our library which can encode the core set of messages), it can work with the rest of the system. Scripts written in a convenient scripting language such as Python, Lua, or Ruby are just one way to extend objects. The object host may also provide other extensions (implemented as plugins) which provide other fixed functionality for objects via the same extension interface. Examples of these might be timers, an interface for web requests, or an inventory service.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_Development/ComponentsGuides/Platform Development/Components2012-05-25T19:17:47Z<p>Ewencp: Drastically simplify. We already have an explanation of the functionality and composition of the components elsewhere. We only need to introduce the level of detail we're giving here</p>
<hr />
<div>= Sirikata Components =<br />
<br />
The [[Guides/Architecture|architecture]] describes the components and their basic jobs. But to start working with the system you'll need more details about their components and how they work:<br />
<br />
* [[Guides/Platform Development/Components/Space|Space and the Space Server]]<br />
* [[Guides/Platform Development/Components/Object Host|Object Hosts]]<br />
* [[Guides/Platform Development/Components/Content Distribution Network|Content Distribution Network (CDN)]]</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/Platform_DevelopmentGuides/Platform Development2012-05-25T19:15:19Z<p>Ewencp: /* Getting Started */ Fix link to the tutorials</p>
<hr />
<div>= Introduction for Platform Developers =<br />
<br />
This guide helps you get started working on the code that runs Sirikata -- fixing bugs or adding new functionality to the system, rather than scripting objects in a running system. It provides:<br />
<br />
* A high-level map of the components of the system and the code base to help you find our way around the code and figure out what you want to be modifying.<br />
* A breakdown a detailed description of each service so you can find where in a service you need to work.<br />
* A small set of general tutorials. These are specific to the Sirikata code base, but not specific to any component. Look here to understand the code infrastructure and idioms, such as plugin architecture, the options system, and the event system.<br />
<br />
It's oriented towards the primary C++ code base; for other projects (e.g., KataJS), you'll need to look at their documentation.<br />
<br />
== Getting Started ==<br />
<br />
As mentioned above, you probably want to start with one of the three main sections:<br />
<br />
* [[Guides/Platform_Development/Tour of the Code|Tour of the Code]] - A technical tour of the system and the code repositories.<br />
* [[Guides/Platform_Development/Components|Components]] - A breakdown of the services and components of the system, with details of their operation.<br />
* [[Guides/Platform_Development/Tutorials|Tutorials]] - A series of tutorials describing certain aspects of the system which aren't specific to any component but which any developer will encounter when working with the system.<br />
<br />
== Resources ==<br />
<br />
Besides documentation and tutorials included in this guide, there's a lot of infrastructure around Sirikata and its development, e.g. the code repository, bug tracking, IRC, mailing lists, debugging tools and libraries, and more.<br />
{{:Getting_Started_for_Platform_Developers}}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Guides/ArchitectureGuides/Architecture2012-05-25T19:05:36Z<p>Ewencp: Clean up, update, and fix up references</p>
<hr />
<div>= Sirikata Architecture =<br />
<br />
== Introduction ==<br />
<br />
This document describes the basic components of a Sirikata world at the highest (and hopefully non-technical) level. Whether you're developing an application in a Sirikata world or creating and deploying your own world, you'll need to understand these basic components. World developers need to understand these components because they will configure and run them to pull together a virtual world. Application developers need to understand them because they interact with each component.<br />
<br />
At the highest level, Sirikata is composed of three parts, the space, the object hosts, and the content distribution network:<br />
<br />
;Object Host<br />
:Simulates object behavior in the world by running scripts. User clients are object hosts that also know how to run a display.<br />
<br />
;Space<br />
:A collection of one or more servers that simulate the world. Mediates interaction between objects, such as physics and communication.<br />
<br />
;Content Distribution Network<br />
:Stores semi-permanent to permanent data and delivers it to the other components. For instance, meshes that are used to display objects are stored on a CDN and client object hosts can download them to view the world.<br />
<br />
All of these components are required for a functioning world. Without object hosts, there wouldn't be any scripted behavior and no objects would connect to the world. Without the space, object hosts wouldn't know how to interact and other centralized global services like physics wouldn't be available. Without the content distribution network, there wouldn't be a place to store and retrieve data lets us display the world.<br />
<br />
These components can be put together in different ways to create different types of worlds:<br />
<br />
[[File:Deployment_open.png|200px]]<br />
[[File:Deployment_game.png|200px]]<br />
<br />
These images show two ways to deploy Sirikata. In the first, one company runs the infrastructure for the world (space), but leaves other services up to users and third parties. In the second, to ensure game rules are enforced and a good user experience, the game company runs all servers except for object hosts acting as clients.<br />
<br />
The rest of this document gives a little more detail on these components, but tries to remain non-technical. For more technical detail, look at the [[Guides/Platform Development|Platform Development Guide]].<br />
<br />
== Space ==<br />
<br />
The space is what you might think of as the laws of the world: it isn't the objects but the set of rules they must follow and how they interact with each other. In Sirikata this boils down to only a small set of services: the space manages objects locations, physics simulation, lets objects learn about other nearby objects, and enables those objects to communicate with each other. All the rest of the functionality of the world can be built on this very small base.<br />
<br />
Spaces may also provide additional services. For example, a world could function perfectly well with sounds handled entirely by exchanges between objects. However, it might be more cost effective to have the space manage sound to efficiently generate sound for each object that wants to listen.<br />
<br />
Spaces can be simulated using a single server, but are commonly simulated across a number of ''space servers'', enabling them to handle larger regions, more objects, and more clients.<br />
<br />
== Object Host ==<br />
<br />
An object host simulates objects, allowing them to specify their behavior in scripts and providing them access to spaces and CDNs. At their core, object hosts are simple: they embed a scripting language for objects and expose ways for the objects to connect to spaces and CDNs and usually provide some easier methods for interacting with other objects.<br />
<br />
The earlier examples of deployment suggest how object hosts might be used. In an open world, anybody running an object host can connect to the space. The owner adds their scripted objects, which connect to that space and start interacting with other objects. They might add code while they are in the world to extend the behavior of objects, perhaps teaching it how to interact with a new type of object or provide a new service to other avatars.<br />
<br />
In the second example, a company is developing a game. Because they want complete control over how objects behave in the world, they run all the object hosts containing objects in the world (from mountains, to swords, to goblins), except for those with the players.<br />
<br />
In both cases, clients are just a special type of object host that knows how to display the world and respond to user input. The object that manages this is the avatar. This means that clients and objects in the world aren't differentiated, both can be and are scripted using the same tools.<br />
<br />
A graphical display isn't the only extension an object host can have. Object host can support a variety of plugins: display of the 3D world, input from the user, sound input and output, different scripting languages, access to permanent storage (e.g. disk), and interoperation with other systems (e.g. HTTP access) are just a few examples.<br />
<br />
== Content Distribution Network ==<br />
<br />
The content distribution network stores and serves long-lived content the world requires to run. The most obvious example is mesh data, which often can't be distributed up-front (for instance, because users add objects with their own meshes to the world).<br />
<br />
A &quot;content distribution network&quot; can be as simple as a web server, and in fact that is a common solution. The CDN really only needs to be able to serve requests for files. However, the CDN might be much more complicated, handling a very large number of users, intelligently serving data from servers near the source of requests, doing advanced processing of content (like simplification, conversion to progressive formats for streaming), and caching files to reduce the cost of running the CDN.<br />
<br />
= The Sirikata Ecosystem =<br />
<br />
Sirikata isn't a monolithic piece of software. At its most basic, Sirikata is an architecture and set of protocols that allow the components of that architecture to interact. Implementations of these components allow a world developer to collect and tie together all the pieces necessary to run a world.<br />
<br />
The above described the high level components of Sirikata and below we list the available implementations. To run a world, you'd select at least one implementation for each component and tie them together. Within implementations there may be a lot of configuration flexibility as well. For example, the C++ implementation has a wide variety of plugins and feature toggles.<br />
<br />
== Protocol ==<br />
<br />
There is one source for the protocols that allow Sirikata components to interact. The repository is at [http://github.com/sirikata/sirikata-protocol http://github.com/sirikata/sirikata-protocol] and is referenced by all implementations listed here. Note that some components which support distributed deployment (e.g. the C++ space server) have additional, internal protocols. These internal protocols are always maintained within the repository for the specific project. Other implementations are not required or expected to support these internal protocols. Only protocols in the protocol repository should be used or relied on.<br />
<br />
== Space Server ==<br />
<br />
* C++ Space Server -- [http://github.com/sirikata/sirikata http://github.com/sirikata/sirikata] -- Currently the only implementation. Easy setup for running a single server, but also supports large, distributed deployment.<br />
<br />
== Object Host ==<br />
<br />
* C++ Object Host -- [http://github.com/sirikata/sirikata http://github.com/sirikata/sirikata] -- Plugin based scripting.<br />
** JavaScript - embeds Google's V8 and exposes core C++ object host API to JavaScript.<br />
** Emerson - A custom, domain specific language for virtual world scripting. Built as an extension on the Javascript plugin.<br />
** .NET Languages (Mono) - embeds the Mono .NET runtime and exposes core C++ object host API to .NET. Depends only on the runtime and is therefore language agnostic.<br />
<br />
* KataJS -- [http://github.com/sirikata/katajs http://github.com/sirikata/katajs] -- Runs in modern web browsers.<br />
** WebSockets for communicating with space servers.<br />
** WebGL for 3D graphics.<br />
** WebWorkers support for parallelism, script isolation.<br />
** HTML5 for UI and interaction.<br />
<br />
== Content Distribution ==<br />
<br />
So far, content distribution has been focused around HTTP based solutions.<br />
<br />
* Web Server (e.g. Apache)<br />
** Trivial implementation that just serves up static files.<br />
** Good for centrally controlled content, e.g. not incorporating user generated content.<br />
** Currently only CDN for KataJS since access from the browser requires using stock HTTP requests.<br />
<br />
* Progressive HTTP CDN -- [http://github.com/sirikata/sirikata http://github.com/sirikata/sirikata]<br />
** Allows content to be intelligently chunked and progressively loaded.<br />
** Scripts on top of web server, based on HTTP using additional headers.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=GuidesGuides2012-05-25T19:00:41Z<p>Ewencp: Rewrite to simplify for new layout, make more concise, and link to correct pages.</p>
<hr />
<div>= Welcome =<br />
<br />
== What is Sirikata? ==<br />
<br />
Sirikata is a BSD-licensed platform for virtual world applications. Virtual worlds are shared, online, 3D, interactive spaces. They have a lot of applications -- from games and entertainment, to education, to social applications. Sirikata makes creating virtual worlds easy.<br />
<br />
If you're not sure if Sirikata is, start by learning more on the [http://sirikata.com home page] or just try it out by following the instructions below to login.<br />
<br />
== How to get started ==<br />
<br />
Sirikata provides all the tools for creating a virtual world, but it isn't a single world that you can log into. Instead, you use Sirikata to run your own world or to log into someone else's world to interact with others and write scripts.<br />
<br />
If you want to join a world, start out with the [[Guides/Scripting Guide|Scripting Guide]]. It'll help you get connected to a world and write some simple scripts to make objects in the world do some simple things. Almost everyone should start here.<br />
<br />
If you're an advanced scripter, check out the [[Guides/Architecture|Architecture Guide]] to better understand Sirikata's architecture, it's features, and it's limitations.<br />
<br />
And if you're interested helping build Sirikata itself, look at the [[Guides/Platform Development|Platform Development Guide]] to help you take your first steps into the Sirikata source code.<br />
<br />
== List of Guides ==<br />
{{:Guides/TOC}}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Large_City_WorldLarge City World2012-04-02T00:57:15Z<p>Ewencp: Add screenshot</p>
<hr />
<div>This space contains a large city scene and demonstrates the automatic aggregation and simplification of objects and queries using cuts to always provide a complete view of the world. [sirikata:http://sirikata.com/demos/merustadt/merustadt.json Click here to launch with slauncher]. <br />
<br />
[[File:large-city-world-screenshot.jpg]]<br />
<br />
* Currently has about 30,000 individual meshes and the client usually displays around 1,400 at any one time.<br />
* Use arrows or AWSD to navigate. Use '[' and ']' to slow down and speed up, respectively.<br />
<br />
This just uses the stock client and none of the objects are scriptable because it is intended to demonstrate the aggregation and simplification features.<br />
<br />
<br />
Notes:<br />
<br />
* This is an experimental world which you should expect to be offline sometimes. If it's offline for a long time, please [[Platform_Developer_Communication|let us know]].<br />
* Loading is currently slow only because thousands of CDN name lookups are required even though the data is cached. We already have a [https://github.com/sirikata/sirikata-cdn/issues/9 bug] filed which should drastically reduce loading time.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Basic_Demo_WorldBasic Demo World2012-04-01T19:45:40Z<p>Ewencp: Add screenshot</p>
<hr />
<div>The basic demo world ([sirikata:http://sirikata.com/demos/basic/melville.json click here to launch with slauncher]) is a small server containing the [https://github.com/sirikata/sirikata-sample-deployment/tree/master/templates/melville Melville] [https://github.com/sirikata/sirikata-sample-deployment sample deployment]. It has:<br />
<br />
* A client with a scripted chat interface. You'll be prompted for a username when the world starts.<br />
* A simple scene containing a few buildings.<br />
* A building (the tall one you start in front of) which generates objects on our server (so they will remain in the world after you close your client).<br />
<br />
[[File:basic-melville-world-screenshot.jpg]]<br />
<br />
Some controls:<br />
<br />
* Move around with the arrow keys or AWSD.<br />
* Hit 'c' to move into third person view.<br />
* Click the tall building and hit enter to create a new object. Select the object and hit Alt+S to open the scripting window.<br />
* Hit Ctrl+S to script your own avatar.<br />
<br />
This world is intended to let you try out the system and experiment with scripting. You might be interested in [http://sirikata.com/docs/guides/appguide/tutorials/ some scripting tutorials] after you get up and running. Beware that objects you create aren't persistent: this is just a sandbox which we might restart periodically.<br />
<br />
Having trouble connecting to the world or something doesn't look right? Please [[Platform_Developer_Communication|let us know]].</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=List_of_WorldsList of Worlds2012-04-01T00:04:27Z<p>Ewencp: Clarify how slauncher links works.</p>
<hr />
<div>This is a list of worlds that are publicly available. You can use [[Sirikata_URIs|slauncher]], included with Sirikata, to connect to these worlds by just clicking the link in the '''slauncher''' column. If you used an installer, this should already be setup.<br />
<br />
{| class="wikitable"<br />
|-<br />
! World Name & Homepage<br />
! slauncher<br />
! Description<br />
<br />
|-<br />
| [[Basic Demo World]]<br />
| [sirikata:http://sirikata.com/demos/basic/melville.json Launch]<br />
| A very simple world where you can chat and experiment with Sirikata's scripting language, Emerson.<br />
<br />
|-<br />
| [[Large City World]]<br />
| [sirikata:http://sirikata.com/demos/merustadt/merustadt.json Launch]<br />
| A city scene, demonstrating aggregation & simplification for large scenes.<br />
<br />
|}</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Getting_StartedGetting Started2012-03-31T22:26:33Z<p>Ewencp: Add stand-alone getting started page to point people to more specific details depending on whether they're a developer, user, etc.</p>
<hr />
<div>Want to connect to a Sirikata virtual world to interact with others? Then you're an '''User'''. Get started at the [[Getting_Started_for_Users|user starting page.]]<br />
<br />
Want to start creating and scripting objects? Then you're an '''Application Developer'''. Get started at the [[Getting_Started_for_Application_Developers|application developer starting page]].<br />
<br />
Want to create content for the world (models and avatars)? Then you're an '''Artist'''. Get started at the [[Getting_Started_for_Artists|artist starting page.]]<br />
<br />
Want to extend Sirikata's functionality (add a new scripting language, a different physics simulation, or better rendering)? Then you're a '''Platform Developer'''. Get Started at the [[Getting_Started_for_Platform_Developers|platform developer's starting page.]]</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=DeploymentNotesDeploymentNotes2012-02-28T19:30:27Z<p>Bmistree: </p>
<hr />
<div>On sns30.cs.princeton.edu, all relevant files are located in /disk/local/sirikata/bskata/, and the rest assumes that you cd-d to this directory.<br />
<br />
===To update code:===<br />
git pull origin master:master<br />
<br />
===To re-build:===<br />
(From root directory or build/cmake)<br />
make -j6<br />
<br />
===To run space:===<br />
Open a screen session.<br />
<br />
cd /disk/local/sirikata/bskata/build/cmake<br />
<br />
* general:<br />
./space_d --servermap-options=--port=6880<br />
<br />
* with physics on:<br />
./space_d --servermap-options=--port=6880 --loc=bulletphysics<br />
<br />
* with no separate static and dynamic trees:<br />
./space_d --servermap-options=--port=6880 --prox.split-dynamic=false<br />
<br />
* with gdb around it:<br />
gdb --args <command you were going to run><br />
<br />
<br />
===To run OH on sns30:===<br />
<br />
Open a screen session.<br />
cd /disk/local/sirikata/bskata/build/cmake<br />
<br />
* pointed at your own db:<br />
./cppoh_d --object-factory-opts=--db=<path to your db file> "--servermap-options=--host=sns30.cs.princeton.edu --port=6880"<br />
<br />
* pointed at a basic small town + birthing tower db (note: requires physics to look "right")<br />
./cppoh_d --object-factory-opts=--db=demo.db "--servermap-options=--host=sns30.cs.princeton.edu --port=6880"<br />
<br />
* to run with gdb:<br />
gdb --args <command you were going to run><br />
<br />
<br />
<br />
===Notes:===<br />
Please don't modify the following files for your own testing, everyone uses them:<br />
: /disk/local/sirikata/bskata/build/cmake/demo.db<br />
: /disk/local/sirikata/bskata/build/cmake/generate.em</div>Bmistreehttps://www.sirikata.com/wiki/index.php?title=BuildbotBuildbot2012-02-08T05:08:32Z<p>Ewencp: /* Try Jobs */ Add details for waiting for try builds to finish</p>
<hr />
<div>== Buildbot ==<br />
* The buildbot can be found at http://buildbot.sirikata.com/.<br />
* Start at the buildbot [http://buildbot.sirikata.com/waterfall waterfall], which shows the build configurations horizontally and builds in chronological order (newest first) vertically. Newest builds are at the top, including in-progress builds.<br />
* The waterfall lets you check the current build status of the tree (some may still be building, so you might need to wait to ensure the latest commits are functional). It's a good way to sanity check that pushing commits on top of current master will only result in errors due to your commits.<br />
* All pushes to <tt>origin/master</tt> result in builds on the ''update'' builders.<br />
* Nightly builds are performed starting at midnight Pacific time on the ''full'' builders. These always build all dependencies: they check that 'from scratch' builds are working.<br />
* Additionally, documentation builds are performed nightly. The generated documentation is then automatically pushed to the web server.<br />
<br />
== Testing Builds ==<br />
There are two ways to test builds before pushing to master: try jobs and test branches.<br />
<br />
=== Try Jobs ===<br />
Try jobs allow you to send a diff to the buildbot, which it applies on top of the most recent commits to the repository.<br />
<br />
{{note}} For this method, you need access to the buildbot server: it works by using <tt>ssh</tt> to upload the request. Ask Ewen for access.<br />
<br />
* Install buildbot (first time only). Buildbot needs to do some work locally to generate the diff and communicate with the server, so you need it installed. Assuming your python and pip are up-to-date, the following should work:<br />
<br />
sudo pip install buildbot<br />
<br />
* Setup some configuration options so you don't have to pass them on the command line (first time only). Add the following to <tt>~/.buildbot/options</tt>:<br />
<br />
try_connect = 'ssh'<br />
try_vc = 'git'<br />
try_host = 'buildbot.sirikata.com'<br />
try_dir = '~sirikatabuildbot/master/try_jobdir'<br />
try_username = 'YOUR_USERNAME'<br />
try_builders = ["linux-update-build",<br />
"mac-update-build",<br />
"windowsxp-vc9-sp1-update-build"<br />
]<br />
# This says where to check for status updates. Useful if you want to use --wait<br />
masterstatus = 'buildbot.sirikata.com:5278'<br />
<br />
The first two options are generic, just indicating the protocol and version control system. The next two specify the machine and request location. The username is the one you get on the buildbot host. Finally, the builders can be customized, but these are good defaults. They check all three platforms using ''full'' builds, which test all dependencies. Check the main buildbot page for the names of all builders if you want to customize this.<br />
<br />
* Issue the try job, sending the diff build request to the server. In the Sirikata directory, first check the diff being submitted with the <tt>--dryrun</tt> option (<tt>-n</tt> is equivalent). Then, when satisfied, submit the job by removing that option. You may need to enter your password for your buildbot server account.<br />
<br />
cd sirikata.git/<br />
buildbot try --dryrun | less<br />
buildbot try<br />
<br />
* Buildbot ''should'' be able to figure out the base revision (i.e. where to take the diff from) and the branch to use, but you can configure these with <tt>--baserev</tt> and <tt>--branch</tt> options if necessary.<br />
<br />
* You can have the command wait until the builds finish to return. This is helpful if you want a notification when the builds complete:<br />
<br />
(buildbot try --wait || true) && notify "Try build finished"<br />
<br />
* For more options, check the help:<br />
<br />
buildbot try --help<br />
<br />
=== Test Branches ===<br />
An alternative to try jobs is to just push to the central repository on a branch and force a build. This is useful if you have a long-term branch you'll be developing on anyway.<br />
<br />
You can control builds through IRC or the web interface. IRC is generally simpler since you can easily request multiple builders to build your branch and get notified when the build finishes.<br />
<br />
==== IRC Bot ====<br />
The IRC bot sits in #sirikata on Freenode (usually as SirikataBuildBot, although sometimes as SirikataBuildBot'). Beware that if you address it as shown below, everything is public -- please don't flood the channel with a bunch of requests to the buildbot!<br />
<br />
* You can request a build of a branch <tt>foo</tt>:<br />
<br />
SirikataBuildBot: force build --branch=foo linux-full-build<br />
<br />
* Once you've got some builds running, you can ask for them to be watched so they'll be reported on in IRC when the complete. Following the example from above, we could do<br />
<br />
SirikataBuildBot: watch linux-full-build<br />
<br />
* To check the status of all builds (equivalent of waterfall view on the web page):<br />
<br />
SirikataBuildBot: status<br />
<br />
* There are plenty of other commands you can use on the IRC bot:<br />
<br />
SirikataBuildBot: help<br />
<br />
==== Web Interface ====<br />
* Push to <tt>origin</tt> on a new branch.<br />
* Go to buildbot page.<br />
* Find builder you want to test, e.g. <tt>linux-update-build</tt>, and click on it to see the builder page for it.<br />
* On the right, under the 'Force build' section, enter your username, password, reason for build, and under 'Branch to build', fill in the branch you pushed to <tt>origin</tt>. Hit the 'Force Build' button.<br />
* Wait on your build by checking the waterfall page or the builder page.<br />
* Once your done with the branch, remember to clean it up!<br />
<br />
git push origin :your_branch</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Debugging_Performance_IssuesDebugging Performance Issues2012-02-03T04:00:39Z<p>Ewencp: /* Details */ gdb prompt</p>
<hr />
<div>Sirikata is large, complicated, and uses multiple languages. Debugging performance issues can be tricky. The following tries to describe the available tools, how to use them, and which is best for different situations.<br />
<br />
== External Tools ==<br />
=== OProfile ===<br />
If you're looking for hotspots in C++ code, this is the suggested tool. It works by having the kernel periodically trigger sampling, collecting stacktraces from Sirikata (and other applications). You run opcontrol to enable sampling, run the application, and then turn off opcontrol. A separate program, opreport, will report the collected data. See [http://oprofile.sourceforge.net/doc/ the OProfile documentation] for details.<br />
<br />
A simple wrapper script for whichever binary you're targeting can be very handy:<br />
<br />
#!/bin/bash<br />
<br />
sudo opcontrol --no-vmlinux --start<br />
sudo opcontrol --reset<br />
sudo opcontrol --callgraph=6<br />
<br />
./cppoh_d "$@"<br />
<br />
sudo opcontrol --stop<br />
sudo opcontrol --shutdown<br />
<br />
When you run opreport, you'll need to filter out non-Sirikata modules (because OProfile examines the entire system). Make sure you include Sirikata's libraries and plugins as well as the binary you're examining!<br />
<br />
=== Google Perftools ===<br />
Google Perftools is already included as we also use it for [[Debugging Memory Issues]]. To use it, set the CMake variable <tt>GOOGLE_PERFTOOLS_SETTING=CPU</tt> and recompile. When you execute the program you want to examine, set the environment variable <tt>CPUPROFILE</tt> to a location to save profiling data to, e.g.,<br />
<br />
> env CPUPROFILE=/tmp/cppoh.prof /home/me/sirikata/build/cmake/cppoh_d<br />
<br />
Then run <tt>pprof</tt> to analyze the output.<br />
<br />
See the [http://code.google.com/p/gperftools/wiki/GooglePerformanceTools Google Perftools page] for more details, and specifically the [http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html CPU profiling instructions].<br />
<br />
=== Emerson ===<br />
Theoretically [http://code.google.com/p/v8/wiki/V8Profiler V8's internal profiler] can be used, which should give information about both Javascript and V8 CPU usage. You can use the <tt>--v8-flags</tt> setting or change the value directly in JSObjectScriptManager.cpp. However, so far we've only been able to get information about C++.<br />
<br />
=== GNU Profiler ===<br />
You can build Sirikata with GNU Profiler settings. Set <tt>CMAKE_BUILD_TYPE=Profile</tt>. This is an instrumentation-based statistical profiler. It uses the same basic idea as OProfile and will report information in a similar manner. However, it's more intrusive and seems to have a higher impact on performance. Therefore, you should generally use it when you can't get the information you need from OProfile, or to double check OProfile's results.<br />
<br />
See the [http://www.cs.utah.edu/dept/old/texinfo/as/gprof.html GNU Profiler guide] for more details.<br />
<br />
== Sirikata Tools ==<br />
<br />
=== Course Grained Profiling ===<br />
For a few parts of code where performance issues might be expected, especially if they could result in long-running event handlers, <tt>TimeProfiler</tt>'s are manually added around event handlers. This is much less heavyweight than a profiler like GProf and minimally invasive, so it is useful to ensure you're getting results that aren't skewed by the profiler.<br />
<br />
To enable profilers, add <tt>--profile=true</tt> to the command line (this should work for all binaries). The statistics will be reported at exit:<br />
<br />
[PROFILER] INFO: Profiler report: Object Host<br />
[PROFILER] INFO: Stage: Session Manager -- Avg: 2us Min: 2us Max:7us Sum: 38us Its: 13<br />
[PROFILER] INFO: Stage: Handle Read Network -- Avg: 10us Min: 5us Max:1.045ms Sum: 125.492ms Its: 12018<br />
[PROFILER] INFO: Stage: Handle Server Message -- Avg: 402us Min: 23us Max:4.346ms Sum: 1.8317s Its: 4550<br />
[PROFILER] INFO: Stage: TimeSync -- Avg: 81us Min: 31us Max:173us Sum: 326us Its: 4<br />
[PROFILER] INFO: Stage: OrphanLocUpdateManager -- Avg: 8us Min: 8us Max:9us Sum: 17us Its: 2<br />
<br />
This data covers the entire run, so be wary of variation or spikes.<br />
<br />
You can add your own 'Stage' by using <tt>TimeProfiler::addStage</tt>. All <tt>Context</tt>s have a TimeProfiler in <tt>Context::profiler</tt>. A few classes (e.g. <tt>PollingService</tt>) will automatically add a Stage if you provide a name for it in their constructor. In fact, <tt>PollingService</tt> is a good example of how to add your own TimeProfiler Stage.<br />
<br />
=== Fine-grained Event Loop Profiling ===<br />
Because everything runs within a single event loop (or a small number of them), you can see the results of a performance issue in seemingly unrelated areas. We provide some fine-grained profiling for the event loops to help track these issues down.<br />
<br />
==== Quick start ====<br />
* Build with the CMake variable <tt>SIRIKATA_TRACK_EVENT_QUEUES</tt> enabled<br />
* During performance issues, break and call <tt>Sirikata::Network::IOService::reportAllStats()</tt><br />
<br />
==== Details ====<br />
The core event loop classes are essentially just queues of event handlers to be executed. Strands provide serialization of related events that are unsafe to execute simultaneously. When you're seeing a performance issue that can't be attributed to the code that exhibits bad behavior, you may be seeing the queues getting backed up.<br />
<br />
But since everything goes through these queues, it's difficult to track down the cause. It could be long-running event handlers clogging up the queue. Or it could be a lot of event handlers all dumped on the queue at once; individually they don't take long, but when handled in order they can block the queue for many seconds.<br />
<br />
To determine what's going through the event queues and break it down by strands, posting to strands or the main event queue allows you to tag the event. For example, this code from the Ogre plugin identifies the target method being called:<br />
<br />
void OgreSystem::onCreateProxy(ProxyObjectPtr p)<br />
{<br />
simStrand->post(<br />
std::tr1::bind(&OgreSystem::iOnCreateProxy,this,<br />
livenessToken(),p, false),<br />
"OgreSystem::iOnCreateProxy"<br />
);<br />
}<br />
<br />
Tags are <tt>const char*</tt> (not Strings!) so that we use a quick hash table lookup to record information as the event handler passes through the queue. We also track some timing information. However, these steps are '''only performed if the CMake variable <tt>SIRIKATA_TRACK_EVENT_QUEUES</tt> is enabled''', so it costs essentially nothing if you use a normal build.<br />
<br />
To report this information, you need to invoke the static method <tt>Sirikata::Network::IOService::reportAllStats</tt>. If you're in <tt>gdb</tt> you can do this with <tt>call</tt><br />
<br />
(gdb) call Sirikata::Network::IOService::reportAllStats()<br />
<br />
This prints a simple report over all IOServices and their child IOStrands in the system. For example, you might get something like this (a shortened, but representative sample):<br />
<br />
[IOSERVICE] INFO: =======================================================<br />
[IOSERVICE] INFO: 'Object Host' IOService Statistics<br />
[IOSERVICE] INFO: Timers: 148 with 895us recent latency<br />
[IOSERVICE] INFO: Event handlers: 0 with 1.384ms recent latency<br />
[IOSERVICE] INFO: (IOStrands) (148)<br />
[IOSERVICE] INFO: -------------------------------------------------------<br />
[IOSERVICE] INFO: Child 'Object Host Main'<br />
[IOSERVICE] INFO: Timers: 148 with 926us recent latency<br />
[IOSERVICE] INFO: Event handlers: 0 with 211us recent latency<br />
[IOSERVICE] INFO: Stream<EndPointType>::sendKeepAlive (95)<br />
[IOSERVICE] INFO: Stream<EndPointType>::serviceStreamNoReturn (47)<br />
[IOSERVICE] INFO: Connection<EndPointType>::checkIfAlive (5)<br />
[IOSERVICE] INFO: Connection<EndPointType>::serviceConnectionNoReturn (1)<br />
[IOSERVICE] INFO: -------------------------------------------------------<br />
[IOSERVICE] INFO: Child 'SessionManager'<br />
[IOSERVICE] INFO: Timers: 0 with 0us recent latency<br />
[IOSERVICE] INFO: Event handlers: 0 with 0us recent latency<br />
[IOSERVICE] INFO: -------------------------------------------------------<br />
[IOSERVICE] INFO: Child 'EmersonScript a8fd93ea-01fb-4f63-b59e-9501df5788ba'<br />
[IOSERVICE] INFO: Timers: 0 with 0us recent latency<br />
[IOSERVICE] INFO: Event handlers: 0 with 1.73ms recent latency<br />
<br />
(Note that this isn't actually from a trace with a performance issue, so there are no obvious issues like large latency numbers or too many outstanding event handlers.)<br />
<br />
The top level is an entire <tt>IOService</tt> and each large sub-item is an <tt>IOStrand</tt>. They both track latency and queue depth, for both timed and immediate <tt>post()</tt>s. Note that since <tt>IOStrands</tt> work through the parent <tt>IOService</tt>, the <tt>IOService</tt> numbers '''include the <tt>IOStrand</tt> numbers'''. The latency is only measured over a window of recent event handlers (currently 100).<br />
<br />
Below these statistics is an list of the tags of handlers currently in the queue, ordered by count. In this example, only <tt>(IOStrands)</tt> is listed under the <tt>IOService</tt>, which means that only handlers posted through <tt>IOStrands</tt> are currently enqueued. Within the child <tt>'Object Host Main'</tt>, we can see that only some networking handlers are in the queue. In this case, <tt>Stream<EndPointType>::sendKeepAlive</tt> is high on the list, but this is actually a timer that waits a long time. Therefore, it will be in the queue, but not blocking anything, for a long time and we can safely ignore it. We could then move onto the next item and check if it's latency, combined with the number of outstanding instances of it are in the queue, is sufficient to cause a performance issue.<br />
<br />
Generally you'll want to wait until you can directly observe the performance issues (e.g. frame rate issues or lag) or use the debugger to break when you can find them programmatically, then print this information. By looking at what's in the queue, you can probably track down the source of the delay. A good approach is to identify the strand or service which has high recent latency and then look at the handlers with the most copies in the queue.<br />
<br />
If you see <tt>(NULL)</tt> in the output, that's because someone didn't tag that callback. You can easily find these missing tags and commit them back by removing the default tag values from the methods in <tt>IOService</tt> and <tt>IOStrand</tt> and trying to compile.<br />
<br />
Finally, beware that these can only capture information from code which uses them. Most code should be using these classes, but anything which works directly with the <tt>boost::asio::ioservice</tt> will not be accurately represented.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=Creating_a_ReleaseCreating a Release2012-02-01T18:48:55Z<p>Ewencp: Fix minor typos</p>
<hr />
<div>This guide describes all the steps for creating a new release. The process is mostly automated, so this mostly serves as a checklist.<br />
<br />
== Before Building Packages ==<br />
<br />
* Test! Make sure that things are working well on all the platforms. In order to do this you need a fully functional build on all platforms. You'll need this setup to build the packages as well.<br />
* Update the version number.<br />
** In build/cmake/CMakeLists.txt, search for the SIRIKATA_VERSION_* variables and update them.<br />
** See [[Debian Packaging]] for how to update the Debian packaging information.<br />
* Commit '''but do not tag''' the release.<br />
** Ideally bumping the version number is the last commit.<br />
** These commits need to be in a public repository that you can clone them when building packages. One way to accomplish this is to build<br />
** We don't tag the release until we've got all the packages built and tested so that tags don't become public until they are finalized. If you aren't using the central repository to get the source for building packages, you can safely tag now since the tag can be deleted and changed if necessary.<br />
<br />
== Building Packages ==<br />
<br />
This step is entirely automated on each platform. <br />
<br />
=== Windows ===<br />
From a fully functional checkout (i.e. you've built from within the directory and have the latest dependencies) run<br />
<br />
./tools/release/build-win32-release.bat x.y.z<br />
<br />
This depends on a bunch of tools being available in their default locations: CMake and Visual Studio for the build, Python (to run a script that extracts Breakpad symbols), 7zip (for generating the archive).<br />
<br />
The version number here is only used for naming the archive, you don't necessarily need a tag or branch with the name vx.y.z. '''However, this means that you do need to already have the correct revision checked out in your working copy.'''<br />
<br />
This should result in two files, sirikata-x.y.z-win32.zip and sirikata-x.y.z-win32.dbg.zip, sitting in the top directory.<br />
<br />
=== Mac ===<br />
From a fully functional checkout (i.e. you've built from within the directory and have the latest dependencies) run<br />
<br />
./tools/release/build-mac-release.sh [--debug] x.y.z<br />
<br />
The version number here is only used for naming the archive, you don't necessarily need a tag or branch with the name vx.y.z. '''However, this means that you do need to already have the correct revision checked out in your working copy.'''<br />
<br />
This should result in one file, sirikata-x.y.z-mac.tar.gz, sitting in the top directory.<br />
<br />
=== Linux ===<br />
See [[Debian Packaging]] for details. As long as you've tested on Linux this package can be generated after the rest.<br />
<br />
=== Source ===<br />
From an existing checkout, run<br />
<br />
./tools/release/build-source-release.sh x.y.z<br />
<br />
where x.y.z is the version number you're building. One of the steps in this script is<br />
<br />
git checkout vx.y.z<br />
<br />
so you need a branch or tag with that name that points at the latest commit for this release, i.e. the version number bumping commit.<br />
<br />
This should result in one file, sirikata-x.y.z-src.zip, sitting in the top directory.<br />
<br />
== Building Installers ==<br />
<br />
We also provide simple installers for Windows and Mac. We use BitRock's InstallBuilder. Ask Ewen for license info. Once you have it, you need to checkout the [http://github.com/sirikata/sirikata-installer sirikata-installer] repository. Then, just do<br />
<br />
./create-release.sh x y z<br />
<br />
from the top-level of that repository, where x, y, and z correspond to the version number.<br />
<br />
You need to have the <tt>builder</tt> binary from InstallBuilder on your path.<br />
<br />
The output should be:<br />
<br />
* sirikata-x.y.z-win32-installer.exe<br />
* sirikata-x.y.z-mac-installer.dmg<br />
* sirikata-x.y.z-mac-installer.tgz (which contains the same thing as the dmg, but in a format the autoupdater can use)<br />
* update.xml (which allows the autoupdaters to figure out what the most recent version is and where to download it)<br />
<br />
You'll need to upload these along with the simple packages.<br />
<br />
{{note}} '''Always''' upload the update.xml file last, and only after testing that everything else is available for download.<br />
<br />
== After Building Packages ==<br />
<br />
* Test! Make sure the packages built on each platform are sane -- at a minimum extract them and run a space and object host.<br />
* Upload to sirikata.com/releases/.<br />
** Just scp the archives into the appropriate win32/, mac/, and src/ directories on the web server. This includes the installer packages.<br />
** scp update.xml into sirikata.com/releases/<br />
** Grab the Ubuntu data from [http://ppa.launchpad.net/sirikata/sirikata/ubuntu/pool/main/s/sirikata/ launchpad's package archive] after it's built and put it under ubuntu/{DISTRO}/<br />
** Ask Ewen for the account details.<br />
* Upload the crash reporter symbols to crashes.sirikata.com.<br />
** Take the package sirikata-x.y.z-win32.dbg.zip generated in the build process and extract it. The directory sirikata_win32_syms/ contains Breakpad symbols that the crash collector uses to generate stacktraces. You just need to scp these to the crash server.<br />
** Ask Ewen for account details.<br />
* Update the version number on the release page.<br />
** This is handled through a WordPress page called 'Downloads'. Edit the source of that page, just search for 'version' and update the number.<br />
** Again, ask Ewen for account details.<br />
* Test the download page links. Make sure they work on each platform.</div>Ewencphttps://www.sirikata.com/wiki/index.php?title=CDN_API_DocumentationCDN API Documentation2012-01-31T19:16:37Z<p>Jterrace: /* Searching the CDN */</p>
<hr />
<div>=Model URLs=<br />
The URL for a model consists of:<br />
meerkat://[HOSTNAME]/BASENAME/FORMAT[/VERSION]<br />
<br />
Where:<br />
* BASENAME = The user-chosen path for the model, e.g. /jterrace/duck.dae<br />
* HOSTNAME = Address of the CDN server. If not specified, the OH client defaults to open3dhub.com<br />
* FORMAT = One of the CDN formats. Currently supported are "priginal", "pptimized" and "progressive".<br />
* VERSION = The version number of the model. If not specified, the latest version is returned by the CDN.<br />
<br />
===Examples===<br />
* Returns the latest version of optimized format:<br />
meerkat:///jterrace/models/plantbox.dae/optimized/plantbox.dae<br />
* Returns progressive format, version 0:<br />
meerkat:///jterrace/models/plantbox.dae/progressive/0/plantbox.dae<br />
* Loads from a server on localhost:<br />
meerkat://localhost:8080/jterrace/box.dae<br />
<br />
===Note===<br />
The filename at the end of the URL is technically optional, but the OH won't pick up dependent files, like textures, without it.<br />
<br />
=Retrieving Single Model Info=<br />
/api/modelinfo/BASENAME/VERSION<br />
<br />
This retrieves the JSON for a single model with all of its formats.<br />
<br />
===Example===<br />
http://open3dhub.com/api/modelinfo/jterrace/models/plantbox.dae/0<br />
<br />
=Browsing the CDN=<br />
/api/browse/[?start=TIMESTAMP]<br />
<br />
This browses the models on the CDN. Without a start argument, returns the most recent 25 models on the CDN. It will also contain a "next_start" value, which you can pass later to start at the next timestamp to continue browsing.<br />
<br />
===Examples===<br />
* http://open3dhub.com/api/browse/<br />
* http://open3dhub.com/api/browse/?start=1313667443311513<br />
<br />
=Searching the CDN=<br />
/api/search?q=QUERY&start=START&rows=ROWS<br />
<br />
This searches the CDN for models matching the query QUERY.<br />
<br />
===Params===<br />
* q (optional) - something to search for (ex: duck). If not specified, the search returns all models.<br />
* start (optional) - an index value to continue searching from. Defaults to 0.<br />
* rows (optional) - how many rows to return. Defaults to 10. Maximum value of 100.<br />
<br />
===Returns===<br />
Return value is JSON. Contains 4 keys:<br />
* content_items - same as /api/browse<br />
* hits - the total number of models on the CDN matching the query<br />
* next_start - the index value to pass as "start" parameter to continue where the query left off<br />
* previous_start - the index value to go backwards in search results<br />
<br />
===Examples===<br />
* http://open3dhub.com/api/search<br />
* http://open3dhub.com/api/search?q=duck<br />
* http://open3dhub.com/api/search?q=test&rows=50&start=20000<br />
<br />
=Uploading=<br />
/api/upload<br />
<br />
This requires authentication using OAuth. Only an access token is required, and you can get that from a user's profile page on the CDN site.<br />
<br />
===Params===<br />
* title - The title of the model<br />
* username - The username that is being used to upload. This must match the username of the OAuth key.<br />
* path - Where to place the file, relative to the user's path. For example, if username is jterrace and path is "test/duck.dae", the final path will be "/jterrace/test/duck.dae"<br />
* main_filename - If uploading multiple files, this should be the main file (e.g. COLLADA). This is still required even if only a single file is being uploaded. If you upload a zip file, this should be the name of the zip file.<br />
* description - Description for the model<br />
* labels - Any labels you want on the model<br />
* ephemeral - Set to '1' if this is an ephemeral upload<br />
* ttl_time - (ephemeral only) The time to live for an ephemeral upload.<br />
* subfiles - (ephemeral only) A json-encoded dictionary mapping textures to existing texture paths on the CDN. Example:<br />
<br />
{"duckCM.tga": "/jterrace/duck_triangulate.dae/original/duckCM.tga/0"}<br />
<br />
The keys are always the bare filename. For example, even if the file is listed as '/home/jterrace/duck/duckCM.tga' in the model, the key will be 'duckCM.tga'.<br />
<br />
The actual files should be multipart encoded.<br />
<br />
===Returns===<br />
If successfull, the HTTP code should be 200. The reponse will be a JSON string. There will be a field named 'success' set to True. If an application-level error happened, there will be a field named 'error' that contains a human-readable string with the error in it. On success, a field name 'task_id' will contain the upload task identifier (used later to get the status of the upload).<br />
<br />
=Upload Status=<br />
/upload/processing/TASK_ID?api&username=USERNAME<br />
<br />
This allows you to get the status of an upload. The TASK_ID should be the 'task_id' string returned from /api/upload. The username should be the username used to upload the file. The returned value will be a JSON string. There will be a field called 'state'. When the value of this field is either SUCCESS or FAILURE, it means the upload process has completed. Otherwise, a human-friendly status code will be returned indicating what stage the import is in. If the state is FAILURE, it means the upload has failed. If the state is SUCCESS, an additional field named 'path' will contain the new path of the file that has been imported. Once SUCCESS or FAILURE has been returned, the given TASK_ID is no longer a valid argument for this URL, e.g. you can only consume it once.<br />
<br />
=Keepalive Update=<br />
/api/keepalive/BASENAME/VERSION?ttl=TTL&username=USERNAME<br />
<br />
This requires authentication using OAuth.<br />
<br />
This allows updating the TTL value for ephemeral uploads.<br />
<br />
===Params===<br />
* ttl - TTL time to update to<br />
* username - The username this model belongs to<br />
<br />
===Returns===<br />
An empty 200 response on success.<br />
<br />
===Examples===<br />
* http://open3dhub.com/api/keepalive/jterrace/apiupload/duck_triangulate.dae/13?username=jterrace&ttl=600</div>Jterracehttps://www.sirikata.com/wiki/index.php?title=Debian_PackagingDebian Packaging2012-01-04T21:08:24Z<p>Ewencp: /* Creating Release */ Update distribution specification for new version note to precise.</p>
<hr />
<div>==Prerequisites==<br />
* Create a PGP key (required) and import into Launchpad (optional): https://help.launchpad.net/YourAccount/ImportingYourPGPKey<br />
* Install debian packaging tools: <code>sudo apt-get install pbuilder debootstrap devscripts</code><br />
* Set your /etc/pbuilderrc to something like this:<br />
MIRRORSITE=http://us.archive.ubuntu.com/ubuntu/<br />
<br />
BUILDUSERID=12345<br />
BUILDUSERNAME=fakeuser<br />
<br />
DISTRIBUTION=oneiric<br />
COMPONENTS="main restricted universe multiverse"<br />
<br />
EXTRAPACKAGES="nano ssh"<br />
<br />
TIMEOUT_TIME=24h<br />
* After setting up /etc/pbuilderrc, run:<br />
sudo pbuilder --create<br />
<br />
==Creating Release==<br />
Create a directory to be used for packaging. The rest of the commands assume you are in that directory.<br />
mkdir packaging<br />
cd packaging<br />
<br />
Next, decide what release you are making. The release version should be the upstream release version. The minor version is if the upstream release has a minor release. The debian version is for making new packaged versions for the same upstream release. The debian version for each upstream release should always start with 1. The minor version should be 0 if the upstream release has no minor number.<br />
export SIRIKATA_RELEASE="0.0.20"<br />
export SIRIKATA_MINOR="0"<br />
export SIRIKATA_DEBIAN="1"<br />
<br />
Clone the repository, switch to the release tag, and check out submodules:<br />
git clone git://github.com/sirikata/sirikata.git sirikata-${SIRIKATA_RELEASE}<br />
cd sirikata-${SIRIKATA_RELEASE}<br />
git checkout v${SIRIKATA_RELEASE}<br />
git submodule update --init --recursive<br />
make update-dependencies<br />
cd dependencies<br />
./install --download-only sdl bullet opencollada v8 ogre chromium ffmpeg<br />
cd ..<br />
<br />
Now edit the changelog file to add a new section (you might do this step *before* the tag so it can be part of the "original" tgz). Make sure that the email address in the signature is identical to your Launchpad address:<br />
dch --newversion ${SIRIKATA_RELEASE}-${SIRIKATA_MINOR}ubuntu${SIRIKATA_DEBIAN}<br />
<br />
If you are on an older version of Ubuntu, you might need to specify the distribution:<br />
dch --newversion ${SIRIKATA_RELEASE}-${SIRIKATA_MINOR}ubuntu${SIRIKATA_DEBIAN} --distribution precise<br />
<br />
Now go back up a directory and create the "orig" tar file that debian requires (note _ instead of -, it matters):<br />
cd ..<br />
tar --exclude-vcs -cvzf sirikata_${SIRIKATA_RELEASE}.orig.tar.gz sirikata-${SIRIKATA_RELEASE}<br />
<br />
Go back into the directory and create the build:<br />
cd sirikata-${SIRIKATA_RELEASE}<br />
debuild -S<br />
<br />
Go back up and run pbuilder to test if the build works:<br />
cd ..<br />
sudo pbuilder --build sirikata_${SIRIKATA_RELEASE}-${SIRIKATA_MINOR}ubuntu${SIRIKATA_DEBIAN}.dsc<br />
<br />
To upload to launchpad:<br />
dput ppa:sirikata/sirikata sirikata_${SIRIKATA_RELEASE}-${SIRIKATA_MINOR}ubuntu${SIRIKATA_DEBIAN}_source.changes<br />
<br />
==Installing==<br />
=== The Easy Way ===<br />
<br />
sudo add-apt-repository ppa:sirikata/sirikata<br />
sudo apt-get update<br />
sudo apt-get install sirikata<br />
<br />
=== The Manual Way ===<br />
Put this:<br />
deb http://ppa.launchpad.net/sirikata/sirikata/ubuntu oneiric main<br />
in this file:<br />
/etc/apt/sources.list.d/sirikata.list<br />
Then run:<br />
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E3BB648B583006F3<br />
sudo apt-get update<br />
sudo apt-get install sirikata</div>Jterrace