<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[Esenthel Forum - Code Snippets]]></title>
		<link>https://esenthel.com/forum/</link>
		<description><![CDATA[Esenthel Forum - https://esenthel.com/forum]]></description>
		<pubDate>Tue, 21 Apr 2026 01:51:40 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[Position inside Waypoint]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=9573</link>
			<pubDate>Sat, 27 Jul 2019 22:26:30 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=9573</guid>
			<description><![CDATA[If we are using Waypoints to define/limit areas, sometimes we need to check if the position (of a character) is inside of a Waypoint.<br />
<br />
For complex polygons there is an algorithm <a href="http://alienryderflex.com/polygon/" target="_blank">HERE</a>, and here's the code for EE to use it:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
/******************************************************************************/<br />
//<br />
struct saWaypointChecker<br />
{<br />
public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;void init(C UID &amp;waypointID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;Bool posInside(C Vec2 &amp;pos);<br />
&nbsp;&nbsp;&nbsp;&nbsp;C UID &amp;waypointID(){&nbsp;&nbsp;&nbsp;&nbsp;return T._waypointID;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;C Rect rect(){&nbsp;&nbsp;&nbsp;&nbsp;return T._waypointRect;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
private:<br />
&nbsp;&nbsp;&nbsp;&nbsp;volatile Bool _init = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *_waypoint&nbsp;&nbsp; = nullptr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;UID _waypointID = UIDZero;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;Flt&gt; _constant;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;Flt&gt; _multiple;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Rect _waypointRect;<br />
}<br />
<br />
/******************************************************************************/<br />
/******************************************************************************/<br />
//<br />
void saWaypointChecker::init(C UID &amp;waypointID)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;C Flt minMax = 32767.0f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypoint&nbsp;&nbsp;&nbsp;&nbsp; = Game::World.findWaypoint(waypointID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypointID&nbsp;&nbsp; = (T._waypoint ? waypointID : UIDZero);<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect = Rect(minMax, minMax, -minMax, -minMax);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Perform precalculation<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(T._waypoint)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint &amp;wp = *T._waypoint;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant.setNum(wp.points.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple.setNum(wp.points.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int j = wp.points.elms() - 1;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(Int i = 0; i &lt; wp.points.elms(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wp.points[j].pos.z == wp.points[i].pos.z) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant[i] = wp.points[i].pos.x;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple[i] = 0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant[i] = wp.points[i].pos.x - (wp.points[i].pos.z * wp.points[j].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z) + <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(wp.points[i].pos.z * wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple[i] = (wp.points[j].pos.x - wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = i; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Defining bounding Rect<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.min.x = Min(T._waypointRect.min.x, wp.points[i].pos.x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.min.y = Min(T._waypointRect.min.y, wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.max.x = Max(T._waypointRect.max.x, wp.points[i].pos.x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.max.y = Max(T._waypointRect.max.y, wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._init = (T._waypoint &amp;&amp; T._waypointID != UIDZero);<br />
}<br />
<br />
Bool saWaypointChecker::posInside(C Vec2 &amp;pos)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!T._init)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// First and fastest check<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!T._waypointRect.includes(pos))<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// If position is inside rect, perform more precise check<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(T._waypoint)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint &amp;wp = *T._waypoint;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool oddNodes = false, current = wp.points.last().pos.z &gt; pos.y, previous; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(Int i = 0; i &lt; wp.points.elms(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;previous = current; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current = wp.points[i].pos.z &gt; pos.y; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(current != previous)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oddNodes ^= (pos.y * T._multiple[i] + T._constant[i] &lt; pos.x); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return oddNodes;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
}<br />
<br />
/******************************************************************************/<br />
/******************************************************************************/</code></div></div>
<br />
the usage is the following (initialization to perform precalculations just once):<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>saWaypointChecker wpHandler;<br />
<br />
... init just once ...<br />
wpHandler.init(UID(0, 0, 0, 0)); // your Waypoint ID here<br />
<br />
... and then check XZ position in any loop ...<br />
if(wpHandler.posInside(pos.xz()))<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// do something<br />
}</code></div></div>
<br />
P.S. Greg, maybe you can move these precalculations to waypoint class and add "Waypoint.Cuts" function? <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" />]]></description>
			<content:encoded><![CDATA[If we are using Waypoints to define/limit areas, sometimes we need to check if the position (of a character) is inside of a Waypoint.<br />
<br />
For complex polygons there is an algorithm <a href="http://alienryderflex.com/polygon/" target="_blank">HERE</a>, and here's the code for EE to use it:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
/******************************************************************************/<br />
//<br />
struct saWaypointChecker<br />
{<br />
public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;void init(C UID &amp;waypointID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;Bool posInside(C Vec2 &amp;pos);<br />
&nbsp;&nbsp;&nbsp;&nbsp;C UID &amp;waypointID(){&nbsp;&nbsp;&nbsp;&nbsp;return T._waypointID;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;C Rect rect(){&nbsp;&nbsp;&nbsp;&nbsp;return T._waypointRect;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
private:<br />
&nbsp;&nbsp;&nbsp;&nbsp;volatile Bool _init = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *_waypoint&nbsp;&nbsp; = nullptr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;UID _waypointID = UIDZero;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;Flt&gt; _constant;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;Flt&gt; _multiple;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Rect _waypointRect;<br />
}<br />
<br />
/******************************************************************************/<br />
/******************************************************************************/<br />
//<br />
void saWaypointChecker::init(C UID &amp;waypointID)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;C Flt minMax = 32767.0f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypoint&nbsp;&nbsp;&nbsp;&nbsp; = Game::World.findWaypoint(waypointID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypointID&nbsp;&nbsp; = (T._waypoint ? waypointID : UIDZero);<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect = Rect(minMax, minMax, -minMax, -minMax);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Perform precalculation<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(T._waypoint)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint &amp;wp = *T._waypoint;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant.setNum(wp.points.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple.setNum(wp.points.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int j = wp.points.elms() - 1;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(Int i = 0; i &lt; wp.points.elms(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(wp.points[j].pos.z == wp.points[i].pos.z) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant[i] = wp.points[i].pos.x;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple[i] = 0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._constant[i] = wp.points[i].pos.x - (wp.points[i].pos.z * wp.points[j].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z) + <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(wp.points[i].pos.z * wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._multiple[i] = (wp.points[j].pos.x - wp.points[i].pos.x) / (wp.points[j].pos.z - wp.points[i].pos.z); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = i; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Defining bounding Rect<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.min.x = Min(T._waypointRect.min.x, wp.points[i].pos.x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.min.y = Min(T._waypointRect.min.y, wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.max.x = Max(T._waypointRect.max.x, wp.points[i].pos.x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._waypointRect.max.y = Max(T._waypointRect.max.y, wp.points[i].pos.z);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;T._init = (T._waypoint &amp;&amp; T._waypointID != UIDZero);<br />
}<br />
<br />
Bool saWaypointChecker::posInside(C Vec2 &amp;pos)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!T._init)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// First and fastest check<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!T._waypointRect.includes(pos))<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// If position is inside rect, perform more precise check<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(T._waypoint)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Game::Waypoint &amp;wp = *T._waypoint;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool oddNodes = false, current = wp.points.last().pos.z &gt; pos.y, previous; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(Int i = 0; i &lt; wp.points.elms(); i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;previous = current; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current = wp.points[i].pos.z &gt; pos.y; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(current != previous)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oddNodes ^= (pos.y * T._multiple[i] + T._constant[i] &lt; pos.x); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return oddNodes;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
}<br />
<br />
/******************************************************************************/<br />
/******************************************************************************/</code></div></div>
<br />
the usage is the following (initialization to perform precalculations just once):<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>saWaypointChecker wpHandler;<br />
<br />
... init just once ...<br />
wpHandler.init(UID(0, 0, 0, 0)); // your Waypoint ID here<br />
<br />
... and then check XZ position in any loop ...<br />
if(wpHandler.posInside(pos.xz()))<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// do something<br />
}</code></div></div>
<br />
P.S. Greg, maybe you can move these precalculations to waypoint class and add "Waypoint.Cuts" function? <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" />]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Algorithms (Esenthel Project)]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8737</link>
			<pubDate>Mon, 26 Oct 2015 08:00:45 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8737</guid>
			<description><![CDATA[Hello everyone,<br />
<br />
I needed to test an algorithm that I had to use at work, so I did what anyone would do: Make a new application in Esenthel and slap some things together there just to see if it works!<br />
<br />
Then, of course, I got a little bit carried away and added some more algorithms and put them together in a small, simple application.<br />
<br />
So, I'm putting that project up here in case this is of interest to someone. It's very basic, really, but it can always be nice to have some more tutorials!<br />
<br />
What it does (all algorithms are for image processing):<br />
- Bilinear interpolation (on colours)<br />
- Convert to Gray<br />
- Blur<br />
- Oil painting filter<br />
- Sin-wave blur. My god, it's so useless, why did I put time in that?<br />
<br />
<a href="https://www.dropbox.com/s/49bh3pyhnug549u/Algorithms.EsenthelProject?dl=0" target="_blank">Download</a><br />
<br />
Enjoy!]]></description>
			<content:encoded><![CDATA[Hello everyone,<br />
<br />
I needed to test an algorithm that I had to use at work, so I did what anyone would do: Make a new application in Esenthel and slap some things together there just to see if it works!<br />
<br />
Then, of course, I got a little bit carried away and added some more algorithms and put them together in a small, simple application.<br />
<br />
So, I'm putting that project up here in case this is of interest to someone. It's very basic, really, but it can always be nice to have some more tutorials!<br />
<br />
What it does (all algorithms are for image processing):<br />
- Bilinear interpolation (on colours)<br />
- Convert to Gray<br />
- Blur<br />
- Oil painting filter<br />
- Sin-wave blur. My god, it's so useless, why did I put time in that?<br />
<br />
<a href="https://www.dropbox.com/s/49bh3pyhnug549u/Algorithms.EsenthelProject?dl=0" target="_blank">Download</a><br />
<br />
Enjoy!]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Code Snippet for more efficient tessellation]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8619</link>
			<pubDate>Tue, 25 Aug 2015 12:51:11 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8619</guid>
			<description><![CDATA[I use tessellation on higher graphic settings, but, it completely kills the performance when you have lots of objects (solid + with transparency) in your scene.<br />
<br />
By default, tessellation is applied to everything. All LODs and even transparant objects.<br />
So, with the next snippet, we are are calling the shader with different parameters: Only allow tessellation if the material has no transparancy and if it is the first LOD of the mesh.<br />
<br />
In Main:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
// Only allow tessellation on solid objects with first LOD.<br />
ShaderTech* get_shader(RENDER_MODE mode, Material *material[4], UInt mesh_base_flag, Int lod_index, Bool allow_tesselation)<br />
{<br />
&nbsp;&nbsp; bool tessellate = false;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // Some things should not be tessellated (like terrain when D.tessellateHeightmap == false), set_shader sets this for us<br />
&nbsp;&nbsp; if(allow_tesselation)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If material is a normal material (no alpha)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(material[0] != null &amp;&amp; material[0].technique == MTECH_DEFAULT) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We are in solid/simple rendering mode and this is the first LOD<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(IsTessellationRenderMode(mode) &amp;&amp; lod_index == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tessellate = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; return GetDefaultShader(mode, material, mesh_base_flag, lod_index, tessellate); <br />
}<br />
/******************************************************************************/<br />
bool IsTessellationRenderMode(RENDER_MODE mode)<br />
{<br />
&nbsp;&nbsp; return (mode == RM_SIMPLE ||&nbsp;&nbsp;mode == RM_SOLID);<br />
}<br />
/******************************************************************************/</code></div></div>
<br />
In InitPre:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>D.tesselation(true).tesselationDensity(50).tesselationHeightmap(true);<br />
D.setGetShaderFunc(get_shader);</code></div></div>
]]></description>
			<content:encoded><![CDATA[I use tessellation on higher graphic settings, but, it completely kills the performance when you have lots of objects (solid + with transparency) in your scene.<br />
<br />
By default, tessellation is applied to everything. All LODs and even transparant objects.<br />
So, with the next snippet, we are are calling the shader with different parameters: Only allow tessellation if the material has no transparancy and if it is the first LOD of the mesh.<br />
<br />
In Main:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
// Only allow tessellation on solid objects with first LOD.<br />
ShaderTech* get_shader(RENDER_MODE mode, Material *material[4], UInt mesh_base_flag, Int lod_index, Bool allow_tesselation)<br />
{<br />
&nbsp;&nbsp; bool tessellate = false;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // Some things should not be tessellated (like terrain when D.tessellateHeightmap == false), set_shader sets this for us<br />
&nbsp;&nbsp; if(allow_tesselation)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If material is a normal material (no alpha)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(material[0] != null &amp;&amp; material[0].technique == MTECH_DEFAULT) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We are in solid/simple rendering mode and this is the first LOD<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(IsTessellationRenderMode(mode) &amp;&amp; lod_index == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tessellate = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; return GetDefaultShader(mode, material, mesh_base_flag, lod_index, tessellate); <br />
}<br />
/******************************************************************************/<br />
bool IsTessellationRenderMode(RENDER_MODE mode)<br />
{<br />
&nbsp;&nbsp; return (mode == RM_SIMPLE ||&nbsp;&nbsp;mode == RM_SOLID);<br />
}<br />
/******************************************************************************/</code></div></div>
<br />
In InitPre:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>D.tesselation(true).tesselationDensity(50).tesselationHeightmap(true);<br />
D.setGetShaderFunc(get_shader);</code></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Step counter for mobile platforms]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8618</link>
			<pubDate>Mon, 24 Aug 2015 13:27:23 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8618</guid>
			<description><![CDATA[I thought I'd share this code. It's a simple step-counter for mobile devices. I don't suppose Esenthel will be used any time soon to make a 'personal health assistant', but it might be useful for interaction. I'm using it to make decisions based on whether the user is walking or not.<br />
<br />
cheers,<br />
<br />
yvan<br />
<br />
<div class="codeblock phpcodeblock"><div class="title">PHP Code:<br />
</div><div class="body"><div dir="ltr"><code><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">stepDetector<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;activate</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;h&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">480</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">h&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">0.5f</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">scale&nbsp;</span><span style="color: #007700">=&nbsp;-&nbsp;(</span><span style="color: #0000BB">h&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">0.5f&nbsp;</span><span style="color: #007700">*&nbsp;(</span><span style="color: #0000BB">1.0f&nbsp;</span><span style="color: #007700">/&nbsp;(</span><span style="color: #0000BB">MAGNETIC_FIELD_EARTH_MAX</span><span style="color: #007700">)));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">MagnetometerRefresh</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;deactivate</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">MagnetometerDisable</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;sensitivity</span><span style="color: #007700">(</span><span style="color: #0000BB">float&nbsp;value</span><span style="color: #007700">)&nbsp;</span><span style="color: #FF8000">//&nbsp;lower&nbsp;is&nbsp;more&nbsp;sensitive,&nbsp;default&nbsp;is&nbsp;3<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">limit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;update</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Device&nbsp;rotation&nbsp;also&nbsp;cause&nbsp;acceleration.&nbsp;To&nbsp;counter<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;this,&nbsp;rotation&nbsp;is&nbsp;measured&nbsp;with&nbsp;the&nbsp;magnetometer.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;magValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Magnetometer</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Distance&nbsp;compared&nbsp;to&nbsp;the&nbsp;previous&nbsp;update<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">Dist</span><span style="color: #007700">(</span><span style="color: #0000BB">magValue</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">lastMagValue</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMagValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">magValue</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;When&nbsp;5&nbsp;point&nbsp;average&nbsp;&gt;&nbsp;0.6&nbsp;or&nbsp;current&nbsp;value&nbsp;&gt;&nbsp;1,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;the&nbsp;device&nbsp;is&nbsp;rotated.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if(</span><span style="color: #0000BB">getMagAverage</span><span style="color: #007700">()&nbsp;&gt;&nbsp;</span><span style="color: #0000BB">0.6&nbsp;</span><span style="color: #007700">||&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">]&nbsp;&gt;&nbsp;</span><span style="color: #0000BB">1.0</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">)&nbsp;</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">)&nbsp;</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;To&nbsp;avoid&nbsp;double&nbsp;triggers,&nbsp;a&nbsp;sleep&nbsp;period&nbsp;of&nbsp;0.3&nbsp;seconds<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;is&nbsp;added&nbsp;after&nbsp;a&nbsp;step<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if(</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">-=&nbsp;</span><span style="color: #0000BB">Time</span><span style="color: #007700">.</span><span style="color: #0000BB">ad</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;don't&nbsp;do&nbsp;anything&nbsp;if&nbsp;the&nbsp;value&nbsp;hasn't&nbsp;changed<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;accValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Accelerometer</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">accValue&nbsp;</span><span style="color: #007700">!=&nbsp;</span><span style="color: #0000BB">lastAccValue</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;this&nbsp;part&nbsp;is&nbsp;based&nbsp;on&nbsp;code&nbsp;found&nbsp;at:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;https://github.com/bagilevi/android-pedometer/blob/master/src/name/bagi/levente/pedometer/StepDetector.java<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastAccValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;calc&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">x&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">y&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">z&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">/=&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;if&nbsp;the&nbsp;movement&nbsp;direction&nbsp;has&nbsp;changed,&nbsp;this&nbsp;is&nbsp;a&nbsp;strong&nbsp;indication<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;of&nbsp;a&nbsp;step&nbsp;occurance<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;direction&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">:&nbsp;(</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;-</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">:&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">));&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">direction&nbsp;</span><span style="color: #007700">==&nbsp;-</span><span style="color: #0000BB">lastDirection</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;direction&nbsp;changed<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;extType&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">direction&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">:&nbsp;&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">);&nbsp;</span><span style="color: #FF8000">//&nbsp;minimum&nbsp;or&nbsp;maximum?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">extType</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">lastCalc</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;diff&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Abs</span><span style="color: #007700">(</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">extType</span><span style="color: #007700">]&nbsp;-&nbsp;</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">-&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">]);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">limit</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isAlmostAsLargeAsPrevious&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">&gt;&nbsp;(</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">2&nbsp;</span><span style="color: #007700">/&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isPreviousLargeEnough&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">&gt;&nbsp;(</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">/&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isNotContra&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">!=&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">-&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">isAlmostAsLargeAsPrevious&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">isPreviousLargeEnough&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">isNotContra</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;this&nbsp;counts&nbsp;as&nbsp;a&nbsp;step.&nbsp;Sleep&nbsp;for&nbsp;0.3&nbsp;seconds<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0.3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;-</span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">diff</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastDirection&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">direction</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">calc</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Helper&nbsp;function&nbsp;to&nbsp;get&nbsp;an&nbsp;average&nbsp;magnetometer&nbsp;value<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;getMagAverage</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(</span><span style="color: #0000BB">int&nbsp;i&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;&nbsp;&nbsp;</span><span style="color: #0000BB">i&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">;&nbsp;</span><span style="color: #0000BB">i</span><span style="color: #007700">++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">i</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">/=&nbsp;</span><span style="color: #0000BB">10</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br /><br />private:<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">C&nbsp;float&nbsp;MAGNETIC_FIELD_EARTH_MAX&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">60.f</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;for&nbsp;accelerometer&nbsp;calculations<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;limit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;lastCalc</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">lastDiff</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">offset</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">2</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;lastDirection&nbsp;</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;-</span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;lastAccValue</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;for&nbsp;magnetometer&nbsp;calculations<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;&nbsp;&nbsp;lastMagValue</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;magDist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">[</span><span style="color: #0000BB">5</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;&nbsp;&nbsp;magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">;&nbsp;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;sleep&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">stepDetector&nbsp;StepDetector</span><span style="color: #007700">;&nbsp;<br /></span></code></div></div></div>
]]></description>
			<content:encoded><![CDATA[I thought I'd share this code. It's a simple step-counter for mobile devices. I don't suppose Esenthel will be used any time soon to make a 'personal health assistant', but it might be useful for interaction. I'm using it to make decisions based on whether the user is walking or not.<br />
<br />
cheers,<br />
<br />
yvan<br />
<br />
<div class="codeblock phpcodeblock"><div class="title">PHP Code:<br />
</div><div class="body"><div dir="ltr"><code><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">stepDetector<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;activate</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;h&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">480</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">h&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">0.5f</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">scale&nbsp;</span><span style="color: #007700">=&nbsp;-&nbsp;(</span><span style="color: #0000BB">h&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">0.5f&nbsp;</span><span style="color: #007700">*&nbsp;(</span><span style="color: #0000BB">1.0f&nbsp;</span><span style="color: #007700">/&nbsp;(</span><span style="color: #0000BB">MAGNETIC_FIELD_EARTH_MAX</span><span style="color: #007700">)));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">MagnetometerRefresh</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;deactivate</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">MagnetometerDisable</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">void&nbsp;sensitivity</span><span style="color: #007700">(</span><span style="color: #0000BB">float&nbsp;value</span><span style="color: #007700">)&nbsp;</span><span style="color: #FF8000">//&nbsp;lower&nbsp;is&nbsp;more&nbsp;sensitive,&nbsp;default&nbsp;is&nbsp;3<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">limit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;update</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Device&nbsp;rotation&nbsp;also&nbsp;cause&nbsp;acceleration.&nbsp;To&nbsp;counter<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;this,&nbsp;rotation&nbsp;is&nbsp;measured&nbsp;with&nbsp;the&nbsp;magnetometer.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;magValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Magnetometer</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Distance&nbsp;compared&nbsp;to&nbsp;the&nbsp;previous&nbsp;update<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">Dist</span><span style="color: #007700">(</span><span style="color: #0000BB">magValue</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">lastMagValue</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMagValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">magValue</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;When&nbsp;5&nbsp;point&nbsp;average&nbsp;&gt;&nbsp;0.6&nbsp;or&nbsp;current&nbsp;value&nbsp;&gt;&nbsp;1,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;the&nbsp;device&nbsp;is&nbsp;rotated.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if(</span><span style="color: #0000BB">getMagAverage</span><span style="color: #007700">()&nbsp;&gt;&nbsp;</span><span style="color: #0000BB">0.6&nbsp;</span><span style="color: #007700">||&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">]&nbsp;&gt;&nbsp;</span><span style="color: #0000BB">1.0</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">)&nbsp;</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">magDistPtr</span><span style="color: #007700">++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">)&nbsp;</span><span style="color: #0000BB">magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;To&nbsp;avoid&nbsp;double&nbsp;triggers,&nbsp;a&nbsp;sleep&nbsp;period&nbsp;of&nbsp;0.3&nbsp;seconds<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;is&nbsp;added&nbsp;after&nbsp;a&nbsp;step<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">if(</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">-=&nbsp;</span><span style="color: #0000BB">Time</span><span style="color: #007700">.</span><span style="color: #0000BB">ad</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;don't&nbsp;do&nbsp;anything&nbsp;if&nbsp;the&nbsp;value&nbsp;hasn't&nbsp;changed<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;accValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Accelerometer</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">accValue&nbsp;</span><span style="color: #007700">!=&nbsp;</span><span style="color: #0000BB">lastAccValue</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;this&nbsp;part&nbsp;is&nbsp;based&nbsp;on&nbsp;code&nbsp;found&nbsp;at:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;https://github.com/bagilevi/android-pedometer/blob/master/src/name/bagi/levente/pedometer/StepDetector.java<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastAccValue&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;calc&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">x&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">y&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">offset&nbsp;</span><span style="color: #007700">+&nbsp;</span><span style="color: #0000BB">accValue</span><span style="color: #007700">.</span><span style="color: #0000BB">z&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">/=&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;if&nbsp;the&nbsp;movement&nbsp;direction&nbsp;has&nbsp;changed,&nbsp;this&nbsp;is&nbsp;a&nbsp;strong&nbsp;indication<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;of&nbsp;a&nbsp;step&nbsp;occurance<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;direction&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">:&nbsp;(</span><span style="color: #0000BB">calc&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;-</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">:&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">));&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">direction&nbsp;</span><span style="color: #007700">==&nbsp;-</span><span style="color: #0000BB">lastDirection</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;direction&nbsp;changed<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;extType&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">direction&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">?&nbsp;&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">:&nbsp;&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">);&nbsp;</span><span style="color: #FF8000">//&nbsp;minimum&nbsp;or&nbsp;maximum?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">extType</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">lastCalc</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;diff&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Abs</span><span style="color: #007700">(</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">extType</span><span style="color: #007700">]&nbsp;-&nbsp;</span><span style="color: #0000BB">lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">-&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">]);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">limit</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isAlmostAsLargeAsPrevious&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">&gt;&nbsp;(</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">*&nbsp;</span><span style="color: #0000BB">2&nbsp;</span><span style="color: #007700">/&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isPreviousLargeEnough&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">&gt;&nbsp;(</span><span style="color: #0000BB">diff&nbsp;</span><span style="color: #007700">/&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">bool&nbsp;isNotContra&nbsp;</span><span style="color: #007700">=&nbsp;(</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">!=&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">-&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">isAlmostAsLargeAsPrevious&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">isPreviousLargeEnough&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">isNotContra</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;this&nbsp;counts&nbsp;as&nbsp;a&nbsp;step.&nbsp;Sleep&nbsp;for&nbsp;0.3&nbsp;seconds<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">extType</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">sleep&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0.3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;-</span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastDiff&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">diff</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastDirection&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">direction</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">lastCalc&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">calc</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Helper&nbsp;function&nbsp;to&nbsp;get&nbsp;an&nbsp;average&nbsp;magnetometer&nbsp;value<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;getMagAverage</span><span style="color: #007700">()<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(</span><span style="color: #0000BB">int&nbsp;i&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;&nbsp;&nbsp;</span><span style="color: #0000BB">i&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">5</span><span style="color: #007700">;&nbsp;</span><span style="color: #0000BB">i</span><span style="color: #007700">++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">+=&nbsp;</span><span style="color: #0000BB">magDist</span><span style="color: #007700">[</span><span style="color: #0000BB">i</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">result&nbsp;</span><span style="color: #007700">/=&nbsp;</span><span style="color: #0000BB">10</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">result</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br /><br />private:<br /><br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">C&nbsp;float&nbsp;MAGNETIC_FIELD_EARTH_MAX&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">60.f</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;for&nbsp;accelerometer&nbsp;calculations<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;limit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">3</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;lastCalc</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">lastDiff</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">scale</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">offset</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;lastExtremes</span><span style="color: #007700">[</span><span style="color: #0000BB">2</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;lastDirection&nbsp;</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;lastMatch&nbsp;</span><span style="color: #007700">=&nbsp;-</span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;lastAccValue</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;for&nbsp;magnetometer&nbsp;calculations<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Vec&nbsp;&nbsp;&nbsp;lastMagValue</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;magDist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">[</span><span style="color: #0000BB">5</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">int&nbsp;&nbsp;&nbsp;magDistPtr&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">;&nbsp;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">float&nbsp;sleep&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">stepDetector&nbsp;StepDetector</span><span style="color: #007700">;&nbsp;<br /></span></code></div></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[A JointHelper object to assemble Jointed Objects]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8475</link>
			<pubDate>Wed, 06 May 2015 17:52:22 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8475</guid>
			<description><![CDATA[At present there is no visual way of placing any type of joint between any two physics-based objects. I have to do it all in code, trying to remember positions, rotations, constraint limits for exact placement of the specific joint type. So I decided to put my newly acquired knowledge of Esenthel Custom Parameters to some use, and I have put together a JointHelper object for use in the World Editor. This should also enable new users to gain a little understanding of Custom Parameters.<br />
<br />
Here is the JointHelper object:<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/jointhelperobject.jpg" border="0" alt="[Image: jointhelperobject.jpg]" /><br />
<br />
Basically, you place it (using the current tools in the World Editor) at the desired position between the two objects you wish to join.<br />
The axis of rotation (for Hinge joints) and axis for lateral movement (for Sliding joints) is the GREEN Y axis, so be sure to orientate the JointHelper accordingly.<br />
By selecting its Param tab you are able to change its parameters to suit your desired situation. These parameters are:<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/jointhelperparams.jpg" border="0" alt="[Image: jointhelperparams.jpg]" /><br />
<br />
"actor0" : supply the name of the first Item object to be joined<br />
"actor1" : supply the name of the second Item object to be joined (or "null" if only the "actor0" is valid)<br />
"drawme" : tick this if you wish the joint name to be displayed (recommended only for debugging purposes)<br />
"JOINT_TYPE" : supply the type of joint using the dropdown list<br />
"limit1" : supply a lower constraint limit for the joint (further explained in the code comments)<br />
"limit2" : supply an upper constraint limit for the joint<br />
"name" : whatever unique name you wish to give for the JointHelper<br />
<br />
The object Items to be joined have only one parameter:<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/itemobjectparams.jpg" border="0" alt="[Image: itemobjectparams.jpg]" /><br />
<br />
"name" : whatever unique name you wish to give for the Item object<br />
<br />
I have supplied an example project (with code), together with a simple set of primitive assets, which demonstrates the use of my JointHelper.<br />
You can also have a bit of fun firing some missile balls at the assembled objects to determine which joints have been used.<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/TestProject.jpg" border="0" alt="[Image: TestProject.jpg]" /><br />
<br />
<a href="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/JointHelper.EsenthelProject" target="_blank">Esenthel Project file</a><br />
<br />
<a href="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/JointHelperAssets.rar" target="_blank">Zipped Assets</a>]]></description>
			<content:encoded><![CDATA[At present there is no visual way of placing any type of joint between any two physics-based objects. I have to do it all in code, trying to remember positions, rotations, constraint limits for exact placement of the specific joint type. So I decided to put my newly acquired knowledge of Esenthel Custom Parameters to some use, and I have put together a JointHelper object for use in the World Editor. This should also enable new users to gain a little understanding of Custom Parameters.<br />
<br />
Here is the JointHelper object:<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/jointhelperobject.jpg" border="0" alt="[Image: jointhelperobject.jpg]" /><br />
<br />
Basically, you place it (using the current tools in the World Editor) at the desired position between the two objects you wish to join.<br />
The axis of rotation (for Hinge joints) and axis for lateral movement (for Sliding joints) is the GREEN Y axis, so be sure to orientate the JointHelper accordingly.<br />
By selecting its Param tab you are able to change its parameters to suit your desired situation. These parameters are:<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/jointhelperparams.jpg" border="0" alt="[Image: jointhelperparams.jpg]" /><br />
<br />
"actor0" : supply the name of the first Item object to be joined<br />
"actor1" : supply the name of the second Item object to be joined (or "null" if only the "actor0" is valid)<br />
"drawme" : tick this if you wish the joint name to be displayed (recommended only for debugging purposes)<br />
"JOINT_TYPE" : supply the type of joint using the dropdown list<br />
"limit1" : supply a lower constraint limit for the joint (further explained in the code comments)<br />
"limit2" : supply an upper constraint limit for the joint<br />
"name" : whatever unique name you wish to give for the JointHelper<br />
<br />
The object Items to be joined have only one parameter:<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/itemobjectparams.jpg" border="0" alt="[Image: itemobjectparams.jpg]" /><br />
<br />
"name" : whatever unique name you wish to give for the Item object<br />
<br />
I have supplied an example project (with code), together with a simple set of primitive assets, which demonstrates the use of my JointHelper.<br />
You can also have a bit of fun firing some missile balls at the assembled objects to determine which joints have been used.<br />
<br />
<img src="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/TestProject.jpg" border="0" alt="[Image: TestProject.jpg]" /><br />
<br />
<a href="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/JointHelper.EsenthelProject" target="_blank">Esenthel Project file</a><br />
<br />
<a href="https://dl.dropboxusercontent.com/u/21041885/Esenthel/JointHelperProject/JointHelperAssets.rar" target="_blank">Zipped Assets</a>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Auto screenshot make for iOS]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8433</link>
			<pubDate>Sat, 11 Apr 2015 00:50:21 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8433</guid>
			<description><![CDATA[I've used this code for auto-generation of screenshots needed for submitting apps to Apple App Store.<br />
It will generate the 3.5, 4.0, 4.7, 5.5 inch and iPad JPG's.<br />
<br />
Step 1 modify const Str ScreenShotPath="d:/Screens/";<br />
Step 2 Run your game fullscreen<br />
Step 3 call ScreenShot() anytime in your StateGame draw function<br />
Step 4 Place 'ScreenShotFinish()' in global 'Shut'<br />
<br />
Screenshots are created in multi-threaded mode on secondary threads so you can keep running the game, and correct aspect ratio is calculated.<br />
<br />
Enjoy! <img src="images/smilies/grin.gif" style="vertical-align: middle;" border="0" alt="grin" title="grin" /><br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
const Str ScreenShotPath="d:/Screens/";<br />
/******************************************************************************/<br />
class ScreenCapture<br />
{<br />
&nbsp;&nbsp; Image src;<br />
&nbsp;&nbsp; VecI2 res;<br />
&nbsp;&nbsp; Str&nbsp;&nbsp; name;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; ScreenCapture&amp; create(C Image &amp;src, C VecI2 &amp;res, C Str &amp;name)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.copy(T.src, -1, -1, -1, -1, IMAGE_SOFT, 1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.res=res;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.name=name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return T;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void process()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.copy(src, res.x, res.y, -1, -1, -1, -1, FILTER_BEST);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.Export(name, 0.95); src.del(); name.del();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; static void Process(ScreenCapture &amp;sc, ptr user, int thread_index) {sc.process();}<br />
}<br />
/******************************************************************************/<br />
Memx&lt;ScreenCapture&gt; ScreenCaptures;<br />
bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot, SkipGUI;<br />
Threads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScreenShotThreads;<br />
/******************************************************************************/<br />
void ScreenShot()<br />
{<br />
&nbsp;&nbsp; if(!TakingScreenShot)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SkipGUI=Kb.ctrl();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!ScreenShotThreads.threads())ScreenShotThreads.create(true, Cpu.threads()-1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flt aspect=D.aspectRatio();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void (*draw)()=StateActive.draw;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Str path=FFirst(ScreenShotPath); FCreateDirs(path); path.tailSlash(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Image capture;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(1920./1080);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(2208, 1242), path+"5.5.jpg"), ScreenCapture.Process);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(1334,&nbsp;&nbsp;750), path+"4.7.jpg"), ScreenCapture.Process);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(1136,&nbsp;&nbsp;640), path+"4.0.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(960./640);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(960, 640), path+"3.5.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(2048./1536);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(2048, 1536), path+"iPad.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(aspect);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SkipGUI=false;<br />
&nbsp;&nbsp; }<br />
}<br />
void ScreenShotFinish()<br />
{<br />
&nbsp;&nbsp; ScreenShotThreads.wait().del();<br />
}<br />
/******************************************************************************/</code></div></div>
]]></description>
			<content:encoded><![CDATA[I've used this code for auto-generation of screenshots needed for submitting apps to Apple App Store.<br />
It will generate the 3.5, 4.0, 4.7, 5.5 inch and iPad JPG's.<br />
<br />
Step 1 modify const Str ScreenShotPath="d:/Screens/";<br />
Step 2 Run your game fullscreen<br />
Step 3 call ScreenShot() anytime in your StateGame draw function<br />
Step 4 Place 'ScreenShotFinish()' in global 'Shut'<br />
<br />
Screenshots are created in multi-threaded mode on secondary threads so you can keep running the game, and correct aspect ratio is calculated.<br />
<br />
Enjoy! <img src="images/smilies/grin.gif" style="vertical-align: middle;" border="0" alt="grin" title="grin" /><br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
const Str ScreenShotPath="d:/Screens/";<br />
/******************************************************************************/<br />
class ScreenCapture<br />
{<br />
&nbsp;&nbsp; Image src;<br />
&nbsp;&nbsp; VecI2 res;<br />
&nbsp;&nbsp; Str&nbsp;&nbsp; name;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; ScreenCapture&amp; create(C Image &amp;src, C VecI2 &amp;res, C Str &amp;name)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.copy(T.src, -1, -1, -1, -1, IMAGE_SOFT, 1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.res=res;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.name=name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return T;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void process()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.copy(src, res.x, res.y, -1, -1, -1, -1, FILTER_BEST);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;src.Export(name, 0.95); src.del(); name.del();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; static void Process(ScreenCapture &amp;sc, ptr user, int thread_index) {sc.process();}<br />
}<br />
/******************************************************************************/<br />
Memx&lt;ScreenCapture&gt; ScreenCaptures;<br />
bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot, SkipGUI;<br />
Threads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScreenShotThreads;<br />
/******************************************************************************/<br />
void ScreenShot()<br />
{<br />
&nbsp;&nbsp; if(!TakingScreenShot)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SkipGUI=Kb.ctrl();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!ScreenShotThreads.threads())ScreenShotThreads.create(true, Cpu.threads()-1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flt aspect=D.aspectRatio();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void (*draw)()=StateActive.draw;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Str path=FFirst(ScreenShotPath); FCreateDirs(path); path.tailSlash(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Image capture;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(1920./1080);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(2208, 1242), path+"5.5.jpg"), ScreenCapture.Process);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(1334,&nbsp;&nbsp;750), path+"4.7.jpg"), ScreenCapture.Process);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(1136,&nbsp;&nbsp;640), path+"4.0.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(960./640);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(960, 640), path+"3.5.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(2048./1536);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renderer.capture(capture, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScreenShotThreads.queue(ScreenCaptures.New().create(capture, VecI2(2048, 1536), path+"iPad.jpg"), ScreenCapture.Process);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.aspectRatio(aspect);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TakingScreenShot=false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SkipGUI=false;<br />
&nbsp;&nbsp; }<br />
}<br />
void ScreenShotFinish()<br />
{<br />
&nbsp;&nbsp; ScreenShotThreads.wait().del();<br />
}<br />
/******************************************************************************/</code></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Creating/moving along a path]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8424</link>
			<pubDate>Mon, 06 Apr 2015 09:29:42 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8424</guid>
			<description><![CDATA[Hello everyone!<br />
<br />
For my benchmarking tool, I needed a way to create and visualize smooth paths. And then, I needed a way to move an object (camera) along that path. Since it's a benchmarking tool, it has to work flawlessly at any framerate. <br />
This required a bit more work than I had anticipated, since movement could just stop working or be totally wrong with low FPS, or high movement speed. <br />
But after redesigning the movement calculation, it now works absolutely perfect under all conditions.<br />
<br />
I present to you, a test project that allows you to:<br />
- Place points by left-clicking on the screen. A continuous spline will be generated, connecting these points (you need a minimum of 4 points first).<br />
- Move a dot along the path by holding Right mouse<br />
- Set speed and resolution in real time<br />
- Movement is always exact and smooth, no matter what framerate or dot-speed you run at.<br />
<br />
I have made this test project in 2D so I could easily isolate just the path and movement code. I'm using the same code for my 3D application, all you need to do is replace Vec2 with Vec. <br />
Lastly, I use "points" that I placed in the world editor, instead of placing them with clicking.<br />
<br />
Have fun! I hope it's useful for someone.<br />
<br />
<a href="http://www.mediafire.com/download/rzot0edwto5ox2x/Splines.EsenthelProject" target="_blank">Spline Project</a><br />
<br />
(Yes, the project is just 3KB)]]></description>
			<content:encoded><![CDATA[Hello everyone!<br />
<br />
For my benchmarking tool, I needed a way to create and visualize smooth paths. And then, I needed a way to move an object (camera) along that path. Since it's a benchmarking tool, it has to work flawlessly at any framerate. <br />
This required a bit more work than I had anticipated, since movement could just stop working or be totally wrong with low FPS, or high movement speed. <br />
But after redesigning the movement calculation, it now works absolutely perfect under all conditions.<br />
<br />
I present to you, a test project that allows you to:<br />
- Place points by left-clicking on the screen. A continuous spline will be generated, connecting these points (you need a minimum of 4 points first).<br />
- Move a dot along the path by holding Right mouse<br />
- Set speed and resolution in real time<br />
- Movement is always exact and smooth, no matter what framerate or dot-speed you run at.<br />
<br />
I have made this test project in 2D so I could easily isolate just the path and movement code. I'm using the same code for my 3D application, all you need to do is replace Vec2 with Vec. <br />
Lastly, I use "points" that I placed in the world editor, instead of placing them with clicking.<br />
<br />
Have fun! I hope it's useful for someone.<br />
<br />
<a href="http://www.mediafire.com/download/rzot0edwto5ox2x/Splines.EsenthelProject" target="_blank">Spline Project</a><br />
<br />
(Yes, the project is just 3KB)]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[Tuto]Ineisis - Inv & Item]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8354</link>
			<pubDate>Sun, 15 Feb 2015 10:47:36 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8354</guid>
			<description><![CDATA[Hello EWorld.<br />
<br />
This post is to add Item and Inventory code for Ineisis. i copy mmo code for work.<br />
<br />
Ok let's go.<br />
<br />
1/ Create new Code in <span style="font-weight: bold;">Shared</span> =&gt; <span style="color: #FFA500;">Net Inventory.cpp</span><br />
<br />
Paste this code: <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
enum SLOT_TYPE // inventory item slot<br />
{<br />
&nbsp;&nbsp; SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;, // head&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for helmet<br />
&nbsp;&nbsp; SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;, // neck&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for amulet/necklace<br />
&nbsp;&nbsp; SLOT_ARM_L&nbsp;&nbsp; , // left&nbsp;&nbsp;arm&nbsp;&nbsp;&nbsp;&nbsp;slot for weapon/shield/ammo<br />
&nbsp;&nbsp; SLOT_ARM_R&nbsp;&nbsp; , // right arm&nbsp;&nbsp;&nbsp;&nbsp;slot for weapon/shield/ammo<br />
&nbsp;&nbsp; SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;, // body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for armor/clothing<br />
&nbsp;&nbsp; SLOT_HANDS&nbsp;&nbsp; , // hands&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slot for gloves<br />
&nbsp;&nbsp; SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;, // legs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for pants<br />
&nbsp;&nbsp; SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;, // feet&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for shoes<br />
&nbsp;&nbsp; SLOT_FINGER_L, // left&nbsp;&nbsp;finger slot for ring<br />
&nbsp;&nbsp; SLOT_FINGER_R, // right finger slot for ring<br />
&nbsp;&nbsp; SLOT_TEMP&nbsp;&nbsp;&nbsp;&nbsp;, // temporary&nbsp;&nbsp;&nbsp;&nbsp;slot (current item moved with mouse cursor)<br />
&nbsp;&nbsp; SLOT_SHLD&nbsp;&nbsp;&nbsp;&nbsp; , // number of slots<br />
&nbsp;&nbsp; SLOT_NUM&nbsp;&nbsp;&nbsp;&nbsp; , // number of slots<br />
}<br />
/******************************************************************************/<br />
class NetInventory // net inventory<br />
{<br />
&nbsp;&nbsp; Memc&lt;NetItem&gt; items;<br />
&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slots[SLOT_NUM]; // each array value represents a slot, and is equal to index of item in 'items' container or -1 if slot doesn't have an item<br />
//&nbsp;&nbsp; Reference&lt;Item&gt; slot[SLOT_NUM];<br />
&nbsp;&nbsp; NetInventory() {REPAO(slots)=-1;}<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void del()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.del();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(slots)=-1;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; bool valid(int slot)C {return InRange(slot, T.slots) &amp;&amp; InRange(T.slots[slot], items);} // if 'slot' points to a valid item<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; void compress(File &amp;f, bool equipped_only=false) // compress data so it can be sent using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(equipped_only)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check which items should be compressed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equipped_items=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memc&lt;bool&gt; equipped; FREPA(items)equipped .New()=false; FREPA(slots)if(i!=SLOT_TEMP)if(InRange(slots[i], equipped))equipped[slots[i]]=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memc&lt;int&gt; new_index; FREPA(items)new_index.New()=(equipped[i] ? equipped_items++ : -1);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // compress<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.putInt(equipped_items); FREPA(items)if(equipped[i])items[i].compress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(InRange(slots[i], new_index) ? new_index[slots[i]] : -1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // compress<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.putInt(items.elms()); FREPA(items)items[i].compress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(slots[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REP(f.getInt())items.New().decompress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREPA(slots)if(i!=SLOT_TEMP)f.decIntV(slots[i]);<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // io<br />
&nbsp;&nbsp; void save(File &amp;f) // save item to file<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.save(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;slots;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool load(File &amp;f) // load item from file, false on fail<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!items.load(f))return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&gt;&gt;slots;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/</code></div></div>
 <br />
<br />
2/ Create new Code in <span style="font-weight: bold;">Shared</span> =&gt; <span style="color: #FFA500;">Net Item.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>class NetItem // net item<br />
{<br />
&nbsp;&nbsp; Game.ObjParamsPtr obj;<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create(C UID &amp;obj_id)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.obj=obj_id;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; virtual void compress(File &amp;f) // compress data so it can be sent using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;obj.id();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; virtual void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj=f.getUID();<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // io<br />
&nbsp;&nbsp; void save(File &amp;f) // save item to file<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.cmpUIntV(0); // version<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;obj.id();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool load(File &amp;f) // load item from file, false on fail<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(f.decUIntV()) // version<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj=f.getUID();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/<br />
Memx&lt;NetItem&gt; Items;<br />
/******************************************************************************/</code></div></div>
<br />
3/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">GUI Inventory.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; 'InventoryGui' is a set of visual gui objects which represent character's inventory.<br />
<br />
/******************************************************************************/<br />
class InventoryGui<br />
{<br />
&nbsp;&nbsp; class InventoryWindow : Window<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual void update(C GuiPC &amp;gpc)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.update(gpc);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==this &amp;&amp; Ms.bp(1))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ms.eat(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hide();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; Inventory&nbsp;&nbsp;&nbsp;&nbsp;*inv=null; // Inventory which InventoryGui is linked with<br />
&nbsp;&nbsp; GuiObjs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gobjs; // gui objects<br />
&nbsp;&nbsp; List&lt;NetItem&gt; list; // list of items<br />
&nbsp;&nbsp; GuiImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slot_image [SLOT_NUM]; // slot images&nbsp;&nbsp;[slot index of SLOT_TYPE]<br />
&nbsp;&nbsp; Region&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *slot_region[SLOT_NUM]; // slot regions [slot index of SLOT_TYPE]<br />
<br />
&nbsp;&nbsp; InventoryGui() {REPAO(slot_region)=null;}<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gobjs.replaceWindow&lt;InventoryWindow&gt;(); gobjs=UID(3696073335, 1090330182, 4248471980, 2484485872); gobjs.hide(); Gui+=gobjs;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Window &amp;window=gobjs.getWindow(S);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.move(Vec2(D.w()-0.05-window.rect().max.x, 0));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("head"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("neck"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_ARM_L&nbsp;&nbsp; ].create((slot_region[SLOT_ARM_L&nbsp;&nbsp; ]=&amp;gobjs.getRegion("arm l"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_ARM_R&nbsp;&nbsp; ].create((slot_region[SLOT_ARM_R&nbsp;&nbsp; ]=&amp;gobjs.getRegion("arm r"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("body"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_HANDS&nbsp;&nbsp; ].create((slot_region[SLOT_HANDS&nbsp;&nbsp; ]=&amp;gobjs.getRegion("hands"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("legs"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("feet"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FINGER_L].create((slot_region[SLOT_FINGER_L]=&amp;gobjs.getRegion("finger l")).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FINGER_R].create((slot_region[SLOT_FINGER_R]=&amp;gobjs.getRegion("finger r")).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_SHLD].create((slot_region[SLOT_SHLD]=&amp;gobjs.getRegion("shld")).rect());<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(slot_image).rect_color.zero();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ListColumn lc[]=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, icon ), 0.21, "+"&nbsp;&nbsp;&nbsp;&nbsp;), // 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, name ), 0.52, "Nom" ), // 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, power), 0.21, "Dégât"), // 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gobjs.getRegion("Backpack")+=list.create(lc, Elms(lc));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.column(0).text_align=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.column(2).precision=1; // set showing only 1 decimal precision for power float attribute<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list. cur_mode=LCM_MOUSE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.drawMode(LDM_RECTS);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.flag|=LIST_SCALABLE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.elmHeight(0.08);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.zoom_max*=1.44 ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; bool visible()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Window *window=gobjs.findWindow(S))return window.visible();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // operations<br />
&nbsp;&nbsp; void link(Inventory *inv) // link with 'inv' Inventory<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(T.inv!=inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T.inv=inv;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void setGui() // set visual gui components<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set item list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// here we have to hide the items which are assigned to slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// create a 'visible' array which determines visibility of an element<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Memt&lt;bool&gt; visible; visible.setNum(inv.items.elms()); // allocate array of item visibility<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(visible)=true; // set all visibility by default to true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(inv.slots) // iterate through all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(inv.valid(i)) // if the slot is valid<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visible[inv.slots[i]]=false; // set visibility for item assigned to a slot to false, to be hidden on the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.setData(inv.items, visible); // set list data from items container and visibility list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set slot images<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(SLOT_NUM) // for all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(i!=SLOT_TEMP) // skip temporary slot because it's not drawn using 'Image' class<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(slot_region[i])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rect&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image_rect=slot_region[i].rect(); // gui rect<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GuiImage &amp;image_item=slot_image [i]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; // gui image<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!inv.valid(i))image_item.set(null);else // if there is no item then clear the item image slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImagePtr icon=inv.item(inv-&gt;slots[i]).icon; // access item's icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image_item.set(icon);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set slot image as the item's icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(icon)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// set proper scaling<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec2 size=icon-&gt;size(); size*=PixelSize; // set default size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(size.x&gt;image_rect.w())size*=image_rect.w()/size.x; // clamp item size to background slot width<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(size.y&gt;image_rect.h())size*=image_rect.h()/size.y; // clamp item size to background slot height<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rect rect(image_rect.center()); rect.extend(size/2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image_item.rect(rect);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REPAO(slot_image).set(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void toggle() {if(visible())hide();else show();} // toggle visibility<br />
&nbsp;&nbsp; void show() {gobjs.getWindow(S).show();}<br />
&nbsp;&nbsp; void hide() {gobjs.getWindow(S).hide();}<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update(Player &amp;owner) // handle moving items with mouse<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Ms.bp(0)) // if mouse button pressed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(InRange(inv.slots[SLOT_TEMP], inv.items)) // if we have an item attached with mouse<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;list) // if mouse cursor is on the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.slots[SLOT_TEMP]=-1; // clear the slot reference which will result in "putting back the item into the list"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else // we don't have an item so we want to get one<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;list) // from the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(list())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inv.slots[SLOT_TEMP]=list.visToAbs(list.cur);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui(); // update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(slot_image)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;slot_image[i] || Gui.ms()==slot_region[i]) // if we want to swap temp item with i-th slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv.slotsCanBeSwapped(SLOT_TEMP, SLOT_TYPE(i)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(inv.slots[SLOT_TEMP], inv.slots[i]); // swap temporary with i-th slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; void draw() // draw item being moved with mouse<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv &amp;&amp; InRange(inv.slots[SLOT_TEMP], inv.items))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vec2 pos=Ms.pos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inv.item(inv.slots[SLOT_TEMP]).drawIcon(pos);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
}<br />
InventoryGui InvGui;<br />
/******************************************************************************/</code></div></div>
<br />
4/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">Inventory.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
class Inventory : NetInventory<br />
{<br />
&nbsp;&nbsp;~Inventory() {if(InvGui.inv==this)InvGui.link(null);}<br />
&nbsp;&nbsp; Inventory() {items.replaceClass&lt;Item&gt;();}<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; Item&amp; item(int i) {return (Item&amp;)items[i];} // we can perform direct cast since 'items' had 'replaceClass' called in constructor<br />
<br />
&nbsp;&nbsp; bool slotCanBePutTo(SLOT_TYPE src, SLOT_TYPE dest) // test if slot 'src' can be put to 'dest' slot<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!InRange(src, SLOT_NUM) || !InRange(dest, SLOT_NUM))return false;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return valid(src) ? item(slots[src]).canBePutTo(dest) : true;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool slotsCanBeSwapped(SLOT_TYPE a, SLOT_TYPE b) // test if slot 'a' can be swapped with slot 'b'<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return slotCanBePutTo(a, b) &amp;&amp; slotCanBePutTo(b, a);<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create(NetInventory &amp;src)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.setNum(src.items.elms()); FREPA(src.items)item(i).create(src.items[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Copy(slots, src.slots);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; /*void itemRemoved(Game.Obj &amp;item) // called when an item is being removed<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// perform check if it is a equipped item<br />
&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;REPA(slot) // for all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;if(slots[i]==item) // if i-th slot is set to item which is being removed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;slots[i].clear(); // clear the slot so it can no longer be referenced to the removed item<br />
&nbsp;&nbsp; }*/<br />
&nbsp;&nbsp; void itemRemoved() // called when an item has been removed<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void itemAdded() // called when an item has been added<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void setGui()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(InvGui.inv==this)InvGui.setGui();<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update(AnimatedSkeleton &amp;skel, Player *owner)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(owner &amp;&amp; InvGui.inv==this)if(Player *player=CAST(Player, owner))InvGui.update(*player);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// set matrixes for items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"HandL"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_ARM_L]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"HandR"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_ARM_R]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"Shld"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_SHLD]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; uint drawPrepare()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// draw items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint modes=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))modes|=item(slots[SLOT_ARM_L]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))modes|=item(slots[SLOT_ARM_R]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))modes|=item(slots[SLOT_SHLD]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return modes;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void drawShadow()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// draw items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))item(slots[SLOT_ARM_L]).drawShadow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))item(slots[SLOT_ARM_R]).drawShadow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))item(slots[SLOT_SHLD]).drawShadow();<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/</code></div></div>
<br />
5/ copy the "<span style="color: #9370DB;">gui inventory</span>" file located in <a href="http://www.esenthel.com/?id=store" target="_blank">MMO Source</a> to you project.<br />
<br />
6/ In Net Chr.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">class ClientChr : NetChr</span></span> add this :<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>NetInventory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv;</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void create(CreateChr &amp;cc)</span></span> add this :<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.items.New().create("ITEM UID");</code></div></div>
  <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">virtual void save(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.save(f);</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">virtual bool load(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>if(!inv.load(f))return false;</code></div></div>
     <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> void compress(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.compress(f);</code></div></div>
     <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> void decompress(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.decompress(f);</code></div></div>
  <br />
<br />
7/ In Commands.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">enum CLIENT_SERVER_COMMANDS</span></span>  just down why CS_CHR_ANIM, add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>CS_CHR_INV_SLOTS&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;&nbsp; // Inv</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> class ChrVisuals</span></span> Copy this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>class ChrVisuals<br />
{<br />
&nbsp;&nbsp; SockAddr addr;<br />
&nbsp;&nbsp; MeshPtr&nbsp;&nbsp;mesh;<br />
&nbsp;&nbsp; NetInventory inv;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void save(File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr.save(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;mesh.id();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.compress(f, true);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void load(File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr.load(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mesh=f.getUID();<br />
&nbsp;&nbsp;&nbsp;&nbsp; inv.decompress(f);<br />
&nbsp;&nbsp; }<br />
}<br />
void ServerWriteChrVisuals(File &amp;f, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; f.writeMem(); cv.save(f);<br />
}<br />
void ServerSendChrVisuals(Connection &amp;conn, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_VISUALS); cv.save(f); f.pos(0); conn.send(f, -1, false);<br />
}<br />
void ClientRecvChrVisuals(File &amp;f, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; cv.load(f);<br />
}</code></div></div>
  <br />
=&gt; just down why<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// CS_CHR_ANIM<br />
/******************************************************************************/<br />
void ClientSendChrAnim(Connection &amp;conn, C UID &amp;anim, C UID &amp;sound=UIDZero)<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_ANIM)&lt;&lt;anim&lt;&lt;sound; f.pos(0); conn.send(f);<br />
}<br />
void ServerRecvChrAnim(File &amp;f, UID &amp;anim, UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; f&gt;&gt;anim&gt;&gt;sound;<br />
}<br />
void ServerWriteChrAnim(File &amp;f, C SockAddr &amp;addr, C UID &amp;anim, C UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; f.writeMem().putByte(CS_CHR_ANIM); addr.save(f); f&lt;&lt;anim&lt;&lt;sound;<br />
}<br />
void ClientRecvChrAnim(File &amp;f, SockAddr &amp;addr, UID &amp;anim, UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; addr.load(f); f&gt;&gt;anim&gt;&gt;sound;<br />
}</code></div></div>
 add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// CS_CHR_INV_SLOTS<br />
/******************************************************************************/<br />
void ClientSendChrInvSlots(Connection &amp;conn, int (&amp;slots)[SLOT_NUM])<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_INV_SLOTS); f&lt;&lt;slots; f.pos(0); conn.send(f);<br />
}<br />
void ServerRecvChrInvSlots(File &amp;f, int (&amp;slots)[SLOT_NUM])<br />
{<br />
&nbsp;&nbsp; f&gt;&gt;slots;<br />
}</code></div></div>
  <br />
<br />
8/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">Item.cpp</span><br />
<br />
Paste this code: <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
class Item : NetItem<br />
{<br />
&nbsp;&nbsp; ITEM_TYPE type=ITEM_NONE;<br />
&nbsp;&nbsp; byte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type2=0;<br />
&nbsp;&nbsp; flt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale=1, power=0;<br />
&nbsp;&nbsp; Str&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name;<br />
&nbsp;&nbsp; MeshPtr&nbsp;&nbsp; mesh;<br />
&nbsp;&nbsp; ImagePtr&nbsp;&nbsp;icon;<br />
&nbsp;&nbsp; Vec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vel, ang_vel;<br />
&nbsp;&nbsp; Actor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp; //Particles particles;<br />
&nbsp;&nbsp; //bool particles_under_water=false;<br />
<br />
&nbsp;&nbsp; void create(NetItem &amp;src)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SCAST(NetItem, T)=src;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(obj)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // name<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("name"))name=p.asText();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // type<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("type" ))type =p.asEnum(ITEM_NONE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("type2"))type2=p.asEnum();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // power<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("power"))power=p.asFlt();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("icon"))icon=p.asID();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale=obj-&gt;scale();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh =obj-&gt;mesh ();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get / set<br />
&nbsp;&nbsp; bool canBePutTo(SLOT_TYPE inv_slot) // test if item can be put to 'inv_slot' inventory slot<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv_slot==SLOT_TEMP)return true;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(inv_slot)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_HEAD : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_HELMET&nbsp;&nbsp;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_BODY : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_BODY&nbsp;&nbsp;&nbsp;&nbsp;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_HANDS: return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_GAUNTLET;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_LEGS : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_PANTS&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_FEET : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_BOOT&nbsp;&nbsp;&nbsp;&nbsp;;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_SHLD:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_ARM_L:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_ARM_R:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(type==ITEM_WEAPON)return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(type==ITEM_MISC &amp;&amp; Contains(name, "Torch"))return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void matrix(Matrix &amp;matrix)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._matrix_scaled=T._matrix=matrix;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._matrix_scaled.scaleOrn(scale);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; C Matrix&amp; matrix&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;() {return _matrix&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;}<br />
&nbsp;&nbsp; C Matrix&amp; matrixScaled() {return _matrix_scaled;}<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update() {}<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; void drawIcon(C Vec2 &amp;pos)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(icon)icon-&gt;drawFit(Rect_LU(pos, icon-&gt;size()*PixelSize));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; virtual uint drawPrepare()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(mesh &amp;&amp; Frustum(mesh-&gt;box, matrixScaled()))mesh-&gt;draw(matrixScaled(), vel, ang_vel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight((Cur.obj, this &amp;&amp; Cur.highlight) ? Color(34, 85, 85, 0) : TRANSPARENT); //uint modes=super.drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRANSPARENT);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; // if(particles.is() &amp;&amp; !particles_under_water)<br />
&nbsp;&nbsp;&nbsp;&nbsp; // {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //modes|=IndexToFlag(particles.renderMode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //modes|=IndexToFlag(RM_BLEND); // single particle<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Vec center;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //flt opacity=particles.opacity(&amp;center);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //LightSqr(6*opacity, center).add(true, this);<br />
&nbsp;&nbsp;&nbsp;&nbsp; // }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;virtual void drawShadow()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(mesh &amp;&amp; Frustum(mesh-&gt;box, matrixScaled()))mesh-&gt;drawShadow(matrixScaled());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//if(CurrentLight.src!=this); //super.drawShadow();<br />
&nbsp;&nbsp; }<br />
//virtual void drawPalette () {if(!particles_under_water){particles.draw();}}<br />
&nbsp;&nbsp;//virtual void drawPalette1() {if(!particles_under_water){particles.draw();}}<br />
&nbsp;&nbsp; //virtual void drawBlend&nbsp;&nbsp; () {if(!particles_under_water){particles.draw(); DrawParticle(*Images(UID(4250561076, 1214902943, 3956203709, 646772750)), 0, Color(255, 255, 170, 0), 0.07, 0.9, 0, particles.shape.pos()*particles.matrix, Vec(0));}}<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; virtual void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.decompress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create(T);<br />
&nbsp;&nbsp; }<br />
<br />
private:<br />
&nbsp;&nbsp; Matrix _matrix, _matrix_scaled;<br />
}<br />
/******************************************************************************/</code></div></div>
9/ In Player.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">class Player : Game.Chr , BlendObject</span></span> add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>Player() {InvGui.link(&amp;inv);}<br />
&nbsp;&nbsp; Inventory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv;</code></div></div>
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// *************************Inv**************** //<br />
&nbsp;&nbsp; void sendInvSlots() // send current equipped items (slots) to server<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClientSendChrInvSlots(Server, inv.slots);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; //************************************************ //</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void Player.create(ClientChr &amp;chr)</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.create(chr.inv);</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">bool Player.update()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.update(skel,&nbsp;&nbsp;this);<br />
<br />
&nbsp;&nbsp; if(InvGui.inv==&amp;inv &amp;&amp; !inv.valid(SLOT_TEMP))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Kb.bp(KB_I))InvGui.toggle();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</code></div></div>
  <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">uint Player.drawPrepare()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>SetHighlight(DamageColor(damage_time));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint draw_mask=~0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool hide_head=(ViewMode==VIEW_FPP &amp;&amp; !Renderer.mirror());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;&nbsp;hide_head)FlagDisable(draw_mask, IndexToFlag(DG_CHR_HEAD));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetDrawMask(draw_mask); mesh-&gt;draw(skel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetDrawMask();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.drawPrepare(); // ADD THIS</code></div></div>
 <br />
10/ In Game.cpp =&gt; <span style="font-style: italic;"><span style="color: #4682B4;">bool InitGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui.create();</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void ShutGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui&nbsp;&nbsp;.hide();</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void DrawGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui.draw();</code></div></div>
11/ In Constants.cpp =&gt; add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>const flt PixelSize=0.002;</code></div></div>
<br />
If you have any questions, Post here. Thanks <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" />]]></description>
			<content:encoded><![CDATA[Hello EWorld.<br />
<br />
This post is to add Item and Inventory code for Ineisis. i copy mmo code for work.<br />
<br />
Ok let's go.<br />
<br />
1/ Create new Code in <span style="font-weight: bold;">Shared</span> =&gt; <span style="color: #FFA500;">Net Inventory.cpp</span><br />
<br />
Paste this code: <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
enum SLOT_TYPE // inventory item slot<br />
{<br />
&nbsp;&nbsp; SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;, // head&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for helmet<br />
&nbsp;&nbsp; SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;, // neck&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for amulet/necklace<br />
&nbsp;&nbsp; SLOT_ARM_L&nbsp;&nbsp; , // left&nbsp;&nbsp;arm&nbsp;&nbsp;&nbsp;&nbsp;slot for weapon/shield/ammo<br />
&nbsp;&nbsp; SLOT_ARM_R&nbsp;&nbsp; , // right arm&nbsp;&nbsp;&nbsp;&nbsp;slot for weapon/shield/ammo<br />
&nbsp;&nbsp; SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;, // body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for armor/clothing<br />
&nbsp;&nbsp; SLOT_HANDS&nbsp;&nbsp; , // hands&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slot for gloves<br />
&nbsp;&nbsp; SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;, // legs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for pants<br />
&nbsp;&nbsp; SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;, // feet&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot for shoes<br />
&nbsp;&nbsp; SLOT_FINGER_L, // left&nbsp;&nbsp;finger slot for ring<br />
&nbsp;&nbsp; SLOT_FINGER_R, // right finger slot for ring<br />
&nbsp;&nbsp; SLOT_TEMP&nbsp;&nbsp;&nbsp;&nbsp;, // temporary&nbsp;&nbsp;&nbsp;&nbsp;slot (current item moved with mouse cursor)<br />
&nbsp;&nbsp; SLOT_SHLD&nbsp;&nbsp;&nbsp;&nbsp; , // number of slots<br />
&nbsp;&nbsp; SLOT_NUM&nbsp;&nbsp;&nbsp;&nbsp; , // number of slots<br />
}<br />
/******************************************************************************/<br />
class NetInventory // net inventory<br />
{<br />
&nbsp;&nbsp; Memc&lt;NetItem&gt; items;<br />
&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slots[SLOT_NUM]; // each array value represents a slot, and is equal to index of item in 'items' container or -1 if slot doesn't have an item<br />
//&nbsp;&nbsp; Reference&lt;Item&gt; slot[SLOT_NUM];<br />
&nbsp;&nbsp; NetInventory() {REPAO(slots)=-1;}<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void del()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.del();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(slots)=-1;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; bool valid(int slot)C {return InRange(slot, T.slots) &amp;&amp; InRange(T.slots[slot], items);} // if 'slot' points to a valid item<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; void compress(File &amp;f, bool equipped_only=false) // compress data so it can be sent using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(equipped_only)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check which items should be compressed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;equipped_items=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memc&lt;bool&gt; equipped; FREPA(items)equipped .New()=false; FREPA(slots)if(i!=SLOT_TEMP)if(InRange(slots[i], equipped))equipped[slots[i]]=true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memc&lt;int&gt; new_index; FREPA(items)new_index.New()=(equipped[i] ? equipped_items++ : -1);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // compress<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.putInt(equipped_items); FREPA(items)if(equipped[i])items[i].compress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(InRange(slots[i], new_index) ? new_index[slots[i]] : -1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // compress<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.putInt(items.elms()); FREPA(items)items[i].compress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(slots[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REP(f.getInt())items.New().decompress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREPA(slots)if(i!=SLOT_TEMP)f.decIntV(slots[i]);<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // io<br />
&nbsp;&nbsp; void save(File &amp;f) // save item to file<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.save(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;slots;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool load(File &amp;f) // load item from file, false on fail<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!items.load(f))return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&gt;&gt;slots;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/</code></div></div>
 <br />
<br />
2/ Create new Code in <span style="font-weight: bold;">Shared</span> =&gt; <span style="color: #FFA500;">Net Item.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>class NetItem // net item<br />
{<br />
&nbsp;&nbsp; Game.ObjParamsPtr obj;<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create(C UID &amp;obj_id)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T.obj=obj_id;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; virtual void compress(File &amp;f) // compress data so it can be sent using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;obj.id();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; virtual void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj=f.getUID();<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // io<br />
&nbsp;&nbsp; void save(File &amp;f) // save item to file<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.cmpUIntV(0); // version<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;obj.id();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool load(File &amp;f) // load item from file, false on fail<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(f.decUIntV()) // version<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 0:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj=f.getUID();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/<br />
Memx&lt;NetItem&gt; Items;<br />
/******************************************************************************/</code></div></div>
<br />
3/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">GUI Inventory.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; 'InventoryGui' is a set of visual gui objects which represent character's inventory.<br />
<br />
/******************************************************************************/<br />
class InventoryGui<br />
{<br />
&nbsp;&nbsp; class InventoryWindow : Window<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;virtual void update(C GuiPC &amp;gpc)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.update(gpc);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==this &amp;&amp; Ms.bp(1))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ms.eat(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hide();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; Inventory&nbsp;&nbsp;&nbsp;&nbsp;*inv=null; // Inventory which InventoryGui is linked with<br />
&nbsp;&nbsp; GuiObjs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gobjs; // gui objects<br />
&nbsp;&nbsp; List&lt;NetItem&gt; list; // list of items<br />
&nbsp;&nbsp; GuiImage&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slot_image [SLOT_NUM]; // slot images&nbsp;&nbsp;[slot index of SLOT_TYPE]<br />
&nbsp;&nbsp; Region&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *slot_region[SLOT_NUM]; // slot regions [slot index of SLOT_TYPE]<br />
<br />
&nbsp;&nbsp; InventoryGui() {REPAO(slot_region)=null;}<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gobjs.replaceWindow&lt;InventoryWindow&gt;(); gobjs=UID(3696073335, 1090330182, 4248471980, 2484485872); gobjs.hide(); Gui+=gobjs;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Window &amp;window=gobjs.getWindow(S);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window.move(Vec2(D.w()-0.05-window.rect().max.x, 0));<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_HEAD&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("head"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_NECK&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("neck"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_ARM_L&nbsp;&nbsp; ].create((slot_region[SLOT_ARM_L&nbsp;&nbsp; ]=&amp;gobjs.getRegion("arm l"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_ARM_R&nbsp;&nbsp; ].create((slot_region[SLOT_ARM_R&nbsp;&nbsp; ]=&amp;gobjs.getRegion("arm r"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_BODY&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("body"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_HANDS&nbsp;&nbsp; ].create((slot_region[SLOT_HANDS&nbsp;&nbsp; ]=&amp;gobjs.getRegion("hands"&nbsp;&nbsp; )).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_LEGS&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("legs"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;].create((slot_region[SLOT_FEET&nbsp;&nbsp;&nbsp;&nbsp;]=&amp;gobjs.getRegion("feet"&nbsp;&nbsp;&nbsp;&nbsp;)).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FINGER_L].create((slot_region[SLOT_FINGER_L]=&amp;gobjs.getRegion("finger l")).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_FINGER_R].create((slot_region[SLOT_FINGER_R]=&amp;gobjs.getRegion("finger r")).rect());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;window+=slot_image[SLOT_SHLD].create((slot_region[SLOT_SHLD]=&amp;gobjs.getRegion("shld")).rect());<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(slot_image).rect_color.zero();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ListColumn lc[]=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, icon ), 0.21, "+"&nbsp;&nbsp;&nbsp;&nbsp;), // 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, name ), 0.52, "Nom" ), // 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListColumn(MEMBER(Item, power), 0.21, "Dégât"), // 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gobjs.getRegion("Backpack")+=list.create(lc, Elms(lc));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.column(0).text_align=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.column(2).precision=1; // set showing only 1 decimal precision for power float attribute<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list. cur_mode=LCM_MOUSE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.drawMode(LDM_RECTS);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.flag|=LIST_SCALABLE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.elmHeight(0.08);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.zoom_max*=1.44 ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; bool visible()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Window *window=gobjs.findWindow(S))return window.visible();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // operations<br />
&nbsp;&nbsp; void link(Inventory *inv) // link with 'inv' Inventory<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(T.inv!=inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T.inv=inv;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void setGui() // set visual gui components<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set item list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// here we have to hide the items which are assigned to slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// create a 'visible' array which determines visibility of an element<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Memt&lt;bool&gt; visible; visible.setNum(inv.items.elms()); // allocate array of item visibility<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPAO(visible)=true; // set all visibility by default to true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(inv.slots) // iterate through all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(inv.valid(i)) // if the slot is valid<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visible[inv.slots[i]]=false; // set visibility for item assigned to a slot to false, to be hidden on the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.setData(inv.items, visible); // set list data from items container and visibility list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set slot images<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(SLOT_NUM) // for all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(i!=SLOT_TEMP) // skip temporary slot because it's not drawn using 'Image' class<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(slot_region[i])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rect&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image_rect=slot_region[i].rect(); // gui rect<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GuiImage &amp;image_item=slot_image [i]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; // gui image<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!inv.valid(i))image_item.set(null);else // if there is no item then clear the item image slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImagePtr icon=inv.item(inv-&gt;slots[i]).icon; // access item's icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image_item.set(icon);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // set slot image as the item's icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(icon)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// set proper scaling<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec2 size=icon-&gt;size(); size*=PixelSize; // set default size<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(size.x&gt;image_rect.w())size*=image_rect.w()/size.x; // clamp item size to background slot width<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(size.y&gt;image_rect.h())size*=image_rect.h()/size.y; // clamp item size to background slot height<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Rect rect(image_rect.center()); rect.extend(size/2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image_item.rect(rect);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REPAO(slot_image).set(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void toggle() {if(visible())hide();else show();} // toggle visibility<br />
&nbsp;&nbsp; void show() {gobjs.getWindow(S).show();}<br />
&nbsp;&nbsp; void hide() {gobjs.getWindow(S).hide();}<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update(Player &amp;owner) // handle moving items with mouse<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Ms.bp(0)) // if mouse button pressed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(InRange(inv.slots[SLOT_TEMP], inv.items)) // if we have an item attached with mouse<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;list) // if mouse cursor is on the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.slots[SLOT_TEMP]=-1; // clear the slot reference which will result in "putting back the item into the list"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else // we don't have an item so we want to get one<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;list) // from the list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(list())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inv.slots[SLOT_TEMP]=list.visToAbs(list.cur);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui(); // update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(slot_image)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Gui.ms()==&amp;slot_image[i] || Gui.ms()==slot_region[i]) // if we want to swap temp item with i-th slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv.slotsCanBeSwapped(SLOT_TEMP, SLOT_TYPE(i)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(inv.slots[SLOT_TEMP], inv.slots[i]); // swap temporary with i-th slot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setGui();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // update visuals<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; owner.sendInvSlots();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; void draw() // draw item being moved with mouse<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv &amp;&amp; InRange(inv.slots[SLOT_TEMP], inv.items))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vec2 pos=Ms.pos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inv.item(inv.slots[SLOT_TEMP]).drawIcon(pos);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
}<br />
InventoryGui InvGui;<br />
/******************************************************************************/</code></div></div>
<br />
4/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">Inventory.cpp</span><br />
<br />
Paste this code: <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
class Inventory : NetInventory<br />
{<br />
&nbsp;&nbsp;~Inventory() {if(InvGui.inv==this)InvGui.link(null);}<br />
&nbsp;&nbsp; Inventory() {items.replaceClass&lt;Item&gt;();}<br />
<br />
&nbsp;&nbsp; // get<br />
&nbsp;&nbsp; Item&amp; item(int i) {return (Item&amp;)items[i];} // we can perform direct cast since 'items' had 'replaceClass' called in constructor<br />
<br />
&nbsp;&nbsp; bool slotCanBePutTo(SLOT_TYPE src, SLOT_TYPE dest) // test if slot 'src' can be put to 'dest' slot<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!InRange(src, SLOT_NUM) || !InRange(dest, SLOT_NUM))return false;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return valid(src) ? item(slots[src]).canBePutTo(dest) : true;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; bool slotsCanBeSwapped(SLOT_TYPE a, SLOT_TYPE b) // test if slot 'a' can be swapped with slot 'b'<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return slotCanBePutTo(a, b) &amp;&amp; slotCanBePutTo(b, a);<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // manage<br />
&nbsp;&nbsp; void create(NetInventory &amp;src)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.setNum(src.items.elms()); FREPA(src.items)item(i).create(src.items[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Copy(slots, src.slots);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; /*void itemRemoved(Game.Obj &amp;item) // called when an item is being removed<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// perform check if it is a equipped item<br />
&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;REPA(slot) // for all slots<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;if(slots[i]==item) // if i-th slot is set to item which is being removed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;slots[i].clear(); // clear the slot so it can no longer be referenced to the removed item<br />
&nbsp;&nbsp; }*/<br />
&nbsp;&nbsp; void itemRemoved() // called when an item has been removed<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void itemAdded() // called when an item has been added<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setGui();<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void setGui()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(InvGui.inv==this)InvGui.setGui();<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update(AnimatedSkeleton &amp;skel, Player *owner)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(owner &amp;&amp; InvGui.inv==this)if(Player *player=CAST(Player, owner))InvGui.update(*player);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// set matrixes for items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"HandL"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_ARM_L]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"HandR"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_ARM_R]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(C OrientP *point=skel.findPoint(8"Shld"))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Item&nbsp;&nbsp; &amp;item&nbsp;&nbsp;=T.item(slots[SLOT_SHLD]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matrix&nbsp;&nbsp;matrix=item.matrix(); // get current matrix<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.update();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// immediately overwrite item members after calling 'update'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; uint drawPrepare()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// draw items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint modes=0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))modes|=item(slots[SLOT_ARM_L]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))modes|=item(slots[SLOT_ARM_R]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))modes|=item(slots[SLOT_SHLD]).drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return modes;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void drawShadow()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// draw items in hands<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_L))item(slots[SLOT_ARM_L]).drawShadow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_ARM_R))item(slots[SLOT_ARM_R]).drawShadow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(valid(SLOT_SHLD))item(slots[SLOT_SHLD]).drawShadow();<br />
&nbsp;&nbsp; }<br />
}<br />
/******************************************************************************/</code></div></div>
<br />
5/ copy the "<span style="color: #9370DB;">gui inventory</span>" file located in <a href="http://www.esenthel.com/?id=store" target="_blank">MMO Source</a> to you project.<br />
<br />
6/ In Net Chr.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">class ClientChr : NetChr</span></span> add this :<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>NetInventory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv;</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void create(CreateChr &amp;cc)</span></span> add this :<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.items.New().create("ITEM UID");</code></div></div>
  <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">virtual void save(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.save(f);</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">virtual bool load(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>if(!inv.load(f))return false;</code></div></div>
     <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> void compress(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.compress(f);</code></div></div>
     <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> void decompress(File &amp;f)</span></span> add this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.decompress(f);</code></div></div>
  <br />
<br />
7/ In Commands.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">enum CLIENT_SERVER_COMMANDS</span></span>  just down why CS_CHR_ANIM, add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>CS_CHR_INV_SLOTS&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;&nbsp; // Inv</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;"> class ChrVisuals</span></span> Copy this :  <br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>class ChrVisuals<br />
{<br />
&nbsp;&nbsp; SockAddr addr;<br />
&nbsp;&nbsp; MeshPtr&nbsp;&nbsp;mesh;<br />
&nbsp;&nbsp; NetInventory inv;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void save(File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr.save(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&lt;&lt;mesh.id();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.compress(f, true);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; void load(File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr.load(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mesh=f.getUID();<br />
&nbsp;&nbsp;&nbsp;&nbsp; inv.decompress(f);<br />
&nbsp;&nbsp; }<br />
}<br />
void ServerWriteChrVisuals(File &amp;f, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; f.writeMem(); cv.save(f);<br />
}<br />
void ServerSendChrVisuals(Connection &amp;conn, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_VISUALS); cv.save(f); f.pos(0); conn.send(f, -1, false);<br />
}<br />
void ClientRecvChrVisuals(File &amp;f, ChrVisuals &amp;cv)<br />
{<br />
&nbsp;&nbsp; cv.load(f);<br />
}</code></div></div>
  <br />
=&gt; just down why<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// CS_CHR_ANIM<br />
/******************************************************************************/<br />
void ClientSendChrAnim(Connection &amp;conn, C UID &amp;anim, C UID &amp;sound=UIDZero)<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_ANIM)&lt;&lt;anim&lt;&lt;sound; f.pos(0); conn.send(f);<br />
}<br />
void ServerRecvChrAnim(File &amp;f, UID &amp;anim, UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; f&gt;&gt;anim&gt;&gt;sound;<br />
}<br />
void ServerWriteChrAnim(File &amp;f, C SockAddr &amp;addr, C UID &amp;anim, C UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; f.writeMem().putByte(CS_CHR_ANIM); addr.save(f); f&lt;&lt;anim&lt;&lt;sound;<br />
}<br />
void ClientRecvChrAnim(File &amp;f, SockAddr &amp;addr, UID &amp;anim, UID &amp;sound)<br />
{<br />
&nbsp;&nbsp; addr.load(f); f&gt;&gt;anim&gt;&gt;sound;<br />
}</code></div></div>
 add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// CS_CHR_INV_SLOTS<br />
/******************************************************************************/<br />
void ClientSendChrInvSlots(Connection &amp;conn, int (&amp;slots)[SLOT_NUM])<br />
{<br />
&nbsp;&nbsp; File f; f.writeMem().putByte(CS_CHR_INV_SLOTS); f&lt;&lt;slots; f.pos(0); conn.send(f);<br />
}<br />
void ServerRecvChrInvSlots(File &amp;f, int (&amp;slots)[SLOT_NUM])<br />
{<br />
&nbsp;&nbsp; f&gt;&gt;slots;<br />
}</code></div></div>
  <br />
<br />
8/ Create new Code in <span style="font-weight: bold;">Client</span> =&gt; <span style="color: #FFA500;">Item.cpp</span><br />
<br />
Paste this code: <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
class Item : NetItem<br />
{<br />
&nbsp;&nbsp; ITEM_TYPE type=ITEM_NONE;<br />
&nbsp;&nbsp; byte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type2=0;<br />
&nbsp;&nbsp; flt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale=1, power=0;<br />
&nbsp;&nbsp; Str&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name;<br />
&nbsp;&nbsp; MeshPtr&nbsp;&nbsp; mesh;<br />
&nbsp;&nbsp; ImagePtr&nbsp;&nbsp;icon;<br />
&nbsp;&nbsp; Vec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vel, ang_vel;<br />
&nbsp;&nbsp; Actor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;<br />
&nbsp;&nbsp; //Particles particles;<br />
&nbsp;&nbsp; //bool particles_under_water=false;<br />
<br />
&nbsp;&nbsp; void create(NetItem &amp;src)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SCAST(NetItem, T)=src;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(obj)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // name<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("name"))name=p.asText();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // type<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("type" ))type =p.asEnum(ITEM_NONE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("type2"))type2=p.asEnum();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // power<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("power"))power=p.asFlt();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // icon<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Param *p=obj-&gt;findParam("icon"))icon=p.asID();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scale=obj-&gt;scale();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mesh =obj-&gt;mesh ();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; // get / set<br />
&nbsp;&nbsp; bool canBePutTo(SLOT_TYPE inv_slot) // test if item can be put to 'inv_slot' inventory slot<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(inv_slot==SLOT_TEMP)return true;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(inv_slot)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_HEAD : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_HELMET&nbsp;&nbsp;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_BODY : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_BODY&nbsp;&nbsp;&nbsp;&nbsp;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_HANDS: return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_GAUNTLET;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_LEGS : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_PANTS&nbsp;&nbsp; ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_FEET : return type==ITEM_ARMOR &amp;&amp; type2==ARMOR_BOOT&nbsp;&nbsp;&nbsp;&nbsp;;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_SHLD:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_ARM_L:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case SLOT_ARM_R:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(type==ITEM_WEAPON)return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(type==ITEM_MISC &amp;&amp; Contains(name, "Torch"))return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void matrix(Matrix &amp;matrix)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._matrix_scaled=T._matrix=matrix;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T._matrix_scaled.scaleOrn(scale);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; C Matrix&amp; matrix&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;() {return _matrix&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;}<br />
&nbsp;&nbsp; C Matrix&amp; matrixScaled() {return _matrix_scaled;}<br />
<br />
&nbsp;&nbsp; // update<br />
&nbsp;&nbsp; void update() {}<br />
<br />
&nbsp;&nbsp; // draw<br />
&nbsp;&nbsp; void drawIcon(C Vec2 &amp;pos)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(icon)icon-&gt;drawFit(Rect_LU(pos, icon-&gt;size()*PixelSize));<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; virtual uint drawPrepare()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(mesh &amp;&amp; Frustum(mesh-&gt;box, matrixScaled()))mesh-&gt;draw(matrixScaled(), vel, ang_vel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight((Cur.obj, this &amp;&amp; Cur.highlight) ? Color(34, 85, 85, 0) : TRANSPARENT); //uint modes=super.drawPrepare();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TRANSPARENT);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; // if(particles.is() &amp;&amp; !particles_under_water)<br />
&nbsp;&nbsp;&nbsp;&nbsp; // {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //modes|=IndexToFlag(particles.renderMode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //modes|=IndexToFlag(RM_BLEND); // single particle<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Vec center;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //flt opacity=particles.opacity(&amp;center);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //LightSqr(6*opacity, center).add(true, this);<br />
&nbsp;&nbsp;&nbsp;&nbsp; // }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;virtual void drawShadow()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(mesh &amp;&amp; Frustum(mesh-&gt;box, matrixScaled()))mesh-&gt;drawShadow(matrixScaled());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//if(CurrentLight.src!=this); //super.drawShadow();<br />
&nbsp;&nbsp; }<br />
//virtual void drawPalette () {if(!particles_under_water){particles.draw();}}<br />
&nbsp;&nbsp;//virtual void drawPalette1() {if(!particles_under_water){particles.draw();}}<br />
&nbsp;&nbsp; //virtual void drawBlend&nbsp;&nbsp; () {if(!particles_under_water){particles.draw(); DrawParticle(*Images(UID(4250561076, 1214902943, 3956203709, 646772750)), 0, Color(255, 255, 170, 0), 0.07, 0.9, 0, particles.shape.pos()*particles.matrix, Vec(0));}}<br />
<br />
&nbsp;&nbsp; // network<br />
&nbsp;&nbsp; virtual void decompress(File &amp;f) // decompress data from data obtained using network connection<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.decompress(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create(T);<br />
&nbsp;&nbsp; }<br />
<br />
private:<br />
&nbsp;&nbsp; Matrix _matrix, _matrix_scaled;<br />
}<br />
/******************************************************************************/</code></div></div>
9/ In Player.cpp <br />
<br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">class Player : Game.Chr , BlendObject</span></span> add this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>Player() {InvGui.link(&amp;inv);}<br />
&nbsp;&nbsp; Inventory&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv;</code></div></div>
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// *************************Inv**************** //<br />
&nbsp;&nbsp; void sendInvSlots() // send current equipped items (slots) to server<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClientSendChrInvSlots(Server, inv.slots);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; //************************************************ //</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void Player.create(ClientChr &amp;chr)</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.create(chr.inv);</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">bool Player.update()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>inv.update(skel,&nbsp;&nbsp;this);<br />
<br />
&nbsp;&nbsp; if(InvGui.inv==&amp;inv &amp;&amp; !inv.valid(SLOT_TEMP))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Kb.bp(KB_I))InvGui.toggle();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</code></div></div>
  <br />
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">uint Player.drawPrepare()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>SetHighlight(DamageColor(damage_time));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint draw_mask=~0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool hide_head=(ViewMode==VIEW_FPP &amp;&amp; !Renderer.mirror());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;&nbsp;hide_head)FlagDisable(draw_mask, IndexToFlag(DG_CHR_HEAD));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetDrawMask(draw_mask); mesh-&gt;draw(skel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetDrawMask();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetHighlight();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inv.drawPrepare(); // ADD THIS</code></div></div>
 <br />
10/ In Game.cpp =&gt; <span style="font-style: italic;"><span style="color: #4682B4;">bool InitGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui.create();</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void ShutGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui&nbsp;&nbsp;.hide();</code></div></div>
=&gt; <span style="font-style: italic;"><span style="color: #4682B4;">void DrawGame()</span></span> add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>InvGui.draw();</code></div></div>
11/ In Constants.cpp =&gt; add this:<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>const flt PixelSize=0.002;</code></div></div>
<br />
If you have any questions, Post here. Thanks <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" />]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[[Tuto] Restater.Bat for application]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8318</link>
			<pubDate>Sun, 25 Jan 2015 21:32:16 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8318</guid>
			<description><![CDATA[Hello,<br />
<br />
 I share this tutorial, here's how to create a restarter for an application. Example: if your server.exe shutdown =&gt; restater.bat restart server app. <br />
<br />
Ok, let's go. <br />
<br />
<span style="font-size: medium;">1</span>= Create a new file.TXT <br />
<br />
<span style="font-size: medium;">2</span>= Opens with BlocNote / Notepad++<br />
<br />
<span style="font-size: medium;">3</span>= Copy this code:   <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>:1<br />
start /WAIT server.exe<br />
goto 1</code></div></div>
<br />
<span style="font-size: medium;">4</span>= Replace your NameAPP  = <span style="color: #FF4500;">server.exe</span><br />
<br />
<span style="font-size: medium;">5</span>= Save File =&gt;.bat  (Ex: Restater.bat) <br />
<br />
<span style="font-size: medium;">6</span>= Place the file in folders of <span style="color: #FF4500;">NameApp.exe.</span> <br />
<br />
 Run ! <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
Thanks, Bye]]></description>
			<content:encoded><![CDATA[Hello,<br />
<br />
 I share this tutorial, here's how to create a restarter for an application. Example: if your server.exe shutdown =&gt; restater.bat restart server app. <br />
<br />
Ok, let's go. <br />
<br />
<span style="font-size: medium;">1</span>= Create a new file.TXT <br />
<br />
<span style="font-size: medium;">2</span>= Opens with BlocNote / Notepad++<br />
<br />
<span style="font-size: medium;">3</span>= Copy this code:   <div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>:1<br />
start /WAIT server.exe<br />
goto 1</code></div></div>
<br />
<span style="font-size: medium;">4</span>= Replace your NameAPP  = <span style="color: #FF4500;">server.exe</span><br />
<br />
<span style="font-size: medium;">5</span>= Save File =&gt;.bat  (Ex: Restater.bat) <br />
<br />
<span style="font-size: medium;">6</span>= Place the file in folders of <span style="color: #FF4500;">NameApp.exe.</span> <br />
<br />
 Run ! <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
Thanks, Bye]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Reliable UDP]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8188</link>
			<pubDate>Wed, 10 Dec 2014 00:31:36 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8188</guid>
			<description><![CDATA[I noticed there was no UDP (FastConnection) tutorial included with EE.<br />
<br />
I have been converting my game to RUDP and so decided to make a little tutorial using what I learned. Its useful to see how to use UDP in EE as well as a simple way to do reliable-ordered UDP. See the attached esenthelproject, I have also included the code for people who are not using the latest EE.<br />
<br />
Features<br />
Multiple clients<br />
Auto dropping timed-out clients<br />
Can send packets both reliably and unreliably <br />
Ping calculation<br />
Packet loss calculation<br />
<br />
Project includes a ReliableFastConnectionClass, a Demo Client, and Demo Server.<br />
<br />
Why use this over RakNet? Because its simpler! 100% EE Script code.<br />
<br />
What it missing that would be nice:<br />
Handshakes, Encryption, Packet combining, Limiting Packets to 1500 bytes or auto-fragmenting into smaller, sequential delivery rather than strict ordered etc.. etc..<br />
<br />
I didn't put more effort into it than I needed to, I only use EE on the client so that is why the server isn't more complete (testing for malformed packets, buffer overrun etc), a malicious client could kill it pretty easy!<br />
<br />
The class<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// communication constants<br />
&nbsp;&nbsp; const Byte RFC_PING = 0;<br />
&nbsp;&nbsp; const Byte RFC_PING_REPLY = 1;<br />
&nbsp;&nbsp; const Byte RFC_UNRELIABLE = 2;<br />
&nbsp;&nbsp; const Byte RFC_RELIABLE = 3;<br />
&nbsp;&nbsp; const Byte RFC_CONFIRM_RELIABLE = 4;<br />
<br />
class ReliableFastConnection : FastConnection // UDP connection with optional reliable-ordered delivery<br />
{<br />
&nbsp;&nbsp; // things that can be tweaked..<br />
&nbsp;&nbsp; Int pingFrequency = 10; //times per second to ping, 0 = server, &gt; 0 = client<br />
&nbsp;&nbsp; Int reliableTimeout = 100; // time in milliseconds from last reliable message to try sending it again<br />
&nbsp;&nbsp; Int connectionTimeout = 15; // time in seconds that if no ping is received toremoved the ActiveDestination from remoteAddresses<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // things not to be tweaked..<br />
&nbsp;&nbsp; SockAddr localListenAddress;<br />
&nbsp;&nbsp; Flt lastPingTime = 0; //seconds since app start, used to decide if we need to send another ping or not (client only)<br />
&nbsp;&nbsp; Flt ping = 0; //round trip latency ms<br />
&nbsp;&nbsp; Memc&lt;Flt&gt; ping_times; // container for storing the last 10 ping times<br />
&nbsp;&nbsp; Flt packet_loss = 0; // percentage of ping packets that don't make it across the wire averaged over 10 seconds<br />
&nbsp;&nbsp; Memc&lt;Flt&gt; pings_received_last_10_secs; // pings that have been recieved in last 10 seconds<br />
&nbsp;&nbsp; ULong reliable_received = 0; // data in bytes received<br />
&nbsp;&nbsp; ULong unreliable_received = 0;<br />
&nbsp;&nbsp; ULong reliable_sent = 0; <br />
&nbsp;&nbsp; ULong unreliable_sent = 0;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; struct PacketAddr<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte data[65536];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UShort length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void from_file(File &amp;f,&nbsp;&nbsp;SockAddr addr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; address = addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length = f.size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.get(data, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; struct ActiveDestination<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt received_ping_at_time = 0; // the last time we got a ping in local time, not remote tag time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong local_synchro_on_local&nbsp;&nbsp;= 0; // what our last reliable packet sent out was tagged with<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong local_synchro_on_remote = 0; // the last confirmed received reliable packet from the remote connection<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong remote_synchro_on_local = 0; // the last reliable packet recieved from the remote connection was tagged with this<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;PacketAddr&gt; reliable_queue; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt lastReliableTime = 0;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Memc&lt;ActiveDestination&gt; remoteAddresses;<br />
&nbsp;&nbsp; Memc&lt;PacketAddr&gt; received_queue; // this is currently not put into ActiveDestination like reliable_queue, but it certainly could be..<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // connect(..) doesn't actually send anything to the remote host, its really just setting the remote address and opening the local UDP<br />
&nbsp;&nbsp; // port for listening, after all, UDP is really connection-less, we establish a "connection" through keep-alive pinging in the update loop.<br />
&nbsp;&nbsp; void connect(SockAddr remoteaddr,&nbsp;&nbsp;SockAddr listenaddr) // only the client uses this<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination actdest;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.address = remoteaddr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.add(actdest); // client will only have 1 destination address.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen(listenaddr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void listen(SockAddr addr) // server will just listen, not use connect<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create(addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localListenAddress = addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_reliable(SockAddr addr, File &amp;f) // this actually just adds to a queue<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;padd.from_file(f, addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses_has_remote(addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_remoteAddress(addr).reliable_queue.add(padd); // add to end of queue<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_unreliable(SockAddr destination, File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_UNRELIABLE).putUShort(f.size());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.pos(0); // make sure it is at the beginning of the file before copying<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.copy(f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(destination, f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unreliable_sent += f.size(); // we ar enot including the RFC header and UShort size<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Bool update()<br />
&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int bytes_received = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte datarec[65536];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr sender_addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bytes_received = receive(sender_addr, datarec); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(bytes_received &gt; -1) // needs to be loop more than one command recieved at once is possible? seems like it shoudl onyl return 1 packet at a time, but maybe need multiple calls to receive if low framerate?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;f.readMem(datarec, bytes_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //while(!f.end())&nbsp;&nbsp;// should not need this? we will only send 1 command per packet, doing multiple commands per packet&nbsp;&nbsp;makes it harder when we decide to ignore the rest of a packet like in RFS_RELIABLE case below, we would need to make sure to read out the rest of the data in the packet otherwise will will get buggy stuff<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte command = f.getByte();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(command)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_PING: // only server will receive this, client pings server, not vice-versa<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt ptime = f.getFlt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong loc_synchro_on_remote = f.getULong(); // learn what was the last reliable client got from the server was, lets us know if we need to resend<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses_has_remote(sender_addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination &amp; adest = get_remoteAddress(sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adest.local_synchro_on_remote = loc_synchro_on_remote;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adest.received_ping_at_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_PING_REPLY).putFlt(ptime).putULong(adest.remote_s&#8203;ynchro_on_local).pos(0); // let the client know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(sender_addr,&nbsp;&nbsp;f2); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination actdest;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.address = sender_addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.received_ping_at_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.add(actdest);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_PING_REPLY).putFlt(ptime).putULong(actdest.remote&#8203;_synchro_on_local).pos(0); // let the client know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(sender_addr,&nbsp;&nbsp;f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_PING_REPLY: // client will recieve this<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt lastPingTimeReceived = f.getFlt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// for packet loss calculation<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pings_received_last_10_secs.add(lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// calculate ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(ping_times.elms() &gt; 9)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.add(Time.realTime() - lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.remove(0, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt ping_time_total = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(ping_times){ping_time_total +=ping_times[i];}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping = (ping_time_total / ping_times.elms()) * 1000; // make it in milliseconds<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.add(Time.realTime() - lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check to see if we need to increase our local synchro<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_local_synchro_on_remote(f.getULong(), remoteAddresses[0].local_synchro_on_remote, remoteAddresses[0]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_UNRELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UShort length_of_packet = f.getUShort(); // datarec may contain more than one packet, so we need to only get one at a time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f2.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.copy(f2, length_of_packet); // hopefully f.copy advances pos() of f.. need ot maek sure otherwise this wont work, it will just keep reading the same packet over and over<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; padd.from_file(f2, sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; received_queue.add(padd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unreliable_received += length_of_packet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_RELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULong synchro = f.getULong();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(remoteAddresses_has_remote(sender_addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination &amp; adest = get_remoteAddress(sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(synchro ==&nbsp;&nbsp;(adest.remote_synchro_on_local + 1)) // is it the next synchro message? we need to make sure its not a repeat of something we already received<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UShort length_of_packet = f.getUShort(); // datarec may contain more than one packet, so we need to only get one at a time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f2.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.copy(f2, length_of_packet); // hopefully f.copy advances pos() of f.. need ot maek sure otherwise this wont work, it will just keep reading the same packet over and over<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; padd.from_file(f2, sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; received_queue.add(padd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adest.remote_synchro_on_local += 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reliable_received += length_of_packet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // now we need to send a confirmation back immediately so remote doesn't have to wait for next ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f3;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f3.writeMem().putByte(RFC_CONFIRM_RELIABLE).putULong(adest.remote_synchro_on_loc&#8203;al).pos(0); // let the remote know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send(sender_addr,&nbsp;&nbsp;f3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_CONFIRM_RELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REPA(remoteAddresses)if(remoteAddresses[i].address == sender_addr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_local_synchro_on_remote(f.getULong(), remoteAddresses[i].local_synchro_on_remote, remoteAddresses[i]); // check to see if we need to increase our local synchro<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit("RFC Default, something went wrong, no matching command!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytes_received = receive(sender_addr, datarec); // read the next packet, if it exists<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_ping(); // currently only works for client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_from_reliable_queues();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pingFrequency == 0)remove_dead_remote_addresses(); // only server should do this for now, unless server-&gt;client pings are implemented<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
private: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void remove_dead_remote_addresses()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool removed_one = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(((Time.realTime() - remoteAddresses[i].received_ping_at_time) &gt; connectionTimeout) &amp;&amp; !removed_one)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.remove(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removed_one =true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_from_reliable_queues()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses[i].reliable_queue.elms()) // if there is stuff in the queue<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(remoteAddresses[i].local_synchro_on_local == remoteAddresses[i].local_synchro_on_remote) // if the destination address has received&nbsp;&nbsp;all previous reliable messages<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actually_send_reliable(remoteAddresses[i].reliable_queue.first(),remoteAddresses[i].lastReliableTime, ++remoteAddresses[i].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if((Time.realTime() - remoteAddresses[i].lastReliableTime) &gt; (reliableTimeout/1000) ) // destination has not received our last sent reliable, and timeout has occured to send it again<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actually_send_reliable(remoteAddresses[i].reliable_queue.first(),remoteAddresses[i].lastReliableTime, remoteAddresses[i].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_ping()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pingFrequency &gt; 0) // is a client so ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((Time.realTime() - lastPingTime) &gt; (1/pingFrequency))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.writeMem().putByte(RFC_PING).putFlt(Time.realTime()).putULong(remoteAddre&#8203;sses[0].remote_synchro_on_local).pos(0); //remote_synchro_on_local let the server know what the last reliable the client got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//send(destinationAddress,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(remoteAddresses[0].address,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastPingTime = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// update pack loss stuff only for client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_packet_loss();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;packet_loss = ((pingFrequency * 10) - pings_received_last_10_secs.elms()) / 100.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(packet_loss &lt; 0) packet_loss = 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Time.realTime() &lt; 10.0)packet_loss = 0; // jus tignor eit the first 10 secs of app opening<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void actually_send_reliable(PacketAddr &amp;padd, Flt &amp;last_reliable_sent_time, ULong synchro_to_tag_packet_with)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.writeMem().putByte(RFC_RELIABLE).putULong(synchro_to_tag_packet_with).put&#8203;UShort(padd.length); // tag as reliable, put the synchro, add the length of the packet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.put(padd.data, padd.length); // add packet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(padd.address,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_reliable_sent_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reliable_sent += padd.length; // we are not including the RFC header and UShort size<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void update_packet_loss()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(pings_received_last_10_secs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bool removed_one = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Time.realTime() - pings_received_last_10_secs[i] &gt; 10 &amp;&amp;&nbsp;&nbsp;!removed_one)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pings_received_last_10_secs.remove(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removed_one = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_packet_loss();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void test_local_synchro_on_remote(ULong test_synchro, ULong &amp;loc_synchro_on_remote,&nbsp;&nbsp;ActiveDestination &amp;adest)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(test_synchro == loc_synchro_on_remote + 1) // server has confirmed a new reliable<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loc_synchro_on_remote += 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adest.reliable_queue.remove(0, true); // this will shift memory, is this too slow?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Bool remoteAddresses_has_remote(SockAddr address) // is the remote address in remoteAddresses?<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool found_remote = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)if(address == remoteAddresses[i].address){ found_remote = true; break;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return found_remote;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; ActiveDestination&amp; get_remoteAddress(SockAddr address) <br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)if(address == remoteAddresses[i].address) return remoteAddresses[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit("Couldn't find remote addess, make sure to callremoteAddresses_has_remote first");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return remoteAddresses[0];<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br />
The client demo<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; This tutorial presents a sample&nbsp;&nbsp;Reliable UDP Client Connection.<br />
<br />
&nbsp;&nbsp; It can be used together with second tutorial "Demo Server"<br />
<br />
/******************************************************************************/<br />
Str destinationIP = "127.0.0.1";<br />
Str last_message_string = "nothing";<br />
// destinationPort and listenPort must be different if server is run on localhost, <br />
// because only one process can listen to a UDP port at one time,<br />
// otherwise they can be the same port, and probably should be to help with<br />
// NAT transversal (so that end users don't need to forward ports on router).<br />
Int destinationPort = 8791;<br />
//Int listenPort = 8790; <br />
ReliableFastConnection connection;<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag=APP_WORK_IN_BACKGROUND|APP_NO_PAUSE_ON_WINDOW_MOVE_SIZE; // specify work in background flag to work also when not focused<br />
&nbsp;&nbsp; App.x=1;<br />
&nbsp;&nbsp; D.mode(500, 400);<br />
&nbsp;&nbsp; D.scale(1.25);<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; SockAddr remoteAddress;<br />
&nbsp;&nbsp; remoteAddress.setIP(destinationIP, destinationPort);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; if(Contains(destinationIP, "127.0.0.1")) //can't listen and send from 2 apps on same ip:port over UDP<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address.setIP(destinationIP, destinationPort);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr localAddress;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAddress.setLocalFast(destinationPort + Random(1, 1000)); // choose random port, hopefully no conflicts<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.connect(remoteAddress, localAddress);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; else<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr localAddress;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAddress.setLocalFast(destinationPort); // if we are not running server and client on same PC it is OK to use the same listen port on server and client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.connect(remoteAddress, localAddress);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; <br />
}<br />
/******************************************************************************/<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; connection.update();<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; if(Kb.b(KB_R)) //flood reliable<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "Reliable Random # :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.send_reliable(connection.remoteAddresses[0].address, f); //connection.remoteAddresses[0].address is kind of awkward, clients will only have 1 remoteAddress<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; if(Kb.b(KB_U)) //flood unreliable<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "UNreliable Random # :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.send_unreliable(connection.remoteAddresses[0].address, f);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear(TURQ); <br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.7, S+"Press 'U' to send unreliable packets, 'R' to send reliable packets.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(connection.received_queue.elms())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.put(connection.received_queue.last().data, connection.received_queue.last().length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last_message_string = f.getStr();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.received_queue.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.6, S+"Last Packet Received Had String: " + last_message_string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.5, S+"packet_loss "+ connection.packet_loss * 100 + "%");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.4, S+"connection rec: "+ connection.received());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.3, S+"connection sent: "+ connection.sent());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.2, S+"connectdes: "+connection.remoteAddresses[0].address.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.1, S+"connectloc: "+connection.localListenAddress.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.0, S+"FPS "+ Time.fps());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.1, S+"remote_synchro_on_local "+ connection.remoteAddresses[0].remote_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.2, S+"local_synchro_on_remote "+ connection.remoteAddresses[0].local_synchro_on_remote);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.3, S+"local_synchro_on_local "+ connection.remoteAddresses[0].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.4, S+"ping "+ connection.ping);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.5, S+"reliable_sent "+ connection.reliable_sent);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.6, S+"unreliable_sent "+ connection.unreliable_sent);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br />
The server demo<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; This tutorial presents a sample&nbsp;&nbsp;Reliable UDP Server Connection.<br />
<br />
&nbsp;&nbsp; It can be used together with second tutorial "Demo Client"<br />
<br />
/******************************************************************************/<br />
Int listenPort = 8791; <br />
ReliableFastConnection connection;<br />
Str last_message_string = "nothing";<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag=APP_WORK_IN_BACKGROUND|APP_NO_PAUSE_ON_WINDOW_MOVE_SIZE; // specify work in background flag to work also when not focused<br />
&nbsp;&nbsp; App.x=1;<br />
&nbsp;&nbsp; D.mode(500, 400);<br />
&nbsp;&nbsp; D.scale(1.25);<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; SockAddr addr;<br />
&nbsp;&nbsp; addr.setLocalFast(listenPort);<br />
&nbsp;&nbsp; connection.listen(addr);<br />
&nbsp;&nbsp; connection.pingFrequency = 0; // server doesn't send pings<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; <br />
}<br />
/******************************************************************************/<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; connection.update();<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; if(Kb.b(KB_R)) //flood reliable to all connected (have received recent ping) clients<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "From Server Reliable# :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(connection.remoteAddresses)connection.send_reliable(connection.remoteA&#8203;ddresses[i].address, f);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; if(Kb.b(KB_U)) //flood unreliable to all connected (have received recent ping) clients<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "From Server UNreliable# :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(connection.remoteAddresses)connection.send_unreliable(connection.remot&#8203;eAddresses[i].address, f); <br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear(TURQ);<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.7, S+"Press 'U' to send unreliable packets, 'R' to send reliable packets.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(connection.received_queue.elms())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.put(connection.received_queue.last().data, connection.received_queue.last().length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last_message_string = f.getStr();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.received_queue.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.6, S+"Last Packet Received Had String: " + last_message_string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.5, S+"FPS "+ Time.fps());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.4, S+"connection.received()"+ connection.received());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.3, S+"connection.sent()"+ connection.sent());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.2, S+"connection.unreliable_received "+ connection.unreliable_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.1, S+"connection.reliable_received "+ connection.reliable_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.0, S+"number of clients: "+connection.remoteAddresses.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.1, S+"connection.localListenAddress: "+connection.localListenAddress.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.2, S+"remote_synchro_on_local "+ connection.remote_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.3, S+"local_synchro_on_remote "+ connection.local_synchro_on_remote);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.4, S+"local_synchro_on_local "+ connection.local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, 0.0, S+"Received Data: "+data);<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".zip" />&nbsp;&nbsp;<a href="attachment.php?aid=2611" target="_blank">ReliableFastConnection7.zip</a> (Size: 6.82 KB / Downloads: 16)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[I noticed there was no UDP (FastConnection) tutorial included with EE.<br />
<br />
I have been converting my game to RUDP and so decided to make a little tutorial using what I learned. Its useful to see how to use UDP in EE as well as a simple way to do reliable-ordered UDP. See the attached esenthelproject, I have also included the code for people who are not using the latest EE.<br />
<br />
Features<br />
Multiple clients<br />
Auto dropping timed-out clients<br />
Can send packets both reliably and unreliably <br />
Ping calculation<br />
Packet loss calculation<br />
<br />
Project includes a ReliableFastConnectionClass, a Demo Client, and Demo Server.<br />
<br />
Why use this over RakNet? Because its simpler! 100% EE Script code.<br />
<br />
What it missing that would be nice:<br />
Handshakes, Encryption, Packet combining, Limiting Packets to 1500 bytes or auto-fragmenting into smaller, sequential delivery rather than strict ordered etc.. etc..<br />
<br />
I didn't put more effort into it than I needed to, I only use EE on the client so that is why the server isn't more complete (testing for malformed packets, buffer overrun etc), a malicious client could kill it pretty easy!<br />
<br />
The class<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// communication constants<br />
&nbsp;&nbsp; const Byte RFC_PING = 0;<br />
&nbsp;&nbsp; const Byte RFC_PING_REPLY = 1;<br />
&nbsp;&nbsp; const Byte RFC_UNRELIABLE = 2;<br />
&nbsp;&nbsp; const Byte RFC_RELIABLE = 3;<br />
&nbsp;&nbsp; const Byte RFC_CONFIRM_RELIABLE = 4;<br />
<br />
class ReliableFastConnection : FastConnection // UDP connection with optional reliable-ordered delivery<br />
{<br />
&nbsp;&nbsp; // things that can be tweaked..<br />
&nbsp;&nbsp; Int pingFrequency = 10; //times per second to ping, 0 = server, &gt; 0 = client<br />
&nbsp;&nbsp; Int reliableTimeout = 100; // time in milliseconds from last reliable message to try sending it again<br />
&nbsp;&nbsp; Int connectionTimeout = 15; // time in seconds that if no ping is received toremoved the ActiveDestination from remoteAddresses<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // things not to be tweaked..<br />
&nbsp;&nbsp; SockAddr localListenAddress;<br />
&nbsp;&nbsp; Flt lastPingTime = 0; //seconds since app start, used to decide if we need to send another ping or not (client only)<br />
&nbsp;&nbsp; Flt ping = 0; //round trip latency ms<br />
&nbsp;&nbsp; Memc&lt;Flt&gt; ping_times; // container for storing the last 10 ping times<br />
&nbsp;&nbsp; Flt packet_loss = 0; // percentage of ping packets that don't make it across the wire averaged over 10 seconds<br />
&nbsp;&nbsp; Memc&lt;Flt&gt; pings_received_last_10_secs; // pings that have been recieved in last 10 seconds<br />
&nbsp;&nbsp; ULong reliable_received = 0; // data in bytes received<br />
&nbsp;&nbsp; ULong unreliable_received = 0;<br />
&nbsp;&nbsp; ULong reliable_sent = 0; <br />
&nbsp;&nbsp; ULong unreliable_sent = 0;<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; struct PacketAddr<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte data[65536];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UShort length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void from_file(File &amp;f,&nbsp;&nbsp;SockAddr addr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; address = addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length = f.size();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.get(data, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; struct ActiveDestination<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt received_ping_at_time = 0; // the last time we got a ping in local time, not remote tag time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong local_synchro_on_local&nbsp;&nbsp;= 0; // what our last reliable packet sent out was tagged with<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong local_synchro_on_remote = 0; // the last confirmed received reliable packet from the remote connection<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong remote_synchro_on_local = 0; // the last reliable packet recieved from the remote connection was tagged with this<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Memc&lt;PacketAddr&gt; reliable_queue; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt lastReliableTime = 0;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Memc&lt;ActiveDestination&gt; remoteAddresses;<br />
&nbsp;&nbsp; Memc&lt;PacketAddr&gt; received_queue; // this is currently not put into ActiveDestination like reliable_queue, but it certainly could be..<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; // connect(..) doesn't actually send anything to the remote host, its really just setting the remote address and opening the local UDP<br />
&nbsp;&nbsp; // port for listening, after all, UDP is really connection-less, we establish a "connection" through keep-alive pinging in the update loop.<br />
&nbsp;&nbsp; void connect(SockAddr remoteaddr,&nbsp;&nbsp;SockAddr listenaddr) // only the client uses this<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination actdest;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.address = remoteaddr; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.add(actdest); // client will only have 1 destination address.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen(listenaddr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void listen(SockAddr addr) // server will just listen, not use connect<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;create(addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localListenAddress = addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_reliable(SockAddr addr, File &amp;f) // this actually just adds to a queue<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;padd.from_file(f, addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses_has_remote(addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_remoteAddress(addr).reliable_queue.add(padd); // add to end of queue<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_unreliable(SockAddr destination, File &amp;f)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_UNRELIABLE).putUShort(f.size());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.pos(0); // make sure it is at the beginning of the file before copying<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.copy(f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(destination, f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unreliable_sent += f.size(); // we ar enot including the RFC header and UShort size<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Bool update()<br />
&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int bytes_received = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte datarec[65536];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr sender_addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bytes_received = receive(sender_addr, datarec); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(bytes_received &gt; -1) // needs to be loop more than one command recieved at once is possible? seems like it shoudl onyl return 1 packet at a time, but maybe need multiple calls to receive if low framerate?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;f.readMem(datarec, bytes_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //while(!f.end())&nbsp;&nbsp;// should not need this? we will only send 1 command per packet, doing multiple commands per packet&nbsp;&nbsp;makes it harder when we decide to ignore the rest of a packet like in RFS_RELIABLE case below, we would need to make sure to read out the rest of the data in the packet otherwise will will get buggy stuff<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte command = f.getByte();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(command)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_PING: // only server will receive this, client pings server, not vice-versa<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt ptime = f.getFlt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ULong loc_synchro_on_remote = f.getULong(); // learn what was the last reliable client got from the server was, lets us know if we need to resend<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses_has_remote(sender_addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination &amp; adest = get_remoteAddress(sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adest.local_synchro_on_remote = loc_synchro_on_remote;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adest.received_ping_at_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_PING_REPLY).putFlt(ptime).putULong(adest.remote_s&#8203;ynchro_on_local).pos(0); // let the client know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(sender_addr,&nbsp;&nbsp;f2); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination actdest;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.address = sender_addr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actdest.received_ping_at_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.add(actdest);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2.writeMem().putByte(RFC_PING_REPLY).putFlt(ptime).putULong(actdest.remote&#8203;_synchro_on_local).pos(0); // let the client know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(sender_addr,&nbsp;&nbsp;f2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_PING_REPLY: // client will recieve this<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt lastPingTimeReceived = f.getFlt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// for packet loss calculation<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pings_received_last_10_secs.add(lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// calculate ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(ping_times.elms() &gt; 9)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.add(Time.realTime() - lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.remove(0, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt ping_time_total = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(ping_times){ping_time_total +=ping_times[i];}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping = (ping_time_total / ping_times.elms()) * 1000; // make it in milliseconds<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping_times.add(Time.realTime() - lastPingTimeReceived);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check to see if we need to increase our local synchro<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_local_synchro_on_remote(f.getULong(), remoteAddresses[0].local_synchro_on_remote, remoteAddresses[0]); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_UNRELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UShort length_of_packet = f.getUShort(); // datarec may contain more than one packet, so we need to only get one at a time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f2.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.copy(f2, length_of_packet); // hopefully f.copy advances pos() of f.. need ot maek sure otherwise this wont work, it will just keep reading the same packet over and over<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; padd.from_file(f2, sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; received_queue.add(padd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unreliable_received += length_of_packet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_RELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULong synchro = f.getULong();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(remoteAddresses_has_remote(sender_addr))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActiveDestination &amp; adest = get_remoteAddress(sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(synchro ==&nbsp;&nbsp;(adest.remote_synchro_on_local + 1)) // is it the next synchro message? we need to make sure its not a repeat of something we already received<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UShort length_of_packet = f.getUShort(); // datarec may contain more than one packet, so we need to only get one at a time<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f2.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.copy(f2, length_of_packet); // hopefully f.copy advances pos() of f.. need ot maek sure otherwise this wont work, it will just keep reading the same packet over and over<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PacketAddr padd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; padd.from_file(f2, sender_addr);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; received_queue.add(padd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adest.remote_synchro_on_local += 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reliable_received += length_of_packet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // now we need to send a confirmation back immediately so remote doesn't have to wait for next ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f3;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f3.writeMem().putByte(RFC_CONFIRM_RELIABLE).putULong(adest.remote_synchro_on_loc&#8203;al).pos(0); // let the remote know what the last reliable the server got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send(sender_addr,&nbsp;&nbsp;f3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case RFC_CONFIRM_RELIABLE: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REPA(remoteAddresses)if(remoteAddresses[i].address == sender_addr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_local_synchro_on_remote(f.getULong(), remoteAddresses[i].local_synchro_on_remote, remoteAddresses[i]); // check to see if we need to increase our local synchro<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit("RFC Default, something went wrong, no matching command!");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytes_received = receive(sender_addr, datarec); // read the next packet, if it exists<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_ping(); // currently only works for client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_from_reliable_queues();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pingFrequency == 0)remove_dead_remote_addresses(); // only server should do this for now, unless server-&gt;client pings are implemented<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
private: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void remove_dead_remote_addresses()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool removed_one = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(((Time.realTime() - remoteAddresses[i].received_ping_at_time) &gt; connectionTimeout) &amp;&amp; !removed_one)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remoteAddresses.remove(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removed_one =true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_from_reliable_queues()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(remoteAddresses[i].reliable_queue.elms()) // if there is stuff in the queue<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(remoteAddresses[i].local_synchro_on_local == remoteAddresses[i].local_synchro_on_remote) // if the destination address has received&nbsp;&nbsp;all previous reliable messages<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actually_send_reliable(remoteAddresses[i].reliable_queue.first(),remoteAddresses[i].lastReliableTime, ++remoteAddresses[i].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if((Time.realTime() - remoteAddresses[i].lastReliableTime) &gt; (reliableTimeout/1000) ) // destination has not received our last sent reliable, and timeout has occured to send it again<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actually_send_reliable(remoteAddresses[i].reliable_queue.first(),remoteAddresses[i].lastReliableTime, remoteAddresses[i].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void send_ping()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pingFrequency &gt; 0) // is a client so ping<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((Time.realTime() - lastPingTime) &gt; (1/pingFrequency))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.writeMem().putByte(RFC_PING).putFlt(Time.realTime()).putULong(remoteAddre&#8203;sses[0].remote_synchro_on_local).pos(0); //remote_synchro_on_local let the server know what the last reliable the client got from it was<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//send(destinationAddress,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(remoteAddresses[0].address,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastPingTime = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// update pack loss stuff only for client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_packet_loss();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;packet_loss = ((pingFrequency * 10) - pings_received_last_10_secs.elms()) / 100.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(packet_loss &lt; 0) packet_loss = 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Time.realTime() &lt; 10.0)packet_loss = 0; // jus tignor eit the first 10 secs of app opening<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp; void actually_send_reliable(PacketAddr &amp;padd, Flt &amp;last_reliable_sent_time, ULong synchro_to_tag_packet_with)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.writeMem().putByte(RFC_RELIABLE).putULong(synchro_to_tag_packet_with).put&#8203;UShort(padd.length); // tag as reliable, put the synchro, add the length of the packet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.put(padd.data, padd.length); // add packet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(padd.address,&nbsp;&nbsp;f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_reliable_sent_time = Time.realTime();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reliable_sent += padd.length; // we are not including the RFC header and UShort size<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void update_packet_loss()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(pings_received_last_10_secs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bool removed_one = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(Time.realTime() - pings_received_last_10_secs[i] &gt; 10 &amp;&amp;&nbsp;&nbsp;!removed_one)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pings_received_last_10_secs.remove(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;removed_one = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;update_packet_loss();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; void test_local_synchro_on_remote(ULong test_synchro, ULong &amp;loc_synchro_on_remote,&nbsp;&nbsp;ActiveDestination &amp;adest)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(test_synchro == loc_synchro_on_remote + 1) // server has confirmed a new reliable<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loc_synchro_on_remote += 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adest.reliable_queue.remove(0, true); // this will shift memory, is this too slow?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Bool remoteAddresses_has_remote(SockAddr address) // is the remote address in remoteAddresses?<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bool found_remote = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)if(address == remoteAddresses[i].address){ found_remote = true; break;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return found_remote;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; ActiveDestination&amp; get_remoteAddress(SockAddr address) <br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(remoteAddresses)if(address == remoteAddresses[i].address) return remoteAddresses[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Exit("Couldn't find remote addess, make sure to callremoteAddresses_has_remote first");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return remoteAddresses[0];<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br />
The client demo<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; This tutorial presents a sample&nbsp;&nbsp;Reliable UDP Client Connection.<br />
<br />
&nbsp;&nbsp; It can be used together with second tutorial "Demo Server"<br />
<br />
/******************************************************************************/<br />
Str destinationIP = "127.0.0.1";<br />
Str last_message_string = "nothing";<br />
// destinationPort and listenPort must be different if server is run on localhost, <br />
// because only one process can listen to a UDP port at one time,<br />
// otherwise they can be the same port, and probably should be to help with<br />
// NAT transversal (so that end users don't need to forward ports on router).<br />
Int destinationPort = 8791;<br />
//Int listenPort = 8790; <br />
ReliableFastConnection connection;<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag=APP_WORK_IN_BACKGROUND|APP_NO_PAUSE_ON_WINDOW_MOVE_SIZE; // specify work in background flag to work also when not focused<br />
&nbsp;&nbsp; App.x=1;<br />
&nbsp;&nbsp; D.mode(500, 400);<br />
&nbsp;&nbsp; D.scale(1.25);<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; SockAddr remoteAddress;<br />
&nbsp;&nbsp; remoteAddress.setIP(destinationIP, destinationPort);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; if(Contains(destinationIP, "127.0.0.1")) //can't listen and send from 2 apps on same ip:port over UDP<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr address;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;address.setIP(destinationIP, destinationPort);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr localAddress;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAddress.setLocalFast(destinationPort + Random(1, 1000)); // choose random port, hopefully no conflicts<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.connect(remoteAddress, localAddress);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; else<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SockAddr localAddress;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localAddress.setLocalFast(destinationPort); // if we are not running server and client on same PC it is OK to use the same listen port on server and client<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.connect(remoteAddress, localAddress);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; <br />
}<br />
/******************************************************************************/<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; connection.update();<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; if(Kb.b(KB_R)) //flood reliable<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "Reliable Random # :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.send_reliable(connection.remoteAddresses[0].address, f); //connection.remoteAddresses[0].address is kind of awkward, clients will only have 1 remoteAddress<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; if(Kb.b(KB_U)) //flood unreliable<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "UNreliable Random # :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.send_unreliable(connection.remoteAddresses[0].address, f);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear(TURQ); <br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.7, S+"Press 'U' to send unreliable packets, 'R' to send reliable packets.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(connection.received_queue.elms())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.put(connection.received_queue.last().data, connection.received_queue.last().length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last_message_string = f.getStr();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.received_queue.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.6, S+"Last Packet Received Had String: " + last_message_string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.5, S+"packet_loss "+ connection.packet_loss * 100 + "%");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.4, S+"connection rec: "+ connection.received());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.3, S+"connection sent: "+ connection.sent());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.2, S+"connectdes: "+connection.remoteAddresses[0].address.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.1, S+"connectloc: "+connection.localListenAddress.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.0, S+"FPS "+ Time.fps());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.1, S+"remote_synchro_on_local "+ connection.remoteAddresses[0].remote_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.2, S+"local_synchro_on_remote "+ connection.remoteAddresses[0].local_synchro_on_remote);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.3, S+"local_synchro_on_local "+ connection.remoteAddresses[0].local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.4, S+"ping "+ connection.ping);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.5, S+"reliable_sent "+ connection.reliable_sent);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.6, S+"unreliable_sent "+ connection.unreliable_sent);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br />
The server demo<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************<br />
<br />
&nbsp;&nbsp; This tutorial presents a sample&nbsp;&nbsp;Reliable UDP Server Connection.<br />
<br />
&nbsp;&nbsp; It can be used together with second tutorial "Demo Client"<br />
<br />
/******************************************************************************/<br />
Int listenPort = 8791; <br />
ReliableFastConnection connection;<br />
Str last_message_string = "nothing";<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag=APP_WORK_IN_BACKGROUND|APP_NO_PAUSE_ON_WINDOW_MOVE_SIZE; // specify work in background flag to work also when not focused<br />
&nbsp;&nbsp; App.x=1;<br />
&nbsp;&nbsp; D.mode(500, 400);<br />
&nbsp;&nbsp; D.scale(1.25);<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; SockAddr addr;<br />
&nbsp;&nbsp; addr.setLocalFast(listenPort);<br />
&nbsp;&nbsp; connection.listen(addr);<br />
&nbsp;&nbsp; connection.pingFrequency = 0; // server doesn't send pings<br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; <br />
}<br />
/******************************************************************************/<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; connection.update();<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; if(Kb.b(KB_R)) //flood reliable to all connected (have received recent ping) clients<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "From Server Reliable# :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(connection.remoteAddresses)connection.send_reliable(connection.remoteA&#8203;ddresses[i].address, f);<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; if(Kb.b(KB_U)) //flood unreliable to all connected (have received recent ping) clients<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File f; f.writeMem().putStr(S+ "From Server UNreliable# :" + Random(0, 1000)).pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REPA(connection.remoteAddresses)connection.send_unreliable(connection.remot&#8203;eAddresses[i].address, f); <br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; return true;<br />
}<br />
/******************************************************************************/<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear(TURQ);<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.7, S+"Press 'U' to send unreliable packets, 'R' to send reliable packets.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(connection.received_queue.elms())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.writeMem();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.put(connection.received_queue.last().data, connection.received_queue.last().length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.pos(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; last_message_string = f.getStr();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.received_queue.clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.6, S+"Last Packet Received Had String: " + last_message_string);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.5, S+"FPS "+ Time.fps());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.4, S+"connection.received()"+ connection.received());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.3, S+"connection.sent()"+ connection.sent());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.2, S+"connection.unreliable_received "+ connection.unreliable_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.1, S+"connection.reliable_received "+ connection.reliable_received);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, 0.0, S+"number of clients: "+connection.remoteAddresses.elms());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D.text(0, -0.1, S+"connection.localListenAddress: "+connection.localListenAddress.asText());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.2, S+"remote_synchro_on_local "+ connection.remote_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.3, S+"local_synchro_on_remote "+ connection.local_synchro_on_remote);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, -0.4, S+"local_synchro_on_local "+ connection.local_synchro_on_local);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//D.text(0, 0.0, S+"Received Data: "+data);<br />
&nbsp;&nbsp; }<br />
}</code></div></div>
<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".zip" />&nbsp;&nbsp;<a href="attachment.php?aid=2611" target="_blank">ReliableFastConnection7.zip</a> (Size: 6.82 KB / Downloads: 16)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Rebuild MipMaps Tool]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=8051</link>
			<pubDate>Sun, 12 Oct 2014 04:34:29 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=8051</guid>
			<description><![CDATA[Recently I've released an update that improves quality of texture mip maps, this however affects only newly created images/textures.<br />
<br />
Run this utility on an existing project, to rebuild all your existing images/textures mip-maps.<br />
<br />
Usage Instructions:<br />
-compile the tool but don't run yet<br />
-enable "editor network interface" in the editor<br />
-switch to your desired project (open it in the editor) to rebuild mip maps<br />
-now run the previously compiled utility<br />
<br />
Warning:<br />
After rebuilding all texture mip-maps, Android and iOS Optimized textures will need to be rebuilt by the editor!<br />
This may take a long time.<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".7z" />&nbsp;&nbsp;<a href="attachment.php?aid=2574" target="_blank">Rebuild Mip-Maps Esenthel Project.7z</a> (Size: 1.2 KB / Downloads: 15)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[Recently I've released an update that improves quality of texture mip maps, this however affects only newly created images/textures.<br />
<br />
Run this utility on an existing project, to rebuild all your existing images/textures mip-maps.<br />
<br />
Usage Instructions:<br />
-compile the tool but don't run yet<br />
-enable "editor network interface" in the editor<br />
-switch to your desired project (open it in the editor) to rebuild mip maps<br />
-now run the previously compiled utility<br />
<br />
Warning:<br />
After rebuilding all texture mip-maps, Android and iOS Optimized textures will need to be rebuilt by the editor!<br />
This may take a long time.<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".7z" />&nbsp;&nbsp;<a href="attachment.php?aid=2574" target="_blank">Rebuild Mip-Maps Esenthel Project.7z</a> (Size: 1.2 KB / Downloads: 15)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Lambda in EE]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=7612</link>
			<pubDate>Thu, 27 Mar 2014 15:54:38 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=7612</guid>
			<description><![CDATA[Hi!<br />
<br />
Just wanted to share a micro code snippet, hope you like it!<br />
Most people know Lambda-functions in C++11, i think this way of using them is very cool:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>D.screen_changed = <br />
&nbsp;&nbsp;&nbsp;&nbsp;[] (Flt old_width, Flt old_height) -&gt; void<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// paste your screen changes here<br />
&nbsp;&nbsp;&nbsp;&nbsp;};</code></div></div>
<br />
No need to declare separate functions to perform screen changing! You can paste this code in <span style="font-weight: bold;">Init()</span> state <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
<span style="text-decoration: underline;"><span style="font-weight: bold;">EDIT:</span></span><br />
Of course it works with button functions also <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>button-&gt;func([](Ptr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gui.msgBox("Test", "Lambda test in button function"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );</code></div></div>
<br />
<span style="text-decoration: underline;"><span style="font-weight: bold;">EDIT2:</span></span><br />
And, and, and... No need to create <span style="font-weight: bold;">static void</span>'s inside classes! <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>struct MyStruct<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;Window wnd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Button btn;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;//... here we create window and button ...//<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;btn-&gt;func(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[](Ptr strct) -&gt; void<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((MyStruct*)strct)-&gt;wnd.fadeToggle();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, this);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
}</code></div></div>
]]></description>
			<content:encoded><![CDATA[Hi!<br />
<br />
Just wanted to share a micro code snippet, hope you like it!<br />
Most people know Lambda-functions in C++11, i think this way of using them is very cool:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>D.screen_changed = <br />
&nbsp;&nbsp;&nbsp;&nbsp;[] (Flt old_width, Flt old_height) -&gt; void<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// paste your screen changes here<br />
&nbsp;&nbsp;&nbsp;&nbsp;};</code></div></div>
<br />
No need to declare separate functions to perform screen changing! You can paste this code in <span style="font-weight: bold;">Init()</span> state <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
<span style="text-decoration: underline;"><span style="font-weight: bold;">EDIT:</span></span><br />
Of course it works with button functions also <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>button-&gt;func([](Ptr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gui.msgBox("Test", "Lambda test in button function"); <br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );</code></div></div>
<br />
<span style="text-decoration: underline;"><span style="font-weight: bold;">EDIT2:</span></span><br />
And, and, and... No need to create <span style="font-weight: bold;">static void</span>'s inside classes! <img src="images/smilies/smile.gif" style="vertical-align: middle;" border="0" alt="smile" title="smile" /><br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>struct MyStruct<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;Window wnd;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Button btn;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;//... here we create window and button ...//<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;btn-&gt;func(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[](Ptr strct) -&gt; void<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((MyStruct*)strct)-&gt;wnd.fadeToggle();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}, this);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
}</code></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[More precision to pathfinder.]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=7178</link>
			<pubDate>Thu, 17 Oct 2013 00:34:23 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=7178</guid>
			<description><![CDATA[Since I am having issues with pathfinder at ramps (confirmed in pathfinder tutorial, EE 1.0 and 2.0), I did an algorithm to give more precision:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>Game::Chr::actionMoveTo(pos);<br />
Int precision = 2;<br />
<br />
for(Int x = 0; x&lt; precision; x++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(path.elms()&gt;1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int tocheck = path.elms()-1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int index = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREP(tocheck)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec midpoint = (path[index] + path[index+1]) / 2.f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec surface_pos;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Game::World.path().nearestSurface(midpoint, Vec(0.9f,0.9f,0.9f), surface_pos))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path.NewAt(index+1) = surface_pos;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index+=2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</code></div></div>
]]></description>
			<content:encoded><![CDATA[Since I am having issues with pathfinder at ramps (confirmed in pathfinder tutorial, EE 1.0 and 2.0), I did an algorithm to give more precision:<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>Game::Chr::actionMoveTo(pos);<br />
Int precision = 2;<br />
<br />
for(Int x = 0; x&lt; precision; x++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(path.elms()&gt;1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int tocheck = path.elms()-1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int index = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FREP(tocheck)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec midpoint = (path[index] + path[index+1]) / 2.f;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Vec surface_pos;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Game::World.path().nearestSurface(midpoint, Vec(0.9f,0.9f,0.9f), surface_pos))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path.NewAt(index+1) = surface_pos;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index+=2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</code></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Save/Load Engine Settings]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=7167</link>
			<pubDate>Mon, 14 Oct 2013 05:02:01 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=7167</guid>
			<description><![CDATA[Small tutorial showing how to load a few basic engine settings:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
void SaveSettings(TextData &amp;data)<br />
{<br />
&nbsp;&nbsp; data.getNode("Width"&nbsp;&nbsp;&nbsp;&nbsp; ).value=S+D.x();<br />
&nbsp;&nbsp; data.getNode("Height"&nbsp;&nbsp;&nbsp;&nbsp;).value=S+D.y();<br />
&nbsp;&nbsp; data.getNode("Fullscreen").value=S+D.full();<br />
}<br />
void LoadSettings(TextData &amp;data)<br />
{<br />
&nbsp;&nbsp; int x=-1, y=-1, full=-1;<br />
&nbsp;&nbsp; if(TextNode *node&nbsp;&nbsp;=data.findNode("Fullscreen"))full=node&nbsp;&nbsp;.asInt();<br />
&nbsp;&nbsp; if(TextNode *width =data.findNode("Width"&nbsp;&nbsp;&nbsp;&nbsp; ))x&nbsp;&nbsp; =width .asInt();<br />
&nbsp;&nbsp; if(TextNode *height=data.findNode("Height"&nbsp;&nbsp;&nbsp;&nbsp;))y&nbsp;&nbsp; =height.asInt();<br />
&nbsp;&nbsp; D.mode(x, y, full);<br />
}<br />
void SaveSettings(C Str &amp;name="Settings.txt")<br />
{<br />
&nbsp;&nbsp; TextData settings; SaveSettings(settings); settings.save(name);<br />
}<br />
void LoadSettings(C Str &amp;name="Settings.txt")<br />
{<br />
&nbsp;&nbsp; TextData settings; if(settings.load(name))LoadSettings(settings);<br />
}<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag|=APP_MAXIMIZABLE|APP_MINIMIZABLE|APP_RESIZABLE|APP_FULL_TOGGLE;<br />
&nbsp;&nbsp; LoadSettings();<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; return true;<br />
}<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; SaveSettings();<br />
}<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; return true;<br />
}<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear();<br />
}<br />
/******************************************************************************/</code></div></div>
]]></description>
			<content:encoded><![CDATA[Small tutorial showing how to load a few basic engine settings:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>/******************************************************************************/<br />
void SaveSettings(TextData &amp;data)<br />
{<br />
&nbsp;&nbsp; data.getNode("Width"&nbsp;&nbsp;&nbsp;&nbsp; ).value=S+D.x();<br />
&nbsp;&nbsp; data.getNode("Height"&nbsp;&nbsp;&nbsp;&nbsp;).value=S+D.y();<br />
&nbsp;&nbsp; data.getNode("Fullscreen").value=S+D.full();<br />
}<br />
void LoadSettings(TextData &amp;data)<br />
{<br />
&nbsp;&nbsp; int x=-1, y=-1, full=-1;<br />
&nbsp;&nbsp; if(TextNode *node&nbsp;&nbsp;=data.findNode("Fullscreen"))full=node&nbsp;&nbsp;.asInt();<br />
&nbsp;&nbsp; if(TextNode *width =data.findNode("Width"&nbsp;&nbsp;&nbsp;&nbsp; ))x&nbsp;&nbsp; =width .asInt();<br />
&nbsp;&nbsp; if(TextNode *height=data.findNode("Height"&nbsp;&nbsp;&nbsp;&nbsp;))y&nbsp;&nbsp; =height.asInt();<br />
&nbsp;&nbsp; D.mode(x, y, full);<br />
}<br />
void SaveSettings(C Str &amp;name="Settings.txt")<br />
{<br />
&nbsp;&nbsp; TextData settings; SaveSettings(settings); settings.save(name);<br />
}<br />
void LoadSettings(C Str &amp;name="Settings.txt")<br />
{<br />
&nbsp;&nbsp; TextData settings; if(settings.load(name))LoadSettings(settings);<br />
}<br />
/******************************************************************************/<br />
void InitPre()<br />
{<br />
&nbsp;&nbsp; EE_INIT();<br />
&nbsp;&nbsp; App.flag|=APP_MAXIMIZABLE|APP_MINIMIZABLE|APP_RESIZABLE|APP_FULL_TOGGLE;<br />
&nbsp;&nbsp; LoadSettings();<br />
}<br />
bool Init()<br />
{<br />
&nbsp;&nbsp; return true;<br />
}<br />
void Shut()<br />
{<br />
&nbsp;&nbsp; SaveSettings();<br />
}<br />
bool Update()<br />
{<br />
&nbsp;&nbsp; if(Kb.bp(KB_ESC))return false;<br />
&nbsp;&nbsp; return true;<br />
}<br />
void Draw()<br />
{<br />
&nbsp;&nbsp; D.clear();<br />
}<br />
/******************************************************************************/</code></div></div>
]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Simple Rigid Follow Cam]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=6490</link>
			<pubDate>Mon, 27 May 2013 19:58:57 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=6490</guid>
			<description><![CDATA[I tried a bunch of different ways to set the camera, but it always ended up wonky in some way, whether jumping around at the top and bottom of the rotation arc, or by not allowing going upside-down. <br />
<br />
This code will follow an object around at a certain offset. If your character goes up side down, so will the camera(hence, I call it 'rigid'). This might be fun to attach as a 3rd person car camera, or for a jet plane or a spaceship.<br />
<br />
The easiest way to make this work is to call something similar to this pseudo code: <br />
SetCustomCam(mychar.matrix(), mychar.....getPoint("camera_slot").pos, mychar.....getPoint("camera_slot").dir, false);<br />
<br />
Now you can do a barrel roll! <br />
<br />
Alternatively, <br />
SetCustomCam(mychar.matrix(), Vec(0, 5, 0), interestingObjectPos);<br />
<br />
A periscope feel!<br />
<br />
If you want to move the camera around, you can modify offset. <br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>void SetCustomCam( C Matrix &amp;mat,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Matrix that belongs to the object for the cam to follow<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C Vec &amp;offset,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The offset in local coords<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C Vec &amp;facing,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The direction to face<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;facingIsLocation = true ) // Whether the direction is a point in the world to face or a normalized direction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
{<br />
&nbsp;&nbsp; Vec pos = offset;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The offset to move the camera by<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; pos.mul( mat.orn( ) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Transform the local vector by the rotation<br />
&nbsp;&nbsp; pos += mat.pos;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Apply to world coords<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; Vec up( 0, 1, 0 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Create the up vector<br />
&nbsp;&nbsp; up .mul(mat.orn( ) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Rotate the up vector so the camera up is relative to the object up<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; Vec dir = facingIsLocation ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!( facing - pos ) :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Set the direction towards a point<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dir = facing&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Set the direction the same as passed in<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; Cam.setPosDir( pos, dir, up );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Apply the transforms to the camera<br />
&nbsp;&nbsp; Cam.updateVelocities(&nbsp;&nbsp;).set(&nbsp;&nbsp;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Update Velocities for effects and set the camera active<br />
}</code></div></div>
<br />
Hopefully, this will save someone a lot of the time it took me to experiment.]]></description>
			<content:encoded><![CDATA[I tried a bunch of different ways to set the camera, but it always ended up wonky in some way, whether jumping around at the top and bottom of the rotation arc, or by not allowing going upside-down. <br />
<br />
This code will follow an object around at a certain offset. If your character goes up side down, so will the camera(hence, I call it 'rigid'). This might be fun to attach as a 3rd person car camera, or for a jet plane or a spaceship.<br />
<br />
The easiest way to make this work is to call something similar to this pseudo code: <br />
SetCustomCam(mychar.matrix(), mychar.....getPoint("camera_slot").pos, mychar.....getPoint("camera_slot").dir, false);<br />
<br />
Now you can do a barrel roll! <br />
<br />
Alternatively, <br />
SetCustomCam(mychar.matrix(), Vec(0, 5, 0), interestingObjectPos);<br />
<br />
A periscope feel!<br />
<br />
If you want to move the camera around, you can modify offset. <br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>void SetCustomCam( C Matrix &amp;mat,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Matrix that belongs to the object for the cam to follow<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C Vec &amp;offset,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The offset in local coords<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C Vec &amp;facing,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The direction to face<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;facingIsLocation = true ) // Whether the direction is a point in the world to face or a normalized direction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
{<br />
&nbsp;&nbsp; Vec pos = offset;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The offset to move the camera by<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; pos.mul( mat.orn( ) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Transform the local vector by the rotation<br />
&nbsp;&nbsp; pos += mat.pos;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Apply to world coords<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; Vec up( 0, 1, 0 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Create the up vector<br />
&nbsp;&nbsp; up .mul(mat.orn( ) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Rotate the up vector so the camera up is relative to the object up<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; Vec dir = facingIsLocation ?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;!( facing - pos ) :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Set the direction towards a point<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dir = facing&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Set the direction the same as passed in<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; Cam.setPosDir( pos, dir, up );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Apply the transforms to the camera<br />
&nbsp;&nbsp; Cam.updateVelocities(&nbsp;&nbsp;).set(&nbsp;&nbsp;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Update Velocities for effects and set the camera active<br />
}</code></div></div>
<br />
Hopefully, this will save someone a lot of the time it took me to experiment.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Auto Fov]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=6425</link>
			<pubDate>Thu, 16 May 2013 17:29:30 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=6425</guid>
			<description><![CDATA[Let say that you like 65º of FOVY for 1,33 aspect ratio (for example 1024x768).<br />
<br />
When you change aspect ratio, you will see a different viewport because fov must be changed too.<br />
<br />
I want to share this function for those ppl working with different resolutions or for mobiles.<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// deg param is relative to 1.3333 aspect ratio.<br />
Flt AutoFov(Flt deg, FOV_MODE fov)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(fov == FOV_X)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt vertical = 2 * Atan( Tan(DegToRad(deg)/2.f) * (1.f / 1.3333f) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt finalHorizontal = 2 * Atan( Tan(vertical/2.f) * D.w() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return finalHorizontal;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt horizontal = 2 * Atan( Tan(DegToRad(deg)/2.f) * 1.3333f );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt finalVertical = 2 * Atan( Tan(horizontal/2.f) * (1.f / D.w()) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return finalVertical;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div>
<br />
How it works:<br />
<br />
1) Set aspect ratio of 1.333 =&gt; D.mode(1024,768);<br />
2) Choice a fov value playing with D.viewFov(); For this example D.viewFov(65,FOV_Y);<br />
3) Change the resolution =&gt; D.mode(1280,720);<br />
4) Change D.viewFov(65,FOV_Y) by D.viewFov(AutoFov(65,FOV_Y),FOV_Y);<br />
<br />
You will get the same viewport for any resolution. It also works with FOV_X.<br />
<br />
<img src="images/smilies/wink.gif" style="vertical-align: middle;" border="0" alt="wink" title="wink" />]]></description>
			<content:encoded><![CDATA[Let say that you like 65º of FOVY for 1,33 aspect ratio (for example 1024x768).<br />
<br />
When you change aspect ratio, you will see a different viewport because fov must be changed too.<br />
<br />
I want to share this function for those ppl working with different resolutions or for mobiles.<br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>// deg param is relative to 1.3333 aspect ratio.<br />
Flt AutoFov(Flt deg, FOV_MODE fov)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(fov == FOV_X)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt vertical = 2 * Atan( Tan(DegToRad(deg)/2.f) * (1.f / 1.3333f) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt finalHorizontal = 2 * Atan( Tan(vertical/2.f) * D.w() );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return finalHorizontal;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt horizontal = 2 * Atan( Tan(DegToRad(deg)/2.f) * 1.3333f );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flt finalVertical = 2 * Atan( Tan(horizontal/2.f) * (1.f / D.w()) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return finalVertical;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div>
<br />
How it works:<br />
<br />
1) Set aspect ratio of 1.333 =&gt; D.mode(1024,768);<br />
2) Choice a fov value playing with D.viewFov(); For this example D.viewFov(65,FOV_Y);<br />
3) Change the resolution =&gt; D.mode(1280,720);<br />
4) Change D.viewFov(65,FOV_Y) by D.viewFov(AutoFov(65,FOV_Y),FOV_Y);<br />
<br />
You will get the same viewport for any resolution. It also works with FOV_X.<br />
<br />
<img src="images/smilies/wink.gif" style="vertical-align: middle;" border="0" alt="wink" title="wink" />]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[EE 2.0 Example Project - Tower Defense!]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=6235</link>
			<pubDate>Fri, 05 Apr 2013 14:29:02 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=6235</guid>
			<description><![CDATA[Hey there EE community!<br />
<br />
For learning purposes, I was working on a tower defense project using Esenthel. Along the way, I decided to make it open-source so that everyone can benefit from it (or curse at me for how I programmed it..).<br />
<br />
Features:<br />
<br />
- Lots of comments that should make clear what I did<br />
- Custom RTS camera controls (zoom in/out, move with WASD, rotate)<br />
- Load world from editor<br />
- Load waypoints from editor<br />
- Enemies spawn in waves and run along waypoints<br />
- GUI to place turrets and upgrade them.<br />
- Placeable turrets (1 type so far), turrets shoot at, and kill, enemies<br />
- Turrets rotate when idle, turn to enemies, fire with particles<br />
- Turrets construct gradually, using mesh masking.<br />
- Turrets can't be placed on the road<br />
- ...<br />
<br />
Not included (yet):<br />
- Sounds<br />
- Winning/losing <img src="images/smilies/grin.gif" style="vertical-align: middle;" border="0" alt="grin" title="grin" /><br />
- Resources<br />
- Turrets can be placed on top of each other<br />
<br />
<br />
I'm not a superb programmer by any means. This project taught me a lot, so I would do things a bit differently if I would start over-new. Different turret types has to be more flexible, same with enemies. <br />
<br />
<a href="http://www.mediafire.com/download/nux7qwv9eu1x446/TowerDefense.7z" target="_blank">Published Project (.exe (32/64bit) + packed data)</a><br />
<br />
<a href="http://www.mediafire.com/download/4hao44f5k595j70/TowerDefense_Sources_v2.7z" target="_blank">Source Project</a><br />
<br />
Make sure to read the ReadMe in the sources for the licenses.<br />
<br />
If you have any suggestions, feel free to post them here. In the meantime, I hope this can show people a bit more of how Esenthel works.]]></description>
			<content:encoded><![CDATA[Hey there EE community!<br />
<br />
For learning purposes, I was working on a tower defense project using Esenthel. Along the way, I decided to make it open-source so that everyone can benefit from it (or curse at me for how I programmed it..).<br />
<br />
Features:<br />
<br />
- Lots of comments that should make clear what I did<br />
- Custom RTS camera controls (zoom in/out, move with WASD, rotate)<br />
- Load world from editor<br />
- Load waypoints from editor<br />
- Enemies spawn in waves and run along waypoints<br />
- GUI to place turrets and upgrade them.<br />
- Placeable turrets (1 type so far), turrets shoot at, and kill, enemies<br />
- Turrets rotate when idle, turn to enemies, fire with particles<br />
- Turrets construct gradually, using mesh masking.<br />
- Turrets can't be placed on the road<br />
- ...<br />
<br />
Not included (yet):<br />
- Sounds<br />
- Winning/losing <img src="images/smilies/grin.gif" style="vertical-align: middle;" border="0" alt="grin" title="grin" /><br />
- Resources<br />
- Turrets can be placed on top of each other<br />
<br />
<br />
I'm not a superb programmer by any means. This project taught me a lot, so I would do things a bit differently if I would start over-new. Different turret types has to be more flexible, same with enemies. <br />
<br />
<a href="http://www.mediafire.com/download/nux7qwv9eu1x446/TowerDefense.7z" target="_blank">Published Project (.exe (32/64bit) + packed data)</a><br />
<br />
<a href="http://www.mediafire.com/download/4hao44f5k595j70/TowerDefense_Sources_v2.7z" target="_blank">Source Project</a><br />
<br />
Make sure to read the ReadMe in the sources for the licenses.<br />
<br />
If you have any suggestions, feel free to post them here. In the meantime, I hope this can show people a bit more of how Esenthel works.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Lightmaps for RM_SIMPLE]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=5886</link>
			<pubDate>Tue, 29 Jan 2013 21:21:07 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=5886</guid>
			<description><![CDATA[Thanks esenthel for the last sdk update. This is a custom shader for lightmaps + alpha test on RM_SIMPLE renderer mode. <br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>#include "Main.h"<br />
<br />
/******************************************************************************/<br />
// VERTEX SHADER<br />
/******************************************************************************/<br />
void VS<br />
(<br />
&nbsp;&nbsp; // vertex input<br />
&nbsp;&nbsp; VtxInput vtx,<br />
<br />
&nbsp;&nbsp; // output<br />
&nbsp;&nbsp; out Vec4 oPos:POSITION,<br />
&nbsp;&nbsp; out Vec2 oDiffuseTex:TEXCOORD0,<br />
&nbsp;&nbsp; out Vec2 oLightTex:TEXCOORD1<br />
<br />
)<br />
{<br />
&nbsp;&nbsp; oDiffuseTex=vtx.tex();<br />
&nbsp;&nbsp; oLightTex=vtx.tex1();<br />
&nbsp;&nbsp; oPos=Project(TransformPos(vtx.pos4()));<br />
}<br />
/******************************************************************************/<br />
// PIXEL SHADER<br />
/******************************************************************************/<br />
Vec4 PS<br />
(<br />
&nbsp;&nbsp; Vec2 DiffuseTex:TEXCOORD0,<br />
&nbsp;&nbsp; Vec2 LightTex:TEXCOORD1<br />
):COLOR<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Alpha test<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(Tex(Col, DiffuseTex).a&lt;1.f-MaterialColor().a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;discard;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Diffuse texture color * Material Color * Lightmap color<br />
&nbsp;&nbsp;&nbsp;&nbsp;return Vec4(Tex(Col, DiffuseTex).rgb * MaterialColor().rgb * Tex(Lum, LightTex).rgb,1.f);<br />
}<br />
/******************************************************************************/<br />
// TECHNIQUE<br />
/******************************************************************************/<br />
TECHNIQUE(Main, VS(), PS()); <br />
/******************************************************************************/</code></div></div>
<br />
And the screenshots:<br />
iOS<br />
<img src="http://i50.tinypic.com/2w5ujwz.png" border="0" alt="[Image: 2w5ujwz.png]" /><br />
<br />
Android<br />
<img src="http://i45.tinypic.com/2yv6txl.png" border="0" alt="[Image: 2yv6txl.png]" /><br />
<br />
Both running at 60 fps.]]></description>
			<content:encoded><![CDATA[Thanks esenthel for the last sdk update. This is a custom shader for lightmaps + alpha test on RM_SIMPLE renderer mode. <br />
<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>#include "Main.h"<br />
<br />
/******************************************************************************/<br />
// VERTEX SHADER<br />
/******************************************************************************/<br />
void VS<br />
(<br />
&nbsp;&nbsp; // vertex input<br />
&nbsp;&nbsp; VtxInput vtx,<br />
<br />
&nbsp;&nbsp; // output<br />
&nbsp;&nbsp; out Vec4 oPos:POSITION,<br />
&nbsp;&nbsp; out Vec2 oDiffuseTex:TEXCOORD0,<br />
&nbsp;&nbsp; out Vec2 oLightTex:TEXCOORD1<br />
<br />
)<br />
{<br />
&nbsp;&nbsp; oDiffuseTex=vtx.tex();<br />
&nbsp;&nbsp; oLightTex=vtx.tex1();<br />
&nbsp;&nbsp; oPos=Project(TransformPos(vtx.pos4()));<br />
}<br />
/******************************************************************************/<br />
// PIXEL SHADER<br />
/******************************************************************************/<br />
Vec4 PS<br />
(<br />
&nbsp;&nbsp; Vec2 DiffuseTex:TEXCOORD0,<br />
&nbsp;&nbsp; Vec2 LightTex:TEXCOORD1<br />
):COLOR<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Alpha test<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(Tex(Col, DiffuseTex).a&lt;1.f-MaterialColor().a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;discard;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Diffuse texture color * Material Color * Lightmap color<br />
&nbsp;&nbsp;&nbsp;&nbsp;return Vec4(Tex(Col, DiffuseTex).rgb * MaterialColor().rgb * Tex(Lum, LightTex).rgb,1.f);<br />
}<br />
/******************************************************************************/<br />
// TECHNIQUE<br />
/******************************************************************************/<br />
TECHNIQUE(Main, VS(), PS()); <br />
/******************************************************************************/</code></div></div>
<br />
And the screenshots:<br />
iOS<br />
<img src="http://i50.tinypic.com/2w5ujwz.png" border="0" alt="[Image: 2w5ujwz.png]" /><br />
<br />
Android<br />
<img src="http://i45.tinypic.com/2yv6txl.png" border="0" alt="[Image: 2yv6txl.png]" /><br />
<br />
Both running at 60 fps.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Server sided AI]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=5826</link>
			<pubDate>Mon, 07 Jan 2013 16:56:21 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=5826</guid>
			<description><![CDATA[Hello, I have made up my mind, and I have decided that I will now start my programming series for this Community. I came to this conclusion because I think there are too few Examples / Tutorials. Today I begun working on the basic structure of the Server and Client. <br />
<br />
When I have enough time to spend on this, I will not be making separate files or posts. This will eventually be one bigger sized project. But hold your thoughts, I am not aiming on creating a fully functional huge project for you, I am here to provide a basic structure of which i would like to call Project X Online. This will not be in the size of an MMO, but will give a beginning for people to work from.<br />
<br />
This project will be using EE's Networking for folks who would like to use EE MMO to integrate, or Ineisis. <br />
As of right now, i will provide you with the beginning of this, which contains: <br />
<br />
Client,<ul>
<li>Basic AI (Movement, visual, name)</li>
<li>Player class for the future</li>
<li>Connection to server</li>
<li>Menu state for the future<br />
</li></ul>
<br />
Server,<ul>
<li>AI Movement</li>
<li>AI Spawn</li>
<li>AI Radius for movement</li>
<li>Client connections</li>
<li>Image Map used for checking (Not provided fully yet)<br />
</li></ul>
<br />
NOTE: I will not comment basic C++, I hope that you have understanding in C++ and also a little of Esenthel, so that this will give you more of an Idea.<br />
<br />
I would also like to thank <span style="font-weight: bold;">Esenthel </span>for providing us with this Engine, and credit also goes to <span style="font-weight: bold;">Yvan</span> for giving me an Idea from his previous post for the AI. ( <a href="http://www.esenthel.com/community/showthread.php?tid=4573" target="_blank">http://www.esenthel.com/community/showth...p?tid=4573</a> )<br />
<br />
Best regards TBJOKERS.<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".rar" />&nbsp;&nbsp;<a href="attachment.php?aid=1910" target="_blank">ProjectX.rar</a> (Size: 142.93 KB / Downloads: 199)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[Hello, I have made up my mind, and I have decided that I will now start my programming series for this Community. I came to this conclusion because I think there are too few Examples / Tutorials. Today I begun working on the basic structure of the Server and Client. <br />
<br />
When I have enough time to spend on this, I will not be making separate files or posts. This will eventually be one bigger sized project. But hold your thoughts, I am not aiming on creating a fully functional huge project for you, I am here to provide a basic structure of which i would like to call Project X Online. This will not be in the size of an MMO, but will give a beginning for people to work from.<br />
<br />
This project will be using EE's Networking for folks who would like to use EE MMO to integrate, or Ineisis. <br />
As of right now, i will provide you with the beginning of this, which contains: <br />
<br />
Client,<ul>
<li>Basic AI (Movement, visual, name)</li>
<li>Player class for the future</li>
<li>Connection to server</li>
<li>Menu state for the future<br />
</li></ul>
<br />
Server,<ul>
<li>AI Movement</li>
<li>AI Spawn</li>
<li>AI Radius for movement</li>
<li>Client connections</li>
<li>Image Map used for checking (Not provided fully yet)<br />
</li></ul>
<br />
NOTE: I will not comment basic C++, I hope that you have understanding in C++ and also a little of Esenthel, so that this will give you more of an Idea.<br />
<br />
I would also like to thank <span style="font-weight: bold;">Esenthel </span>for providing us with this Engine, and credit also goes to <span style="font-weight: bold;">Yvan</span> for giving me an Idea from his previous post for the AI. ( <a href="http://www.esenthel.com/community/showthread.php?tid=4573" target="_blank">http://www.esenthel.com/community/showth...p?tid=4573</a> )<br />
<br />
Best regards TBJOKERS.<br /><!-- start: postbit_attachments_attachment -->
<br /><img src="images/attachtypes/zip.gif" border="0" alt=".rar" />&nbsp;&nbsp;<a href="attachment.php?aid=1910" target="_blank">ProjectX.rar</a> (Size: 142.93 KB / Downloads: 199)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[EE containers & C++11 ranged for loops]]></title>
			<link>https://esenthel.com/forum/showthread.php?tid=5504</link>
			<pubDate>Thu, 18 Oct 2012 08:40:54 +0000</pubDate>
			<guid isPermaLink="false">https://esenthel.com/forum/showthread.php?tid=5504</guid>
			<description><![CDATA[If anyone miss C++11 functionality with EE containers, here is a little helper class that can be used:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>template &lt;typename T, template &lt;typename&gt; class Container&gt;<br />
struct ArrayIter<br />
{<br />
public:<br />
&nbsp;&nbsp;ArrayIter(Ptr array, Int idx) :<br />
&nbsp;&nbsp;&nbsp;&nbsp; _array(array),<br />
&nbsp;&nbsp;&nbsp;&nbsp; _idx(idx)<br />
&nbsp;&nbsp;{}<br />
<br />
&nbsp;&nbsp;bool operator!=(const ArrayIter &amp; right) const { return _idx != right._idx; }<br />
&nbsp;&nbsp;const ArrayIter&lt;T, Container&gt; &amp; operator++() { ++_idx; return *this; }<br />
<br />
&nbsp;&nbsp;T &amp; operator*() const;<br />
<br />
protected:<br />
&nbsp;&nbsp;Ptr _array;<br />
&nbsp;&nbsp;Int&nbsp;&nbsp;_idx;<br />
};<br />
<br />
<br />
template &lt;typename T, template &lt;typename&gt; class Ancestor&gt;<br />
struct Array : public Ancestor&lt;T&gt;<br />
{<br />
&nbsp;&nbsp;typedef ArrayIter&lt;T, Ancestor&gt; Iterator;<br />
<br />
&nbsp;&nbsp;const Iterator begin() const { return Iterator(this, 0); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator begin()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return Iterator(this, 0); }<br />
&nbsp;&nbsp;const Iterator end()&nbsp;&nbsp; const { return Iterator(this, elms()); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator end()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return Iterator(this, elms()); }<br />
};<br />
<br />
<br />
template &lt;typename T, template &lt;typename&gt; class Container&gt;<br />
T &amp; ArrayIter&lt;T, Container&gt;::operator*() const<br />
{<br />
&nbsp;&nbsp;return static_cast&lt;Container&lt;T&gt; *&gt;(_array)-&gt;operator[](_idx);<br />
}</code></div></div>
<br />
so you can use it like this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>typedef Array&lt;Player, EE::Game::ObjMemx&gt; ObjPlayers;<br />
ObjPlayers players;<br />
for (auto &amp; player : players) player.drawPrepare();</code></div></div>
<br />
C++11 is supported (not yet fully though) with VS2012. We are using it for a couple of months already for developing EE and I strongly encourage you to do so if you would like it too..]]></description>
			<content:encoded><![CDATA[If anyone miss C++11 functionality with EE containers, here is a little helper class that can be used:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>template &lt;typename T, template &lt;typename&gt; class Container&gt;<br />
struct ArrayIter<br />
{<br />
public:<br />
&nbsp;&nbsp;ArrayIter(Ptr array, Int idx) :<br />
&nbsp;&nbsp;&nbsp;&nbsp; _array(array),<br />
&nbsp;&nbsp;&nbsp;&nbsp; _idx(idx)<br />
&nbsp;&nbsp;{}<br />
<br />
&nbsp;&nbsp;bool operator!=(const ArrayIter &amp; right) const { return _idx != right._idx; }<br />
&nbsp;&nbsp;const ArrayIter&lt;T, Container&gt; &amp; operator++() { ++_idx; return *this; }<br />
<br />
&nbsp;&nbsp;T &amp; operator*() const;<br />
<br />
protected:<br />
&nbsp;&nbsp;Ptr _array;<br />
&nbsp;&nbsp;Int&nbsp;&nbsp;_idx;<br />
};<br />
<br />
<br />
template &lt;typename T, template &lt;typename&gt; class Ancestor&gt;<br />
struct Array : public Ancestor&lt;T&gt;<br />
{<br />
&nbsp;&nbsp;typedef ArrayIter&lt;T, Ancestor&gt; Iterator;<br />
<br />
&nbsp;&nbsp;const Iterator begin() const { return Iterator(this, 0); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator begin()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return Iterator(this, 0); }<br />
&nbsp;&nbsp;const Iterator end()&nbsp;&nbsp; const { return Iterator(this, elms()); }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator end()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return Iterator(this, elms()); }<br />
};<br />
<br />
<br />
template &lt;typename T, template &lt;typename&gt; class Container&gt;<br />
T &amp; ArrayIter&lt;T, Container&gt;::operator*() const<br />
{<br />
&nbsp;&nbsp;return static_cast&lt;Container&lt;T&gt; *&gt;(_array)-&gt;operator[](_idx);<br />
}</code></div></div>
<br />
so you can use it like this:<br />
<div class="codeblock">
<div class="title">Code:<br />
</div><div class="body" dir="ltr"><code>typedef Array&lt;Player, EE::Game::ObjMemx&gt; ObjPlayers;<br />
ObjPlayers players;<br />
for (auto &amp; player : players) player.drawPrepare();</code></div></div>
<br />
C++11 is supported (not yet fully though) with VS2012. We are using it for a couple of months already for developing EE and I strongly encourage you to do so if you would like it too..]]></content:encoded>
		</item>
	</channel>
</rss>