<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Andrew</title>
	<atom:link href="https://floodyberry.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://floodyberry.wordpress.com</link>
	<description>Just another WordPress.com weblog</description>
	<lastBuildDate>Thu, 27 Jun 2013 21:01:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='floodyberry.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://s0.wp.com/i/buttonw-com.png</url>
		<title>Andrew</title>
		<link>https://floodyberry.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://floodyberry.wordpress.com/osd.xml" title="Andrew" />
	<atom:link rel='hub' href='https://floodyberry.wordpress.com/?pushpress=hub'/>
	<item>
		<title>High Performance C++ Profiling</title>
		<link>https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/</link>
					<comments>https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Wed, 07 Oct 2009 15:40:44 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=50</guid>

					<description><![CDATA[[This is about my C++ Profiler which may be found on Google Code under High Performance C++ Profiler] My interest in code profiling started when I was making hudbot. What with code injection and patching, function hooking, data hijacking, and OpenGL, I knew I had relatively no experience in what I was attempting and that [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>[This is about my C++ Profiler which may be found on Google Code under <a href="http://code.google.com/p/high-performance-cplusplus-profiler/">High Performance C++ Profiler</a>]</p>
<p>My interest in code profiling started when I was making <a href="http://www.team5150.com/~andrew/project.hudbot/">hudbot</a>. What with code injection and patching, function hooking, data hijacking, and OpenGL, I knew I had relatively no experience in what I was attempting and that I could easily be producing some amazing slowdowns if I wasn&#8217;t careful.</p>
<p>Unfortunately, C++ profilers seem to come in three varieties, all of which have a fatal downside:</p>
<ol>
<li><a href="http://en.wikipedia.org/wiki/Profiling_%28computer_programming%29#Statistical_profilers">Sampling Profilers</a> which are <strong>fast</strong>, <strong>multi-threaded</strong>, but <strong>inaccurate</strong> and have <strong>decent output</strong> (sometimes too detailed).  Some examples are <a href="http://software.intel.com/en-us/intel-vtune/">VTune</a>, <a href="http://developer.amd.com/CPU/CODEANALYST/Pages/default.aspx">CodeAnalyst</a>, <a href="http://code.google.com/p/google-perftools/">google-perftools</a> and <a href="http://www.codersnotes.com/sleepy/">Sleepy</a>.</li>
<li><a href="http://en.wikipedia.org/wiki/Profiling_%28computer_programming%29#Instrumenting_profilers">Instrumenting Profilers</a> which are <strong>accurate</strong>, <strong>multi-threaded</strong>, but <strong>slow</strong>, and have <strong>decent output</strong>.  Some examples are <a href="http://www.glowcode.com/">GlowCode</a> and the now defunct DevPartner Profiler Community Edition.</li>
<li>Instrumenting Profilers which are <strong>fast</strong>, <strong>accurate</strong>, but <strong>single threaded</strong> and have <strong>limited output</strong>.  These range from extremely simple profilers like Peter Kankowski&#8217;s <a href="http://smallcode.weblogs.us/oldblog/2006/09/17/poor-man-profiler/">Poor Man&#8217;s Profiler</a> to the more complicated and full-featured <a href="http://sourceforge.net/projects/shinyprofiler/">Shiny C++ Profiler</a>.</li>
</ol>
<p>The obvious outcome is that if you want <strong>fast</strong> and <strong>accurate</strong>, like I did, you&#8217;ll have to use an existing profiler or write it yourself and instrument your code manually. With a little work, fancy stuff like call trees can be added. Once you get it tested and working, you can start going crazy profi<em>Segmentation fault</em>.</p>
<p>Oh yeah, about that. There are no multi-threaded instrumented profilers that are open source, and depending on how your single threaded profiler works, the results when trying to use it in a multi-threaded environment can range from bad data to outright crashing. It&#8217;s possible to patch the profiler to only allow the main thread in, but this adds unnecessary slowdowns and doesn&#8217;t address how to profile other threads. This is where my profiler comes in!<br />
<span id="more-50"></span></p>
<h4>Pieces of a high performance multi-threaded C++ profiler</h4>
<h5>Timing</h5>
<div data-shortcode="caption" id="attachment_77" style="width: 346px" class="wp-caption alignright"><img aria-describedby="caption-attachment-77" data-attachment-id="77" data-permalink="https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/timingmethods/" data-orig-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png" data-orig-size="336,245" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="Timing Methods" data-image-description="" data-image-caption="" data-medium-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png?w=300" data-large-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png?w=336" class="size-full wp-image-77       " title="Timing Methods" src="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png?w=336&#038;h=245" alt="Timing Methods" width="336" height="245" srcset="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png 336w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png?w=150&amp;h=109 150w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png?w=300&amp;h=219 300w" sizes="(max-width: 336px) 100vw, 336px" /><p id="caption-attachment-77" class="wp-caption-text">Latency in cycles and resolution of various timing methods (resolution is hand wavy, not to scale)</p></div>
<p>The main piece of a high performance profiler is what mechanism is used to get the timestamps. High precision is the obvious main requirement, but it must also have as low a latency as possible. If you&#8217;re making millions of calls a second to your profiler, the timestamp mechanism could become the limiting factor in your app&#8217;s performance and make it so unresponsive that testing it is infeasible.</p>
<p>On an x86, this means you must go with <strong><a href="http://en.wikipedia.org/wiki/Time_Stamp_Counter">rdtsc</a></strong>. It is low latency, high precision, and is portable to gcc. This choice is unfortunately not without it&#8217;s trade offs. rdtsc does not serialize, so unless you insert a serializing instruction like cpuid before it (and bloat the latency in the process) or use the new rtdscp instruction, the cycle count you receive may not be 100% accurate. rdtsc is not guaranteed to be sync&#8217;d across all CPUs in a multi-core / multi-CPU system, so even single threaded timing has the possibility of being incorrect if the thread is scheduled across multiple CPUs. <strong>But</strong>, and this is a big but, for what I want there is nothing else to use. If someone else has different needs they can replace the timer function, but for the volume of calls I&#8217;m interested in, latency needs to be the bare minimum.</p>
<h5>Multi-threading</h5>
<p>This is the part nobody seems to know or care how to do so I was on my own. To avoid overhead, synchronization must be avoided at all costs for the general path.</p>
<p>Easy solution: Track each thread&#8217;s profiler state with <a href="http://en.wikipedia.org/wiki/Thread-local_storage">thread-local storage</a> and do the heavyweight statistics work on-demand instead of worrying about aggregating on the fly. A little more work needs to be done depending on the details of the profiler implementation, but nothing difficult.</p>
<p>I didn&#8217;t want anything complicated or OS specific for the synchronization, so I decided on a home-made <a href="http://en.wikipedia.org/wiki/Compare-and-swap">CAS</a> solution (i.e. lock xchg on the x86) for the <a href="http://en.wikipedia.org/wiki/Spinlock">spinlocks</a> and such.</p>
<p>The only change for the user is needing to explicitly enter &amp; exit threads for the profiler. An important note is that while threads must be explicitly instrumented, if you do not instrument a thread, it will not hurt the system in any way; the thread will just not show up in the profile stats.</p>
<h5>Storage</h5>
<div data-shortcode="caption" id="attachment_64" style="width: 309px" class="wp-caption alignright"><img aria-describedby="caption-attachment-64" data-attachment-id="64" data-permalink="https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/calltree-2/" data-orig-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png" data-orig-size="299,202" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="Call Tree" data-image-description="" data-image-caption="" data-medium-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png?w=299" data-large-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png?w=299" class="size-full wp-image-64 " title="Call Tree" src="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png?w=299&#038;h=202" alt="Call Tree" width="299" height="202" srcset="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png 299w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png?w=150&amp;h=101 150w" sizes="(max-width: 299px) 100vw, 299px" /><p id="caption-attachment-64" class="wp-caption-text">Example of a Call Tree</p></div>
<p>How the profiler data is stored is a function of how much detail is needed. In my case I wanted full call trees which means it has to be dynamically allocated and call nodes must be dynamically located. Obviously this will require a hash table, but it should not be a generic fully functional hash table! Because of the limited scope of  what the profiler needs,  corners can be cut so that it does what it needs to quickly.</p>
<p>Probably the easiest gain to be made is not hashing the function name when searching for it in the hash table! If you use compile time constant strings like <a href="http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html">__FUNCTION__</a>, you can simply take the address of the string as the hash value and skip the O(n) hashing of the string. Small fixups may be needed (I use &gt;&gt; 5 on the address as the strings are possibly aligned), but in the end it&#8217;s a big win.</p>
<p>If using an <a href="http://en.wikipedia.org/wiki/Hash_table#Open_addressing">open hash table</a> like I am, there is never a need to delete individual entries, so you do not need a tombstone value for a deleted key or a check in your lookup against them. There&#8217;s either a value in a slot, or it&#8217;s empty.</p>
<p>I also use <a href="http://en.wikipedia.org/wiki/Linear_probing">linear probing</a> because the table should be empty enough and the hash dispersion should be spread out enough that the extra code to do quadratic or better probing would slow the search down in the general case. I do not inline the elements in the table however; The hash table is an array of pointers to individually created profiler nodes, with each node being its own hash table. The size of each node is nearing 64 bytes with 32 bit pointers, so I figured scanning them would produce cache misses regardless, and inlining them in the table was more trouble than it was worth.</p>
<h5>Synchronizing</h5>
<p>If the goal is to profile an entire run of a program, then you don&#8217;t need synchronization. Profile in to the threadlocal profilers, wait for all threads to finish, and combine the results. Easy!</p>
<p>My goal is more difficult. I want to not only dump the profiling results at any time, I want to be able to <em>reset</em> the results at any time. When I&#8217;m profiling games, I often want to profile a specific action or sequence of actions. I don&#8217;t want to include the startup time and whatever is required to get to that specific thing I want to profile, e.g. running a timedemo or <a href="https://floodyberry.wordpress.com/2008/07/09/the-id-tech-4-script-compiler-sucks-hard/">analyzing a horrible script compiler</a>.</p>
<p>So how to synchronize without slowing everything down, while still being able to crawl a potentially mutating hash table safely? I compromised by accepting that a few call nodes may get extra calls by locking on any mutation to the hash table array, but <strong>not</strong> mutations to the timing information. When the dump/reset are using a thread&#8217;s hash table, it will take the thread&#8217;s lock, crawl it&#8217;s information, and release it. The thread is still free to profile to existing nodes during this time, but any attempt to insert a new node will block.</p>
<p>Reset is handled not by deleting a call tree, but by crawling the tree and resetting each node&#8217;s timer to zero (threads which are no longer active are of course fully deleted). This has the byproduct of not only being able to reset all threads when they&#8217;re at arbitrary positions in their call tree, but also to call reset from arbitrary positions in any call tree. I ran in to this need the hard way when profiling Tribes script system, and the call to reset the profiler is done with a script command, bad things happened. To keep reset-but-not-yet-active nodes out of dumps, it&#8217;s necessary to check that nodes have a non-zero time before walking them.</p>
<p>A  <em>small</em> caveat with reset: Because there is no synchronization for existing nodes, it&#8217;s possible that</p>
<pre class="brush: cpp; title: ; notranslate">ticks += ( getticks() - started )</pre>
<p>could execute at the same time the thread that is resetting everything executes</p>
<pre class="brush: cpp; title: ; notranslate">ticks = 0</pre>
<p>Now, if the code is generated so the value is summed directly in to ticks, there is no issue. ticks will either get incremented, then stomped, or stomped, then incremented. This seems to be true in both gcc and msvc release builds, so there is no issue. But in debug builds, ticks can be read in to a temporary variable, summed, and written back to ticks, which could stomp the 0 written by the reset thread. Since this isn&#8217;t an issue in release builds and will only happen on a freak chance in debug builds, I don&#8217;t see it being an issue, but it&#8217;s something to be aware of.</p>
<h5>Output</h5>
<p>A fully working profiler is still not useful if it&#8217;s output is incomplete or difficult to read. Look at the documentation for understanding gprof&#8217;s <a href="http://www.cs.utah.edu/dept/old/texinfo/as/gprof.html#SEC6">call graph</a>. 5-6 pages of text for a glut of confusing numbers and diagrams when a well-made call tree/graph doesn&#8217;t need documentation and can be understood easily with visual examination. Google&#8217;s <a href="http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html">perf-tools</a> require you to run the output through a perl script, and still the results are hideous and hard to read! Which is why I came up with:</p>
<div data-shortcode="caption" id="attachment_88" style="width: 210px" class="wp-caption aligncenter"><a href="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii2.png"><img aria-describedby="caption-attachment-88" data-attachment-id="88" data-permalink="https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/profiler-ascii-small/" data-orig-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png" data-orig-size="200,94" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="profiler-ascii-small" data-image-description="" data-image-caption="" data-medium-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png?w=200" data-large-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png?w=200" class="size-full wp-image-88 " title="ASCII Profiler Output" src="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png?w=200&#038;h=94" alt="profiler-ascii-small" width="200" height="94" srcset="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png 200w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png?w=150&amp;h=71 150w" sizes="(max-width: 200px) 100vw, 200px" /></a><p id="caption-attachment-88" class="wp-caption-text">Profiler Dump - ASCII</p></div>
<p>I originally only had the ASCII dumper. For games (which use text consoles) or command line apps, text output is quick and easy. A real tree structure is rendered so you aren&#8217;t left playing guessing games as to how far each item is indented or trying to match up rows of numbers to their function names on the other side of the screen. Self time while inside the tree is only useful to that specific branch, so I also include the top callers overall by self time so global bottlenecks can be identified.</p>
<div data-shortcode="caption" id="attachment_91" style="width: 210px" class="wp-caption aligncenter"><a href="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html1.png"><img aria-describedby="caption-attachment-91" loading="lazy" data-attachment-id="91" data-permalink="https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/profiler-html-small/" data-orig-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png" data-orig-size="200,166" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="profiler-html-small" data-image-description="" data-image-caption="" data-medium-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png?w=200" data-large-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png?w=200" class="size-full wp-image-91   " title="profiler-html-small" src="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png?w=200&#038;h=166" alt="profiler-html-small" width="200" height="166" srcset="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png 200w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png?w=150&amp;h=125 150w" sizes="(max-width: 200px) 100vw, 200px" /></a><p id="caption-attachment-91" class="wp-caption-text">Profiler Dump - HTML</p></div>
<p>Text is great, but I thought it would also be useful to have a fancier dump with things like colored hotspots and mouse hover highlighting. Archiving the generated HTML files is also an excellent way to track and show improvements over time.</p>
<p>As an aside, the HTML dump is actually the main source of the code bloat in the profiler now. I chose to integrate the generation of the HTML dump in the C++ code versus post-processing data with a script because every step between you and the final product is another reason to not use it at all.</p>
<h4>Performance</h4>
<p>To test out the performance of the type of applications I&#8217;m interested in profiling, I ran Thierry Berger-Perrin&#8217;s <a href="http://code.google.com/p/high-performance-cplusplus-profiler/source/browse/trunk/examples/example-sphereflake.cpp">sphereflake</a> app through a variety of profilers on my E8400. sphereflake was built for a single thread so Shiny would run, while my profiler (and everyone else) was running in multi-threaded mode. The only difference in the general case between single and multi-threading mode in my profiler is whether the pointer to the local state is a)  static, or b) a thread-local static. The overhead from tls handling is non-applicable, so it can be run in multi-threading mode at all times without worry.</p>
<div data-shortcode="caption" id="attachment_108" style="width: 418px" class="wp-caption alignright"><img aria-describedby="caption-attachment-108" loading="lazy" data-attachment-id="108" data-permalink="https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/perf-2/" data-orig-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png" data-orig-size="408,268" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="perf" data-image-description="" data-image-caption="" data-medium-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png?w=300" data-large-file="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png?w=408" class="size-full wp-image-108" title="Profiler Performance Comparison" src="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png?w=408&#038;h=268" alt="perf" width="408" height="268" srcset="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png 408w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png?w=150&amp;h=99 150w, https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png?w=300&amp;h=197 300w" sizes="(max-width: 408px) 100vw, 408px" /><p id="caption-attachment-108" class="wp-caption-text">Performance from various profilers on example-sphereflake.cpp. ¹-Glowcode was unable to get an accurate profile.</p></div>
<p>Non-instrumented run time for sphereflake is about <strong>3</strong> seconds on my E8400, and the functions I profile result in around <strong>10 million</strong> calls during that period. The breakdown of performance by profiler:</p>
<ul>
<li>My profiler is <strong>1.09x</strong> slower than baseline.</li>
<li>Sleepy (the sampling profiler) is inexplicably is <strong>1.19x</strong> slower. Sleepy itself didn&#8217;t seem to use any CPU time, so I can only guess that something it did with the system was affecting context switches or whatnot.</li>
<li>Shiny, switched to use <em>rdtsc</em> as it&#8217;s timing mechanism, is <strong>1.27x</strong> slower.</li>
<li>GlowCode was unable to profile all of the functions needed regardless of how many optimizations I tried to turn off, hence the ¹. I eventually got it up to around <strong>4.5</strong> million calls, at which point it was slowing the program down by <strong>1.89x</strong>. Not too impressive for the &#8220;<strong><em>WORLD&#8217;S FASTEST PROFILER!&#8221;.</em></strong></li>
<li>Shiny, using <em>QueryPerformanceCounter</em>, is <strong>1.95x</strong> slower. This is why QPC is bad for high volume profiling, the latency adds up fast.</li>
<li>Visual Studio 2005&#8217;s &#8220;Profile Guided Optimization&#8221; (not pictured) not only ran<strong> 4.75x</strong> slower than baseline during profiling, but after it &#8220;optimized&#8221; the app from the profile data, the app ran slower!</li>
</ul>
<h4>Fin</h4>
<p>So that&#8217;s how to do high performance profiling! Even with Tribes generating <strong>480</strong>+ million calls during a <strong>2 ½</strong> minute timedemo of a <strong>25</strong> minute map, it still runs at <strong>300</strong>fps+ and accurately reports what is using time where. (No, it&#8217;s not OpenGL::setupBitmapTexCoords. <strong>BAD</strong> VTune!)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2009/10/07/high-performance-cplusplus-profiling/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>

		<media:content url="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/timingmethods2.png" medium="image">
			<media:title type="html">Timing Methods</media:title>
		</media:content>

		<media:content url="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/calltree1.png" medium="image">
			<media:title type="html">Call Tree</media:title>
		</media:content>

		<media:content url="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-ascii-small.png" medium="image">
			<media:title type="html">ASCII Profiler Output</media:title>
		</media:content>

		<media:content url="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/profiler-html-small.png" medium="image">
			<media:title type="html">profiler-html-small</media:title>
		</media:content>

		<media:content url="https://floodyberry.wordpress.com/wp-content/uploads/2009/09/perf1.png" medium="image">
			<media:title type="html">Profiler Performance Comparison</media:title>
		</media:content>
	</item>
		<item>
		<title>Generating .DLL Wrappers</title>
		<link>https://floodyberry.wordpress.com/2008/09/08/generating-dll-wrappers/</link>
					<comments>https://floodyberry.wordpress.com/2008/09/08/generating-dll-wrappers/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Mon, 08 Sep 2008 10:25:49 +0000</pubDate>
				<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Win32]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[dll]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=31</guid>

					<description><![CDATA[A while ago I came across Create your Proxy DLLs automatically by Michael Chourdakis. I thought it was a good idea, but had some room for improvement: Having to use an external .exe (dumpbin/tdump) was an unnecessary step, all the information you need is in the PE header! He did not handle wrapping mangled names [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>A while ago I came across <a href="http://www.codeproject.com/KB/DLL/CreateYourProxyDLLs.aspx">Create your Proxy DLLs automatically</a> by <a href="http://www.turboirc.com/main2/">Michael Chourdakis</a>. I thought it was a good idea, but had some room for improvement:</p>
<ul>
<li>Having to use an external .exe (dumpbin/tdump) was an unnecessary step, all the information you need is in the PE header!</li>
<li>He did not handle wrapping <a href="http://en.wikipedia.org/wiki/Name_mangling">mangled names</a> or forwarding forwards.</li>
<li>Generating an actual project instead of a command line compile call would be a lot more useful considering you will want to do some actual coding instead of generating an empty wrapper.</li>
<li>His coding style was somewhat awkward and not easy to modify.</li>
</ul>
<p>With this in mind, I set about writing my own version. <span id="more-31"></span> Dumping the export information from the PE header was the first step and relatively straightforward as the PE header is not complicated. I did, however, need to steal GetPtrFromRVA and GetSectionFromRVA from <a href="http://www.wheaty.net/">Matt Pietrek</a> because the RVAs (Relative Virtual Addresses) are only relative when the sections are properly mapped out in memory, not while in the PE container! Those two functions also happen to be used for game hacks when the cheat-maker want to bypass any LoadLibrary &amp; EnumProcessModules hooks by manually mapping a .DLL in to memory.</p>
<p>Handling export forwards is tricky if you don&#8217;t know what they are and simple once you find out.  Since there are no flags to indicate if an export is a forward, and an export name can contain any non-zero character, the system needs a way to tell if &#8220;NTDLL.RtlAllocHeap&#8221; is a forward or not. The linker solves this by pointing the exported function address at the name of the export in the export table, so you merely need to check if the exported function address is within the export table or not.</p>
<p>Proxying name mangling is unfortunately not as simple. Say a .DLL exports</p>
<pre class="brush: cpp; title: ; notranslate">void __stdcall SimpleExport( void ) {
}</pre>
<p>as a C++ function, resulting in the mangled export of &#8220;?SimpleExport@@YGXXZ&#8221;. Now say your proxy .DLL implements a stub and attempts to forward it (the @1 at the end of the export is telling the linker which ordinal to assign the export to):</p>
<pre class="brush: cpp; title: ; notranslate">.cpp file:

int __stdcall SimpleExport__YGXXZ() {
	...
}</pre>
<p>&nbsp;</p>
<pre class="brush: cpp; title: ; notranslate">.def file

?SimpleExport@@YGXXZ=SimpleExport__YGXXZ @1</pre>
<p>When you compile your .DLL, you&#8217;ll be surprised to find that it is exporting &#8220;SimpleExport&#8221;, not &#8220;?SimpleExport@@YGXXZ&#8221;! What is going on?! It turns out the Microsoft linker checks the target function for name mangling (an @ symbol), and if the target function name isn&#8217;t mangled, formats the exported name as a C function. The only way that I&#8217;ve found to export a mangled name is to <strong>point it at a mangled name</strong>:</p>
<pre class="brush: cpp; title: ; notranslate">.def file v2

?SimpleExport@@YGXXZ=?SimpleExport__YGXXZ@@YGXH@Z @1</pre>
<p>The good news is that this works great. The bad news is that if you alter your proxy function to match the source function, the name mangling changes and your .def file will need to be updated with the new name (not a trivial thing!). The &#8220;at least it works&#8221; solution I came up with is to have proxy functions for your proxy functions, i.e. functions whose name mangling will never change and which jmp to the real proxy function:</p>
<pre class="brush: cpp; title: ; notranslate">.cpp file:

int __stdcall SimpleExport__YGXXZ() {
	...
}

naked void __stdcall decorated1() {
	__asm {
		jmp SimpleExport__YGXXZ
	}
}
</pre>
<p>&nbsp;</p>
<pre class="brush: cpp; title: ; notranslate">.def file:

?SimpleExport@@YGXXZ=?decorated1@YGXXZ @1</pre>
<p>Now you can alter the calling conventions, parameters, and return type of the actual proxy function as much as you like and it won&#8217;t affect the linking.</p>
<p>A benefit the trouble mangled names produce is that, with the <a href="http://msdn.microsoft.com/en-us/library/ms681400(VS.85).aspx">UnDecorateSymbolName</a> DbgHelp API call, it is trivial to annotate the return type, calling conventions, and parameters of the proxied function; e.g. you can now see &#8220;?func1@a@@AAEXH@Z&#8221; actually means &#8220;private: void __thiscall a::func1(int)&#8221;.</p>
<h4>My Version</h4>
<p>There are a lot of ways to generate the wrapper and I thought Michael&#8217;s generated source also had room for improvement. For example, he doesn&#8217;t name any of the generated functions, and calling through to the original function requires a typedef (doesn&#8217;t work with intellisense), a non-obvious index in to the imported function array, and a cast. Extending the code so any function can call through to any original function would require the typedef to be global (which still won&#8217;t work with intellisense).</p>
<p>The main points I wanted to hit were:</p>
<ol>
<li>Allow the original functions to be easily callable from anywhere</li>
<li>Require as few changes as possible to if you want to convert a stub to a proxied function</li>
<li>Intellisense has to work!</li>
</ol>
<p>#1 meant creating dummy functions which jmp to their target proc. By creating them as:</p>
<pre class="brush: cpp; title: ; notranslate">
inline __declspec(naked) int call_AcceptEx() {
	__asm {
		jmp dword ptr [ mProcs + 0 * 4 ]
	}
}</pre>
<p>I&#8217;m not only able to stuff them in the header (keeping the source file clean), but naked means you can alter their parameters and return type as much as you like and don&#8217;t need to worry about how to use the FARPROC entry or which index to use.</p>
<p>To make one of the original functions globally callable, you only need to change the function signature in two places: The header stub, and the proxy function in the .cpp file. I would have loved to only have a single signature to change but wasn&#8217;t able to come up with a clean method. It&#8217;s &#8220;possible&#8221; with some god-awful macro magic, but I don&#8217;t even have a need for a wrapper at this point and the macros really obfuscate the code.</p>
<p>That is about it! More work could be done, but it&#8217;s decently functional now and I think I&#8217;ve been sitting on it for long enough now. My version generates projects for both Visual Studio 2003 &amp; 2005 and attempts to load the original .DLL from the Windows system directory by default (fairly arbitrary, easy to change). There&#8217;s also a sample .DLL (dll.dll) with odd exports (a forwarded function, a mangled class function, a mangled C++ global function, and a __stdcall C function) so you can make sure any changes you make still compile fine.</p>
<p>Now I just need to find something to wrap with it..</p>
<h4>Downloads</h4>
<ul>
<li>GitHub repo: <a href="https://github.com/floodyberry/genwrapper">genwrapper</a></li>
<li>Example output for sample DLL: <a href="https://github.com/floodyberry/genwrapper/tree/master/dll">genwrapper/dll</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/09/08/generating-dll-wrappers/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>The id Tech 4 Script Compiler Sucks Hard!</title>
		<link>https://floodyberry.wordpress.com/2008/07/09/the-id-tech-4-script-compiler-sucks-hard/</link>
					<comments>https://floodyberry.wordpress.com/2008/07/09/the-id-tech-4-script-compiler-sucks-hard/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Wed, 09 Jul 2008 20:23:05 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[compiler]]></category>
		<category><![CDATA[etqw]]></category>
		<category><![CDATA[id]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=23</guid>

					<description><![CDATA[Whoever did most of the work on the id Tech 4 Script Compiler, I&#8217;m calling you out! I&#8217;ll grant that you managed to write a major component of a successful commercial engine, but&#8230; it&#8217;s just so bad. What confounds me even more is that all of the engines after DooM III did almost nothing (effective) [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Whoever did most of the work on the <a href="http://en.wikipedia.org/wiki/Id_Tech_4">id Tech 4</a> Script Compiler, I&#8217;m calling you out! I&#8217;ll grant that you managed to write a major component of a successful commercial engine, but&#8230; it&#8217;s just so bad. What confounds me even more is that all of the engines after DooM III did almost nothing (effective) to try and fix it: If you check out the Quake IV, Prey, and ET:QW SDKs, they all have the same basic compiler with a couple things bolted on. The ET:QW guys did do a bit of work on it and tried to speed it up a bit, but &#8220;glacially slow&#8221; doesn&#8217;t seem like much of an improvement on &#8220;geologically slow&#8221;.</p>
<p>I first noticed how bad it was when I was doing the ET:QW -&gt; Tribes stuff and started playing around with the scripts. Being so use to Tribes style scripting, two things hit me right off:</p>
<ol>
<li>You have to exit the mission and recompile every script if you want to update a script you just edited. Ok, pretty annoying, but I&#8217;m just playing around so it should get easier.</li>
<li>On my AMD64 3200+, recompiling was &#8220;damn slow&#8221; (<strong>~20</strong> seconds) in Release mode and &#8220;I&#8217;m going to read a book&#8221; (<strong>~60</strong> seconds) in Debug. Issue #1 just got a lot more annoying.</li>
</ol>
<p>How did they manage to develop on this for longer than 10 minutes before going crazy, let alone create an entire game? Apparently I was the first to get fed up enough about it, so I went to check out the compiler and see if I could find any hot spots.</p>
<p><span id="more-23"></span></p>
<h4>Putting Out Dead Fires</h4>
<p>What is most depressing about looking at the source is that you can tell someone <em>tried</em> to optimize it, but failed miserably.</p>
<ul>
<li>There are static lists for some elements (strings, functions, globals, statements, objects). <strong>idList</strong> grows linearly, not exponentially, so I assume someone noticed adding XXXX elements was really slow, knew it must be <strong>idList</strong> resizing itself far too many times, but didn&#8217;t know of an actual solution. A static list also means the code will break if you add too many items.</li>
<li>A Hash <strong>is</strong> used for <strong>idVarDef</strong>s (a catch all struct to hold scope/info for variables, functions, objects, and constants), but it is based on name only, i.e. every time it looks up a variable named &#8220;i&#8221;, it gets a linked list of <strong>every</strong> variable named &#8220;i&#8221; and has to check every one to see if they match the scope of the &#8220;i&#8221; you want.
<p>Even better, the list of constants is kept in the <strong>idVarDef</strong> list named &#8220;&lt;Immediate&gt;&#8221;, which means a lookup to see if a constant value exists requires that you iterate over every string constant, numeric constant, stack return constant, etc.</li>
<li>Splash Damage did add a Hash for the <strong>idTypeDef</strong> list in ET:QW, but <strong>only</strong> for the user defined types i.e. objects. The default types were still checked for with a cascaded if statement.
<p>They also added blockAllocators for a couple elements, but allocations weren&#8217;t the main problem.</li>
</ul>
<h4>Active Volcanos</h4>
<p>So what were the (major) problems?</p>
<p><em>Script_Compiler.cpp</em>:</p>
<ul>
<li><strong>idCompiler::FindImmediate</strong> lumped all constants under a single name (&lt;Immediate&gt;), leading to a linear search every time one was looked up</li>
<li><strong>idCompiler::CheckType</strong> checked for default types (string, boolean, virtual, etc) with a cascaded if statement.</li>
<li><strong>idCompiler::GetExpression</strong> did a linear search through the opcode list</li>
<li><strong>idCompiler::ParseReturnStatement</strong> did a linear search through the opcode list to find the &#8220;=&#8221; opcode</li>
</ul>
<p><em>Script_Program.cpp</em></p>
<ul>
<li><strong>idVarDef</strong> was stored in a hash by name only. Each <strong>idVarDef</strong> is a unique pair of name &amp; scope, so the entire list of <strong>idVarDef</strong>s would have to be searched for the proper scope member</li>
<li>The <strong>idVarDef</strong>s were also stored in a weird linked list thing that required constant maintenance</li>
<li><strong>idProgram::FindType</strong> used a linear search even when the hash table was available</li>
<li><strong>idProgram::MatchesVirtualFunction</strong> used a linear search through the virtual functions</li>
</ul>
<p>The generous explanation is that nobody got around to storing things in hash tables properly because the <strong>idHashTable</strong> implementations suck. They&#8217;re hardcoded to be key&#8217;d on a string so you can&#8217;t construct custom keys (such as an object containing a name and a scope for <strong>idVarDef</strong>s).</p>
<p>What is especially ironic (maybe only to me) is that Carmack ran in to performance problems <a href="http://www.team5150.com/~andrew/carmack/johnc_plan_1996.html#d19960903">due to linear searches</a> before with qcc! I have no idea if he contributed at all to the compiler, but it still tickles me.</p>
<h4>Postmature Optimization</h4>
<p>The main fix for this type of problem should be obvious: more hash tables! It took me around a week and a half or so to figure out what exactly was going on, identify the hotspots, and fix them. This involved lookups for the compiler default types, the opcode table, and the global virtuals table, as well as creating an <strong>idScopeName</strong> object to key the list of <strong>idVarDef</strong>s on.</p>
<p>To cope with the bloat the hash tables might introduce, I also used an <strong>idStrPool</strong> for all the strings inside <em>idProgram.cpp</em>. This had the added bonus of allowing pointer hashing and comparisons on the <strong>idPoolStr*</strong> since they are guaranteed to be unique.</p>
<p>If you remember that I said the <strong>idHashTable</strong> implementations were awful, they are! Luckily the Splash Damage guys created <strong>sdHashMapGeneric</strong> so I didn&#8217;t have to make my own or figure out what exactly the weird id stuff is doing (I still don&#8217;t understand it).</p>
<p>There were some structural changes that had to be made to accommodate all of this, but nothing earth shattering. I chopped out some useless classes and created new ones such as <strong>idTypeDef_Static</strong> (<strong>idTypeDef</strong>s need an <strong>idPoolStr*</strong> name now, but you can&#8217;t statically create one), etc.</p>
<h4>Did It Get Faster?</h4>
<p>Yes! I don&#8217;t really have a wide assortment of test systems, but these are the improvements I saw:</p>
<pre class="brush: cpp; title: ; notranslate">                           Default    Optimized     Speedup
FeaRog&#039;s Laptop(Debug):  ~180-300s         ~12s      15-25x
AMD64 3200+(Release):         ~20s          ~1s         20x
AMD64 3200+(Debug):           ~60s          ~4s         15x
E8400@3.6ghz(Release):       ~1.5s        ~0.3s          5x
E8400@3.6ghz(Debug):        ~32.5s        ~2.3s         14x</pre>
<p>Memory usage did go up by ~0.5mb, but that&#8217;s really nothing when the compiler is using 6-7mb as it is. I also spiffed up <strong>idProgram::CompileStats</strong> to produce more detailed stats so you can see exactly where the memory is going (and the overhead on the various containers). I would have fixed <strong>idList</strong> to resize exponentially and gotten rid of the awful <strong>.setGranularity</strong> calls, but editing anything in <strong>idLib</strong> always forced nearly the entire solution to recompile so I let it go.</p>
<h4>Fin</h4>
<p><a href="http://www.team5150.com/~andrew/blog/files/etqwcompiler-1.5.zip">Download the source</a> (for ET:QW SDK 1.5) and try it out! Simply unzip it to your ET:QW SDK source directory and re-compile, it should work flawlessly unless you&#8217;ve made conflicting modifications to the 1.5 SDK.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/07/09/the-id-tech-4-script-compiler-sucks-hard/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Tribes 1 Physics, Part Four: Explosions</title>
		<link>https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/</link>
					<comments>https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Tue, 29 Apr 2008 17:30:23 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Tribes]]></category>
		<category><![CDATA[tribes physics]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=21</guid>

					<description><![CDATA[Explosions (or more accurately, knockback), the final piece to the physics puzzle! If you implement all of the previous articles, make a disc launcher, plug in the apparently simple knockback force and radius from baseProjData.cs, and finally attempt to disc jump, you will be greeted with&#8230; a nice and wimpy boost. Playing around with the [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Explosions (or more accurately, knockback), the final piece to the physics puzzle! If you implement all of the previous articles, make a disc launcher, plug in the apparently simple knockback force and radius from baseProjData.cs, and finally attempt to disc jump, you will be greeted with&#8230; a nice and wimpy boost. Playing around with the knockback force will only break explosions in new ways. Argh, you were so close! How could Tribes possibly screw this one up? <span id="more-21"></span></p>
<h4>Basic Knockback</h4>
<p>The basic idea for knockbacks from explosions is you want to take the position of the explosion and the object, scale the explosion force, and apply an impulse to the object in the appropriate direction. Generally this is implemented something like so:</p>
<pre class="brush: cpp; title: ; notranslate">Player.onExplosion( Vector3 explosion, float radius, float knockback, float damage ) {
    Vector3 distance = ( hitbox.center - explosion ), direction = distance.Normalize
    if ( distance.Length &gt; radius )
        return

    float power = 1 - ( distance.Length / radius )
    ApplyDamage( power * damage )
    ApplyImpulse( knockback * ( power * direction ) / armor.Mass )   
}
</pre>
<p><em>power</em> is where the magic happens and while it should be an exponential falloff, it is common to do linear because there is not much of a noticeable difference. It is also where Tribes deviates from the norm in a fairly big way.</p>
<h4>Tribes Knockback</h4>
<p>What is obvious when you implement the basic knockback is that it packs a much smaller punch than Tribes. What you might not notice is that the Tribes knockback up close, e.g. at your feet from a standstill, is actually weaker than from a bit of a distance, e.g. at your feet while you&#8217;re in the air after jumping. Whether this was intended as an aid to disc jumping or an accident of a botched formula is impossible to say, but it doubtless would have been harder to gain speed from disc jumps without this odd feature.</p>
<p>If you work out exactly what the Tribes knockback function does (not fun) and re-factor the formula (not fun and also confusing), you come out with a somewhat familiar power calculation. Instead of the basic ( 1 &#8211; ( d / r ) ), Tribes uses ( ( d / Max( d &#8211; minHitboxDimension, 1 ) ) &#8211; ( d / r ) ), i.e. instead of using a constant ( 100% &#8211; linear falloff ) for the power, Tribes does some weird calculations which I can only guess are trying to account for the hitbox in some way. This image illustrates the power falloff for Tribes, the power falloff for the basic formula, and the power falloff for the basic formula if it were boosted so players were able to disc jump properly:</p>
<p><img src="https://i0.wp.com/www.team5150.com/~andrew/blog/images/t1knockback.png" /></p>
<p>This shows why the linear falloff formula cannot be fixed by boosting the knockback force without getting wildly inaccurate up close. Here is the proper formula:</p>
<pre class="brush: cpp; title: ; notranslate">Player.onExplosion( Vector3 explosion, float radius, float knockback, float damage ) {
    Vector3 distance = ( hitbox.Center - explosion ), direction = distance.Normalize
    float minbox = Min( Min( hitbox.Width.x, hitbox.Width.y ), hitbox.Width.z )
    float d = Max( distance.Length - minbox, MetersToUnits( 1 ) )
    if ( d &gt; radius )
        return

    float power = ( distance.Length / d ) - ( distance.Length / radius )
    ApplyDamage( damage * ( 1 - d / radius ) )
    ApplyImpulse( knockback * ( power * direction ) / armor.Mass )   
}
</pre>
<p>For the Light Armor with a BOX_WIDTH of 0.5, BOX_DEPTH of 0.5, and BOX_HEIGHT of 2.3, minbox equates to Min( Min( BOX_WIDTH * 2, BOX_DEPTH * 2 ), BOX_HEIGHT ), or 1.0. The player origin is at the center of the player&#8217;s feet and the hitbox dimensions extend out from that, so the width and depth extend out in either direction and need to be doubled while the height goes from the feet to the head. Note that if you increase the smallest hitbox dimension, e.g. increase BOX_WIDTH and BOX_DEPTH to have a value of 2.3 when doubled, the linear ramp leading up to the downward falloff of the power will grow, presumably to account for greater surface contact area with the explosion.</p>
<h4>You&#8217;re Done!</h4>
<p>You should have all you need to get authentic Tribes 1 Physics going in your engine of choice! After this you should only need to create some dummy weapons, scale their velocities to whatever units you are using, add two flags, and you can get an honest game of LT going. </p>
<p>What? You don&#8217;t believe me that it works and you don&#8217;t want to waste your time implementing the physics only to find out that I lied? Hmmm, here&#8217;s something that should convince you. This is the full T1 physics running on Raindance in ET:QW. I did this for the ET:QW Tribes mod that was in the works, but unfortunately things kind of fizzled out. The map is authentic Raindance (every crevasse and triangle is there) with an 8192&#215;8192 command map texture overlaid on top with Arcanox&#8217;s bases and bridge. This is currently the closest thing to Tribes you will ever see in another engine.</p>
<iframe class="youtube-player" width="640" height="360" src="https://www.youtube.com/embed/zOcwJX-nNok?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en&#038;autohide=2&#038;wmode=transparent" allowfullscreen="true" style="border:0;" sandbox="allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox"></iframe>
<p>You can also download the <a href="http://www.team5150.com/~andrew/blog/files/etqw-raindance-discjump.avi">hi-res version (15mb)</a>, although the burps are more apparent since my computer wasn&#8217;t quite up to spec to run QW. How I got the terrain in and textured will have to wait for another day.</p>
<h4>Tribes 1 Physics Series</h4>
<ul>
<li>Part One: <a href="https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/">Overview</a></li>
<li>Part Two: <a href="https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/">Movement</a></li>
<li>Part Three: <a href="https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/">Collision</a></li>
<li>Part Four: <a href="https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/">Explosions</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		<enclosure url="http://www.team5150.com/~andrew/blog/files/etqw-raindance-discjump.avi" length="15779840" type="video/x-msvideo" />

		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>

		<media:content url="http://www.team5150.com/~andrew/blog/images/t1knockback.png" medium="image" />
	</item>
		<item>
		<title>Tribes 1 Physics, Part Three: Collision</title>
		<link>https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/</link>
					<comments>https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Sat, 12 Apr 2008 00:47:59 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Tribes]]></category>
		<category><![CDATA[tribes physics]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=20</guid>

					<description><![CDATA[This article covers the collision physics of Tribes 1, i.e. attempting to actually move the player and what to do when the player runs in to something. This is the most convoluted part of the physics and requires a lot of little touches to get right. Tribes movement and collision handling actually gets a little [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>This article covers the collision physics of Tribes 1, i.e. attempting to actually move the player and what to do when the player runs in to something. This is the most convoluted part of the physics and requires a lot of little touches to get right. Tribes movement and collision handling actually gets a little too low level, so I won&#8217;t be able to show <em>exactly</em> how it works (it gets down to dealing with the raw triangle lists which I don&#8217;t think all collision detection systems will let you get at), but it will be detailed enough so that there will be no major differences. <span id="more-20"></span></p>
<h4>Warning!</h4>
<p>Before I get in to the details, a little explanation is required. When Tribes attempts to move an object, it takes the maximum distance the object will cover in the remaining time (X), then divides the remaining time by ceil(X) and does ceil(X) collision detection loops. This is ostensibly to ensure that an object only moves 1m at a time, but for what reason, I don&#8217;t know. The engine is obviously capable of fairly arbitrary translations (or else Gambase::GetLosInfo would not work) so I can only imagine many short translations proved to be more efficient than a single large translation.</p>
<p>I am going to be using a single translation, and normally this would not make a difference, but Tribes does something a little weird on collisions which necessitates a rather odd fix-up when you are using a single translation versus slicing them up. Instead of adjusting the position based on velocity when there is no collision and adjusting the velocity &amp; setting the position to the collision point on a collision, Tribes adjusts the position based on the velocity <em>no matter what</em>. This means Tribes will attempt to move the player, hit a surface, adjust the velocity based on the collision, and then move the player anyway <em>from their original position</em> based on the new velocity, usually resulting in the player bouncing ever so slightly away from the contacted surface. There is actually a noticeable difference between the correct way and Tribes way of handling collisions, as the correct way feels slightly velcroish while Tribes feels more fluid. </p>
<p>Things get more complicated when you move the player in a single translation instead of sliced up translations as the weird adjustment on collisions is only done for the last fraction of the translation and not the entire thing. I worked around this by calculating some values which let me figure out how many &#8220;non-collision&#8221; slices have occurred and only do the weird handling on the last slice.</p>
<h4>Collision Code</h4>
<pre class="brush: cpp; title: ; notranslate">Player.UpdatePosition( float tickLen ) {
    float decayFriction = currentFriction * Physics.FRICTIONDECAY
    float lastSurfDirection = lastJumpableNormal.Dot( Gravity.upNormal )
    float timeLeft = tickLen
    int maxBumps = 4, bumps
    
    currentFriction = 0
    collisionLastTick = false
    
    for ( bumps = 0; ( bumps &lt; maxBumps ) &amp;&amp; ( timeLeft &gt; 0 ); bumps++ ) {
        // slice fixup values
        Vector3 maxDistance = ( velocity * timeLeft )
        int iterations = ceil( UnitsToMeters( maxDistance.Length ) )
        float sliceTime = timeLeft / iterations
        
        // attempt to move through the world
        Vector3 originalPos = position, endPos = position + maxDistance
        moveFraction, finalPos, contactNormal = Physics.Translate( originalPos, endPos )

        // figure out how long we moved for and adjust the remaining time
        float duration = timeLeft * moveFraction
        timeLeft -= duration
        position = finalPos

        // did we move the entire distance safely?
        if ( !timeLeft )
            break
        
        // collisionLastFrame gets set even if we step up and don&#039;t have an actual collision
        collisionLastFrame = true
        float surfDirection = contactNormal.Dot( Gravity.upNormal )

        if ( surfDirection &lt; armor.JUMPSURFACE_MINDOT ) {
            // code to handle potentially stepping up sheer surfaces
            if ( steppedUp )
                continue
        }
        
        float impactDot = -velocity.Dot( contactNormal )
            
        // take damage if needed
        if ( UnitsToMeters( impactDot ) &gt; armor.MINDAMAGESPEED )
            OnDamage( ( UnitsToMeters( impactDot ) - armor.MINDAMAGESPEED ) * armor.DAMAGESCALE )

        // if we hit a jumpable surface, update the jumpable normal and reset the timestamp
        if ( surfDirection &gt;= armor.JUMPSURFACE_MINDOT ) {
            if ( ( lastJumpableNormalTimestamp &gt; ( Physics.TICKBASE * 1000 ) ) ||
                 ( surfDirection &lt; lastSurfDirection ) ) {
                lastSurfDirection = surfDirection
                lastJumpableNormalTimestamp = 0
                lastJumpableNormal = contactNormal
            }
        }
        
        // do some voodoo for tribes collision adjustments and timeslices
        int impactIterations = ceil( duration / sliceTime )
        float fullMotionTime = sliceTime * ( impactIterations - 1 ) 
        float fixupTime = duration - fullMotionTime
        position = originalPosition + ( velocity * fullMotionTime )

        // bounce
        Vector3 bounce = ( contactNormal * ( impactDot + MetersToUnits( Physics.ELASTICITY ) ) )
        velocity += bounce

        // readjust position based on bounced velocity
        position = Physics.Translate( position, position + ( velocity * fixupTime ) )

        // only update friction on upward facing surfaces
        if ( surfDirection &gt; 0 ) {
            currentFriction = surfDirection

            if ( crawledToStop &amp;&amp; ( velocity &lt; MetersToUnits( Physics.MINSPEED ) ) ) {
                velocity = Vector3( 0, 0, 0 )
                position = originalPosition
                break
            }
        }
    }

    if ( bumps &gt;= maxBumps ) {
        // Tribes sets the velocity to 0 here, this is where skibugs happen
    }
    
    if ( collisionLastFrame ) 
        currentFriction = Min( Max( currentFriction, decayFriction ), 1 )
        
    return ( collisionLastFrame )
}</pre>
<h4>Notes</h4>
<p>Ski bugs are caused when the translation loop exceeds the maximum number of collisions. When this happens, Tribes zeros the player&#8217;s velocity as it is having trouble successfully moving. I think there is something in the velocity <em>bounce</em> that occasionally causes the translation loop to get stuck running in to the surface over and over with no change in velocity. When this happens, there is obviously no right answer as to what to do, but zeroing the velocity is fairly annoying answer. I&#8217;ve found that just ignoring the situation and hoping the next tick results in the player getting dislodged appears to work much better.</p>
<p>Also note that I keep forgetting to add constants (MINDAMAGESPEED and DAMAGESCALE in this post) and need to update the original post to include them. Since nobody is reading this and I am taking a while in getting it together, I do not think anyone will mind.</p>
<h4>Tribes 1 Physics Series</h4>
<ul>
<li>Part One: <a href="https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/">Overview</a></li>
<li>Part Two: <a href="https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/">Movement</a></li>
<li>Part Three: <a href="https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/">Collision</a></li>
<li>Part Four: <a href="https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/">Explosions</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Tribes 1 Physics, Part Two: Movement</title>
		<link>https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/</link>
					<comments>https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Sun, 24 Feb 2008 16:48:55 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Tribes]]></category>
		<category><![CDATA[tribes physics]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=19</guid>

					<description><![CDATA[This article covers the movement physics of Tribes 1, i.e. jumping, jetting, and ground movement/friction. These account for ~90% of the &#8220;Tribes&#8221; feeling, although even 90% will still feel wrong to anyone who knows the authentic feel well. There will be some variables which are only set in the Collision code, but there shouldn&#8217;t be [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>This article covers the movement physics of Tribes 1, i.e. jumping, jetting, and ground movement/friction. These account for ~90% of the &#8220;Tribes&#8221; feeling, although even 90% will still feel wrong to anyone who knows the authentic feel well. There will be some variables which are only set in the Collision code, but there shouldn&#8217;t be any confusion as to what they do. <span id="more-19"></span></p>
<h4>Movement Code</h4>
<p>There are a few spots where Tribes took shortcuts with it&#8217;s math and assumed that gravity would always be &#8220;0 0 -X&#8221;, saving a couple multiplies on dots and such. I&#8217;ve replaced these spots to be gravity agnostic as I don&#8217;t think the CPU savings are that big and they make the code difficult to understand. It shouldn&#8217;t be hard to &#8220;re-optimize&#8221; if you feel the need. Dot products will be a .Dot method because overloaded multiplication operators confuse me.</p>
<h5>Player.Tick</h5>
<p>Player.Tick starts off by taking the user&#8217;s movement input (left, right, forward, back) and creating the speed vector for walking and direction vector for jumping and jetting. This is pretty basic and there is nothing out of the ordinary here.</p>
<pre class="brush: cpp; title: ; notranslate">Player.Tick( Move move, int tickLenMs ) {
    float tickLen = ( 1000 / tickLenMs )

    float maxSpeed = MetersToUnits( armor.WALKSPEED )
    float forwardSpeed = MetersToUnits( armor.WALKSPEED ), sideSpeed = MetersToUnits( armor.WALKSPEED - 1 )

    move.speed = Vector3( ( move.right - move.left ) * forwardSpeed, ( move.forward - move.back ) * sideSpeed, 0 )
    if ( move.speed.Length &gt; maxSpeed )
        move.speed *= ( maxSpeed / move.speed.Length )

    move.speed = self.ToWorldSpace( move.speed )
    move.direction = move.speed.Normalize
}
</pre>
<p>After this, the Player energy is updated, we check lastJumpableNormalTimestamp to see if a jump should be allowed, and then do the jumping, jetting, and walking. Most of the real work takes place in Jump, Jet, and Friction, so the tick function is fairly sparse.</p>
<p>A few things to note:</p>
<ul>
<li>Tribes lets you jump up to 256ms after your last ground contact, allowing you to jump smoothly through little bumps and such where you technically leave the ground, but don&#8217;t really appear to.</li>
<li>Tribes handles jetpack energy a little differently, i.e. once you get to around 5% of your jets, they cut off and recharge a little causing the jets to stutter. I haven&#8217;t worked this part out yet, but may re-edit this section if I do.</li>
<li>Tribes applies gravity <em>constantly</em>, it is not hacked off when you are resting on a surface.</li>
<li>JETENERGY_CHARGE equals &#8220;8 + 3&#8221; with the &#8220;+ 3&#8221; being the recharge boost from an energy pack.</li>
</ul>
<pre class="brush: cpp; title: ; notranslate">    bool isJetting = ( move.jetting &amp;&amp; ( energy &gt; 0 ) )
    bool isJumping = ( move.jumping &amp;&amp; ( lastJumpableNormalTimestamp &lt; Physics.MAXJUMPTICKS ) )

    // jump 
    if ( isJumping )
        velocity += Jump( move.direction )
    crawlToStop = ( velocity.Length &lt; MetersToUnits( Physics.CRAWLTOSTOP ) )

    // jets and acceleration
    accel = Gravity.force
    energy += ( armor.JETENERGY_CHARGE * tickLen )
    if ( isJetting ) {
        accel += Jet( move.direction, tickLen )
        energy -= ( armor.JETENERGY_DRAIN * tickLen )
    }
    energy.Clamp( 0, armor.MAXENERGY )
    velocity += ( accel / tickLen )

    // walking and friction
    if ( collisionLastTick )
        velocity += Friction( move.speed, tickLen )

    // update jumpableNormal timestamp and try to move
    lastJumpableNormalTimestamp += tickLenMs
    /* position, velocity = UpdatePosition( tickLen ) */
}  

&amp;#91;/sourcecode&amp;#93;




&lt;h5&gt;Player.Jump&lt;/h5&gt;




Player.Jump( Vector3 moveDirection ) {
    // need another ground contact before we can jump again
    lastJumpableNormalTimestamp = Physics.MAXJUMPTICKS

    // jump up
    float surfaceDirection = lastJumpableNormal.Dot( Gravity.upNormal ) 
    float impulse = MetersToUnits( armor.JUMPIMPULSE / armor.MASS )
    Vector3 jump = ( surfaceDirection * impulse ) * Gravity.upNormal 

    // if we&#039;re moving away from the surface, jump away
    float orientation = lastJumpableNormal.Dot( moveDirection )
    if ( orientation &gt; 0 ) 
        jump += ( impulse * orientation ) * moveDirection

    return ( jump )
}
</pre>
<h5>Player.Jet</h5>
<p>Side jets only kick in if the player is holding down a movement key and it&#8217;s been longer than MAXJUMPTICKS since the last ground contact. Since jumping sets lastJumpableNormalTimestamp to the limit, jumping and jetting results in side jets being enabled immediately, while simply holding down your jets on the ground will give a little startup time of full jets regardless of whether a direction key is down.</p>
<pre class="brush: cpp; title: ; notranslate">Player.Jet( Vector3 moveDirection ) {
    float forwardVelocity = MetersToUnits( armor.JETFORWARD )
    float jetForce = MetersToUnits( armor.JETFORCE / armor.MASS )

    if ( ( lastJumpableNormalTimestamp &gt;= Physics.MAXJUMPTICKS ) &amp;&amp; ( moveDirection.Length != 0 ) ) {
        float sidePower
        float orientation = velocity.Dot( moveDirection )
        if ( orientation &gt; forwardVelocity )
            sidePower = 0
        else if ( orientation &lt; 0 )
            sidePower = armor.JETSIDEFORCE
        else
            sidePower = ( 1 - ( orientation / forwardVelocity ) )

        sidePower = Min( sidePower, armor.JETSIDEFORCE )
        Vector3 sideForce = ( sidePower * jetForce ) * moveDirection
        Vector3 upForce = ( ( 1 - sidePower ) * jetForce ) * Gravity.upNormal 
        return ( upForce + sideForce )       
    } else {
        // straight up, full jets
        return ( jetForce * Gravity.upNormal ) 
    }
}
&amp;#91;/sourcecode&amp;#93;




&lt;h5&gt;Vector.ProjectOntoPlane&lt;/h5&gt;

This is needed for the gravity agnostic Friction function. I don&#039;t know how common it is.




Vector3.ProjectOntoPlane( Vector3 normal ) {
    this -= ( this.Dot( normal ) * normal ) )
}
</pre>
<h5>Player.Friction</h5>
<p>Multiplying GROUNDTRACTION by currentFriction is unfortunately not the magical &#8220;Friction = 0&#8221; that supposedly causes skiing. currentFriction is decayed every tick when there hasn&#8217;t been a ground contact, resulting in the ability to jet and slide against walls and ceilings without being slowed down by the contact friction.</p>
<p>ProjectOntoPlane is probably not needed since the player should always be oriented so the move will never include a component not in the gravity plane, but it doesn&#8217;t hurt to include it.</p>
<pre class="brush: cpp; title: ; notranslate">Player.Friction( Vector3 moveSpeed, float tickLen ) {
    Vector3 dampen = ( moveSpeed - velocity )
    dampen.ProjectOntoPlane( Gravity.downNormal )

    float traction = Min( currentFriction * armor.GROUNDTRACTION, 1 )
    float force = ( MetersToUnits( armor.GROUNDFORCE / armor.MASS ) * traction * tickLen )
    if ( dampen.Length &gt; force )
        dampen *= ( force / dampen.Length )
    else
        crawlToStop = true

    return ( dampen )
}
</pre>
<h4>Tribes 1 Physics Series</h4>
<ul>
<li>Part One: <a href="https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/">Overview</a></li>
<li>Part Two: <a href="https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/">Movement</a></li>
<li>Part Three: <a href="https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/">Collision</a></li>
<li>Part Four: <a href="https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/">Explosions</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Tribes 1 Physics, Part One: Overview</title>
		<link>https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/</link>
					<comments>https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Thu, 21 Feb 2008 04:04:35 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Tribes]]></category>
		<category><![CDATA[tribes physics]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=18</guid>

					<description><![CDATA[Games have been trying replicate the feel of Tribes 1 for almost as long as it&#8217;s been out (Tribes 2 started development in mid-1999) and every single one of them has failed, usually miserably. Tribes 2 physics are an abomination, although in hindsight it should have come as no surprise after the Base+ mod Dynamix [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Games have been trying replicate the feel of Tribes 1 for almost as long as it&#8217;s been out (Tribes 2 started development in mid-1999) and every single one of them has failed, usually miserably.</p>
<ul>
<li>Tribes 2 physics are an abomination, although in hindsight it should have come as no surprise after the <a href="http://www.gamers.org/pub/idgames2/planetquake/planetstarsiege/tribes/mods/plus.zip">Base+ mod</a> Dynamix play-tested in Tribes 1 to massive disdain. It&#8217;s as if they were trying to build on the success of Tribes 1 when it was 2 weeks old, not 2 years. Unfortunately for the majority of the community not in the beta, we didn&#8217;t find this out until after the game was paid for. Further mods such as Base++, Team Rabbit 2, and Classic attempted to rectify the situation yet were still only a pale ghost of Tribes 1.</li>
<li><a href="http://legendsthegame.net/">Legends</a> has always felt wrong despite how often they tweaked and twiddled the physics and <a href="http://www.tribalwar.com/forums/showthread.php?p=9349485#post9349485">boasted of having the original physics source code</a>. If they did have the source, they either didn&#8217;t know how to implement it or didn&#8217;t have enough of the source to properly replicate all of the required physics.</li>
<li>Tribes Vengeance is so far removed from the feel of Tribes that it shouldn&#8217;t even enter the discussion. Jetting is wrong, air movement shouldn&#8217;t even exist, collisions are wrong, and skiing is a sick joke. I can only hope KineticPoet remembered what used to be and silently winced every time he sat down to work on the game.</li>
<li>The yet-to-be-released <a href="http://pc.ign.com/objects/142/14228914.html">Fallen Empire: Legions</a> appears to be following the &#8220;We&#8217;re not a Tribes 1 clone, so let&#8217;s make wacky changes to ram that home&#8221; mantra. Ideas like 6 way jetting (jetting down while in the air and laterally while on the ground), non-friction sliding a-la T:V, jetpack overdrive, a charge up sniper rifle, etc., sound like they could easily alter the game beyond good taste.</li>
</ul>
<p>What all of these games ostensibly want is to appeal to Tribes 1 players, yet they attempt to accomplish this by using a different and/or completely arbitrary physics system, adding something that resembles a jetpack and skiing and hoping everyone likes it. While I don&#8217;t know if a carbon copy of Tribes 1 on a modern engine would be a success, I do know that almost any Tribes 1 veteran will be unsatisfied with any Tribes style game that does not replicate the feel of Tribes 1 regardless of how often the developers hide behind the claim of &#8220;not Tribes 1&#8221;. </p>
<p>These articles will solve that problem. I will provide everything needed for a 99% re-creation of the Tribes 1 physics on any 3d engine. There are a few pieces to the puzzle so I&#8217;ll be breaking the topics in to separate articles for movement, collision, and explosions. This article will go over the basics of the engine and document the structures and constants I&#8217;ll be using.<span id="more-18"></span></p>
<h4>Basics</h4>
<p>To start off, all units will be in <strong>meters</strong>, the default unit of Tribes. You will need to provide a separate function to convert the Tribes meters to your engine&#8217;s native units, e.g. if 1 unit in your engine of choice is roughly equal to an inch, you will need to convert from Tribes meters to inches, i.e. multiply ~39.37. This will ensure that the authentic Tribes 1 constants are being used and that nothing has been messed up to due to being mis-scaled by hand. I will use <strong>MetersToUnits</strong> and <strong>UnitsToMeters</strong> to indicate when a conversion needs to be made.</p>
<p>Tribes runs at 31.25 ticks a second, or 0.032s per tick. Altering the ticks per second <strong>will</strong> result in slightly different physics as the gravity is accumulated based on the tick length while jumping is a singular impulse, so as the tick length grows, gravity slowly subsumes the jump impulse. There are other less obvious calculations based on the tick length which will be altered as well; some of these can be accounted for, some not.</p>
<p>The coordinate system is Z up, and Vectors are assumed to have overloaded operators.</p>
<p>All code examples will be in a pseudo C-like language and should be easy to translate in to any engine.</p>
<h5>Physics Workflow (details omitted)</h5>
<pre class="brush: cpp; title: ; notranslate">Tick( Move move, float ticklen ) {
    if ( jumping and canJump )
        velocity += Jump( move.direction )

    accel = Gravity.force
    if ( jetting )
        accel += Jet( move.direction )

    velocity += ( accel / ticklen )
    if ( collisionLastTick )
        velocity += Friction( move.speed, ticklen )

    position, velocity = UpdatePosition( ticklen )
}</pre>
<p>There is nothing special in Tribes 1 physics, skiing is not achieved by &#8220;Friction = 0&#8221;, and the only feature an engine needs is the ability to properly detect collisions. There are a lot of nuances required to achieve a simulation that doesn&#8217;t feel subtly wrong, but none are of the earth-shatteringly unique variety that many claim only the Tribes/Torque engine can replicate. They are, however, nuances that you are highly unlikely to match with pure guesswork.</p>
<h5>Structures</h5>
<p>These are the structures and values I will be using for detailed explanations of the physics workflow. Don&#8217;t worry if you don&#8217;t know what a value does just yet.</p>
<pre class="brush: cpp; title: ; notranslate">Gravity {
    Vector3 force = ( 0, 0, -20 )
    Vector3 upNormal = -force.Normalize
    Vector3 downNormal = force.Normalize
}

Physics {
    float TICKBASE = 0.032
    float ELASTICITY = 0.001
    float CRAWLTOSTOP = 0.1
    float MINSPEED = 0.75
    float FRICTIONDECAY = 0.6
    int MAXJUMPTICKS = 256
}

LightArmor : Armor {
    float MASS = 9
    float GROUNDFORCE = 9 * 40
    float GROUNDTRACTION = 3
    float WALKSPEED = 11
    float JUMPIMPULSE = 75
    float JUMPSURFACE_MINDOT = 0.2

    float MINDAMAGESPEED = 25
    float DAMAGESCALE = 0.005

    float JETFORCE = 236
    float JETSIDEFORCE = 0.8
    float JETFORWARD = 22
    float MAXENERGY = 60
    float JETENERGY_DRAIN = 25
    float JETENERGY_CHARGE = 8 + 3

    float BOX_WIDTH = 0.5
    float BOX_DEPTH = 0.5
    float BOX_HEIGHT = 2.3
}

Player {
    Armor armor
    Vector3 position, velocity
    float energy

    bool crawledToStop
    bool collisionLastTick
    Vector3 lastJumpableNormal
    int lastJumpableNormalTimestamp
    float currentFriction
}
</pre>
<h4>Tribes 1 Physics Series</h4>
<ul>
<li>Part One: <a href="https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/">Overview</a></li>
<li>Part Two: <a href="https://floodyberry.wordpress.com/2008/02/24/tribes-1-physics-part-two-movement/">Movement</a></li>
<li>Part Three: <a href="https://floodyberry.wordpress.com/2008/04/11/tribes-1-physics-part-three-collision/">Collision</a></li>
<li>Part Four: <a href="https://floodyberry.wordpress.com/2008/04/29/tribes-1-physics-part-four-explosions/">Explosions</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/02/20/tribes-1-physics-part-one-overview/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Writing a (Tribes 1) Master Server</title>
		<link>https://floodyberry.wordpress.com/2008/02/15/writing-a-tribes-1-master-server/</link>
					<comments>https://floodyberry.wordpress.com/2008/02/15/writing-a-tribes-1-master-server/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Fri, 15 Feb 2008 15:59:10 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tribes]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[master server]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=16</guid>

					<description><![CDATA[While I wrote this in September 2007, for various reasons I did not get around to putting the finishing touches on it. Please pretend you&#8217;re reading it then and not now! After the hubbub over Sierra&#8217;s announcement that they were ceasing multiplayer support for Tribes 1 and the resulting scramble to locate a replacement master [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><em>While I wrote this in September 2007, for various reasons I did not get around to putting the finishing touches on it. Please pretend you&#8217;re reading it then and not now!</em></p>
<p>After the hubbub over Sierra&#8217;s <a href="http://www.sierra.com/en/home/news/product_news/071607_-_sierra_heritage.html">announcement</a> that they were ceasing multiplayer support for Tribes 1 and the resulting scramble to locate a replacement master server, I decided to give a shot at writing one. The required feature set appeared simple enough to only take a week or so to implement but with enough gotchas to keep it suitably interesting. While I only had a vague idea of what was required, I got a jump start on proper design by finding <a href="http://www.gamasutra.com/features/20000511/bernier_01.htm">Half-Life and Team Fortress Networking: Closing the Loop on Scalable Network Gaming Backend Services</a> by Yahn W. Bernier, an article detailing the design, implementation, and potential problems of the Half Life master server. Even though some of the topics did not apply to the Tribes 1 requirements, e.g. I can&#8217;t alter the client&#8217;s behavior to auto rate-limit the server list transmission, the article was still quite valuable and an interesting read even if you aren&#8217;t implementing a master server. <span id="more-16"></span></p>
<h4>Getting Started</h4>
<p>My initial server was as basic as you can get: a hash table of servers behind a udp socket which wakes up periodically to time out servers. Tribes servers do not send a &#8220;going offline&#8221; packet, but as their heartbeat period is every 2 minutes the server will not remain in the list for long.</p>
<p>If the intended environment was a closed setting with a limited number of servers to track, this would be more than sufficient, but in the real world it is vulnerable to many issues and attacks, intentional or otherwise.</p>
<h4>Issues and Attacks</h4>
<p><strong>Bogus Servers</strong>: The ability to add bogus servers is probably the most damaging problem due to the ability to inflate the server list which makes it possible to easily saturate the master server&#8217;s upload by requesting the server list repeatedly. The two ways of adding bogus servers are either by IP spoofing or simply sending thousands of keepalives from your IP with different ports. The Half Life Networking article goes in to this problem in depth and offers the solution of a challenge-response system where the master server, on receiving a heartbeat, sends a random value to the server and only allows the heartbeat to be registered if the server sends the correct value back.</p>
<p>While the challenge/response system solves the problem of IP spoofing completely, it is still trivial to listen and respond to the challenges on your real IP. To defeat this attack, it is necessary to limit each IP to a certain number of registered servers. This way, even if you can intercept and respond to 20,000 challenges, only X will be accepted and the server list will be no worse for the wear. To be honest, limiting an IP to a low number of servers, say 3-5, should be in place regardless of the chance for spam. The only reason to run multiple servers on a single IP is either NAT or that the additional servers are backups/rarely used. Server CPU lag is one of the worst experiences to have online, although many mods run so poorly they tend to anticipate this fact and over-compensate with ridiculous weapons and items which leave skill completely out of the equation. That is a topic for another day though.</p>
<p>Of note is the fact that while Tribes network protocol does include a sequence number which can be used as a challenge, it is only 16 bits wide. To prevent brute force attacks (however unlikely), the challenge-response value should have a timeout of a few seconds at most.</p>
<p><strong>Upload Starvation</strong>: If an IP is spamming list requests to the master server, it might be possible to saturate the master server&#8217;s upload even with a relatively small server list. I wanted to be able to address the problem of spamming requests without requiring human intervention, but at the same time not penalize legitimate users who may click the refresh button a few times too often or have multiple players behind NAT.</p>
<p>The solution, ironically, came from Tribes. I implemented a penalty per IP system similar to the in-game chat spam penalty. Each request accrues a certain amount of penalty, and when the penalty reaches a certain limit the master server stops responding to that IP. The penalty is decreased by 1 for each second that passes, allowing the client to eventually access the master again. I also added a maximum penalty cap (currently at 10 seconds) so that bans will be over fairly quickly once the IP ceases to spam.</p>
<p><strong>Unintentional flooding</strong>: Because Tribes has no auto-rate limiting mechanism to control the server list download speed, it&#8217;s possible the master server could either upload the server list faster than the client can handle or saturate it&#8217;s own upload by firing off too many packets at once when multiple requests come in. The obvious solution is for the master server to throttle it&#8217;s upload, i.e. queuing up packets instead of sending them off instantly. While a simple rate limited FIFO queue would keep the server&#8217;s upload from becoming saturated, it would also mean that after a certain point the packets on the tail end of a large queue would be timed out by the client before they had a chance to arrive. This means rate limiting needs to be done <em>per-connection</em> and not globally.</p>
<p>Tribes, however, throws a wrench in to how low you can rate limit a connection. When the first packet of a master server response arrives, Tribes creates X pending &#8220;ping&#8221; responses to wait for, where X is the number of packets left in the master server response. Because both the master server list request and server ping packets are the same (\x10\x03), Tribes piggybacks the master server list request in the server pending ping list and simply re-pings any packet in the list which times out. Unfortunately, the timestamps for a particular set of master server response packets are <em>never updated</em> when succeeding packets come in, meaning that if Tribes does not receive <em>every</em> master server packet within $pref::pingTimeoutTime milliseconds (default 900ms), it sends a new request for each remaining packet in the list.</p>
<p>So lets say the server list contains 3000 servers, and the master server batches 64 servers per packet. This would result in 47 packets at around ~450 bytes each, or 21k of data. If the master server uploads at 4k/s to the client, only 4k*0.9s = 3.6k of data will make it to the client before the remaining 38 packets are timed out. Tribes would then see 38 &#8220;pings&#8221; that timed out and re-ping each one, updating their packet keys and timestamps so that the packets still coming in from the previous request would be discarded. If Tribes hits $pref::pingRetryCount on any single master server packet, it will decide it can&#8217;t contact a master server and either move on to the next master or pop up an error box. This unfortunately means the per-client rate limit has to be set high enough to make sure the server list can be transmitted within a couple seconds at most, or 900ms to be safe. Assuming a maximum of 500 servers, or ~4k of data, 5k/s per client should be a decent limit.</p>
<p>Due to a poor choice of data structures, Tribes itself limits how large the list can grow. The server list and pending ping list are stored in vectors which grow by 5 items at a time!, leading to tons of potential copying on vector resizes and painful O(N) lookups. When the &#8220;to ping&#8221; list reaches ~6000 servers, Tribes locks up for longer than I care to wait. This is exacerbated when you raise $pref::pingTimeoutTime to accommodate larger server lists, leading to a realistic ceiling of around 4000 servers regardless of the timeout bug.</p>
<h4>Unresolved Attacks</h4>
<p>Because Tribes has no challenge-response mechanism available for server list requests, there is nothing to be done about Upload Starvation by IP spoofing. Please try not to annoy anyone who has the ability to spoof and the desire to spam your master server!</p>
<h4>Mirrors</h4>
<p>I thought about doing something with mirrors, but there really is no good reason to bother.</p>
<p>1. CPU load is a non-issue. Even if there were 50,000 live servers sending heartbeats every 2 minutes, that&#8217;s only 415 heartbeats a second. A heartbeat requires 1 hashtable lookup for the IP penalty, 1 hashtable lookup for the server table, and 3 hashtable lookups for the pending servers table if the server doesn&#8217;t exist. A worst case of 5 hash table lookups * 415 = 2075 hashtable lookups a second which would not even register on a load monitor.</p>
<p>Using a separate process to spam my master with heartbeats, I can get up to ~50,000 heartbeats a second without sending a challenge packet and ~35,000 heartbeats sending the challenge (and using ~1000kb/s up in the process). Using a separate machine to spam heartbeats peaks at around ~14,000 a second with around ~30% CPU load for the master server.</p>
<p>A &#8220;realistic&#8221; test of 18,000 servers, 22 server list requests a second, and 450 heartbeats a second resulted in ~3-10% CPU load and 2,800 kb/s upload. Memory usage peaked at around 40mb, largely due to the 530 concurrent 120k server lists being served from memory at 5kb/s. Reducing the server count to 1,000 while keeping the requests and heartbeats the same results in no measurable CPU load and 900k peak memory usage.</p>
<p>2. Bandwidth, while an issue with a community supporting 50,000 servers, is not an issue with the Tribes community.</p>
<ul>
<li>There are currently 121 active servers in the current master list.</li>
<li>According to archive.org&#8217;s snapshot of gamespy&#8217;s <a href="http://web.archive.org/web/20040612064055/http://archive.gamespy.com/stats/">stats page</a>, Tribes only had ~250 servers up in July 2004.</li>
<li>Going back even farther is one of Tim Sweeney&#8217;s <a href="http://www.team5150.com/~andrew/sweeney/tims_news_1999.html#d19991002">old news posts</a> from October 1999, showing 589 servers during Tribes&#8217; heyday.</li>
</ul>
<p>Lets do the math:</p>
<pre class="brush: cpp; title: ; notranslate">        Servers    Bytes / List     Req/s 40kb up   160kb up
1999        589            4323              9.47      37.90
2004        250            1950             21.01      84.02
2007        121            1047             39.12     156.49</pre>
<p>Even a crappy cable modem can handle 39 reqs/s with the current list, and a T1 could do just as well with the server count from 1999. Obviously it makes more sense to find a host that will stay up than to make a tangled net of mirrors. There are also other problems with unorganized mirrors such as all of the mirrors a server reports to going down and the fact that the Tribes client queries mirrors sequentially instead of randomly.</p>
<p>If a host can&#8217;t be found that is guaranteed to be up, then finding 5 such hosts and needlessly complicating the master server isn&#8217;t going to make the system more robust.</p>
<h4>Code!</h4>
<p>The only thing I don&#8217;t really like about the current code is the packet queuing. While the current server can obviously scale quite high, it should be possible to construct packets on the fly instead of batching them up in memory. The problem to be solved is how to keep multiple iterators in a hash table which can have elements added/removed at any time, and since the master has to tell Tribes how many packets it will be sending, to not send any additional servers which are added after the time of the list request. I have some ideas, but I should probably post this first instead of continuing to put it off.</p>
<p>The code is cross-platform, although I don&#8217;t have anything other than Linux to test on so you will probably need to jump through some hoops to compile on BSD or OSX.</p>
<p>All of the tunable parameters are at the top of t1master.cpp and should be fairly self explanatory. I didn&#8217;t want any external dependencies so the MOTD is &#8220;hardcoded&#8221;, although you can pass it on the command line. I also didn&#8217;t see a point in backing up the server list at any point since the list will fully regenerate itself in 2 minutes. Note that I do randomize the hash seed so even if a spoofer floods the server with bogus IPs, he won&#8217;t be able to logjam the hash tables with collisions!</p>
<p>t1spam.cpp is the program I used for stress testing by hammering the server with heartbeats and listreqs. You should see the lines to comment/uncomment in t1master.cpp(masterserver::process) and optionally in t1master.cpp(main) to simulate random request sources to get realistic loads for the hash tables and penalties.</p>
<ul>
<li>GitHub Repo: <a href="https://github.com/floodyberry/t1master">t1master</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2008/02/15/writing-a-tribes-1-master-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>C++ Templates and Class Inheritance</title>
		<link>https://floodyberry.wordpress.com/2007/05/17/c-templates-and-class-inheritance/</link>
					<comments>https://floodyberry.wordpress.com/2007/05/17/c-templates-and-class-inheritance/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Thu, 17 May 2007 06:03:31 +0000</pubDate>
				<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[templates]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=14</guid>

					<description><![CDATA[The following code is not legal C++:

[sourcecode language='cpp']
template 
struct A {
	void f() {}
	type mX;
};

template 
struct B : public A {
	void g() { mY = ( mX ); f(); }
	type mY;
};
[/sourcecode]

The best part is that unless you know the obscure reason why it is not legal, it appears legal and might even compile and run perfectly depending on which compiler you're using. Not surprisingly, that is exactly how I ran in to it. I was doing templated class inheritance and thought I was in the clear because everything ran fine with MSVC7.1 and ICC 9, but when I belatedly tried to compile with g++ 3.4.4, I ran in to the following errors..]]></description>
										<content:encoded><![CDATA[<p>The following code is not legal C++:</p>
<pre class="brush: cpp; title: ; notranslate">
template &lt; class type &gt;
struct A {
	void f() {}
	type mX;
};

template &lt; class type &gt;
struct B : public A&lt;type&gt; {
	void g() { mY = ( mX ); f(); }
	type mY;
};
</pre>
<p>The best part is that unless you know the obscure reason why it is not legal, it appears legal and might even compile and run perfectly depending on which compiler you&#8217;re using. Not surprisingly, that is exactly how I ran in to it. I was doing templated class inheritance and thought I was in the clear because everything ran fine with MSVC7.1 and ICC 9, but when I belatedly tried to compile with g++ 3.4.4, I ran in to the following errors: <span id="more-14"></span></p>
<blockquote>
<div>tmpl.cpp: In member function `void B&lt;type&gt;::g()&#8217;:<br />
tmpl.cpp:9: error: `mX&#8217; undeclared (first use this function)<br />
tmpl.cpp:9: error: (Each undeclared identifier is reported only once for each function it appears in.)<br />
tmpl.cpp:9: error: there are no arguments to `f&#8217; that depend on a template parameter, so a declaration of `f&#8217; must be available<br />
tmpl.cpp:9: error: (if you use `-fpermissive&#8217;, G++ will accept your code, but allowing the use of an undeclared name is deprecated)</div>
</blockquote>
<p>What the who? Why can&#8217;t it find mX or f? How are you supposed to inherit templated classes in g++? Why does it work on some compilers and not others? Is this a bug? The answer is C++ Standards and in this case, gcc 3.4. It didn&#8217;t take me long to find a response to this exact same problem on the gcc mailing list from 2004:</p>
<p><a href="http://gcc.gnu.org/ml/gcc-help/2004-04/msg00382.html">re: gcc 3.4 template problem</a></p>
<blockquote>
<div>This happens because gcc 3.4 now implements two-phase name lookup, see <a href="http://gcc.gnu.org/gcc-3.4/changes.html">http://gcc.gnu.org/gcc-3.4/changes.html</a> and page down until you see the 2nd example in the C++ section, which is much like yours.</p>
<p>Also see DR 213 <a href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#213">http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#213</a> whose resolution adds:</p>
<blockquote>
<div>In the definition of a class template or a member of a class template, <strong>if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup</strong> either at the point of definition of the class template or member or during an instantiation of the class template or member.</div>
</blockquote>
<p>to the standard.</p>
<p><strong>You can also use &#8216;this-&gt;x&#8217; to make x dependent, making the implementation to look into the base class.</strong></div>
</blockquote>
<p>The C++ FAQ Lite has some further information on the subject with the understandable disclaimer &#8220;This might hurt your head; better if you sit down&#8221;: <a href="http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19">[35.19] Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?</a>.</p>
<p>While I can understand what the standard is saying and the consequences of it, I can&#8217;t figure why some compilers still allow the now illegal behavior (leading to portability nightmares if you don&#8217;t know what the heck just broke), and why the intuitive interpretation was made illegal in the first place. Unfortunately, supporting the intuitive version when the standard says the opposite only opens up more opportunities to create non-portable code. While I dislike &#8220;this-&gt;&#8221; litter in my classes, it looks like the cleanest portable solution that doesn&#8217;t open up other issues (such as explicit A&lt;type&gt;:: prefixing which would break virtual functions).</p>
<p>If you haven&#8217;t had enough, try making sense of this thread in comp.lang.c++.moderated: <a href="http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/eb1a641f1807aad0/533e7e39fd887ab4?tvc=1#533e7e39fd887ab4"> Dependent names in templates, or are they?</a> What a horrid little rule.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2007/05/17/c-templates-and-class-inheritance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>UTF-8 Conversion Tricks</title>
		<link>https://floodyberry.wordpress.com/2007/04/14/utf-8-conversion-tricks/</link>
					<comments>https://floodyberry.wordpress.com/2007/04/14/utf-8-conversion-tricks/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Sat, 14 Apr 2007 08:04:03 +0000</pubDate>
				<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[utf-8]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=11</guid>

					<description><![CDATA[UTF-8 is a wonderfully simple encoding format with some very nice properties, but the juggling required to convert to UTF-16, and UTF-32 can be a little tricky and fairly easy to do poorly. This is further compounded by the various error conditions you must keep an eye out for, such as overlong encodings, reserved ranges, [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a> is a wonderfully simple encoding format with some very nice properties, but the juggling required to convert to UTF-16, and UTF-32 can be a little tricky and fairly easy to do poorly. This is further compounded by the various error conditions you must keep an eye out for, such as overlong encodings, reserved ranges, surrogate markers, incomplete sequences, and so on.</p>
<p>These are a couple tricks you can employ to hopefully keep the conversion fast <em>and</em> robust.</p>
<p><span id="more-11"></span></p>
<h4>Tail Length Lookup</h4>
<p>Our first trick is to use a lookup table for the initial byte. This allows you to both a) tell whether the byte is valid (80 to bf and fe to ff are invalid leading bytes, as well as f5 to fd if you don&#8217;t want to handle 5 and 6 byte sequences) and b) determine the number of trailing bytes in the expected sequence. We will also need the length of the sequence to quickly ensure there are enough bytes in left in the input as well as for other upcoming tricks, so this actually results in multiple wins.</p>
<p>If you want to cut down on the table size, you could use 128 values and take (c&lt;&lt;1), or 64 values and take ((c-0x80)&lt;&lt;1), although you&#8217;ll need an extra check for 80-bf with 64 values.</p>
<pre class="brush: cpp; title: ; notranslate">
const UTF32 Replacement = ( 0xfffd );

const unsigned char UTF8TailLengths[256] = {
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
	3,3,3,3,3,3,3,3,4,4,4,4,5,5,0,0
};
</pre>
<pre class="brush: cpp; title: ; notranslate">
UTF32 utf8_to_utf32( UTF8 *&amp;s, const UTF8 *end ) {
	UTF32 c = ( *s++ );
	if ( c &lt; 0x80 )
		return ( c );
	unsigned int tail = ( UTF8TailLengths&amp;#91; c &amp;#93; );
	if ( !tail ) || ( s + tail &gt; end )
		return ( Replacement );
</pre>
<h4>Overlong Encodings and Magic Subtraction</h4>
<p>Once we know the length of the expected sequence, we can attempt to decode it.The basic decoding loop is something like:</p>
<pre class="brush: cpp; title: ; notranslate">
c &amp;= ( 0x3f &gt;&gt; tail );

unsigned int i;
for (  i = 0; i &lt; tail; ++i ) {
	if ( ( s&amp;#91;i&amp;#93; &amp; 0xc0 ) != 0x80 )
		break;

	c = ( ( c &lt;&lt; 6 ) + ( s&amp;#91;i&amp;#93; &amp; 0x3f ) );
}

s += i;
if ( i != tail )
	return ( Replacement );
&amp;#91;/sourcecode&amp;#93;

At the end of decoding, we will still be faced with a problem: How do you tell if it was an overlong encoding? To keep the mapping of UTF-8 to UTF-32 one to one, we are required to reject any encoding that uses more bytes than it requires. Markus Kuhn&#039;s &lt;a href=&quot;http://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c&quot;&gt;utf8_check.c&lt;/a&gt; has a jungle of conditionals to detect the specific lead and tail byte encodings that would indicate an overlong encoding, but this is not something we want to do in our innerloop!

This is where our Overlong Encoding and Magic Subtraction lookup comes in. Since we know the length of the tail, we can create a lookup of the &lt;em&gt;minimum&lt;/em&gt; value a sequence with &lt;em&gt;tail&lt;/em&gt; bytes needs to be.

Magic Subtraction is a side bonus to knowing the length of the tail. With Magic Subtraction, we can skip masking off the lead byte as well as eliminating the &amp;amp;0x3f mask in the innerloop! Magic Subtraction works by accumulating the value of the masked off bits into a single value, and subtracting that value at the end. Because we&#039;re making sure each byte is well formed, we can be sure that the masked off bits will add up to a constant value. I got this trick from &lt;a href=&quot;http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c&quot;&gt;ConvertUTF.c&lt;/a&gt; by Mark E. Davis.

If you want to double check the magic subtraction values, you can calculate them yourself like so: Find the constant value for the lead byte of each sequence, then for each byte in the sequence, shift the value over 6 bits and add 80.
&lt;ul&gt;
	&lt;li&gt;1 tail byte: (c0&amp;lt;&amp;lt;6)+80&lt;/li&gt;
	&lt;li&gt;2 tail bytes: (((e0&amp;lt;&amp;lt;6)+80)&amp;lt;&amp;lt;6)+80&lt;/li&gt;
	&lt;li&gt;3 tail bytes: (((((f0&amp;lt;&amp;lt;6)+80)&amp;lt;&amp;lt;6)+80)&amp;lt;&amp;lt;6)+80&lt;/li&gt;
	&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

struct UTF8Lookup {
	UTF32 mOverlongMinimum, mMagicSubtraction;
} const UTF8Lookups[ 6 ] = {
	{ 0x00000000, 0x00000000 },
	{ 0x00000080, 0x00003080 },
	{ 0x00000800, 0x000E2080 },
	{ 0x00010000, 0x03C82080 },
	{ 0x00200000, 0xFA082080 },
	{ 0x04000000, 0x82082080 },
};
</pre>
<pre class="brush: cpp; title: ; notranslate">
unsigned int i;
for ( i = 0; i &lt; tail; ++i ) {
	if ( ( s&amp;#91;i&amp;#93; &amp; 0xc0 ) != 0x80 )
		break;

	c = ( c &lt;&lt; 6 ) + s&amp;#91;i&amp;#93;;
}

s += i;
if ( i != tail )
	return ( Replacement );

const UTF8Lookup &amp;lookup = UTF8Lookups&amp;#91; tail &amp;#93;;
c -= ( lookup.mMagicSubtraction );
if ( c &lt; lookup.mOverlongMinimum )
	return ( Replacement );
&amp;#91;/sourcecode&amp;#93;
&lt;h4&gt;Tail Byte Error Bits&lt;/h4&gt;
You may have noticed that we are checking every single tail byte to see if it is well formed ( *s &amp;amp; 0xc0 != 0x80 ). Even if we used a switch on &lt;em&gt;tail&lt;/em&gt; to unroll our loop, we would still need to have all the conditionals. The Tail Byte Error Bits trick is what I came up with to remove the checks.

If we have a lookup table that has 1 for invalid tail bytes and 0 for valid bytes, we can accumulate these values in a mask variable which will be non-zero at the end of our decoding loop if any of the tail bytes were invalid. Further more, if we accumulate them so that ( mask = ( mask &amp;lt;&amp;lt; 1 ) | UTFInvalidTailBytes[ s[i] ] ), we can also tell which was the first invalid tail byte by looking at which bits in &lt;em&gt;mask&lt;/em&gt; are set. This allows us to back the source pointer up to the last valid byte.

&lt;em&gt;Feb. 27, 2008&lt;/em&gt;: Re-looking at this, I realized you can shrink the table to just 4 values since only the top 2 bits are being checked. This leaves us with ( mask = ( mask &amp;lt;&amp;lt; 1 ) | UTFInvalidTailBits[ s[i]&amp;gt;&amp;gt;6 ] ).


const unsigned char UTF8InvalidTailBits[4] = {
	1,1,0,1,
};

const unsigned int UTF8InvalidOffset[32] = {
	0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
	5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
};
</pre>
<pre class="brush: cpp; title: ; notranslate">
unsigned int mask = ( 0 );
for ( unsigned int i = 0; i &lt; tail; ++i ) {
	c = ( c &lt;&lt; 6 ) + s&amp;#91;i&amp;#93;;
	mask = ( mask &lt;&lt; 1 ) | UTF8InvalidTailBits&amp;#91; s&amp;#91;i&amp;#93;&gt;&gt;6 ];
}

s += tail;
if ( mask ) {
	s -= UTF8InvalidOffset[ mask ];
	return ( Replacement );
}

const UTF8Lookup &amp;lookup = UTF8Lookups[ tail ];
c -= ( lookup.mMagicSubtraction );
if ( c &lt; lookup.mOverlongMinimum )
	return ( Replacement );

&amp;#91;/sourcecode&amp;#93;
&lt;h4&gt;Finishing Up&lt;/h4&gt;
If we made it this far, we can be sure that our UTF-8 sequence is valid. Well, &lt;em&gt;almost&lt;/em&gt; valid. There are still certain UTF-32 values that, even when properly encoded in UTF-8, are still illegal, and must be checked for if you want a robust converter.

The offending values:
&lt;div&gt;
&lt;blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;d800-dfff&lt;/strong&gt;: UTF-16 uses d800-dfff to encode it&#039;s surrogate pairs, i.e. values that don&#039;t fit in to 16 bits. This means UTF-8/UTF-32 are not allowed to encode these values.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;fdd0-fdef&lt;/strong&gt;: This range was added to make your life more difficult.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;xfffe-xffff&lt;/strong&gt;: x ranges from 0 to 10 (hex), so the values to check for are fffe-ffff, 1fffe-1ffff, etc.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&amp;gt; 10ffff&lt;/strong&gt;: 10ffff is the highest Unicode codepoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
The first two ranges can be checked using a subtraction and a compare instead of two compares, a trick I got from uClibc&#039;s &lt;a href=&quot;http://www.uclibc.org/cgi-bin/viewcvs.cgi/trunk/uClibc/libc/misc/wchar/wchar.c&quot;&gt;wchar.c&lt;/a&gt;. The third range can be checked with a simple and.. and compare. The last range (10ffff) is a simple compare.


bool InRange( UTF32 c, UTF32 lo, UTF32 hi ) { return ( (UTF32 )( c - lo ) &lt; ( hi - lo + 1 ) ); }

bool IsSurrogate( UTF32 c ) { return ( InRange( c, 0xd800, 0xdfff ) ); }
bool IsNoncharacter( UTF32 c ) { return ( InRange( c, 0xfdd0, 0xfdef ) ); }
bool IsReserved( UTF32 c ) { return ( ( c &amp; 0xfffe ) == 0xfffe ); }
bool IsOutOfRange( UTF32 c ) { return ( c &gt; 0x10ffff ); }
</pre>
<p>This can be further simplified if you want to make use of a rather excessive lookup table. If you initialize a 32k entry lookup table like so, you can check any value under 10000 with a simple lookup.</p>
<pre class="brush: cpp; title: ; notranslate">
for ( UTF32 c = 0; c &lt; 0x10000; ++c )
	BMPInvalid&amp;#91; c &gt;&gt; 1 ] = ( IsSurrogate( c ) || IsNonCharacter( c ) || IsReserved( c ) );

bool IsInvalidBMP( UTF32 c ) { return ( BMPInvalid[ c &gt;&gt; 1 ] ); }
</pre>
<h4>Cheating</h4>
<p>Ok, all we have to do is paste this all together and we&#8217;ll have a lightning fast UTF-8 to UTF-32 converter, right? Well.. consider the following example: You have a 1000k UTF-8 file which is 90% ASCII that you want converted to UTF-32. Would you rather convert it with a function that takes 30 cycles for an ASCII character and 50 cycles for a multibyte character, or a function that takes 10 cycles for an ASCII character and 90 cycles for a multibyte character?</p>
<p>If you have an input agnostic converter and/or unlucky compiler optimizations, your conversion function can end up looking something like:</p>
<pre class="brush: cpp; title: ; notranslate">
mov esi, [ start ]
mov edi, [ dest ]
cmp esi, [ end ]
jge finished
loop:
	movzx eax, byte ptr [ esi ]
	inc esi
	cmp eax, 80
	jle ascii

	...130 bytes of code to handle multi-byte encodings...

ascii:
	mov [ edi ], eax
	add edi, 4
	cmp esi, [ end ]
	jl loop
finished:
</pre>
<p>Yuck! Instead of a nice tight loop for the easy ASCII case, this will most likely crap all over the cache and slow you down. If you&#8217;re especially unlucky when trusting your compiler to handle templates and functions that should <em>obviously</em> be inlined, you&#8217;ll even end up with a call or two <strong>per character</strong>. Doing a little optimization and tweaking can result in code like:</p>
<p>while ( start < end ) {
	while ( ( *start < 0x80 ) &#038;&#038; ( start < end ) ) {
		*to++ = *start++;
	}
	if ( start < end ) {
	...
	}
}
[/sourcecode]

[sourcecode language='cpp']
mov esi, [ start ]
mov edi, [ dest ]
cmp esi, [ end ]
jge finished
loop:
	movzx eax, byte ptr [ esi ]
	inc esi
	cmp eax, 80
	jge notascii
	mov [ edi ], eax
	add edi, 4
	cmp esi, [ end ]
	jl loop
	jmp finished

notascii:

	...130 bytes of code to handle multi-byte encodings...

	mov [ edi ], eax
	add edi, 4
	cmp esi, [ end ]
	jl loop
finished:
[/sourcecode]

This function should cut through ASCII oriented UTF-8 like butter, even if the multi-byte handling is a little slower than a more optimized converter. This code re-working may have little to no gain if your input is highly varied, but if you have a good idea what you'll be facing, it may be worth it to tweak your functions to the data.


<h4>5 and 6 byte sequences</h4>
<p>The original UTF-8 specification allowed for 5 and 6 byte sequences (up to 31 bits of data), however, only up to 4 byte sequences are valid under <a href="http://www.faqs.org/rfcs/rfc3629.html">RFC 3629</a>. So what do you do with 5 and 6 byte sequences? You can interpret the entire sequence and dump it as a single invalid character, or dump an invalid character for every byte in the sequence. Since the lead byte for 5 and 6 byte sequences (f5-fd) will never appear in <strong>any</strong> 4 byte or shorter sequence, interpreting the sequences as a single (invalid) character appears to make the most sense:</p>
<ul>
<li>If you are not actually processing UTF-8 text, or your input is corrupted, it won&#8217;t matter how you interpret them as any interpretation will produce garbage</li>
<li>If you <em>are</em> processing valid UTF-8 text, they can only appear due to an intentional 5 to 6 byte sequence. While illegal, it still represents a single character, not 5 to 6 invalid characters.</li>
</ul>
<h4>Fin</h4>
<p>dreamprojections&#8217; wonderful <a href="http://code.google.com/p/syntaxhighlighter/">Syntax Highlighter</a> was a contributing factor to the length of this post.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2007/04/14/utf-8-conversion-tricks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Breaking SuperFastHash</title>
		<link>https://floodyberry.wordpress.com/2007/03/29/breaking-superfasthash/</link>
					<comments>https://floodyberry.wordpress.com/2007/03/29/breaking-superfasthash/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Thu, 29 Mar 2007 08:31:40 +0000</pubDate>
				<category><![CDATA[Hashing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[hash]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=7</guid>

					<description><![CDATA[After the problems SuperFastHash had in Hash Algorithm Attacks, I decided to try and break it completely, i.e. generate collisions algorithmically instead of brute forcing them. The attempt was more successful than I had anticipated, although Paul is obviously aware of the weak mixing in the final bits as evidenced by his comment in the [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>After the problems <a href="http://www.azillionmonkeys.com/qed/hash.html">SuperFastHash</a> had in <a href="http://www.team5150.com/~andrew/blog/2007/03/hash_algorithm_attacks.html">Hash Algorithm Attacks</a>, I decided to try and break it completely, i.e. generate collisions algorithmically instead of brute forcing them. The attempt was more successful than I had anticipated, although Paul is obviously aware of the weak mixing in the final bits as evidenced by his comment in the source code, &#8220;Force &#8216;avalanching&#8217; of final 127 bits&#8221;. My favorite collisions encountered would have to be &#8220;10/4 &lt; 3&#8221;, &#8220;10/5 = 2&#8221;, and &#8220;10/6 &gt; 1&#8221;, which have the property of hashing to the same value while being mathematically correct!</p>
<p>As I was writing this, I came up with a way to attack Bob Jenkins&#8217; <a href="http://www.burtleburtle.net/bob/hash/doobs.html">lookup3</a> as well. Unlike SuperFastHash, the lookup3 attack is due to the way the input bytes are being read in and does not indicate a deficiency in the mixing itself. If you are using lookup3 with hash tables, the core function will still be quite safe; it will only need to be modified if you are using it to generate unique 64bit identifiers <em>and</em> the input data could be altered for a malicious purpose.</p>
<p>With that said, let&#8217;s look at the attacks:</p>
<p><span id="more-7"></span></p>
<h4>SuperFastHash</h4>
<p>To begin with, I separated the innerloop in to its 4 steps:</p>
<pre class="brush: cpp; title: ; notranslate">1:	hash  += get16bits (data);
2:	tmp    = (get16bits (data+2) &amp;lt;&amp;lt; 11) ^ hash;
3:	hash   = (hash &amp;lt;&amp;lt; 16) ^ tmp;
4:	hash  += hash &amp;gt;&amp;gt; 11;</pre>
<p>and then ran a couple of known duplicate strings through and printed out the value at each step (input bytes are only consumed in steps 1 and 2):</p>
<blockquote class="fixed-width">
<div>
&#8220;aaaaaaaa&#8221; vs &#8220;aaadadaf&#8221;</p>
<p><strong>aa</strong> 1: 00006169 <strong>aa</strong> 2: 030b6969 3: 62626969 4: 626eb5b6   <strong>aa</strong> 1: 626f<strong>1717</strong> <strong>aa</strong> 2: <strong>61641f17</strong> 3: 76731f17 4: 7681ed7a</p>
<p><strong>aa</strong> 1: 00006169 <strong>ad</strong> 2: 03236969 3: 624a6969 4: 6256b2b6   <strong>ad</strong> 1: 6257<strong>1717</strong> <strong>af</strong> 2: <strong>61641f17</strong> 3: 76731f17 4: 7681ed7a</p>
<p>&#8220;ifkzihfe&#8221; vs &#8220;igdqhtfp&#8221;</p>
<p><strong>if</strong> 1: 00006671 <strong>kz</strong> 2: 03d33e71 3: 65a23e71 4: 65aef2b8   <strong>ih</strong> 1: 65af<strong>5b21</strong> <strong>fe</strong> 2: <strong>66846b21</strong> 3: 3da56b21 4: 3dad1fce</p>
<p><strong>ig</strong> 1: 00006771 <strong>dq</strong> 2: 038b4771 3: 64fa4771 4: 6506e6b9   <strong>ht</strong> 1: 6507<strong>5b21</strong> <strong>fp</strong> 2: <strong>66846b21</strong> 3: 3da56b21 4: 3dad1fce</p>
</div>
</blockquote>
<p>We can see that after round 2 step 1 (2:1) the lower 16 bits of <em>hash</em> are the same, and that after (2:2) all 32 bits of <em>tmp</em> are the same. Looking at step 3 reveals how this creates a collision: <em>hash = (hash &lt;&lt; 16) ^ tmp;</em>. The upper 16 bits of hash are thrown away, leaving the lower 16 bits (which are the same in the observed collisions) and 32 bits of tmp (which is the same in the observed collisions). Thus if after an initial 4 bytes we can find 2 bytes that create the same lower 16 bits in <em>hash</em> at (2:1), and then find the remaining 2 bytes that create the same 32 bits in <em>tmp</em> at (2:2), we have generated a colliding 8 byte string.</p>
<p>This can be further generalized to any string that&#8217;s a multiple of 8 bytes. If, from an initial hash value of X (the length of the string for SuperFastHash), you can find 8 bytes that collide with hash Y, then you simply use Y as the initial hash value and re-work the problem for the next 8 bytes, and so on. This works because SuperFastHash has very poor mixing for last 8 bytes that have been hashed and does not use it&#8217;s avalanching fix-up until it has reached the end of the input.</p>
<h5>Attack</h5>
<p>The attack was fairly straightforward once I identified what needed to be done. After a couple of revisions and refinements, I came up with:</p>
<ol>
<li>Take a source string S that has a length which is a multiple of 8 bytes</li>
<li>Hash S and for each 8 byte sequence, find the values of <em>hash</em> and <em>tmp</em> at steps (2:1) and (2:2)</li>
<li>Hash every permutation of the first 4 bytes of your attack string:
<ul>
<li>Find bytes 5 and 6 for each permutation which generate the lower 16 bits for the constant in (2:1).</li>
<li>Finally find bytes 7 and 8 for which generate the constant in (2:2). If this succeeds, either print the hit or process another 8 bytes until you reach the target length for your source string</li>
</ul>
</li>
</ol>
<p>This will probably not uncover every possible duplicate, especially for keys longer than 8 bytes, but it ran fast enough and generated enough duplicates that I did not need to refine it further.</p>
<h5>Results</h5>
<p>When using an 8 byte source string with all possible characters as input ( bytes 0x00 to 0xff ), <strong>~130,000,000</strong> colliding strings can be found in around 3 minutes. When you restrict the character set to printable charactersI (symbols, numbers, uppercase, and lowercase), anywhere from 10,000 to 200,000 (possibly higher) can be found in a few seconds.</p>
<p>Using a random initial value (keying the hash) reduces the collisions, but does not alleviate them entirely. For example, 108,600 strings were generated that hash to the same value as &#8220;zzzzzzzz&#8221;. When run through a hashtable insertion test with 131072 buckets using &#8220;0xdeadbeef + length&#8221; as the initial value instead of just &#8220;length&#8221;, there were still 3,374,795 compares due to full hash collisions, and the largest bucket had 376 links. By comparison, Bob Jenkins&#8217; lookup3 had 1 compare and 8 links in it&#8217;s largest bucket, and the x31 variant of the Torek/DJB hash had 0 compares and 6 links in it&#8217;s largest bucket. A small win is that increasing the key length does reduce the collisions with a keyed hash: 100,000 strings hashing to the same value as &#8220;zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz&#8221; resulted in only 500,000 compares with the largest bucket containing 158 links.</p>
<h4>lookup3</h4>
<p>The lookup3 attack is very simple and I actually feel dense for not having seen it until now. This is the basic 32bit little endian algorithm (32bit aligned reads) with input lengths assumed to be 24 or larger and a multiple of 12:</p>
<pre class="brush: cpp; title: ; notranslate">1:	a = b = c = ( 0xdeadbeef + len )

2:	for ( ; len &amp;gt; 12; len -= 12, key += 12 ) {
		a += ( key[0] )
		b += ( key[4] )
		c += ( key[8] )
		mix( a, b, c )
	}

3:	c += ( key[8] )
	b += ( key[4] )
	a += ( key[0] )

4:	final( a, b, c )
	
	return ( c );</pre>
<p>mix() and final() mix every bit in a, b, and c very thoroughly, so trying to attack lookup3 algorithmically would be quite futile (for me). However, because every 12 bytes, or 96 bits, of input directly alters every bit of a, b, and c, there is a shortcut: </p>
<ol>
<li>Take any input string and run it through lookup3; record the values of a, b, and c after Step 3</li>
<li>Take your attack string and pad it to be a multiple of 12 bytes long, then add an additional 12 bytes</li>
<li>Run your attack string through lookup3 and stop after Step 2. We should now have the additional 12 bytes remaining to hash</li>
<li>Construct the final 12 bytes so that key[ 8 ] = ( target.c &#8211; c ), key[ 4 ] = ( target.b &#8211; b ), and key[ 0 ] = ( target.a &#8211; a ). The internal state will now match that of the target string before the call to final(), guaranteeing a collision</li>
</ol>
<p>Now, this attack relies completely on knowing what a, b, and c are initialized to at the start of the hash. If you are using lookup3 for hash tables, you should already be initializing a, b, and c to random values to defeat bucket attacks, i.e. attacks searching for keys where the lower 15 to 20 bits match. Even the best algorithm is vulnerable to bucket attacks, so choosing a random initial value should be mandatory no matter what.</p>
<p>However, if you&#8217;re using lookup3 for something like a 64bit unique id or a file checksum, your initial state will need to be static and thus open to attack with this method. I&#8217;m not sure what you could do to get around this safely while retaining lookup3&#8217;s high speed; adding another 32 bits of state that wasn&#8217;t directly altered by the input may help, but where to stick it and how to mix it in isn&#8217;t something I couldn&#8217;t guess at. I&#8217;ve emailed Bob, but I don&#8217;t know if deliberate attacks like this are something he is concerned with. The lookup3 source does state <em>Use for hash table lookup, or anything where one collision in 2^^32 is acceptable.  Do NOT </em>use for cryptographic purposes., so we&#8217;ll see.</p>
<h4>Conclusions</h4>
<p>I already knew SuperFastHash had some peculiar results from my previous tests, and the outcome of this experiment drove the point home. While the offending collisions will not be common (what pathological input is?), the fact that they exist, were so readily obtained, and were still somewhat evident when changing the initial value of the hash suggests that it is probably best to start over from scratch. I should have noticed a problem sooner when SuperFastHash was running in to light collisions in <a href="http://www.team5150.com/~andrew/blog/2007/03/when_bad_hashing_means_good_caching.html">When bad hashing means good caching</a>, and that wasn&#8217;t even an intentional attack. </p>
<p>As far as lookup3, the trivial collisions are disturbing, but they are <em>only</em> a problem if an attacker can craft input for the hash function, and then <em>only</em> when you are using it to generate unique ids. It would be nice to see the issue addressed, though, as lookup3 is still unrivaled in terms of mixing and actually faster than SuperFastHash in some cases.</p>
<h4>Source</h4>
<p>You may download the <a href="http://www.team5150.com/~andrew/blog/files/superfasthash_attack.cpp">SuperFastHash attack source</a> and try it out for yourself. It comes preloaded with attacks against &#8220;********&#8221;, yielding 194 collisions, and &#8220;10/5 = 2&#8221;, yielding my favorite set of collisions. If you want to run it with all possible characters as input, make sure to turn the debug printf off or redirect output to a file; it can take a while to end process a program that has a lot of \x07 bells queued up.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2007/03/29/breaking-superfasthash/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>When Bad Hashing Means Good Caching</title>
		<link>https://floodyberry.wordpress.com/2007/03/07/when-bad-hashing-means-good-caching/</link>
					<comments>https://floodyberry.wordpress.com/2007/03/07/when-bad-hashing-means-good-caching/#comments</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Wed, 07 Mar 2007 18:54:18 +0000</pubDate>
				<category><![CDATA[Hashing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[hash]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=9</guid>

					<description><![CDATA[I was testing various string hashing algorithms on chained hash tables, primarily to look at the bucket distribution and number of key comparisons with both prime and power of 2 sized tables. Each table node was set up to remember it&#8217;s full hash value so bucket collisions would only drop to a key comparison on [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I was testing various string hashing algorithms on chained hash tables, primarily to look at the bucket distribution and number of key comparisons with both prime and power of 2 sized tables. Each table node was set up to remember it&#8217;s full hash value so bucket collisions would only drop to a key comparison on a true key collision. I initially wasn&#8217;t concerned with run times, but I tacked on a timer anyway so I could get a quick metric on how collisions and distribution were affecting performance and wound up running in to a rather odd situation. <span id="more-9"></span> For the purposes of this article, the tables were also pre-sized before inserting keys to avoid resizing overhead.</p>
<p>While I was testing many algorithms, only two are needed for this article: The string hash from <a href="http://www.stlport.org/">STLPort</a> 4.6.2 and Paul Hsieh&#8217;s <a href="http://www.azillionmonkeys.com/qed/hash.html">SuperFastHash</a>. STLPort&#8217;s hash is simply &#8220;hash = ( hash * 5 ) + string[ i ]&#8221; which should be fairly fast but produce weak distribution on large amounts of clustered keys. SuperFastHash should also be quite fast while having much stronger hashing no matter the key size or clustering.</p>
<p>The dataset that caused the problem was a simple 6 character sequential permutation in the form of:</p>
<blockquote>
<div>[ABCDEFGH][EFGHIJKL][IJKLMNOP][MNOPQRST][QRSTUVWX][UVWXYZ01]</p>
<p>e.g.</p>
<p>AEIMQU<br />
AEIMQV<br />
AEIMQW<br />
AEIMQX<br />
AEIMQY<br />
AEIMQZ<br />
AEIMQ0<br />
AEIMQ1<br />
AEIMRU<br />
AEIMRV<br />
AEIMRW<br />
AEIMRX<br />
&#8230;.<br />
HLPTWZ<br />
HLPTW0<br />
HLPTW1<br />
HLPTXU<br />
HLPTXV<br />
HLPTXW<br />
HLPTXX<br />
HLPTXY<br />
HLPTXZ<br />
HLPTX0<br />
HLPTX1</p>
<p>(262144 unique keys in all)</p></div>
</blockquote>
<p>I was hoping to ferret out the weaker algorithms with this dataset and boy did I ever. Almost all the stats were what I expected: STLPort had ~10x bucket density for both prime/pow2 table sizes (i.e. an average of 10 extra links per filled bucket), SuperFastHash had 0.77x for prime and 0.64x for pow2; STLPort had 1.5 million key compares due to full key hashes colliding, SuperFastHash had 0.006 million (6000). Now this is where it got weird: The STLPort powered hash table ran <strong>~55%</strong> faster on my AMD64 3200+ than the SuperFastHash powered hash table. The results were similar on my AMD 1.1ghz TBird with the STLPort hash table running <strong>~36%</strong> faster than SuperFastHash. The raw difference on both CPUs was around the same, 90ms vs 140ms on the AMD64 and 190ms vs 260ms on the Tbird. Something was definitely up.</p>
<p>Initial profiling was not very helpful. The STLPort hash algorithm ran faster than SuperFastHash, but the total difference was a few milliseconds at most even though SuperFastHash&#8217;s weakness is in smaller keys where it can&#8217;t take advantage of it&#8217;s streamlined innerloop. As far as the Insert method for the hash table, the 1.5 million string compares took ~17ms which gave SuperFastHash a slight advantage when checking for duplicates, but even when I stripped out the duplicate checking code (all the keys were unique so it was safe to do so) STLPort still had a healthy advantage.</p>
<p>With the hash functions coming out equal and the duplicate checking code taken out, there really wasn&#8217;t much left to the method at all. The offending statements came down to</p>
<pre class="brush: cpp; title: ; notranslate">node = new Node( key, value, *head, hash );
*head = node;</pre>
<p>which simply allocates a new node with a simple constructor (key, value, next, hash) and points the head of the bucket to our new node. Since the hashtable is using &lt;string *, int&gt; for it&#8217;s key/value pair, this is just couple dword copies to initialize the node and update the bucket list, so how could this be slowing our code down so badly? I suspected the allocator might have something to do with it after noticing that running multiple tests in a single session resulted in increased runtime for each successive test (due to accumulated news/deletes?) for VS7 and to a lesser degree for gcc 3.4.4. I dropped in the <a href="http://www.hoard.org/">Hoard Memory Allocator</a> and while the code sped up a bit and multiple tests were possible in a single run with no degredation, STLPort still held the same lead (STLPort down to 55ms and SuperFastHash down to 105ms). I was about at my wits end when I decided to dump the actual bucket indices for each key to see where they were being placed:</p>
<blockquote>
<div>
<p>STLPort:<br />
273830<br />
273831<br />
273832<br />
273833<br />
273834<br />
273835<br />
273793<br />
273794<br />
273835<br />
273836</p>
<p>SuperFastHash:<br />
4267<br />
391151<br />
77466<br />
272914<br />
376435<br />
77856<br />
225677<br />
489782<br />
292888<br />
97819<br />
9443</p></div>
</blockquote>
<p>Whoops. STLPort&#8217;s bucket accesses were nearly linear and all clustered around the same area (only the middle 1/10th of the buckets were being used), while SuperFastHash&#8217;s accesses were (properly) random across the entire list. STLPort&#8217;s string comparisons were also linearly clustered due to being allocated and inserted in alphabetic order:</p>
<blockquote>
<div>CKKNTX &#8211; CJPNTX<br />
CKKNTX &#8211; CJOTW0<br />
CKKNTX &#8211; CJOSTX<br />
CKKNTY &#8211; CKJTW1<br />
CKKNTY &#8211; CKJSTY<br />
CKKNTY &#8211; CJPPR1<br />
CKKNTY &#8211; CJPOW1<br />
CKKNTY &#8211; CJPNTY<br />
CKKNTY &#8211; CJOTW1<br />
CKKNTY &#8211; CJOSTY<br />
CKKNTZ &#8211; CKJSUU<br />
CKKNTZ &#8211; CKJSTZ<br />
CKKNTZ &#8211; CJPNUU<br />
CKKNTZ &#8211; CJPNTZ<br />
CKKNTZ &#8211; CJOSUU<br />
CKKNTZ &#8211; CJOSTZ</div>
</blockquote>
<p>When the list was randomized and inserted again (under Hoard), SuperFastHash stayed at a cool 105ms while STLPort shot up to 460ms. STLPort gained ~360ms from the now non-linear string comparisons and ~40ms from the non-linear bucket accesses. Same number of compares and resulting bucket contents as with the linear dataset, but now with huge penalties for STLPort&#8217;s cache misses.</p>
<h4>Lessons learned</h4>
<ul>
<li>Test results can be meaningless if you don&#8217;t understand exactly what you&#8217;re testing.</li>
<li>Unless one of the algorithms being tested is explicitly taking advantage of cache lines, it is possible to get highly bogus results if you don&#8217;t generate your test data well. Before this I hadn&#8217;t even considered that caching could have this kind of effect on chained hashtables.</li>
<li>Hashing algorithms giving the <strong>fastest possible</strong> time for a particular dataset isn&#8217;t as important as giving the <strong>least worst</strong> time unless you are certain it will absolutely not be used for anything else. A flawed algorithm can even be dangerous as illustrated by Scott Crosby and Dan Wallach&#8217;s <a href="http://www.cs.rice.edu/~scrosby/hash/">Denial of Service via Algorithmic Complexity Attacks</a>.</li>
</ul>
<h4>Source Code</h4>
<p>You may download the <a href="http://www.team5150.com/~andrew/blog/files/hashdist.rar">C++ Source Code</a> demonstrating the problem and try it out for yourself. While the STLPort execution time should balloon when switching to the randomized dataset, it won&#8217;t always be faster than SuperFastHash on the linear dataset. On a K6-3 450mhz STLPort is actually slower: 580/1500ms for the linear/random datasets versus 500/500ms for SuperFastHash.</p>
<p>Example output on my AMD64 3200+:</p>
<blockquote>
<div>This software uses the Hoard scalable memory allocator (version 3.5.1, libhoard).<br />
Copyright © 2005 Emery Berger, The University of Texas at Austin, and the University of Massachusetts Amherst.<br />
For more information, see <a href="http://www.hoard.org" rel="nofollow">http://www.hoard.org</a><br />
starting..<br />
elapsed for STLPort-4.6.2/string-6-linear PRIME 63, comps 1581380, sdev 10.345448, active bins 27357, items 262144</p>
<p>elapsed for STLPort-4.6.2/string-6-linear POW2 63, comps 1581380, sdev 10.345448, active bins 27357, items 262144<br />
elapsed for STLPort-4.6.2/string-6-random PRIME 484, comps 1581380, sdev 10.345448, active bins 27357, items 262144<br />
elapsed for STLPort-4.6.2/string-6-random POW2 485, comps 1581380, sdev 10.345448, active bins 27357, items 262144</p>
<p>elapsed for Hsieh/string-6-linear PRIME 94, comps 6145, sdev 0.775544, active bins 188020, items 262144<br />
elapsed for Hsieh/string-6-linear POW2 94, comps 6145, sdev 0.639169, active bins 202819, items 262144<br />
elapsed for Hsieh/string-6-random PRIME 109, comps 6145, sdev 0.775544, active bins 188020, items 262144<br />
elapsed for Hsieh/string-6-random POW2 110, comps 6145, sdev 0.639169, active bins 202819, items 262144</p></div>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2007/03/07/when-bad-hashing-means-good-caching/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
		<item>
		<title>Why Blizzard Loves Diablo II Cheats</title>
		<link>https://floodyberry.wordpress.com/2006/10/06/why-blizzard-loves-diablo-ii-cheats/</link>
					<comments>https://floodyberry.wordpress.com/2006/10/06/why-blizzard-loves-diablo-ii-cheats/#respond</comments>
		
		<dc:creator><![CDATA[floodyberry]]></dc:creator>
		<pubDate>Fri, 06 Oct 2006 09:25:27 +0000</pubDate>
				<category><![CDATA[Diablo]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[blizzard]]></category>
		<category><![CDATA[cheats]]></category>
		<category><![CDATA[diablo]]></category>
		<guid isPermaLink="false">http://floodyberry.wordpress.com/?p=5</guid>

					<description><![CDATA[Blizzard loves cheats? Are you sure? What about all their anti-cheat measures, like Rust Storm, Warden, and the mass bans we always hear about? Surely they wouldn&#8217;t fight something they are in favor of. Or would they? Let&#8217;s take a deeper look in to Diablo II and see just who is profiting from the use [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Blizzard loves cheats? Are you sure? What about all their anti-cheat measures, like <a href="http://www.insidemacgames.com/news/story.php?ArticleID=8632">Rust Storm</a>, <a href="http://en.wikipedia.org/wiki/The_Warden_(software)">Warden</a>, and the mass bans we always hear about? Surely they wouldn&#8217;t fight something they are in favor of. Or would they? Let&#8217;s take a deeper look in to Diablo II and see just who is profiting from the use and abuse of cheating.</p>
<p><span id="more-5"></span></p>
<h4>Types of Cheating</h4>
<p>What is meant by a cheat anyway? Do you mean .exe hacks, in-game exploits, trade exploits, activities that affect the game economy, what? Does Blizzard love them all? There are actually quite a few different kinds of activities which can be classified as cheats, each with differing levels of severity. Some, while not being an intended activity of the designers, really don&#8217;t affect the game, while others cripple it to the point of unplayable. We&#8217;ll start with the most benign and work our way up from there.</p>
<h5>Class A cheats (No real harm to the game)</h5>
<ul>
<li><strong>GUI </strong>modifications: Modifying item colors, highlighting items and monsters on the automap.</li>
<li><strong>Pickit hacks</strong>: Allowing your character to automatically pick up a user-defined list of items should they drop.</li>
<li><strong>Map Hacks</strong>: Automatically reveals the entire map.</li>
<li><strong>D2L</strong>oader: A no-cd loader for Diablo II which also allows you to run more than one client at a time.</li>
</ul>
<p>Class A cheats have no real effect on the game outside of providing some automation for tasks a person could do just as well manually or providing some harmless bugs. Map hacks may at first appear to be a clear advantage, but the 10-15 seconds you save searching for an exit or portal are really only useful to a new player. The nature of Diablo II acquaints any player to the map layouts very quickly.</p>
<h5>Class B cheats (Mild harm, more annoying than having any real effect on the game or economy)</h5>
<ul>
<li><strong>Glitch Rush bug</strong>: Normally you may not advance to the next difficulty (From Normal to Nightmare, or Nightmare to Hell) until your character level is sufficiently high enough. This means you must take the time to level up before you can advance, which can be fairly tedious. If you have a character who cannot advance stand in Act 5 while a player who is a high enough to advance, but hasn&#8217;t, defeats Baal, your low level character will advance as well.This is how players get level 1 characters into Hell, which also lets you collect all 3 Hellforges for that player fairly quickly. Before higher runes are widely duped, this is a fast way to get Um, Mal, Ist, and Gul runes.An added detriment to this bug is that once you advance to the next difficulty, you can not see games made from the previous difficulty, e.g. a player in Nightmare difficulty who defeats Baal and advances to Hell will no longer be able to see Nightmare games. The detriment is that players using the glitch rush bug will trick unknowing players into defeating Baal so their lower-level glitch-rushed character can advance. The tricked players will then not be able to join Nightmare games to level in while at the same time be far too weak to participate in Hell games. This is seen by the bug abusers as <a href="http://forums.diabloii.net/showpost.php?p=3706575&amp;postcount=7">humorous</a>.</li>
<li><strong>Drop trade hacks</strong>: Players are only allowed to carry a single <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Gheed&#8217;s Fortune</a>, Hellfire Torch, and <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Annihilus</a> at a time, e.g. if you already possess an <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Annihilus</a>, you may not pick up another one and get twice the benefits. The problem is that these three items were not allowed to be placed in the trade screen, thus you were forced to drop them if you wanted to trade them to another player. Normally two players would stand fairly far apart, drop their items, then run to the other player&#8217;s position to collect their bounty; you had to take it on faith that the player would drop the proper item.As if this wasn&#8217;t bad enough, there were certain ways to cause other players to disconnect/crash from the game, which is where the hack comes in. Scammers would set up the trade, both players would drop their items, and the scammer would cause the other player to disconnect and then collect both valuable items, risk free.To Blizzard&#8217;s &#8220;credit&#8221;, they fixed this in June, 2006 (3 years after Annihilus and Gheed&#8217;s Fortune were introduced) by allowing all items to be placed in the trade screen.</li>
</ul>
<p>Class B cheats can give you temporary advantages, but in the long run really don&#8217;t amount to much. Glitch rushing has no added benefit outside of slightly faster Hellforge quests and drop trade hacks are (finally) patched. Glitch rushing should be fixed, but is not particularly damaging.</p>
<h5>Class C cheats (Severe harm to the game and economy)</h5>
<ul>
<li><strong>Item Bots</strong>: These are bots that are automated to kill major bosses repeatedly while collecting any good items that drop in the process. While they won&#8217;t render the game economy useless by flooding it with thousands of high end items, they can still have a marked effect, especially in regards to mid-level items.The users of these bots are <a href="http://www.blizzsector.net/mm-bot/28174-items-found-mm-bot.html">quite proud</a> of the items they &#8220;find&#8221;. One blizzsector.net forum member <a href="http://www.blizzsector.net/mm-bot/28174-items-found-mm-bot.html#post315824">proclaims</a> (<a href="http://www.team5150.com/~andrew/blog/images/d2-mmbot-8hours.png">alt</a>) &#8220;I bot for about 8 hours a day (sleeping) now, but sometimes I run out of rejuv potions and am too lazy to run around and find them, so I just don&#8217;t bother running it at night.&#8221;Examples of such bots are <a rel="nofollow" href="http://www.d2jsp.org/">d2jsp</a>, <a rel="nofollow" href="http://www.gamemunchers.net/">EasyPlay</a> (Now defunct), and <a rel="nofollow" href="http://www.mmbot.net/">mmBot</a>. Of the three, d2jsp and EasyPlay are somewhat protected against by Blizzard, while mmBot has remained undetected by Blizzard and is widely used.</li>
<li><strong>PvP Bots</strong>: These include auto-aim bots and TPPK (Town Portal Player Kill) bots. TPPK bots are like autoaim bots, except they are used to kill players who are not dueling you. They work by firing a bolt weapon/spell at a player you would like to kill, quickly portaling to town and enabling hostile mode on that player.This is especially damaging when you are playing in hardcore mode, where a single death means the end of your character. If you are not careful about who you play with, your weeks or months of hard work on a character can be gone in an instant.</li>
</ul>
<p>Class C cheats are where the quality of the game starts to deteriorate. The economy is impacted by item bots, the quality of PvP is lessened by aimbots, and the already high risk of hardcore mode is now heightened by the very community you participate in.</p>
<h5>Class D cheats (Render the game unplayable and the economy a sham)</h5>
<ul>
<li><strong>Duping</strong>: Duping is when a player duplicates an item using an exploit. <a href="http://www.diabloii.net/columnists/a-items-origin.shtml">The Origin of Bugged Items</a> is a very good article on the history of duping and bugged items.Duping effects the game in a myriad of ways. The first is that the rarity of any item is completely controlled by the duper. If the government allowed private citizens to both create and spend counterfeit money, money would lose all meaning. This is the exact situation Diablo II is in, and has been in, for years. The rarest items in the game can be found in abundance at any trading forum. Players are decked out in equipment that would literally have taken years to find if they had actually played the game instead of resorting to bots and duped items. The trading elite are not the ones who invest in the game or make shrewd trades, they are the players backed by dupers with virtually unlimited buying and selling potential.Counterfeit items running rampant are not the only problem. As mentioned in <a href="http://www.diabloii.net/columnists/a-items-origin.shtml">The Origin of Bugged Items</a>, <strong>many people make a lot of money creating and selling these counterfeits</strong>. Online item stores such as <a rel="nofollow" href="http://d2legit.com/">d2legit</a>, <a rel="nofollow" href="http://www.jpitems.com/">jpitems</a>, and <a rel="nofollow" href="http://www.enzod2.com/">enzod2</a> are pathetically easy to find, whether by a web search or by getting <a href="http://www.team5150.com/~andrew/blog/images/d2-spam-one.png">spammed in-game</a>. eBay is crawling with snakes selling their counterfeit wares; you can even find <a href="http://www.team5150.com/~andrew/blog/images/d2-scum.png">enterprising individuals on Blizzard&#8217;s forums</a> offering up items for cash. One particularly inventive shyster has even found a way to combine two of his favorite hobbies: Exploiting dupes and defrauding Google&#8217;s Adsense program by <a href="http://d2xp.com/forum2/showthread.php?t=9642">bribing players</a> <a href="http://d2xp.com/forum2/showthread.php?t=9747">to click</a> <a href="http://d2xp.com/forum2/showthread.php?t=9374">his ads</a> (<a href="http://www.team5150.com/~andrew/blog/images/d2-shyster.png">alt1</a> <a href="http://www.team5150.com/~andrew/blog/images/d2-shyster-two.png">alt2</a>). Let&#8217;s hope the <a href="http://www.google.com/support/adsense/bin/answer.py?answer=18386">AdSense abuse team</a> needs Diablo II items more than they need his fraudulent clicks!
<p>The more dishonest merchants (such as d2legit), go so far as to claim &#8220;&#8230;unless otherwise noted, all items on the site, including runes and SoJs, are legit.&#8221; This statement, while it may be true in regards to the extremely common items in stock, is a blatant lie for any exceedingly rare item and especially for any high rune. In their defense, I know of nobody playing Diablo II who would be fooled by their disclaimer, so it is probably meant to sway undecided small time players and not to be taken literally. The hardcore players who buy items from these stores know and accept that the majority of the high end items are dupes.</p>
<p>The counterfeit market additionally creates an atmosphere where you either use the counterfeits yourself or fall painfully behind the rest of the players in the game. When every player except you is using the most powerful items in the game, you either cheat to compete or give up. Futher more, many players don&#8217;t have the time to gather items to trade up for counterfeits or the knowledge of how to use cheats and bots and are forced to spend actual money buying items that a duper can clone to his hearts content. The situation is even worse than printing money in your basement as the sale of dupes is legal.</li>
</ul>
<p>Now you can claim that the players are not forced to play the game, to cheat, to spend money on counterfeit items, and that they find real enjoyment in participating in the community, and you are mostly likely right (This is of course ignoring the players who do not have wads of time to play, refuse to cheat, and refuse to pay money for counterfeit goods). However, the agent that is perpetuating this fraud and benefitting the most is not the scammers or the players who support them; it is Blizzard. After I outline what Blizzard has done to counter the problems in the game and the effects of their efforts, you will hopefully see why I say this.</p>
<h4>What has Blizzard Done?</h4>
<h5>Patch 1.06 &#8211; Dupe Scan</h5>
<p>On April 19th, 2001, Blizzard released <a href="http://www.blizzard.com/support/?id=mdt0454p">Version 1.06</a> of Diablo II. This patch featured a new dupe scan with the following description.</p>
<blockquote>
<div>The Diablo II Realms now scan characters for duplicate items. If a player is found to have more than one of the same item, the duplicate items will be deleted leaving just one of that item.</div>
</blockquote>
<p>Their FAQ further clarifies their altruistic reasoning for leaving a single item behind.</p>
<blockquote>
<div>Q: Why did Blizzard Entertainment only delete some of the dupes, and not every dupe?</p>
<p>A: Blizzard Entertainment wants to maintain an enjoyable and balanced play experience for every user. To that end, we removed all but one duplicate item. We&#8217;re making an effort to protect those players that legitimately traded for those items.</p></div>
</blockquote>
<p>Ahh, how thoughtful! They&#8217;re going to punish the cheaters by removing all but a single dupe from a (possibly legitimate) player&#8217;s inventory! Wait, what? How is this going to deter cheating? If anything, the players who are unable to make dupes and are forced to rely on the dupes as currency will now be penalized for it, while the dupers will enjoy a nice price gouging as the items they print off in their basement become scarce.</p>
<h5>Patch 1.08 &#8211; Dupe Methods Blocked</h5>
<p>On June 19, 2001,  Blizzard released <a href="http://www.blizzard.com/support/?id=mdt0451p">Version 1.08</a> of Diablo II. This patch claimed to block all known duping methods and to continue the dupe deletion started in 1.06</p>
<blockquote>
<div>Q: What is Blizzard&#8217;s policy on item duping?</p>
<p>A:We believe that item duping undermines the basic rules of fair play and detracts from the spirit of true competition. Furthermore, we have discouraged item duping by blocking all known duping exploitations and have removed duped items from our servers. We shall continue to monitor and stop any attempts at item duplication</p></div>
</blockquote>
<p>Despite their claims, duping was not blocked and their generous offer to purge items from legitimate players still stood; just how the dupes were able to survive long enough to propogate into the community and be used by players will be covered in the next section.</p>
<h5>Patch 1.10 &#8211; Mass Bans, The Ladder, Annihilus, Rune Words, and Poofing</h5>
<h6>Mass Bans</h6>
<p>The first of the Diablo II mass bans took place right before <a href="http://www.blizzard.com/support/?id=mdt0763p">Version 1.10</a>. On June, 10, 2003, Blizzard banned <a href="http://www.blizzard.com/SUPPORT/?id=nNews095p">112,000 accounts</a> in keeping with their &#8220;aggressive stance against cheating&#8221;. This will turn out to be the first major tipoff on just how much Blizzard loves cheaters. You don&#8217;t ban 112,000 accounts without either wanting to make a strong statement and risk a community and market backlash or in an attempt to lure back addicted, and now banned, players who cheat and prosper because of your &#8220;aggressive stance against cheating&#8221;.</p>
<p>You see, the cheaters typically have many CD-Keys and run multiple clients at once, either to run multiple bots or to keep games open so they can transfer their items from character to character (especially to characters with clean CD-Keys that have never been flagged for cheating). This obviously means they are always <a href="http://www.battle.net/forums/thread.aspx?fn=d2-uswest-ladder-trading&amp;t=2570428">acquiring new CD-Keys</a> (<a href="http://www.team5150.com/~andrew/blog/images/d2-cdkeys.png">alt</a>) and will re-buy the game if necessary to continue playing. It is common to read about players on forums who have been banned for cheating, yet just buy a new CD-Key and start from scratch. Cheaters getting banned and still attempting to play because their cheats still work? &#8220;Backlash&#8221; is probably not the first thought that springs to mind.</p>
<h6>The Ladder</h6>
<p>A couple months after the first mass ban, <a href="http://www.blizzard.com/support/?id=mdt0763p">Version 1.10</a> was released. A lot of new content was added, most of which is very interesting when you consider it from a cheaters perspective. One of the biggest new features was the introduction of the Ladder.</p>
<blockquote>
<div>Introduced a new Ladder System for those who <strong>prefer to play free from any characters who may have participated in past item duping or hacking</strong>. To use this new feature, a player places a check in the Ladder box upon character creation &#8212; in the same way that Expansion and Hardcore selection is done. Periodically, the Ladder may be reset, adding the old Ladder characters to the regular population &#8212; who, of course, cannot play games with the new season&#8217;s Ladder characters. Thus, every season each new Ladder character truly starts from scratch, as no &#8216;twinking&#8217; is possible from older characters.</div>
</blockquote>
<p>The ladder also introduced many new and powerful Rune Words that were not available in non-ladder games. We will discuss Rune Words later, but for the moment just know that the new Rune Words were a very strong enticement to play on the Ladder, although perhaps not strong enough if you do not take the inevitablilty of cheating into account. The clean slate economy from each ladder reset would also be enticing to any player, but while it may have looked like a great chance for some clean fun to legit players, the low supply and enormous demand would prove to be irresistible to the cheaters and dupers Blizzard claimed to despise so vehemently.</p>
<h6>Annihilus</h6>
<p>The new patch also introduced many new items. The most interesting item is the <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Annihilus</a> charm. You see, by this time there were millions of duped <a href="http://www.planetdiablo.com/library/item-stoneofjordan.htm">Stone of Jordans</a> floating around, commonly referred to as a &#8220;soj&#8221;. Even though sojs are fairly rare when playing normally, they were duped massively early in Diablo II and became the main currency of the game. The designers, possibly in an attempt to clean up the world of duped sojs as their other methods weren&#8217;t working, created an <a href="http://www.battle.net/diablo2exp/monsters/act5-uberdiablo.shtml">Uber Diablo</a> monster who only spawns when 100 sojs have been sold to NPC (Non Player Character) stores in a server. When you kill <a href="http://www.battle.net/diablo2exp/monsters/act5-uberdiablo.shtml">Uber Diablo</a>, he drops a single <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Annihilus</a> (commonly referred to as anni) charm, which is immensely powerful.</p>
<p>Oh, did I forget to mention that Blizzard runs multiple servers per single machine, and that Uber Diablo will spawn on all of them, even if you sell the sojs in a non-ladder game and host a ladder game, and that the ladder economy is much less infested with dupes compared to the non-ladder economy? Oh yeah, the players with the duped sojs will also create co-ops where multiple people each contribute 10-15 sojs, decide on a server to sell sojs on, all create multiple games with D2Loader and their plethora of CD-Keys, then collect their legitimate and very valuable and powerful <a href="http://www.battle.net/diablo2exp/items/normal/ucharms.shtml">Annihilus</a> charms for a fraction of the 100 soj cost.</p>
<p>This may be setting off yet another alarm in your mind in regards to Blizzard&#8217;s &#8220;aggressive stance against cheating&#8221;. Here we have the game designers intentionally creating a way to turn duped items into very valuable new items which legitimate players <strong>can never find legitimately</strong>. You must be playing in a heavily duped environment such as non-ladder and possess a great many sojs to ever intentionally spawn Uber Diablo. A legitimate player will never find 100 sojs of his own outside of cheating with bots or buying dupes from item stores and other players, although even a bot would be hard pressed to find 100 sojs in a timely manner (rough estimates at 70 hours of playing per soj found = 290 days of straight playing to hit 100 sojs. Myself and two friends found 2 sojs in 3-4 months of playing). In case you were wondering, there are still plenty of duped sojs floating around as Blizzard has never fixed duping.</p>
<h6>Runes and Rune Words</h6>
<p>Since we&#8217;re on the subject of rewarding dupers and cheaters, let&#8217;s move on to runes and the new Rune Words in 1.10. The <a href="http://www.battle.net/diablo2exp/items/runes.shtml">description of a rune</a> from The Arreat Summit, Blizzard&#8217;s guide on Diablo II, is as follows:</p>
<blockquote>
<div>Runes are small stones inscribed with magical glyphs that can be inserted into Socketed Items. Runes are different from other Insertable Items: not only do individual Runes have set magical properties, <strong>certain combinations (or Rune Words), when inserted into an item in the proper order, give that item even more wondrous abilities.</strong></div>
</blockquote>
<p>There are 33 runes, each more scarce than the one before it. To give you an idea of how scarce they become, here is a table with the odds of each rune dropping per monster killed. Note: The Countess is a boss monster who drops lower runes with a much higher frequency than most other monsters. All values are approximate and vary per monster.</p>
<pre class="brush: cpp; title: ; notranslate">Rune (Rank)   Countess     Super Boss    Normal Monster
-----------   --------   ------------    --------------
  El (  1 )        1/2          1/150           1/3,400
 Eld (  2 )        1/3          1/200           1/5,000
 Tir (  3 )        1/4          1/300           1/6,200
 Nef (  4 )        1/4          1/450           1/9,200
 Eth (  5 )        1/5          1/430           1/8,800
 Ith (  6 )        1/6          1/600          1/13,000
 Tal (  7 )        1/6          1/530          1/10,000
 Ral (  8 )        1/8          1/700          1/15,000
 Ort (  9 )        1/9          1/750          1/15,000
Thul ( 10 )       1/13        1/1,100          1/22,000
 Amn ( 11 )       1/14        1/1,300          1/24,800
 Sol ( 12 )       1/20        1/1,500          1/12,000
Shael( 13 )       1/27        1/2,600          1/47,000
 Dol ( 14 )       1/41        1/3,500          1/70,000
 Hel ( 15 )       1/53        1/5,000          1/91,000
  Io ( 16 )       1/80        1/6,800         1/130,000
 Lum ( 17 )      1/100        1/9,000         1/180,000
  Ko ( 18 )      1/160       1/13,000         1/270,000
 Fal ( 19 )      1/200       1/17,000         1/350,000
 Lem ( 20 )      1/300       1/28,000         1/530,000
 Pul ( 21 )      1/423       1/35,000         1/715,000
  Um ( 22 )      1/635       1/53,000       1/1,000,000
 Mal ( 23 )      1/739       1/60,000       1/1,200,000
 Ist ( 24 )    1/1,100       1/90,000       1/1,800,000
 Gul ( 25 )  1/120,000      1/100,000       1/2,100,000
 Vex ( 26 )  1/185,000      1/160,000       1/3,200,000
 Ohm ( 27 )  1/210,000      1/200,000       1/3,800,000
  Lo ( 28 )  1/320,000      1/260,000       1/5,000,000
 Sur ( 29 )         NA      1/350,000       1/6,500,000
 Ber ( 30 )         NA      1/500,000      1/10,000,000
 Jah ( 31 )         NA      1/600,000      1/11,000,000
Cham ( 32 )         NA      1/800,000      1/17,000,000
 Zod ( 33 )         NA    1/3,000,000      1/60,000,000</pre>
<p>To put these drop odds in perspective, we will need to figure out how many monsters you can kill on average. Blizzard limits you to joining around 20 games an hour (this is to combat item bots, although it often combats legitimate players from playing), giving you about 3 minutes per game. There are around 10-15 &#8220;Super Bosses&#8221; you can kill to give you a chance at the higher runes. Assuming you can get 5 in 2 minutes (highly unlikely without a bot unless you target weaker super bosses with much worse drop odds), that would give you about a minute for average monsters for which I&#8217;ll generously claim 50 kills. These numbers would give you 5*20 = 100 Super Bosses an hour and 50*20 = 1,000 regular monsters an hour. Plugging these numbers in for the high runes, we get:</p>
<pre class="brush: cpp; title: ; notranslate">Rune (Rank)     Hours Required To Find
-----------   ------------------------
 Gul ( 25 )      693 hours or  28 days
 Vex ( 26 )    1,086 hours or  45 days
 Ohm ( 27 )    1,318 hours or  54 days
  Lo ( 28 )    1,753 hours or  73 days
 Sur ( 29 )    2,275 hours or  94 days
 Ber ( 30 )    3,333 hours or 138 days
 Jah ( 31 )    3,882 hours or 161 days
Cham ( 32 )    5,440 hours or 226 days
 Zod ( 33 )   20,000 hours or 833 days</pre>
<p>Now runes in and of themselves are not that useful. A few of them have nice magical properties, but on the whole you almost never use a rune on it&#8217;s own. Instead, you combine them in to powerful <a href="http://www.battle.net/diablo2exp/items/runewords.shtml">Rune Words</a>. A Rune Word is a set of runes placed in a socketed item in a set order; think of it as a recipe for a powerful item with the runes being the ingredients. The definition of a Rune Word from The Arreat Summit is:</p>
<blockquote>
<div>If the player puts certain combinations of Runes in the correct order into an item with exactly that number of sockets and of the correct item type, the item&#8217;s name will change into a &#8220;unique&#8221; name, displayed in gold, and the item will acquire extra powers, depending on the &#8220;rune word&#8221; that was used.</div>
</blockquote>
<p>Let&#8217;s take a look at the cost of some of the new Rune Words from the 1.10 patch. From the odds, we will assume that finding a single rune will provide one of each rune below it, so finding a Zod will give you one of each rune below to work with. This does not exactly hold up in the real game due to varied drop odds for different monsters.</p>
<pre class="brush: cpp; title: ; notranslate">Runeword                                  Days
-------------------------------------------------------     -------------
Breath of the Dying:   Vex + Hel + El + Eld + Zod + Eth     833(Zod) days
Call To Arms:          Amn + Ral + Mal + Ist + Ohm          54(Ohm) days
Chains of Honor:       Dol + Um + Ber + Ist                 138(Ber) days
Doom:                  Hel + Ohm + Um + Lo + Cham           226(Cham) days
Enigma:                Jah + Ith + Ber                      161(Jah) days
Exile:                 Vex + Ohm + Ist + Dol                54(Ohm) days
Heart of the Oak:      Ko + Vex + Pul + Thul                26(Vex) days
Faith:                 Ohm + Jah + Lem + Eld                161(Jah) days
Grief:                 Eth + Tir + Lo + Mal + Ral           73(Lo) days
Infinity:              Ber + Mal + Ber + Ist                276(Ber*2) days
Last Wish:             Jah + Mal + Jah + Sur + Jah + Ber    483(Jah*3) days
Phoenix:               Vex + Vex + Lo + Jah                 161(Jah) days</pre>
<p>It would take a legit player <strong>2.2 years</strong> of <strong>non-stop</strong> playing before he/she found a Zod rune to complete Breath of the Dying. Last Wish would take a paltry <strong>1.32 years</strong>. Infinity clocks in at <strong>0.75 years</strong>. It should be further pointed out that once a rune is used in an item, it is <strong>gone for good</strong>. There is no way to extract a rune from an item, so if you mess up a recipe or want to create another Rune Word, you will need to find another copy of each rune. The very act of using a rune will implicitly drive the demand for that rune higher. <strong>Every rune and runeword I listed are available virtually without limit from item stores and traders on Blizzard&#8217;s official forums and have been since around one month after the last ladder/economy reset.</strong></p>
<p>To get an idea of how often the higher runes are legitimately found, in about 3-4 months of playing, myself and 2 friends found a total of 1 Mal, 2 Ist, 3 Vex, and 1 Ohm. Meanwhile the market had been so flooded with dupes that high runes were readily available for most of the time we were playing even though the ladder had just been reset and everybody was starting from zero. Now, a year later, traders on forums will make deals involving <a href="http://www.battle.net/forums/thread.aspx?fn=d2-uswest-ladder-trading&amp;t=2554430&amp;tmp=1#post2554430">hundreds of high runes</a> (<a href="http://www.team5150.com/~andrew/blog/images/d2-hundreds.png">alt</a>) at a time. 2.2 years of non-stop playing time to find a Zod and you can purchase <a rel="nofollow" href="http://www.d2legit.com/products.php?cpath=4_6_712&amp;rf=1159900540">40 &#8220;legit&#8221; Zods</a> (<a href="http://www.team5150.com/~andrew/blog/images/d2-rune-packages.png">alt</a>) for $24 at d2legit.com. Many thousands more are implicitly available in pre-made runewords made with the highest grade items. Please remind me again how an &#8220;aggressive stance against cheating&#8221; results in Rune Words blatantly made for cheaters, online stores selling thousands of counterfeit goods, and the absolute destruction of the game&#8217;s economy a month after each ladder reset?</p>
<p>As one player on Blizzard&#8217;s forums <a href="http://www.battle.net/forums/thread.aspx?FN=d2-general&amp;T=1247096&amp;P=12#post1249995">said</a>:</p>
<blockquote>
<div>I agree with most people saying that dupe hack are really a plague but runewords like Last Wish look as they are made to tell people &#8220;Try a dupe mod, it&#8217;s the only way to make this&#8230;&#8221;</div>
</blockquote>
<h6>Poofing</h6>
<p>Up to this point, we&#8217;ve seen Blizzard create a ladder with a clean economy that is ripe for huge profits from cheating (both in game and out), create items such as the Annihilus that a legitimate player can never acquire, and create Rune Words that would take a legitimate player many years of playing to collect the necessary runes. With their &#8220;aggressive stance against cheating&#8221;, you would think they would have done something for the legitimate players. Well, it turns out you are right. They have kept the exact same dupe-scanning system which has been in place since 1.06! You know, the one that doesn&#8217;t hurt dupers and penalizes legitimate players? The &#8220;technical&#8221; term for an illegal item being deleted is &#8220;poofing&#8221;, and it is the cornerstone of Blizzard&#8217;s ability to allow duping while keeping the economy from turning into <a href="http://www.joelscoins.com/exhibger2.htm">World War One Deutschmarks</a>.</p>
<p>While it is true the system will detect and delete dupes, there is a miniscule catch; a tiny, insignificant, hardly worth mentioning, <strong>extremely well known</strong> method of bypassing this check. In fact, there are multiple well known methods (<a href="http://www.hiddenstuff.com/members/diablo2-permitems.htm">Perming Guide from 1.09 anyone</a>?), although there may be many more that are kept secret by the duping community.</p>
<p>The easiest method is simple and extremely reliable. If you socket a duped rune in an item, the duped rune will be safe from poofing. Therefore you can take your duped Vex and Zod runes (along with the easy to find Hel, El, Eld, and Eth runes), socket them properly in an 6 socket Poleaxe weapon, and you will have a &#8220;Breath of The Dying&#8221; Poleaxe which is perfectly safe from poofing. You can even socket a single Vex rune in your weapon for safe keeping until you acquire a Zod to complete the Rune Word.</p>
<p>A more popular method is the one that allows you to protect <strong>any dupe</strong> from poofing, whether it is a rune, item, jewel, charm, whatever. Our good friends at enzod2.com have instructions on how to &#8220;<a rel="nofollow" href="http://www.enzod2.com/index.php?o=tpm">temp perm</a>&#8221; items you buy with real money from their counterfeit store. This method is known by nearly all players and is widely used to keep vast stores of dupes safe from deletion while trading.</p>
<blockquote>
<div>The Temp Perm Method will only allow you to keep your dupes for THAT game ONLY. You MUST repeat the Temp Perm Method for EVERY game in order for your dupes to never disappear. Also, Runewords that are made out of duplicate runes will not have to be permed.</p>
<p>The Temp Perm Method:</p>
<ol>
<li>Open a trade window with another player.</li>
<li>Put your duped/potential duped item you want to perm in the trade window. (This step is actually optional).</li>
<li>Save + Exit immediately after closing your trade window.</li>
<li>The above will work every time, just do not forget to do it every game to be safe.</li>
</ol>
<p>Remember to make sure you have the trade window up before cancelling the trade window and then exiting game.</p></div>
</blockquote>
<p>Note that if you forget to do this, you will risk losing any duped items. If you do not realize that the item you just traded for is a dupe, if you accidently forget to &#8220;temp perm&#8221; your dupes, if you do not think that dupers would traffic in such a low item, you risk losing your items. A search for &#8220;poof&#8221; on Blizzard&#8217;s official USWest <strong>Ladder</strong> forum yields <a href="http://www.battle.net/forums/thread-search.aspx?ForumName=d2-uswest-ladder-trading&amp;SearchType=2&amp;SearchText=poof&amp;x=18&amp;y=9">hundreds of results</a>.</p>
<blockquote>
<div>
<ul>
<li>20/19/7 &#8220;legit&#8221; anni i bought from you poofed.. sigh..</li>
<li> Don&#8217;t feel bad, last night my 399/39/15 Grief, 27× 20 life SC&#8217;s, and my 140/15/40 Dungo poofed. Paid 64 HR&#8217;s for all of it, lol.</li>
<li>the coa that poofed on me was a 2/26/30. hopin for stats around there LEGIT tho plz.</li>
<li> maras must be legit, I have had so many items poof lately its not funny. Post Offers.</li>
<li> My 15 sup 1368 Archon Enigma poofed on me</li>
<li> yep mine just poofed. leave stats and price. this fvcking sucks.</li>
<li> perfect coa, lucky to get 30 for it lately, too many dupes and too many poofing</li>
<li> um both of your sojs poofed on me &#8230;.</li>
<li> ya its duped; just not mass duped..but still will poof w/o perm</li>
</ul>
</div>
</blockquote>
<p>Granted, none of these posts were by legitimate players, but that is to be expected. The economy is so flooded by dupes now that you can not buy or trade any item of higher than medium value without having a high probability of it being duped. You can also not sell a valuable item without risking it finding it&#8217;s way to a duper, who then carefully floods the market with copies. Trading forums will often have a list of banned dupes, such as d2jsp.org&#8217;s <a href="http://forums.d2jsp.org/index.php?showtopic=4164550&amp;f=169">list of banned items</a> on USEast <strong>Ladder</strong>. These lists are of course always incomplete, always growing, and have no effect on the propagation or trading of dupes. <strong>You can not accept Diablo II items from other players and stay legitimate at the same time</strong>. Thanks for looking out for the little guy, Blizzard!</p>
<h4>Where To Now?</h4>
<p>Little has changed since the 1.10 patch. Blizzard did have a <a href="http://www.battle.net/news/0508.shtml">36,000 account</a> mass ban on Aug, 11, 2005. The mass ban happened to coincide with the latest ladder reset and the release of <a href="http://www.blizzard.com/support/?id=mdt01827p">Version 1.11</a> which added a few new items, a new quest, a new anti-cheat tool borrowed from World of Warcraft called <a href="http://en.wikipedia.org/wiki/The_Warden_(software)">Warden</a>, and absolutely nothing against duping. Another mass ban of <a href="http://www.team5150.com/~andrew/blog/images/d2-ban-35000.png">35,000 accounts</a> occurred on July 24, 2006; other than a possible revenue boost to Blizzard, the effects of the ban were little.</p>
<p>To Blizzard&#8217;s credit, Warden has been largely successful in chasing out most hacks. The downside is that it has taken nearly a year for hack authors to back down, mostly due to the glacial update frequency of Warden. Even worse, mmBot, one of the truly damaging programs, has remained completely undetected. Proponents of mmBot claim it is because mmBot is driven by <a href="http://www.autoitscript.com/autoit3/">AutoIt</a>, a script-driven engine which does not hack Diablo in any way and works purely off of graphical analysis, but this is a weak reason to ignore it.</p>
<p>To Blizzard&#8217;s major discredit, duping was not, nor has ever been, fixed. Bugged <strong>Non-Ladder</strong> items from previous patches are <a href="http://www.battle.net/forums/thread-search.aspx?SearchType=2&amp;searchtext=08+valk&amp;x=0&amp;y=0&amp;forumname=d2-uswest-ladder-trading">rampant in the ladder economy</a>, almost any valuable item is a dupe (whether the person trying to trade claims it is legit or not), legitimate players are at risk every time they acquire items they do not find themselves, and nobody cares because business is scamming, and scamming is good. The black market <strong>is</strong> the market and is dictated by what the dupers manage to acquire and sell to the public, nothing else.</p>
<p>You could argue that the game is successful because of the hacks and dupes and not in spite of them. You might also argue that without the joy of finding items with bots, the glee of killing other players with third party hacks, or the pride of selling counterfeit items to strangers is a game in itself, and worthy of supporting. You could even argue that Blizzard is merely giving the people what they want and should be lauded for their keen business sense. Whatever you argue, one thing is certain: With each update to Diablo II and each failure to either fix duping or admit defeat and end the game, Blizzard is saying loud and proud: <strong>We Love Diablo II Cheats!</strong></p>
<h4>Postscript</h4>
<p>I will admit that the community in no way helped inform my feelings on the game. Where exactly is the fun in participating in a community where you must interact with hordes of immature con-artists who have no integrity and whose only goal in life seems to be sucking up to the stronger while trampling the weaker? Who wants to talk with people who think insults, bragging, lying, scamming, and illiteracy are virtues? The have-nots are little better, constantly begging and then insulting you if you do not do enough for them as I have seen many times over while attempting to give items away. The few honest players doing their best to make the game more enjoyable for everyone only hasten the rise of the gutter-trash to the top. Were there no corruption in the game and the players remained the same I would still not interact with them, but I believe the increased enjoyment from a clean economy would make up for their presence.</p>
<p>In any event, there has been a bit of <a href="http://www.battle.net/forums/thread.aspx?fn=d2-general&amp;t=1259277&amp;tmp=1#post1259277">posturing</a> over a possible new patch and ladder reset, and the official suggestions report contains &#8220;Run regular Ruststorms weekly to help remove Duped Items&#8221; and not &#8220;Remove duping entirely&#8221;. If the trends of the past 6 years continue, it looks like everyone can look forward to another glorious ladder season which will slowly spiral downward as the dupers once again squeeze every penny out of the arbitrary economy they have ruled all these years.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://floodyberry.wordpress.com/2006/10/06/why-blizzard-loves-diablo-ii-cheats/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://0.gravatar.com/avatar/f0763395c4ecb8b1ff85e30f6d78323b7a7c85a2bfd2f6d6e218f947c55dc734?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">floodyberry</media:title>
		</media:content>
	</item>
	</channel>
</rss>
