<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3639186260082284014</id><updated>2012-01-28T18:01:38.984-06:00</updated><category term='ibatis'/><category term='flash'/><category term='hibernate'/><category term='java'/><category term='php'/><category term='generics'/><category term='security'/><category term='air cannons'/><category term='programming'/><category term='politics'/><category term='electrotank'/><category term='.net'/><category term='games'/><category term='fun'/><category term='utilities'/><title type='text'>Mike Grundvig's Blog o' Stuff</title><subtitle type='html'>A blog about my life and times. Well, nothing that serious. It's more of just a geek's random drivel posted for all to see. I hope to post some helpful code at times too but that's only when I run out of drivel.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-6983417905440309789</id><published>2009-05-24T20:21:00.003-06:00</published><updated>2009-05-24T20:34:13.502-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='air cannons'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Marshmallow Madness</title><content type='html'>To give me a break from all the remodeling we've been doing I decided to come up with a fun project to waste some time. That project is not the topic of this post :)&lt;br /&gt;&lt;br /&gt;As a precursor to &lt;span style="font-style:italic;"&gt;that&lt;/span&gt; project, I wanted to get a little experience with pneumatic cannons and the like. To that end, I picked up the plans to build the "Ultra Magnum Marshmallow Gun" from &lt;a href="http://www.myaircannons.com/ultramag.html"&gt;here&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The plans are good, I found only a single real issue and that was in the material list. I went ahead and emailed the creator about it for any of you that buy the plans later. It only took me about an hour to put everything together. Honestly, it took me more time to find all the plumbing parts at the local Home Depot. The only thing they didn't have was a stem fill valve and the tire shop at Walmart just gave me a couple out of the goodness of their hearts. Once you get all the pipe cut and glue it together you need to wait forever (24 hours) for the PVC cement to completely cure.&lt;br /&gt;&lt;br /&gt;I can only say one thing about it: WOOHOO! It's a lot more fun than I expected. The power at 50 PSI is surprising. By the time I could test it, it was already dark outside so I didn't get to see the full range but the little mini-marshmallows it shoots were smacking into the wall quite loudly from twenty feet. Tomorrow morning I'll put it though it's paces at higher pressures and see the real range.&lt;br /&gt;&lt;br /&gt;Expect to see an update in the next day or so with maybe even a video once I get it all painted up. In the meantime, go buy the plans and build one yourself :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-6983417905440309789?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/6983417905440309789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=6983417905440309789' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6983417905440309789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6983417905440309789'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2009/05/marshmallow-madness.html' title='Marshmallow Madness'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-5863520389119436134</id><published>2008-01-29T09:30:00.000-06:00</published><updated>2008-01-29T10:07:28.066-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Binary Maps and Data in AS3</title><content type='html'>&lt;p&gt;When talking about maps for games, XML comes up all the time. XML makes great sense with it's readibility and ease of parsing. Then I see people use XML to define their map but to save space, they condense everything heavily inside of it. This makes little sense to me. You lose the readability and the ease of parsing in favor of a smaller file size. The trick is that if file size matters and readability doesn't, lose XML entirely and go for something better suited to small file sizes. &lt;/p&gt;&lt;p&gt;With these requirements, I recomend using a binary file format directly and to heck with human readable at that point. Our next project uses this everywhere and it has turned huge maps into tiny files we just load via HTTP. Very clean, simple and incredibly fast. It also has the advantage of taking very little memory because converting from binary to AS3 data types has so little overhead (unlike string --&gt; number parsing).&lt;/p&gt;&lt;p&gt;So let's say you have a 10x10 map. For simplicity, "X" is rock, "O" is grass, and "=" is path. An ASCI version might look like this:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;X X X X X = X X X X&lt;br /&gt;X O O O O = O O O X&lt;br /&gt;X O O O O = O O O X&lt;br /&gt;X O O O O = O O O X&lt;br /&gt;X O O O O = O O O X&lt;br /&gt;= = = = = = O O O X&lt;br /&gt;X O O O O O O O O X&lt;br /&gt;X O O O O O O O O X&lt;br /&gt;X O O O O O O O O X&lt;br /&gt;X X X X X X X X X X&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This map lets you walk anywhere in the area but you can only leave via the path that enters on the left and exists at the top. Rocks surround everything with grass filling in the gaps. Boring, but a very real-world example.&lt;/p&gt;&lt;p&gt;Now you need to represent that with parsable data. The map data needs to contain two entries per tile, a tile type ID and a boolean for walkable/non walkable. In this case, rock is 1, grass is 2, and a path is 3. The 0/1 next to it indicates if the tile is walkable or not. &lt;/p&gt;&lt;p&gt;Here is an XML version I snagged from a thread on FlashKit game developers forum (sorry Mr. Malee).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;&amp;lt;map name="map1" mapX="10" mapY="10"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;layer name="FLOOR"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 1:0 1:0 1:0 1:0 3:1 1:0 1:0 1:0 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;3:1 3:1 3:1 3:1 3:1 3:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;r&amp;gt;1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0&amp;lt;/r&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/layer&amp;gt;&lt;br /&gt;&amp;lt;/map&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Pretty big, even when using the condensed row format. This comes out to 579 bytes. Fall_X (another FlashKit poster) suggests to just use text if you are going to make your XML still require string.split style parsing. I agree, the format can then be:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;1:0 1:0 1:0 1:0 1:0 3:1 1:0 1:0 1:0 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 3:1 2:1 2:1 2:1 1:0&lt;br /&gt;3:1 3:1 3:1 3:1 3:1 3:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 2:1 2:1 2:1 2:1 2:1 2:1 2:1 2:1 1:0&lt;br /&gt;1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0 1:0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;But even that is still pretty large. Saved as a text file, it is 408 bytes. While this seems small, this is just a 10x10 grid with almost no data. When you make it a 20x20 grid (still quite small) the file size jumps to 1618 bytes. &lt;/p&gt;&lt;p&gt;How would you represent this with binary? You would first need to define the width and height (in tiles) of the map using the smallest logical data type. In this case, we would use a short. A short is a whole number represented by two bytes that goes to a max of 65k or so. The format would look something like this ([ ] indicates many - ie, iterating over them):&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;&amp;lt;Map Width (short)&amp;gt;&amp;lt;Map Height (short)&amp;gt;[&amp;lt;Tile Type ID (short)&gt;&amp;lt;Is Walkable (boolean)&amp;gt;]&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Since we know the exact length in bytes of shorts and booleans (1 byte) then we can easily determine how large this will be for any given map. The header is 4 bytes, each tile is 3 bytes. The 10x10 map above has 100 tiles defined. Final size? 304 bytes for a 10x10 map. What about our 20x20 example? 1204 bytes. &lt;/p&gt;&lt;p&gt;Now you might think that this is a trivial gain, and it is UNTIL you start to realize the more subltle differences. The example map has 3 tile types. Let's say your game has 20 tile types and you decide to replace 2 (grass) with 18 (snow covered grass), 1 (rock) with 19 (snow covered rock) and 3 (path) with 20 (snow covered path). What is the impact on your file size if you are using the text format? The 10x10 map becomes 508 bytes and the 20x20 becomes 2,018 bytes. A 40x40 map would be 8,038 bytes while an 80x80 would be 32,078 bytes.&lt;/p&gt;&lt;p&gt;How big is the binary map? It's exactly the same size as it was before. This is because the "short" we are writing is already capable of holding up to 65k+ tile types without changing. In fact, if you were going to have 256 or less tile types, you could even use a single byte to represent them. If you were going to have 128 tile types or less, you could use a single byte to represent both the tile type AND the walkable state of the tile. This is done by simply taking the most significant bit in the byte and toggling it on or off as needed then ignoring it when determining the number. Thus saving even more space!&lt;/p&gt;&lt;p&gt;So realistically, you probably will have 128 or less tile types in the average Flash game but you could have a map &gt;256x256, so the header should still use "shorts" unless you want to go beyond 65k of tiles in each dimension. With this in mind, the new binary format becomes: &lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;&amp;lt;Map Width (short)&amp;gt;&amp;lt;Map Height (short)&amp;gt;[&amp;lt;Tile Type ID and walkable state(byte)&amp;gt;]&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now let's try those sizes again:&lt;/p&gt;&lt;p&gt;10x10 map - 100 tiles&lt;br /&gt;Text (not XML) = 508 bytes&lt;br /&gt;Binary (1 byte/tile) = 104 bytes&lt;br /&gt;Binary (2 bytes/tile = 204 bytes&lt;br /&gt;Binary (3 bytes/tile) = 304 bytes&lt;/p&gt;&lt;p&gt;20x20 - 400 tiles&lt;br /&gt;Text (not XML) = 2,018 bytes&lt;br /&gt;Binary (1 byte/tile) = 404 bytes&lt;br /&gt;Binary (2 bytes/tile = 804 bytes&lt;br /&gt;Binary (3 bytes/tile) = 1,204 bytes&lt;/p&gt;&lt;p&gt;40x40 - 1600 tiles&lt;br /&gt;Text (not XML) = 8,038 bytes&lt;br /&gt;Binary (1 byte/tile) = 1,604 bytes&lt;br /&gt;Binary (2 bytes/tile = 3,204 bytes&lt;br /&gt;Binary (3 bytes/tile) = 4,804 bytes&lt;/p&gt;&lt;p&gt;80x80 - 6400 tiles&lt;br /&gt;Text (not XML) = 32,078 bytes&lt;br /&gt;Binary (1 byte/tile) = 6,404 bytes&lt;br /&gt;Binary (2 bytes/tile = 12,804 bytes&lt;br /&gt;Binary (3 bytes/tile) = 19,204 bytes&lt;/p&gt;&lt;p&gt;As you can see, there is a massive size difference and it gets better and better as the map grows larger. In case someone is interested, the reason for this is simply that text in a file takes several bytes under the covers to represent it (depending on the encoding, etc). But when you read/write binary directly, you don't have this issue. You know exactly what will be created and how large it will be. Additionally, all the tricks used to make strings smaller work here too, run-length encoding, compression, etc. are all viable options. Flash even has built-in support for compressing/decompressing a byte array!&lt;/p&gt;&lt;p&gt;For more information on binary and how bytes break down into bits and how you can use em to store information: &lt;a href="http://www.freesoft.org/CIE/Topics/19.htm" target="_blank"&gt;http://www.freesoft.org/CIE/Topics/19.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now all this is well and good, but how do you use binary in Flash? Assuming you have AS3, it's a piece of cake. You simply need to load your data via HTTP using the appropriate loader class and use it to get at the ByteArray object. Then accessing bytes is trivial:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new; font-size:12;"&gt;// Get the initial data array&lt;br /&gt;var inputArray:ByteArray = ... // Data loaded externally into a byte array&lt;br /&gt;&lt;br /&gt;// Read all the available parameters&lt;br /&gt;var mapWidth:int = inputArray.readShort();&lt;br /&gt;var mapHeight:int = inputArray.readShort();&lt;br /&gt;&lt;br /&gt;// Iterate over the map&lt;br /&gt;for(var y:int = 0; y &lt; mapHeight; y++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(var x:int = 0; x &lt; mapWidth; x++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Assuming the 3-byte per tile model&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var tileTypeId:int = inputArray.readShort();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var isWalkable:boolean = inputArray.readBoolean();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Piece of cake. Now how do you save binary in the first place - you go in reverse. You build your ByteArray up and then have to fight with Flash a bit. Since Flash can't directly save data, you need to use something else. I'm betting you could do it with AIR, but I know you can do it with PHP. Easiest solution is to use Base64Encoder in Flash and encode the byte array to a string, then send that string to PHP and have it decode using the built-in decode (&lt;a href="http://aspn.activestate.com/ASPN/docs/PHP/function.base64-decode.html"&gt;link&lt;/a&gt;) then simply have PHP save the binary data to the file system. &lt;/p&gt;&lt;p&gt;Now, if you don't want to do the "true" binary file format but you want some of the other advantages binary gives you, you can still just use the Base64 encoded string. It is text and totally usable as such. Just copy it out of a text field and throw it into a text file. Instant binary-ish file format &lt;/p&gt;&lt;p&gt;Nice, clean, and powerful. With binary being finally supported properly, there is very little reason not to take advantage of it. Anyways, enough from me. Have fun!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-5863520389119436134?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/5863520389119436134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=5863520389119436134' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/5863520389119436134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/5863520389119436134'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2008/01/binary-maps-and-data-in-as3.html' title='Binary Maps and Data in AS3'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-2400754362599920121</id><published>2007-08-17T07:56:00.000-06:00</published><updated>2007-09-09T21:54:17.471-06:00</updated><title type='text'>Austin Game Developer's Conference!</title><content type='html'>Hi all, sorry I've not been blogging much lately. I've been super busy on some big projects. I'll start blogging a lot more soon. This is just a quick post to let everyone know that Electrotank is going to be showing off a lot of new stuff at our killer booth at the &lt;a href="http://www.austingdc.net/"&gt;Austin Game Developer's Conference&lt;/a&gt;. This will be the first time anyone has seen our new truss-based booth with a 77" projected screen. Yes, that's 77" of projected image goodness. I'm so happy about how the booth turned out that I'll probably post some pictures of it in a few days.&lt;br /&gt;&lt;br /&gt;I'll also be presenting at the conference as well. My presentation is on &lt;a href="https://www.cmpevents.com/GDAU07/a.asp?option=C&amp;V=11&amp;amp;SessID=5858"&gt;Web Client Development Issues - Best Practices&lt;/a&gt;. The presentation is split into two parts. Michael Bayne (CTO of Three Rings, the guys that made Puzzle Pirates) will be handling the second half. The talk will cover the main technologies used to build web games (Flash, Java, etc), discuss pros and cons of each, and provide tips and tricks on how to avoid the most common development issues. Should be fun. If anyone is going, please let me know and we can meet up at some point.&lt;br /&gt;&lt;br /&gt;-=-=-&lt;br /&gt;Update: Now that the talk is over, I can give the URL out:&lt;br /&gt;&lt;a href="http://samskivert.com/work/2007/agc/web_client_dev.pdf"&gt;http://samskivert.com/work/2007/agc/web_client_dev.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Thanks for everyone that came and saw it or met up with us at the show!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-2400754362599920121?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/2400754362599920121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=2400754362599920121' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/2400754362599920121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/2400754362599920121'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/08/austin-gane-developers-conference.html' title='Austin Game Developer&apos;s Conference!'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-4735899660907482398</id><published>2007-06-05T22:06:00.001-06:00</published><updated>2007-06-05T22:10:46.529-06:00</updated><title type='text'>ElectroServer 4 Feature Request</title><content type='html'>As some of you know, we have been working on ElectroServer 4 for a while. We have now reached a point where we can start added user-requested features. Now is your chance to speak up and tell us anything you'd like to see in a socket server.&lt;br /&gt;&lt;br /&gt;If you were sitting down to make the multi-player game of your dreams, what would the server need to support to make your job easier or even possible? What would it need to do to ensure your success? What would make it easier for you to keep the game running or deploy it?&lt;br /&gt;&lt;br /&gt;Basically, anything you can think of that might be good to see in a socket server. Don't worry if you have never played with one before or if you think it might already be there, just let the ideas come. I can't promise we will get them all in the next release but I suspect we can get most.&lt;br /&gt;&lt;br /&gt;Feel free to contact me directly with &lt;a href="mailto:mike@electrotank.com"&gt;mike@electrotank.com&lt;/a&gt; or just post a comment below.&lt;br /&gt;&lt;br /&gt;Thanks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-4735899660907482398?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/4735899660907482398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=4735899660907482398' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4735899660907482398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4735899660907482398'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/06/electroserver-4-feature-request.html' title='ElectroServer 4 Feature Request'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-33257673478500330</id><published>2007-06-03T07:57:00.000-06:00</published><updated>2007-06-05T22:06:18.477-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>AI and Emergent Behavior Examples</title><content type='html'>Jobe Makar has put together a great set of posts about AI and emergent behavior on his blog. They are well-worth looking at if you have an interest in this sort of thing.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jobemakar.blogspot.com/2007/05/emergent-behavior.html"&gt;Game of Life&lt;/a&gt;&lt;br /&gt;&lt;a href="http://jobemakar.blogspot.com/2007/05/flocking-birds-boids-deviation.html"&gt;Boids&lt;/a&gt;&lt;br /&gt;&lt;a href="http://jobemakar.blogspot.com/2007/06/crowding-behavior-in-games.html"&gt;Boids in an Actual Game&lt;/a&gt; (this one is pretty cool - shows how boids can actually be used to simulate a crowd).&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-33257673478500330?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/33257673478500330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=33257673478500330' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/33257673478500330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/33257673478500330'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/06/ai-and-emergent-behavior-examples.html' title='AI and Emergent Behavior Examples'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-3380017069892088025</id><published>2007-05-30T10:18:00.000-06:00</published><updated>2007-05-30T10:30:01.597-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>The Pitfalls of Polling and How to Avoid Them</title><content type='html'>The topic of polling has come up frequently on the &lt;a href="http://board.flashkit.com/board/forumdisplay.php?f=5"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;FlashKit&lt;/span&gt; Games forum&lt;/a&gt; so I figured I'd do a bit of a post on it.&lt;br /&gt;&lt;br /&gt;Polling is the process by which a client application can repeatedly contact the server to get updates and simulate real-time behavior. Some AJAX systems use polling in places. For example, you could build a chat on a website by having a Flash client call the server once per second asking if any messages have arrived for the current user. It's pretty simple to implement a basic poll-based chat or game. There are a lot of downsides to polling though and being aware of them can help you avoid the worst problems.&lt;br /&gt;&lt;br /&gt;The problem with polling is that under any significant load at all you will be crushing your web server and database. Lets assume each client polls the server every 1000 milliseconds or 1 second. This is quite slow in terms of responsiveness for a game but will work for our example. If you had 100 users, a trivial load overall, you would be generating a hit to your site every 10 milliseconds on average. At 500 users, it would be every 2 milliseconds. At 2500 users it's every 0.4 milliseconds.&lt;br /&gt;&lt;br /&gt;As you can see, this will become a crippling load very quickly. You can use a load &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;balancer&lt;/span&gt; to help but then you need to use clustered sessions or the database to share data between instances. This will in turn decrease performance across the board.&lt;br /&gt;&lt;br /&gt;Another thing to consider is the tremendous bandwidth requirements of that many HTTP requests. Unlike a socket server (like &lt;a href="http://www.electro-server.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;ElectroServer&lt;/span&gt;&lt;/a&gt;) that is event-driven and doesn't have a heavy protocol to begin with; HTTP contains a great deal of header information that gets sent with each and every request. This, in turn, dramatically increases your bandwidth requirements for both clients and the server. How big is the header? Here is a simple "GET" request header for my browser to my blog server. So this is what a client sends with every page request:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;GET / HTTP/1.1[&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;Host: mikegrundvig.blogspot.com[CRLF]&lt;br /&gt;Connection: close[&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;Accept-Encoding: &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;gzip&lt;/span&gt;[&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;Accept: image/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;gif&lt;/span&gt;, image/x-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;xbitmap&lt;/span&gt;, image/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;jpeg&lt;/span&gt;, image/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;pjpeg&lt;/span&gt;, application/x-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;shockwave&lt;/span&gt;-flash, application/x-ms-application, application/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;vnd&lt;/span&gt;.ms-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;xpsdocument&lt;/span&gt;, application/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;xaml&lt;/span&gt;+&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;xml&lt;/span&gt;, application/x-ms-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;xbap&lt;/span&gt;, application/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;msword&lt;/span&gt;, application/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;vnd&lt;/span&gt;.ms-excel, application/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;vnd&lt;/span&gt;.ms-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;powerpoint&lt;/span&gt;, */*[&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;Accept-Language: en-US[&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;User-Agent: Mozilla/4.0 (compatible; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;MSIE&lt;/span&gt; 7.0; Windows NT 6.0; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;SLCC&lt;/span&gt;1; .NET &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;CLR&lt;/span&gt; 2.0.50727; Media Center PC 5.0; .NET &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;CLR&lt;/span&gt; 3.0.04506; .NET &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;CLR&lt;/span&gt; 1.1.4322)[CRLF]&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;Referer&lt;/span&gt;: [&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;CRLF&lt;/span&gt;][&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;CRLF&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While it's just text, it adds up very quickly. Overall polling looks like it would work well but in practice it's often too expensive and slow for most applications.&lt;br /&gt;&lt;br /&gt;Alright, assuming you are sticking with polling then there are some things to keep in mind. The main idea is to keep the script you call as fast as humanly possible. Also, the code on the server must be clean and rock solid. In practice, you should avoid hitting the database at all costs for better performance.&lt;br /&gt;&lt;br /&gt;You also need to make your code on the client AND the server a bit smarter then you might think. The server code should queue up messages that should be delivered to the client in memory rather then on disk. Then when a client sends anything to the server, the messages should be attached to the response. This way if the client sends a "chat message", the response to that request can contain anything queued up for delivery.&lt;br /&gt;&lt;br /&gt;With our previous example, we said the poll call would occur every 1000 milliseconds. That should be thought of as the longest the client will wait before polling. If you use the last approach I suggested, you can make your polling algorithm much more intelligent. As an example:&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;Time Action&lt;br /&gt;0 poll&lt;br /&gt;1000 poll&lt;br /&gt;1500 send chat message&lt;br /&gt;2000 poll&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Should instead be:&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;Time Action&lt;br /&gt;0 poll&lt;br /&gt;1000 poll&lt;br /&gt;1500 send chat message&lt;br /&gt;2500 poll &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the first block, we poll every 1 second no matter what. In the second block, the code is smart enough to realize that since anything queued for delivery would have come back on the "chat" message request then we can delay another 500 milliseconds before polling again. This way you make the least number of requests to the server and still have just as timely updates.&lt;br /&gt;&lt;br /&gt;Likewise, you should have code that prevents the client from sending data to the server too quickly. If you must let them do it, queue up actions to send just like the server is queuing them up to you.  This allows you to send multiple requests at the expense of only one header.&lt;br /&gt;&lt;br /&gt;Finally, the server should attempt to disregard messages as aggressively as it can. For instance, what if someone joined and then left the room in between a user receiving updates? Ideally the users in the room shouldn't even be told because it doesn't matter. The server should just delete that data and not tell the users. Likewise, if people send several movement updates quickly, the client really only cares about the last one in many cases so just disregard the rest. By culling the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_31"&gt;data set&lt;/span&gt; before it gets to the client, you can decrease the bandwidth needed.&lt;br /&gt;&lt;br /&gt;Anyways, I hope this gives you an idea of the pitfalls involved in polling and the techniques you can use to dodge them. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-3380017069892088025?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/3380017069892088025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=3380017069892088025' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/3380017069892088025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/3380017069892088025'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/pitfalls-of-polling-and-how-to-avoid.html' title='The Pitfalls of Polling and How to Avoid Them'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-8383582758373223454</id><published>2007-05-23T21:32:00.000-06:00</published><updated>2007-05-23T21:53:51.994-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>CopyPixel is faster then Sprites?</title><content type='html'>As soon as you think you've come up with a pretty good way to do something you always find something better. So the other day I post a pretty fast AS3 example here on my blog and on the FlashKit forum. The example takes advantage of a couple performance techniques and seemed to work quite well.&lt;br /&gt;&lt;br /&gt;Soon after my post, someone suggested giving it a shot using the copyPixels method on BitmapData to see if it gets faster. I wasn't sure of the results as the copyPixel examples I'd seen were generally really specific to tile engines or some such and not to lots of moving sprites.&lt;br /&gt;&lt;br /&gt;So I figured I'd give it a shot. I ran into some trouble with the alpha channels initially but it's all working now and you can see it here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.electrotank.com/junk/mike/flash/copyPixel/"&gt;http://www.electrotank.com/junk/mike/flash/copyPixel/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The performance is so much better and uses less code that it makes me sad. In short, I have arrow objects in memory to represent every arrow. In the render loop (onEnterFrame event) I update their positions/status and create new ones as needed. Once that's done, I create a new BitmapData, loop over all the arrows and use copyPixels from my sprite sheet onto the correct position of the new BitmapData. Finally, I take the new BitmapData, convert it to a bitmap and replace the old bitmap with the new one. That's it. No tricks for performance or anything and it flys.&lt;br /&gt;&lt;br /&gt;One thing I don't understand though, in the previous engine (located &lt;a href="http://www.electrotank.com/junk/mike/flash/objectpool/"&gt;here&lt;/a&gt;) the time spent in the onEnterFrame event is less (look at the "render" field on the right) but the frame rate is lower too. In the new model, the time in onEnterFrame is higher but the frame rate is higher as well. My thought, and this is a total guess, is that the copyPixels method has more code-execution overhead but produces something easily rendered while the pooling sprite approach is the opposite; small code overhead but lots of objects to render.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sadly, this would mean that you need to choose your approach on what you are trying to do. If you need lots of available horsepower for code, then use pooling. If you need lots of objects then use copyPixels. Obviously this is a generalization but you get the picture. Anyways, have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-8383582758373223454?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/8383582758373223454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=8383582758373223454' title='45 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8383582758373223454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8383582758373223454'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/copypixel-is-faster-then-sprites.html' title='CopyPixel is faster then Sprites?'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>45</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-1977671649992347105</id><published>2007-05-21T21:28:00.000-06:00</published><updated>2007-05-22T06:55:05.258-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>AS3 is FAST!</title><content type='html'>I'm usually the one complaining about ActionScript performance but I have to give credit where it's due. AS3 is just plain fast.&lt;br /&gt;&lt;br /&gt;I'd been kicking around some AS3 ideas I had and ran into some pretty nifty performance tricks. You can see them in action at the URL below - (open it full screen as the swf is 1024x768 - no wimpy resolutions for this!):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.electrotank.com/junk/mike/flash/objectpool/"&gt;http://www.electrotank.com/junk/mike/flash/objectpool/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The controls on the left are simple.&lt;br /&gt;&lt;em&gt;Frames&lt;/em&gt; -how many frames to run the simulation.&lt;br /&gt;&lt;em&gt;Arrows per frame&lt;/em&gt; - how many arrows are to be generated per each frame.&lt;br /&gt;&lt;em&gt;Use pool&lt;/em&gt; - should the object pool be used for this simulation run.&lt;br /&gt;&lt;em&gt;Start&lt;/em&gt; - start the simulation, turns to stop when the simulation is running.&lt;br /&gt;&lt;br /&gt;The stats on the right are a little trickier.&lt;br /&gt;&lt;em&gt;Arrows &lt;/em&gt;- the number of arrows currently on the screen.&lt;br /&gt;&lt;em&gt;Render&lt;/em&gt; - how many milliseconds the enterFrame event has taken to process.&lt;br /&gt;&lt;em&gt;Total Arrows&lt;/em&gt; - the number of arrows used in the simulation thus far.&lt;br /&gt;&lt;em&gt;Total Render&lt;/em&gt; - how many milliseconds for all the enterFrame calls in the simulation.&lt;br /&gt;&lt;br /&gt;A combination of tricks were used to make it perform as well as it does.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1) Sprite sheets + scrollrect&lt;/strong&gt;&lt;br /&gt;This is the same trick VengenceMX is using for his &lt;a href="http://www.birchlabs.co.uk/Invasion5Volley.swf"&gt;Invasion&lt;/a&gt; game. In fact, I'm using his sprite sheet (thanks!). Basically, to handle an object + rotation, you simply have a sheet of images that contains all rotations/angles in a row. Then a little math is used to determine which image of the strip is to be shown. You then use scrollrect to show just that image. Think of it like a film strip you can slide back and forth to see only the image you want.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2) Object pooling&lt;/strong&gt;&lt;br /&gt;Object pooling is the process of storing objects in a pool when they are not in use so as to avoid the overhead of creating them again and again. In AS3, objects that are tied to the library are expensive to create. By storing them in a pool for later use you can greatly reduce memory usage and save a handful of milliseconds every frame.&lt;br /&gt;&lt;br /&gt;To see the pooling in action, simply run the simulation with "use pool" checked and note the "total render" time. Then run it again with out and note the difference. The results vary quite a bit but pooling is always faster. Some times it can be as much as 2x faster. In short, pooling burns less time per frame to create the sprites. The effect is even larger with movie clips. You might not see this as a frame rate increase but it still gives you more time to do code that matters (like AI or pathfinding).&lt;br /&gt;&lt;br /&gt;One other subtle difference occurs with pooling. You can see a slight "jerkiness" to the simulation if pooling is off. The "jerks" will occur every 1/2 - 1 second or so. I'm reasonably sure they are caused by garbage collection runs inside the Flash VM. Pooling uses a great deal less overall memory and so it experiences a lot less garbage collection all around - ie. smoother animation. This is really visible in scrolling tiles.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3) Utilizing the scene graph arrays&lt;/strong&gt;&lt;br /&gt;This is simple, but all the little bits count. I needed to store a collection of arrows so I could iterate over them each enter-frame. Traditionally, I'd create an array of arrows to do this. In AS3 though, there is no need. If you simply create a new empty sprite, and add it as a child to the stage, you have your array already.&lt;br /&gt;&lt;br /&gt;Anything added as a child can be retrieved and accessed easily. For instance, with my arrows, I had some code that looked like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;for(var i:int = 0; i &amp;lt; arrows.numChildren; i++) ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's it. That gives me my array already with no extra overhead. As I said, not a big deal, but the less work you do per frame the better.&lt;br /&gt;&lt;br /&gt;I'll be posting a lot more detail on points one and two in the next day or so. My object pooling code is actually a generic framework that works great as it is and can be dropped into any AS3 project without too much trouble. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-1977671649992347105?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/1977671649992347105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=1977671649992347105' title='146 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1977671649992347105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1977671649992347105'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/as3-is-fast.html' title='AS3 is FAST!'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>146</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-6698574196080988526</id><published>2007-05-18T16:14:00.000-06:00</published><updated>2007-05-18T17:50:56.150-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='utilities'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Encrypting Variables in Memory to Prevent Hacking</title><content type='html'>Previously I talked about how hackers can use memory tools to find and directly update crucial game variables on the fly. The solution to this is to encrypt those values. This means that if a hacker searches for a known value (like score) they will fail to find the right one because the score is encrypted in memory.&lt;br /&gt;&lt;br /&gt;I felt like dabbling in Flash a bit today so I went ahead and created a little utility to make the in-memory encryption easy. It's written as a pair of AS3 classes. One of them is the &lt;a href="http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm"&gt;TEA&lt;/a&gt; implementation from the &lt;a href="http://ascrypt3.riaforge.org/index.cfm"&gt;ASCrypt3&lt;/a&gt; library while the other is the utility itself. This type of system isn't useful if it isn't simple to use so that was the main goal. All methods are implemented as static to avoid needing to instantiate the utility. You can see pretty much every method below:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;// Create a handle for the variable&lt;br /&gt;var scoreName:String = "score"; &lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;// Set the initial score to 100&lt;br /&gt;MemoryCrypto.setValue(scoreName, 100);&lt;br /&gt;&lt;br /&gt;// Increment the score by 100, new value = 200&lt;br /&gt;MemoryCrypto.incrementValue(scoreName, 100);&lt;br /&gt;&lt;br /&gt;// Decrement the score by 50, new value = 150&lt;br /&gt;MemoryCrypto.decrementValue(scoreName, 50);&lt;br /&gt;&lt;br /&gt;// Multiply the score by 4, new value = 600&lt;br /&gt;MemoryCrypto.multiplyValue(scoreName, 4);&lt;br /&gt;&lt;br /&gt;// Divide the score by 2, new value = 300&lt;br /&gt;MemoryCrypto.divideValue(scoreName, 2);&lt;br /&gt;&lt;br /&gt;// Get the score&lt;br /&gt;var score:Number = MemoryCrypto.getValue(scoreName);&lt;br /&gt;&lt;br /&gt;// Display the score, 300&lt;br /&gt;trace(score);&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;Pretty simple. Internally it creates an instance of the TEA cipher and a pair of random numbers become the key. This key is then used for all encryption. The variable values are only unencrypted long enough to change and then re-encrypted for storage.&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;This solution is NOT infallible. A dedicated hacker will be able to actually tear the code apart in memory as opposed to just doing value-based searches but this will make it an order of magnitude harder then otherwise. It will stop many of the script-kiddies dead in their tracks.&lt;br /&gt;&lt;br /&gt;The code is available &lt;a href="http://www.electrotank.com/junk/mike/blog/MemoryCrypto.zip"&gt;here&lt;/a&gt; and free for any use. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-6698574196080988526?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/6698574196080988526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=6698574196080988526' title='37 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6698574196080988526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6698574196080988526'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/encrypting-variables-in-memory-to.html' title='Encrypting Variables in Memory to Prevent Hacking'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-8849935575603431477</id><published>2007-05-16T15:55:00.000-06:00</published><updated>2007-05-17T15:04:59.395-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Ensuring Data Integrity Between a Client and Server</title><content type='html'>In my last post, I talked about how to secure a Flash high score board. One of the steps included &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SSL&lt;/span&gt;. Several people immediately mentioned that they don't have access to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SSL&lt;/span&gt;. To that end, I'm putting together this little post to explain how it can be done without it.&lt;br /&gt;&lt;br /&gt;In the case of a high score board entry the data itself isn't secure. You just need to make sure it hasn't been modified. It doesn't matter if someone sniffs the HTTP data as long as they can't change it, right? To that end, there is no need to go overboard with a true encryption system when you can simply use a "&lt;a href="http://en.wikipedia.org/wiki/Digital_signature"&gt;digital signature&lt;/a&gt;" to get the same result. Basically, the client will "sign" the data and the server will verify that the signature and data match.&lt;br /&gt;&lt;br /&gt;Most digital signature techniques can get pretty complicated and involve using public/private key pairs. In our case, we are going to get the same effect with a ghetto approach. We are going to use a "&lt;a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function"&gt;cryptographic hash&lt;/a&gt;" to do this. A cryptographic hash function will take a block of data and turn it into a fixed length "fingerprint". The results of a hash function are reproducible. This means that it's output will always be the same for a given input. Another property of a good hash function is that a tiny change in the input will produce a dramatic change in the output.&lt;br /&gt;&lt;br /&gt;For the sake of this discussion, we will use MD5 as the hash of choice. There are better ones (like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;SHA&lt;/span&gt;1) but MD5 is supported by just about every language out there and is pretty simple. For example, &lt;a href="http://us.php.net/md5"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;PHP&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://pajhome.org.uk/crypt/md5/"&gt;JavaScript&lt;/a&gt;, &lt;a href="http://www.secureplay.com/product-docs/MD5-Message-Digest.htm"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;ActionScript&lt;/span&gt; 1&lt;/a&gt;, &lt;a href="http://gsolofp.blogspot.com/2006/01/actionscript-3-md5-and-sha1.html"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;ActionScript&lt;/span&gt; 3&lt;/a&gt;, and &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/security/MessageDigest.html"&gt;Java&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now we need to apply our hash function to the data itself. Say you need to submit a new score for user "Mike" with a value of "12345". The easiest approach is to simply concatenate those together and run the hash, IE "Mike12345" results in "3658279626b5ed3&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;cd&lt;/span&gt;137&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;bef&lt;/span&gt;212640144". Then you take the name, score, and hash and send it all to the server. The server duplicates the process to generate a hash and compares them. If the hash from the client matches the hash on the server then the data came across unmodified. If the hashes fail to match, you fail the submission. Nice and simple.&lt;br /&gt;&lt;br /&gt;You're not quite done though. If you stop here, you are still vulnerable to someone hacking the data. They could look and guess what you are doing (or inspect the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;SWF&lt;/span&gt; code) and duplicate the hash by hand, submitting a fake score. The way to prevent this is to append one more piece of data before you generate the hash. Specifically, a pass phrase or key.&lt;br /&gt;&lt;br /&gt;For the sake of argument, lets say you pass phrase is "password". You take the name, score and pass phrase and come up with this "Mike12345password". When you hash it, you get "a0501c5f1276&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;af&lt;/span&gt;9b5be999b980a1e18a". Notice how this is totally different then the previous hash? Then, you send the same data to the server as before; name, score, and hash. The server knows the password already and attempts to duplicate the hash. If it can, the score submission is good.&lt;br /&gt;&lt;br /&gt;If you obfuscate your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;SWF&lt;/span&gt;, this &lt;strong&gt;&lt;em&gt;might&lt;/em&gt;&lt;/strong&gt; be good enough. The problem is that the password itself is contained in your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;SWF&lt;/span&gt; file and the enterprising hacker might &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;decompile&lt;/span&gt; the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;SWF&lt;/span&gt; to figure it out. If this occurs, that will be able to easily duplicate the process and create the hash. The solution to this is for another blog post I'll do in a day or two.&lt;br /&gt;&lt;br /&gt;As you can see, each layer of security makes things that much harder for the hacker. While some of this seems complicated, much of it only needs to be created once and then reused as needed. A little library could be created that hides all these details from the developer and makes things nice and clean. If someone is interested in doing this, post a comment. I'd be willing to help out if there is interest. Have fun!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://us.php.net/md5"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-8849935575603431477?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/8849935575603431477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=8849935575603431477' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8849935575603431477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8849935575603431477'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/ensuring-data-integrity-between-client.html' title='Ensuring Data Integrity Between a Client and Server'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-6126260069861927168</id><published>2007-05-15T13:46:00.000-06:00</published><updated>2007-05-18T18:39:51.104-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Preventing High Score Board Hacks</title><content type='html'>Preventing hackers from ruining high score boards seems to come up all the time on the Flash forums. I end up posting some of this over and over again so I figured I'd blog about it to avoid having to re-post it.&lt;br /&gt;&lt;br /&gt;In short, there are four steps needed to hinder or possibly stop any casual or semi-casual hacking.&lt;br /&gt;&lt;strong&gt;1)&lt;/strong&gt; Use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SSL&lt;/span&gt; to prevent hackers from manipulating the data being sent over the wire&lt;br /&gt;&lt;strong&gt;2)&lt;/strong&gt; Encrypt all important variables in memory to protect from memory hacks&lt;br /&gt;&lt;strong&gt;3)&lt;/strong&gt; Use a Flash &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;obfuscator&lt;/span&gt; to prevent easy &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;decompilation&lt;/span&gt; and patching of the code&lt;br /&gt;&lt;strong&gt;4)&lt;/strong&gt; Validate anything possible on the server (score vs. length of play, etc)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 1)&lt;/strong&gt;&lt;br /&gt;Many of the easiest high-score hacks involve simply packet sniffing the data sent from the Flash client to the server and re-submitting it back to the server with a modified score. Using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;SSL&lt;/span&gt; stops this dead as packet sniffing &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;SSL&lt;/span&gt; traffic won't reveal anything useful to the hacker. Super cheap &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;SSL&lt;/span&gt; certificates can be purchased from &lt;a href="http://www.godaddy.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;GoDaddy&lt;/span&gt;&lt;/a&gt;. If &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;SSL&lt;/span&gt; is not an option, it's possible to use other security techniques to encrypt or ensure the integrity of the data stream. I've covered this process in detail &lt;a href="http://mikegrundvig.blogspot.com/2007/05/ensuring-data-integrity-between-client.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 2)&lt;br /&gt;&lt;/strong&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;&lt;em&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: I've created the utility I suggest below. You can see the post on it &lt;/em&gt;&lt;a href="http://mikegrundvig.blogspot.com/2007/05/encrypting-variables-in-memory-to.html"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt; Encypting&lt;/span&gt; the variables in memory seems odd but is a crucial technique to ensure that the memory hacks out there can't actually manipulate the game state directly. For instance, if you have an unencrypted score variable a memory tool would actually let the hacker find that value and update it to something else directly. Then when they submit their score, the game will send the new value as though it were correct. There is no easy way for the game to really know otherwise. Likewise, if you have stats or character abilities, all are easily hackable the same way.&lt;br /&gt;The fix for this is to store the value encrypted. So while the game shows you have 3 lives left, in memory it looks totally different. There is no easy pattern for the hacker to use to find the number of lives. In practice, updating your score by 1 would work something like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;var &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;rawScore&lt;/span&gt;:Number = decrypt(score);&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;rawScore&lt;/span&gt;++;&lt;br /&gt;score = encrypt(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;rawScore&lt;/span&gt;);&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;In practice, you would probably want to make it even cleaner with some sort of "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;decryptUpdateAndEncrypt&lt;/span&gt;" type methods, something full-service in a single call.&lt;br /&gt;&lt;br /&gt;The other trick to this is that the encryption scheme needs to use a "rotating" key. Every time the game is played, the encrypted value in memory should be different. This prevents any clever hacker from determining the key and writing a little tool to duplicate the encryption scheme - thus breaking your protection. Since the key is internal only, you can simply use a random number and it should work fine. You will want to use a nice and fast encryption scheme as well. Something like &lt;a href="http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm"&gt;TEA&lt;/a&gt; would be idea. A good JavaScript implementation can be found &lt;a href="http://www.shokhirev.com/nikolai/security/crypt.html"&gt;here&lt;/a&gt;. &lt;em&gt;As mentioned above, I've created a version of this utility and posted it &lt;/em&gt;&lt;a href="http://mikegrundvig.blogspot.com/2007/05/encrypting-variables-in-memory-to.html"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;&lt;strong&gt;Step 3)&lt;/strong&gt;&lt;br /&gt;This is a general hardening step. If you obfuscate your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;SWF&lt;/span&gt; file, it will be very hard for hackers to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;decompile&lt;/span&gt; it and determine what's going on under the covers. It's always a good practice if you are concerned about security, but try hard to never rely on this as your primary technique because it isn't prefect. While I haven't used &lt;a href="http://www.amayeta.com/software/swfencrypt/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;SWF&lt;/span&gt; Encrypt&lt;/a&gt;, I know and respect the owner of &lt;a href="http://www.amayeta.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;Amayeta&lt;/span&gt;&lt;/a&gt; and have no doubt his product will be an excellent choice.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Step 4)&lt;br /&gt;&lt;/strong&gt;This is another general step and it's specific implementation depends on the game. Try and validate everything on the server if possible. For instance, if their game session started 2 minutes ago, there should be no way they can submit a very high score. Likewise, track the time of all score submissions, it's not possible to submit high scores with tiny intervals between them. Try and think about how long it takes to play a game and use that as a guide. Also, when you fail a score, don't tell them why. Just say the score submission failed. OR, don't even tell them it failed, just ignore it. This makes the hacker have to work to figure out what went wrong. Don't make it easy for them.&lt;br /&gt;&lt;br /&gt;This post doesn't cover everything, it only covers the things many developers forget when trying to harden a game. Also keep in mind that there are lots of exploits in the games themselves. Tricks like slowing down the game timer (thus slowing down movement), exploiting bugs, etc. Make sure you have those covered as well.&lt;br /&gt;&lt;br /&gt;Finally, this isn't a way to perfectly protect a game. It simply makes it much harder for a casual hacker. They will have to really work at it if they want to cheat and in practice, that is generally good enough. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-6126260069861927168?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/6126260069861927168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=6126260069861927168' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6126260069861927168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6126260069861927168'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/preventing-high-score-board-hacks.html' title='Preventing High Score Board Hacks'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-1611982052440046675</id><published>2007-05-14T21:37:00.000-06:00</published><updated>2007-05-14T21:40:24.381-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Data Structures for Flash Games</title><content type='html'>I'm very happy to see that a nice set of data structures used for game development has been created using AS3. This collection includes many useful structures like hashtables, BSTs, queues, graphs, linked lists and many more. You can find it here:&lt;br /&gt;http://lab.polygonal.de/ds/&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-1611982052440046675?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/1611982052440046675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=1611982052440046675' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1611982052440046675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1611982052440046675'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/data-structures-for-flash-games.html' title='Data Structures for Flash Games'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-6682161258351985082</id><published>2007-05-13T06:51:00.000-06:00</published><updated>2007-05-13T07:44:02.799-06:00</updated><title type='text'>Scripting in Java is now EASY!</title><content type='html'>There are a lot of parts of the Java API that I don't like so much. Some feel clumsy or ackward (java.util.zip - try &lt;a href="https://truezip.dev.java.net/"&gt;TrueZip&lt;/a&gt; to see it handled cleanly) and some are just poor in general (java.net.URLConnection - &lt;a href="http://jakarta.apache.org/commons/httpclient/"&gt;HttpClient&lt;/a&gt; in Jakarta Commons shows how it should be done). But then they come out with a great API that makes you forgive the other irritations. For instance, I've always been impressed with the power of JDBC, the simplicity of JMS, and now, the capability of JSR 232's scripting API which is included with Java 1.6.&lt;br /&gt;&lt;br /&gt;For a current project, we need to support multiple scripting languages inside an application. This was a real headache previously. Every language was handled differently and BSF (Bean Shell Framework from Apache) never seemed to work very well.&lt;br /&gt;&lt;br /&gt;With the advent of JSR 232, It's be downright easy to add scripting to the system. We wanted to allow developers to use scripts to extend the product. Internally the product uses interfaces at these points so it's easy for developers to use. They simply create a class that implements the interface and register it with the server. Nice and clean. This same approach can be done with scripting languages too!&lt;br /&gt;&lt;br /&gt;As an example, consider this interface:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;public interface Calculator {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int square(int number);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This little snippet of code includes everything you need to meet that interface using JavaScript and invoke it with Java. Check it out:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;// Build the script itself&lt;br /&gt;StringBuilder script = new StringBuilder();&lt;br /&gt;script.append("function square(numberIn) { \n");&lt;br /&gt;script.append("&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return numberIn * numberIn; \n");&lt;br /&gt;script.append("} \n");&lt;br /&gt;&lt;br /&gt;// Create the engine manager and get the correct engine&lt;br /&gt;ScriptEngineManager engineManager = new ScriptEngineManager();&lt;br /&gt;ScriptEngine engine = engineManager.getEngineByName("ECMAScript");&lt;br /&gt;&lt;br /&gt;// Get an "invocable" version of the engine&lt;br /&gt;Invocable invocableEngine = (Invocable) engine;&lt;br /&gt;&lt;br /&gt;// Have the engine parse and load the script&lt;br /&gt;engine.eval(script.toString());&lt;br /&gt;&lt;br /&gt;// Use the invocable engine to wrap the script with the interface&lt;br /&gt;Calculator calculator = invocableEngine.getInterface(Calculator.class);&lt;br /&gt;&lt;br /&gt;// Call it&lt;br /&gt;int numberToSquare = 2;&lt;br /&gt;int numberSquared = calculator.square(numberToSquare);&lt;br /&gt;System.out.println(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String.format("%1$d * %1$d = %2$d",&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;numberToSquare,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;numberSquared));&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Slick huh? The key is the Invocable interface. Any scripting engine that meets that interface provides the ability for you to invisibly treat a script just like a class. You simply give it the interface you want to use and internally a wrapper will be created for your script. It even handles type conversion of all primitives nice and cleanly. For all intents and purposes it IS a class as it will retain scope and variables between invocations.&lt;br /&gt;&lt;br /&gt;With a little work, any application that needs it could easily be set up to support scripted extensions. A big thanks to the members involved in JSR 232 for pulling off such a clean approach to a messy problem.&lt;br /&gt;&lt;br /&gt;A good article that goes into this in more detail is available &lt;a href="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-6682161258351985082?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/6682161258351985082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=6682161258351985082' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6682161258351985082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/6682161258351985082'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/scripting-in-java-is-now-easy.html' title='Scripting in Java is now EASY!'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-7658915011936967292</id><published>2007-05-09T19:13:00.000-06:00</published><updated>2007-05-09T21:53:39.471-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='utilities'/><title type='text'>Batch Image Compression Utility</title><content type='html'>A few years ago, Electrotank had a project that involved literally hundreds of images that were loaded in dynamically. These images were generated out of a 3D application as single frames with an alpha channel (PNGs). One of the problems we ran into was compression. Re-rendering the huge set of images took many hours and we were never sure how much compression was needed up front.&lt;br /&gt;&lt;br /&gt;To that end, I created a tool in C# that can go through a directory tree, take every JPG and PNG image and save it out to another directory tree with a given compression level. Nothing too sexy but useful at times. It also supports dragging and dropping the directories to make it a little easier.&lt;br /&gt;&lt;br /&gt;Feel free to use it if it might be useful. You can get the tool here:&lt;br /&gt;&lt;a href="http://www.electrotank.com/junk/mike/blog/ImageSquisher.zip"&gt;http://www.electrotank.com/junk/mike/blog/ImageSquisher.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-7658915011936967292?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/7658915011936967292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=7658915011936967292' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7658915011936967292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7658915011936967292'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/batch-image-compression-utility.html' title='Batch Image Compression Utility'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-4624772131345011064</id><published>2007-05-08T06:14:00.000-06:00</published><updated>2007-05-08T06:38:21.738-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='ibatis'/><title type='text'>I've Had Enough of Hibernate</title><content type='html'>Alright, I know it sounds like sacrilege but I'm fed up with Hibernate. I know it seems to be the Java developers tool of choice when dealing with a database but I've had enough.&lt;br /&gt;&lt;br /&gt;I've had misgivings about it before. The number of jars and dependencies makes me cringe every time I see the list. Also, I've always found debugging errors with it to be very cumbersome. Personally, I've never liked it's weird hybrid SQL syntax either. Some people love it, but I've always found it a hassle and never quite got my head around it.&lt;br /&gt;&lt;br /&gt;The final straw though was when we tried to integrate it into our newest project. We are using a rather deep set of classloaders to isolate parts of the application and keep things clean. Overall it's working very well. The only real issue we've run into is when we use a framework that has it's own classloader hierarchy. Even then, a little tap dancing around with Thread.currentThread().setContextClassLoader(); has solved the issue.&lt;br /&gt;&lt;br /&gt;Until Hibernate that is. For some reason we just can't get Hibernate to work properly in our classloader scenario. CGLib (one of the plethora of jars needed) throws a NoClassDefFound exception. The irritating thing is that right before the call to Hibernate, we can use any of the available classloaders (both current class and thread context) and find the needed class. So somewhere inside of CGLib or Hibernate (or a combination of both) it's doing something screwy and breaking. We know our code works because we can drop Spring (which uses classloaders too) and everything works.&lt;br /&gt;&lt;br /&gt;So, after googling classloader issues with Hibernate (and there are a LOT out there) and finally posting on Hibernate forums with no response I gave up. I decided to give &lt;a href="http://ibatis.apache.org/"&gt;iBatis&lt;/a&gt; from &lt;a href="http://www.apache.org/"&gt;Apache&lt;/a&gt; a try. Wow. I love it. Simple, clean, easy. It has only one required jar for much of the functionality too, always a perk. Even better is that it has the nice Apache 2.0 license which is very corporate friendly. The best part? iBatis solves the whole classloader mess by letting you simply pass in the classloader you want to use when you set it up. It doesn't get any better then that ;)&lt;br /&gt;&lt;br /&gt;In the end, I'll still use Hibernate for things (mostly with Spring, which hides some of the hassle) but I think when I need something quick and easy or more control of the SQL I'll be using iBatis from now on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-4624772131345011064?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/4624772131345011064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=4624772131345011064' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4624772131345011064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4624772131345011064'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/ive-had-enough-of-hibernate.html' title='I&apos;ve Had Enough of Hibernate'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-1613675866026946535</id><published>2007-05-05T13:14:00.000-06:00</published><updated>2007-05-05T13:30:52.040-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Patent a Number? Never!</title><content type='html'>I don't believe it's possible to patent a number yet that's precisly how lawyers are interpreting the whole HD-DVD key release. I won't go into detail on it here, this article covers it fully:&lt;br /&gt;&lt;a href="http://www.macworld.com/weblogs/editors/2007/05/digg/index.php"&gt;http://www.macworld.com/weblogs/editors/2007/05/digg/index.php&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'll just add my two cents:&lt;br /&gt;13256278887989457651018865901401704640&lt;br /&gt;and for those of you who prefer it in hex:&lt;br /&gt;09-F9-11-02-9D-74-E3-5B-D8-41-56-C5-63-56-88-C0&lt;br /&gt;&lt;br /&gt;This blog has lots of other uses for that number too:&lt;br /&gt;&lt;a href="http://www.enigmacurry.com/2007/05/01/my-new-favorite-number-is-being-censored/"&gt;http://www.enigmacurry.com/2007/05/01/my-new-favorite-number-is-being-censored/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-1613675866026946535?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/1613675866026946535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=1613675866026946535' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1613675866026946535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/1613675866026946535'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/patent-number-never.html' title='Patent a Number? Never!'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-7052512756545786616</id><published>2007-05-05T12:51:00.000-06:00</published><updated>2007-05-05T13:13:32.663-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Read The Bills Act</title><content type='html'>Ha, I stumbled across this while surfing and thought it was too good to pass up:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.downsizedc.org/read_the_laws.shtml"&gt;http://www.downsizedc.org/read_the_laws.shtml&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In short, it's a proposal for that ensures that everyone who votes on a law has actually read and hopefully understands it. It's well worth the read. I feel this would really help as it would force, in part, for legislation to be both simpler, cleaner, and more "public". All are very good things.&lt;br /&gt;&lt;br /&gt;The Constitution and Bill of Rights are both quite short and to-the-point in addtion to being elegantly phrased. They can be understood without too much difficulty by even school children. At what point did laws get so complicated that people have become unable to easily understand them? If you think laws arn't that bad, take a look at the Patriot Act, a relatively straightforward piece of legislation:&lt;br /&gt;&lt;a href="http://fl1.findlaw.com/news.findlaw.com/cnn/docs/terrorism/hr3162.pdf"&gt;http://fl1.findlaw.com/news.findlaw.com/cnn/docs/terrorism/hr3162.pdf&lt;/a&gt;&lt;a href="http://www.epic.org/privacy/terrorism/hr3162.pdf"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That single act is 132 pages of dense text and verbiage. I doubt anyone not a lawyer has seen anything that bad since they last read the loan agreement when buying a house. I challenge any layman or average citizen to really dig in and grasp it all.&lt;br /&gt;&lt;br /&gt;If you think the Patriot Act looks hard to follow, try the tax code at 10,000 pages!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-7052512756545786616?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/7052512756545786616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=7052512756545786616' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7052512756545786616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7052512756545786616'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/read-bills-act.html' title='Read The Bills Act'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-2365216631881848573</id><published>2007-05-04T20:02:00.000-06:00</published><updated>2007-05-05T13:31:27.508-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Beta Testers needed for Docunator - ActionScript Documentation Tool</title><content type='html'>&lt;p&gt;We've been working on a pretty slick tool for generating HTML documentation from AS2 or AS3 classes. It is called Docunator and will be commercially available very soon (probably 2 weeks). We need a few beta testers to help us test some real-world code. If interested then contact Jobe at &lt;a href="mailto:jobe@electrotank.com"&gt;jobe@electrotank.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here are some of the features: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create a project that saves your settings. &lt;/li&gt;&lt;li&gt;Point to one to many class paths. &lt;/li&gt;&lt;li&gt;Ignore specific packages or classes. &lt;/li&gt;&lt;li&gt;JavaDocs style tag support &lt;/li&gt;&lt;li&gt;Generates docs that look similar to the Flash CS3 AS3 docs (fully customizable with css) by default&lt;/li&gt;&lt;li&gt;Supports totally custom documentation formats via XML templates and a pseudo-scripting language&lt;/li&gt;&lt;li&gt;Cross linking of data types (go class/property/method surfing) &lt;/li&gt;&lt;li&gt;Syntax-highlighted source code optionally included in output &lt;/li&gt;&lt;li&gt;And more!&lt;/li&gt;&lt;li&gt;..other features to come are automatic UML diagrams and command line support&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-2365216631881848573?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/2365216631881848573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=2365216631881848573' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/2365216631881848573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/2365216631881848573'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/beta-testers-needed-for-docunator.html' title='Beta Testers needed for Docunator - ActionScript Documentation Tool'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-224977563058117542</id><published>2007-05-04T19:29:00.000-06:00</published><updated>2007-05-09T21:52:50.373-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='utilities'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Converting AS2 to AS3 Automatically</title><content type='html'>Jobe and I have a big project that involved a huge ActionScript API that needed to be in both AS2 and AS3. To that end, I created a simple little Java tool that rips through a directory structure and does some migration for ya. It's not perfect at all but it does a good job on the fundamental changes (adding packages, Void to void, and others.). It also has some nifty "annotation"-style functions that give you extra functionality if you need it.&lt;br /&gt;&lt;br /&gt;Jobe goes into all this in a lot more detail (providing the download, instructions, etc.) on his blog &lt;a href="http://jobemakar.blogspot.com/2007/05/convert-actionscript-2-to-actionscript.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-224977563058117542?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/224977563058117542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=224977563058117542' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/224977563058117542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/224977563058117542'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/converting-as2-to-as3-automatically.html' title='Converting AS2 to AS3 Automatically'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-7310179590682068779</id><published>2007-05-02T17:17:00.000-06:00</published><updated>2007-05-04T19:46:55.831-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Preventing SQL Injection Attacks</title><content type='html'>This is a big post I made a year ago on the FlashKit Games Forum. I'm posting it again here so it won't get lost as it's still reasonably accurate.&lt;br /&gt;&lt;br /&gt;This post was created due to a rash of high-score board hacks (not necessarily SQL injection specific) and some general interest in security. That's why the example is based around a high-score board.&lt;br /&gt;&lt;br /&gt;-=-&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;The Problem&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;SQL Injection is the process by which someone sends a snippet of SQL code in place of a real value and it gets executed. Let's say you have a "Scores" table that looks like this (in column name - data type format):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;ScoreId - int (pk), Score - int, Username - varchar, Date - datetime&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And lets say you support the ability to load all the scores for a specific person. The SQL for that would look something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;select ScoreId, Score, Username, Date from Scores where Username = '#name#'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Assume that #name# is the data coming from the client, just posted in directly. So in practice, the query might look like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#333333;"&gt;select ScoreId, Score, Username, Date from Scores where Username = 'webgeek'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now a clever hacker (or a script kiddie with the right tools) will attempt to inject malicious SQL as their name. Something like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;' or '1' = '1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At first glance, that seems like a silly little snippet but when it gets combined with your original SQL statement, it now does this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#333333;"&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;select ScoreId, Score, Username, Date from Scores where Username = '' or '1' = '1'&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And presto, they just returned every score in the system. This might cause huge performance problems or not, but it's something you didn't want them to do.&lt;br /&gt;&lt;br /&gt;Now for the bigger problems. Based on our existing table and query, the evil hacker can go farther. They could drop your table and thus delete all your high scores:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;'; drop table Scores; --&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Becomes:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;select ScoreId, Score, Username, Date from Scores where Username = ''; drop table Scores; --'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The semi-colon tells the SQL engine that it's the end of a query. Most engines will let you run queries back to back like that. The -- is a comment. So they just commented out your closing ' mark.&lt;br /&gt;&lt;br /&gt;And for the best one?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;'; update Scores set Username = 'HAXXOR' where ScoreID in (Select top 1 ScoreId from Scores order by Score desc); --&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This becomes (Formatted for readability):&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;&lt;pre&gt;&lt;br /&gt;select&lt;br /&gt;     ScoreId,&lt;br /&gt;     Score,&lt;br /&gt;     Username,&lt;br /&gt;     Date&lt;br /&gt;from&lt;br /&gt;     Scores&lt;br /&gt;where&lt;br /&gt;     Username = '';&lt;br /&gt;&lt;br /&gt;update&lt;br /&gt;     Scores&lt;br /&gt;set&lt;br /&gt;     Username = 'HAXXOR'&lt;br /&gt;where&lt;br /&gt;     ScoreId in&lt;br /&gt;     (&lt;br /&gt;          Select top 1&lt;br /&gt;               ScoreID&lt;br /&gt;          from&lt;br /&gt;               Scores&lt;br /&gt;          order by&lt;br /&gt;               Score desc&lt;br /&gt;     );&lt;br /&gt;--'&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;The "top 1" command says return only the first record. That's specific to SQL Server and Access but there are equivalent statements for all databases. That query will simply update the highest score in the system with a new username. The name could be a real user and you would never know that your board is being hacked.&lt;br /&gt;&lt;br /&gt;SQL Injection attacks can be used like a sledgehammer or a scalpel and they are VERY difficult to track down. A good hacker can take the "email my password" form and update an admin email address with his own, run the form, get the password, and update the email back. Presto, he now has admin access and no one is the wiser.&lt;br /&gt;&lt;br /&gt;I won't go into more details on what can be done with SQL injection attacks because this isn't a guide for hackers.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;The Solution&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Input Validation&lt;br /&gt;&lt;/strong&gt;This is crucial. Every form on every web application needs server-side validation. This goes for data submitted from Flash to the server as well. Just think of that as a form without an HTML front-end. Validation on the client (Flash or JavaScript) is excellent and should be done but even if you have the greatest client-side validation you MUST also have server-side validation. Remember, the user has the client in their hands. It CAN and WILL be hacked. The server is MUCH harder to hack.&lt;br /&gt;&lt;br /&gt;If you know that "username" can't be more then 30 characters then validate the fact that it's &lt;= 30 characters before you think of using it in a query. If it's too long, just throw it out. Many of the sophisticated SQL injection attacks depend upon large SQL statements. If you know "score" should be a number greater then 0 and no more then 5 digits, validate that it's a number and between &gt; 0 and &lt;= 99999. If you validate before you process then you can help limit the type of attack they can do right off. &lt;strong&gt;Error Handling/Reporting&lt;/strong&gt;&lt;br /&gt;This is another crucial step. In many web application frameworks or languages you get pretty error messages to help developers debug properly. These are good things in development but terrible in production. You want to ALWAYS use generic error messages when something goes wrong. Something like "failed to save score" would be good. This will avoid giving the hacker any information they can use to interpret the success or failure of their attacks.&lt;br /&gt;&lt;br /&gt;If your application is stable (doesn't break too much) then I suggest going one step farther. Every time an error occurs, have it log that to a file or (even better) send an email with all the pertinent error details. This will help you debug it AND give you a heads up when someone is attempting to crack the application. This practice is used by many development shops out there and always pays off in the end.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Quote Escaping&lt;br /&gt;&lt;/strong&gt;It is possible to escape quotes and characters in the incoming data to prevent attacks. I DON'T recommend this though as it's a very difficult process to do properly (very database specific). You can't simply make ' become ''. That will NOT prevent attacks as there are many ways to escape and allow quotes in a given database. Sadly, this is just not a good approach to even attempt. It will provide a false sense of security and not make the app any more difficult to hack.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Prepared Statements&lt;/strong&gt;&lt;br /&gt;Believe it or not, there is a silver bullet (mostly) for SQL Injection attacks. Simply use "Parameterized Statements" (often called "Prepared Statements" as well). A prepared statement is one where you create a query with placeholders for your parameters and you ask the database to simply bind your values to those placeholders. What makes it so nice is that you don't have to worry about the quotes or anything else at all. To use our example from above, here is the parameterized version.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;color:#333333;"&gt;select ScoreId, Score, Username, Date from Scores where Username = ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you bind the parameter, the database will automatically quote it as needed. This will escape any invalid characters. The injection examples above will all fail with prepared statements. Additionally, prepared statements are significantly faster for repeat queries as the database internally optimizes them. If you use a prepared statement over and over again you will see a huge performance increase over concatenated string SQL statements (this is assuming you have appropriate statement caching enabled in your connection pool or on the database). This isn't an article on databases so we won't go into detail here.&lt;br /&gt;&lt;br /&gt;The language/database you use dictates how you interact with prepared statements. In general it's quite simple. Both Java and .NET have database-neutral techniques that you use so your code is the same for Oracle, DB2, SQL Server, MySQL, etc. PHP has that if you are using Pear DB but not if you are going against MySQL (or other databases) directly without Pear.&lt;br /&gt;&lt;br /&gt;Java with any database&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments"&gt;http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;.NET with any database&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconparametersindataadaptercommands.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconparametersindataadaptercommands.asp&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PHP w/Pear DB (database abstraction layer)&lt;br /&gt;&lt;a href="http://www.codepoets.co.uk/doc/php_pear_quickstart_database_web_applications"&gt;http://www.codepoets.co.uk/doc/php_pear_quickstart_database_web_applications&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PHP w/MySQL&lt;br /&gt;&lt;a href="http://www.webdesignforums.net/archive/index.php/t-18762.html"&gt;http://www.webdesignforums.net/archive/index.php/t-18762.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In lieu of prepared statements, you could also use stored procedures. They are a type of parameterized query. I don't go into them here though as most game developers seem to steer clear of them.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Database Security&lt;br /&gt;&lt;/strong&gt;No matter how good you are, it's very likely you will make mistakes. The catch-all for these mistakes is to lock down access to the database. In the high score example, the user account accessing the database only needs the ability to run insert and select statements against the "scores" table. If you restrict the account properly then it would be impossible for them to delete the scores table or even update records in the table. The way to do this is to simple create a few new accounts for your application. NEVER use your admin account to the database as the username/password in your applications. This step will dramatically reduce the damage that an enterprising hacker could do even if they do find a vulnerable form.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-7310179590682068779?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/7310179590682068779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=7310179590682068779' title='40 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7310179590682068779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/7310179590682068779'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/preventing-sql-injection-attacks.html' title='Preventing SQL Injection Attacks'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-4476228628748040853</id><published>2007-05-01T16:12:00.000-06:00</published><updated>2007-05-04T19:46:37.187-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='generics'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Dynamic Class Instantiation with Generics</title><content type='html'>I've been working on a project that required a great deal of dynamic class instantiation lately and this little piece of code caused me a bit of a headache until I figured it out with the help of Peter Royal from the &lt;a href="http://mina.apache.org"&gt;MINA&lt;/a&gt; project.&lt;br /&gt;&lt;br /&gt;Normally, you instatiate a class dynamically using something like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="java"&gt;&lt;span style="color: #000000; font-weight: bold;"&gt;Class&lt;/span&gt; mapClazz = &lt;span style="color: #000000; font-weight: bold;"&gt;null&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;try&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt; &amp;nbsp; &amp;nbsp; mapClazz = &lt;span style="color: #000000; font-weight: bold;"&gt;Class&lt;/span&gt;.&lt;span style="color: #006600;"&gt;forName&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;"java.util.HashMap"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;&amp;#125;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;catch&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.google.com/search?q=allinurl%3AException+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;Exception&lt;/span&gt;&lt;/a&gt; e&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt; &amp;nbsp; &amp;nbsp; e.&lt;span style="color: #006600;"&gt;printStackTrace&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt; &lt;a href="http://www.google.com/search?q=allinurl%3AMap+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;Map&lt;/span&gt;&lt;/a&gt; map = &lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.google.com/search?q=allinurl%3AMap+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;Map&lt;/span&gt;&lt;/a&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt; mapClazz.&lt;span style="color: #006600;"&gt;newInstance&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;All the classloader-ish methods like loadClass, forName, etc. return Class&amp;lt;?&amp;gt; as of 1.5. This little piece of code works fine BUT while this doesn't give you a compiler warning with -Xlint:unchecked enabled, it should.&lt;br /&gt;&lt;br /&gt;The problem comes when you actually try to use generics properly in this case. The final solution ends up looking like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="java"&gt;Class&amp;lt;? &lt;span style="color: #000000; font-weight: bold;"&gt;extends&lt;/span&gt; List&amp;gt; listClazz = &lt;span style="color: #000000; font-weight: bold;"&gt;null&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;try&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt; &amp;nbsp; &amp;nbsp; Class&amp;lt;?&amp;gt; clazz = &lt;span style="color: #000000; font-weight: bold;"&gt;Class&lt;/span&gt;.&lt;span style="color: #006600;"&gt;forName&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #ff0000;"&gt;"java.util.ArrayList"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt; &amp;nbsp; &amp;nbsp; listClazz = clazz.&lt;span style="color: #006600;"&gt;asSubclass&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.google.com/search?q=allinurl%3AList+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;List&lt;/span&gt;&lt;/a&gt;.&lt;span style="color: #000000; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;&amp;#125;&lt;/span&gt; &lt;span style="color: #000000; font-weight: bold;"&gt;catch&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;a href="http://www.google.com/search?q=allinurl%3AException+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;Exception&lt;/span&gt;&lt;/a&gt; e&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt; &amp;nbsp; &amp;nbsp; e.&lt;span style="color: #006600;"&gt;printStackTrace&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt; &lt;a href="http://www.google.com/search?q=allinurl%3AList+java.sun.com&amp;bntl=1"&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;List&lt;/span&gt;&lt;/a&gt; list = listClazz.&lt;span style="color: #006600;"&gt;newInstance&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#40;&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;#41;&lt;/span&gt;;&lt;/div&gt;&lt;br /&gt;Notice that you use "? extends" even if it's an interface? You also need to use the asSubclass method to handle the cast. That method takes the place of the explicit cast used in the first example. It's important to note though that the ClassCastException is still thrown if necessary, just from inside that method instead.&lt;br /&gt;&lt;br /&gt;Maybe it's just me, but I didn't find this whole thing very intuitive which is why I'm posting it. Maybe now others can find the solution without bugging their friends.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-4476228628748040853?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/4476228628748040853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=4476228628748040853' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4476228628748040853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4476228628748040853'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/dynamic-class-instantiation-with.html' title='Dynamic Class Instantiation with Generics'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-8504310116284276068</id><published>2007-04-30T15:23:00.000-06:00</published><updated>2007-05-04T19:46:18.020-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='electrotank'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>New Electrotank Game</title><content type='html'>Electrotank has just finished up a game for MTV. &lt;a href="http://www.mtv.com/games/arcade/game/game.jhtml?arcadeGameId=10080284"&gt;Crowd Magnet&lt;/a&gt; is an interesting little game for the show Pimp My Ride. Jobe talks about it in a lot more detail &lt;a href="http://jobemakar.blogspot.com/2007/05/new-game-for-mtvpimp-my-ride.html"&gt;here&lt;/a&gt;. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-8504310116284276068?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/8504310116284276068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=8504310116284276068' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8504310116284276068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/8504310116284276068'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/new-electrotank-game.html' title='New Electrotank Game'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-4583166682134468409</id><published>2007-04-25T13:55:00.000-06:00</published><updated>2007-05-04T19:45:50.755-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='electrotank'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Jobe Makar's Blog</title><content type='html'>Just a heads up but my good friend and business partner, Jobe Makar, has created a blog &lt;a href="http://jobemakar.blogspot.com"&gt;here&lt;/a&gt;. If you head over there you can read all about his travels in Flash and the seedy underbelly of online commercial game development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-4583166682134468409?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/4583166682134468409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=4583166682134468409' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4583166682134468409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/4583166682134468409'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/jobe-makar.html' title='Jobe Makar&apos;s Blog'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3639186260082284014.post-5408584394952293206</id><published>2007-04-20T13:50:00.000-06:00</published><updated>2007-05-04T19:45:27.594-06:00</updated><title type='text'>Hello!</title><content type='html'>Hello! I've been meaning to create a blog for a long time and figured I might as well get it over with. I plan on using this to post anything I find interesting or fun. In general, it will be Java or Flash code/techniques but sometimes it will be something a bit less geeky. No promises on that ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3639186260082284014-5408584394952293206?l=mikegrundvig.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikegrundvig.blogspot.com/feeds/5408584394952293206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3639186260082284014&amp;postID=5408584394952293206' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/5408584394952293206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3639186260082284014/posts/default/5408584394952293206'/><link rel='alternate' type='text/html' href='http://mikegrundvig.blogspot.com/2007/05/hello.html' title='Hello!'/><author><name>Mike Grundvig</name><uri>http://www.blogger.com/profile/16203288027937281451</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry></feed>
