Java 4k Resources Thread

I think that there are so many different compression tools and byte-saving techniques that the common programmer doesn’t know about that it can be a real detriment to them, and often a bit unfair. We’ve had threads like this one before, so I figured I’d start a new one.

Applet Templates
Start with a good applet template. It will have all the base functionality you need in the fewest bytes possible.
http://www.java-gaming.org/index.php/topic,21626.0.html

Compress your class
There are several ways you can do this. Riven has amazingly provided us with an HTTP service that does all the dirty work for you.
Compile 'n Shrink - HTTP Service - http://www.indiespot.net/app/java-four-kay

If you do not use Riven’s tool, then you should use Pack200 and at least one compression tool (maybe all of them!). This can be a bit time consuming but will save you a massive number of bytes.

Pack200
No matter how you do it, you will want your game to eventually be compressed with Pack200.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/jar/Pack200.html
http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/pack200.html

Compression Tools and Obfuscators
There are lots of different tools out there to squeeze a few extra bytes out of your jar. I will eventually include specific guides with how to use each tool as they are written.
ProGuard - http://proguard.sourceforge.net/
JShrink - http://www.e-t.com/jshrink.html
JoGa - http://www.nq4.de/

Smart Techniques
Note that a lot of these things will be automatically adjusted by most optimizers. Still isn’t it fun to do a lot of it manually? :slight_smile:

  • All global variables should be named only a single character. Local variables can have whatever name you want.
  • All constants should be declared static final so they can go in the constants pool.
  • In general, you should use the shortest possible method names you can, like System.nanoTime() versus System.currentTimeMillis().
  • Every string literal you create adds at least a couple bytes per character. As a result, keep your strings short.
  • Every time you use a method, it will add bytes equal to the number of characters in that method. However, each method will be added only once for all uses.
  • Keep your code all in one class, and put all your code in one Applet method (like start()).
  • Use local variables wherever possible. Because your game is in one method, you should be able to avoid using almost any globals.
  • When concatenating numbers to strings, use String.valueOf() rather than directly adding them together. This will save many bytes.

External Links
A nice big 4k guide: http://wiki.java.net/bin/view/Games/4KGamesDesign

Please please add replies to this, especially extra tips and guides on how to use the compression tools and pack200. We want this thread to eventually be full of step-by-step guides so that people can focus on their code.

I’m not sure whether the below was an intentional simplification, if so I apologise for being overly picky with my technical correctness ::slight_smile:

Due to class files using a UTF-8 encoding (Modified UTF-8) to store string literals, this is not true.
Every string literal ( sl ) you create adds atleast 2 + sl.length bytes, and at most 2 + sl.length*3 bytes.

So if you ignore the 2 byte length, and limit your string to containing only characters from the first 127 positive byte values (~= western-latin alphabets), your statement is sort-of accurate - beyond that, it gets progressively more incorrect.

I’m pretty sure that consensus from the earlier template discussion was that if you want your applet to behave correctly you have to spawn off a thread.

Goodies link page from last year:

http://www.java-gaming.org/index.php/topic,19461.0.html

Oh yeah, I meant to add: correct me my mistakes! Some things (like the one byte per character for strings) were pretty much me working from memory of lsat year, I’m sure I’ve got plenty of little issues up there.

Thanks for the clarifications. I’ll keep editing this as we get more info. I have no experience with the optimizers, so if some things are pointless then I won’t really know it.

I’m personally annoyed I have to use optimizers to be able to contend - the fun part for me is putting in static final etc. etc. in order to get the bytes down. And then doing a smart thing with a loop, etc. When your code literally goes from 4kb to 1/2kb with optimizers and compression, that’s kind of frustrating. Part of the reason I made this thread is because last year I was a bit overwhelmed with the incredibly large number of things I had to do to compress my game, none of which had anything to do with code. I think it’s a really steep hill you have to climb as someone new to 4k.

Pack200 brings my current project down to 1.47 kb from 2.05 kb. That’s very very good. :smiley:

If somebody has the tools that run on linux, I can make my server happy by doing some bruteforce zip-attacks on your cute JARs.

Last year we such an app, but had some reliance on *.exe file, and it was macroing some GUI, and my server is blind. (who did it? Appel??)

So if anybody it willing to give it a gentle kick towards linux, I’m going to write some HTTP service that does all the naughty stuff for you.

I don’t understand. Any security threat I need to worry about?

Uh… somebody (you?) had make this massive script, that fed the JAR through at least 10 compressors/obfuscators. What I was trying to say was that I’d like to make this an online service for everybody to use. But it has to run on Linux, and without a desktop.

That would be really good!

I believe that is the 4kjo tool i had made… it was not ever really robust :stuck_out_tongue: but more of an in house tool that i shared… warts and all :stuck_out_tongue:

http://www.java-gaming.org/index.php/topic,18085.0.html

hmm now i am a little confused… i dont see a way to submit a pack200 version (pack.gz) of the jar on the java4k website.

Does this mean that the java4k website is not configured to deliver pack200 compressed jars?

Or do we have to embed a pack200 version attempt to decompress and add the embedded pack200 jar to the class loader of the applet at run time?

Last year I used Proguard and then decompiled it and saved the last 60-odd bytes by hand-tweaking the bytecode, reassembling with Jasmin. You can still be hardcore if you want to be!

You can upload both .jar and .gz files as “applet jars”.

Interresting results – assuming they both sqeezed their JARs, as I couldn’t find a tool to do it better…

`
Falcon4k (Alan_W)

4,093 bytes (jar)
3,485 bytes (pack.gz)

4,125 bytes (re-zipped with winrar, for baseline)
3,485 bytes (pack.gz => after winrar did the re-zip)

3,467 bytes (pack.gz => 7z on .pack)

Flux4k (Michael Bliem)

4,093 bytes (jar)
3,331 bytes (pack.gz)

3,990 bytes (jar => re-zipped with winrar, for baseline)
3,288 bytes (pack.gz => after winrar did the re-zip)

3,260 bytes (pack.gz => 7z on .pack)

`

Interesting to see that pack200 did a better job after a ‘plain zipper’ like WinRAR.

Use kzip or 7zip for the comparison against jar.
Still impressive savings though; anyone fancy writing an optimised pack200 compressor?

Nvm, redundant - you can skip the gzip step and use whatever gzip compatible super-efficient compressor you like.

I suppose the "pack"ing step might be further optimisable with a home-grown implementation.

Perhaps not everyone are aware that they can use pack200.

I updated the stats, BTW…

pack.gz is simply Java’s default GZ deflater over a .pack file.

I think that’s the only point where we can optimize by doing some bruteforce GZ-ing, as pack200 has to unzip your carefully crafted jar anyway.

I’m curious; does pack200 invalidate the ‘inject binary data into class files’ space saving paradigm?

I updated the table again… it’s getting smaller without any effort.