64k intro in c#
category: code [glöplog]
I found klystrack
https://kometbomb.github.io/klystrack/
https://kometbomb.github.io/klystrack/
.NET isn´t even installed on compo-machines!
(and if, thru WinUpdate, it´s not allowed!)
(and if, thru WinUpdate, it´s not allowed!)
.net is an integral part of the operating system these days and comes pre-installed (though maybe not the latest version). Compo machines typically run the latest version of Windows 10. Don't just make up rules that don't exist.
My NetPacker work in progress ...
I compressed an 73ko executable to 27Ko !
Need now to remove not used classes ...
NetPacker V0.1
ILOptimizer: Original Size: 73216 bytes
ILOptimizer: Total number of classes: 181
ILOptimizer: Total number of methods: 449
ILOptimizer: Used Methods: 320/449
ILOptimizer: Removed methods count: 129
ILOptimizer: Packed Size: 65024 bytes
NetPacker: Compressed ExeToPack Size: 27324
I compressed an 73ko executable to 27Ko !
Need now to remove not used classes ...
NetPacker V0.1
ILOptimizer: Original Size: 73216 bytes
ILOptimizer: Total number of classes: 181
ILOptimizer: Total number of methods: 449
ILOptimizer: Used Methods: 320/449
ILOptimizer: Removed methods count: 129
ILOptimizer: Packed Size: 65024 bytes
NetPacker: Compressed ExeToPack Size: 27324
Quote:
.net is an integral part of the operating system these days and comes pre-installed
Exactly. If we disallowed .NET in the compo rules, the folks using Tooll² for their demos wouldn't be amused either ...
And what about NetCore in demos ?
The idea behind .NET core is to either redistribute the used assemblies or static-link them inside your EXE, to avoid side-by-side conflicts between different versions. That's not really practical for intros.
Good job fxgen!
Making demos in C# actually makes sense. A quick recompile-test cycle is pretty much essential when you explore ideas :)
Out or curiosity, does your 27k thing do anything at all?
Making demos in C# actually makes sense. A quick recompile-test cycle is pretty much essential when you explore ideas :)
Out or curiosity, does your 27k thing do anything at all?
Quote:
Out or curiosity, does your 27k thing do anything at all?
I'll share my code on github but my 27k display a voxelized metaball scene without music.
I'll need some help, we can do better with compression :-)
I am looking forward to seeing your code on github!
Quote:
I am looking forward to seeing your code on github!
...is typically sth a Lamer says, because he can´t code himself!
...then finally gets a GitHub-Link and realizes he doesn´t understand 75% of what´s going on there!
...then goes on writing stupid articles about some Race better than any other, which he thinks belongs to, just to feel better again about his stupid self!
You are in some super-stupid devils circle, get it already! :P
P.S.: FUCK Racism!
P.S.2: Make a fucking prod without stolen code and show off already, maybe i am wrong! :P ;) Make it 4K atleast, anything else is too bad for a person like you, with race-given-superskills! :P
P.S.3: asking Mensa-friends for help is cheating==lame!
There! Sorry to everyone else, had to!
If you want to help me on NetPacker, the project is shared now :-)
https://github.com/procfxgen/NetPacker
https://github.com/procfxgen/NetPacker
nice :D (it even works on mono! \o/)
there's a lot of room for optimizations, though:
* ILOptimizer: most of the stuff I said here and here etc is still TODO it seems
* compression: gzip kinda sucks, but it looks like System.IO.Compression doesn't have anything better (brotli not in mono -> :( )... maybe a 2-stage plain->gzip->custom unpacker might be interesting (and compress the gzip with zopfli)
* unpacker: you really want to write this in IL, not C# :) , and maybe also mess with the headers to make it even smaller. Also, here's the disasm:
as you can see, it's huge!
some small notes:
* don't do a try/catch or try/finally OR using (compiler turns 'using' into try/finally)
* don't call GC.Collect, Stream.Close
* Main() can have no args, so the new string[0] isn't needed
* make all names as short as possible
but most importantly:
* DON'T use Resources! Use a simple byte array (if you need bytes) OR an EmbeddedResource (if you need a Stream). byte arrays and EmbeddedResources go to the Blobs section, but Resources have much more metadata in a wrapper format, and thus are larger! Plus getting data from a Resource needs more code.
P.S. WinForms+OpenGL should be possible (var dc = GetDC(form.Handle); wglMakeCurrent(dc, wglCreateContext(dc)); then use wglGetProcAddress). But do NOT use the GUI designer in Visual Studio, as the code it generates sucks :p
there's a lot of room for optimizations, though:
* ILOptimizer: most of the stuff I said here and here etc is still TODO it seems
* compression: gzip kinda sucks, but it looks like System.IO.Compression doesn't have anything better (brotli not in mono -> :( )... maybe a 2-stage plain->gzip->custom unpacker might be interesting (and compress the gzip with zopfli)
* unpacker: you really want to write this in IL, not C# :) , and maybe also mess with the headers to make it even smaller. Also, here's the disasm:
Code:
.namespace CompressedApp
{
.class private auto ansi beforefieldinit Program
extends [mscorlib]System.Object/*0100000b(TypeRef)*/ {
// method line 1
.method public hidebysig specialname rtspecialname
instance default void '.ctor' () /* 0x6000000 */ cil managed {
// Method begins at RVA 0x2050
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void object/*0a00000f(MemberRef)*/::'.ctor'()/*0a00000f(MemberRef)*/
IL_0006: ret
} // end of method Program::.ctor
// method line 2
.method private static hidebysig
default void Main (string[] args) /* 0x6000001 */ cil managed {
.custom instance void class [mscorlib]System.STAThreadAttribute/*0a000001(MemberRef)*/::'.ctor'()/*0a000001(MemberRef)*/ = (01 00 00 00 ) // ....
// Method begins at RVA 0x2058
.entrypoint
// Code size 164 (0xa4)
.maxstack 6
.locals /*11000001*/ init (
class [mscorlib]System.Resources.ResourceManager V_0,
unsigned int8[] V_1,
int32 V_2,
class [mscorlib]System.IO.MemoryStream V_3,
class [System]System.IO.Compression.GZipStream V_4,
unsigned int8[] V_5,
class [mscorlib]System.Reflection.Assembly V_6,
class [mscorlib]System.Exception V_7)
IL_0000: ldstr "resource"
IL_0005: call class [mscorlib]System.Reflection.Assembly/*01000003(TypeRef)*/ class [mscorlib]System.Reflection.Assembly/*0a000002(MemberRef)*/::GetExecutingAssembly()/*0a000002(MemberRef)*/
IL_000a: newobj instance void class [mscorlib]System.Resources.ResourceManager/*0a000003(MemberRef)*/::'.ctor'(string, class [mscorlib]System.Reflection.Assembly/*01000003(TypeRef)*/)/*0a000003(MemberRef)*/
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: ldstr "app"
IL_0016: callvirt instance object class [mscorlib]System.Resources.ResourceManager/*0a000004(MemberRef)*/::GetObject(string)/*0a000004(MemberRef)*/
IL_001b: castclass unsigned int8[]/*1b000001(TypeSpec)*/
IL_0020: stloc.1
IL_0021: ldc.i4 3072
IL_0026: stloc.2
IL_0027: ldloc.1
IL_0028: newobj instance void class [mscorlib]System.IO.MemoryStream/*0a000005(MemberRef)*/::'.ctor'(unsigned int8[])/*0a000005(MemberRef)*/
IL_002d: stloc.3
IL_002e: ldloc.3
IL_002f: ldc.i4.0
IL_0030: newobj instance void class [System]System.IO.Compression.GZipStream/*0a000006(MemberRef)*/::'.ctor'(class [mscorlib]System.IO.Stream/*01000006(TypeRef)*/, valuetype [System]System.IO.Compression.CompressionMode/*01000007(TypeRef)*/)/*0a000006(MemberRef)*/
IL_0035: stloc.s 4
IL_0037: ldloc.2
IL_0038: newarr [mscorlib]System.Byte/*01000008(TypeRef)*/
IL_003d: stloc.s 5
IL_003f: ldloc.s 4
IL_0041: ldloc.s 5
IL_0043: ldc.i4.0
IL_0044: ldloc.2
IL_0045: callvirt instance int32 class [mscorlib]System.IO.Stream/*0a000007(MemberRef)*/::Read(unsigned int8[], int32, int32)/*0a000007(MemberRef)*/
IL_004a: pop
IL_004b: ldloc.3
IL_004c: callvirt instance void class [mscorlib]System.IO.Stream/*0a000008(MemberRef)*/::Close()/*0a000008(MemberRef)*/
IL_0051: ldloc.s 4
IL_0053: callvirt instance void class [mscorlib]System.IO.Stream/*0a000008(MemberRef)*/::Close()/*0a000008(MemberRef)*/
IL_0058: ldloc.s 5
IL_005a: call class [mscorlib]System.Reflection.Assembly/*01000003(TypeRef)*/ class [mscorlib]System.Reflection.Assembly/*0a000009(MemberRef)*/::Load(unsigned int8[])/*0a000009(MemberRef)*/
IL_005f: stloc.s 6
IL_0061: ldnull
IL_0062: stloc.s 5
IL_0064: call void class [mscorlib]System.GC/*0a00000a(MemberRef)*/::Collect()/*0a00000a(MemberRef)*/
.try { // 0
IL_0069: ldloc.s 6
IL_006b: callvirt instance class [mscorlib]System.Reflection.MethodInfo/*0100000a(TypeRef)*/ class [mscorlib]System.Reflection.Assembly/*0a00000b(MemberRef)*/::get_EntryPoint()/*0a00000b(MemberRef)*/
IL_0070: ldnull
IL_0071: ldc.i4.1
IL_0072: newarr [mscorlib]System.Object/*0100000b(TypeRef)*/
IL_0077: dup
IL_0078: ldc.i4.0
IL_0079: ldc.i4.0
IL_007a: newarr [mscorlib]System.String/*0100000c(TypeRef)*/
IL_007f: stelem.ref
IL_0080: callvirt instance object class [mscorlib]System.Reflection.MethodBase/*0a00000c(MemberRef)*/::Invoke(object, object[])/*0a00000c(MemberRef)*/
IL_0085: pop
IL_0086: leave IL_00a3
} // end .try 0
catch class [mscorlib]System.Exception { // 0
IL_008b: stloc.s 7
IL_008d: ldstr "Invoke Main error ! {0}"
IL_0092: ldloc.s 7
IL_0094: callvirt instance string class [mscorlib]System.Exception/*0a00000d(MemberRef)*/::get_Message()/*0a00000d(MemberRef)*/
IL_0099: call void class [mscorlib]System.Console/*0a00000e(MemberRef)*/::WriteLine(string, object)/*0a00000e(MemberRef)*/
IL_009e: leave IL_00a3
} // end handler 0
IL_00a3: ret
} // end of method Program::Main
} // end of class CompressedApp.Program
}
as you can see, it's huge!
some small notes:
* don't do a try/catch or try/finally OR using (compiler turns 'using' into try/finally)
* don't call GC.Collect, Stream.Close
* Main() can have no args, so the new string[0] isn't needed
* make all names as short as possible
but most importantly:
* DON'T use Resources! Use a simple byte array (if you need bytes) OR an EmbeddedResource (if you need a Stream). byte arrays and EmbeddedResources go to the Blobs section, but Resources have much more metadata in a wrapper format, and thus are larger! Plus getting data from a Resource needs more code.
P.S. WinForms+OpenGL should be possible (var dc = GetDC(form.Handle); wglMakeCurrent(dc, wglCreateContext(dc)); then use wglGetProcAddress). But do NOT use the GUI designer in Visual Studio, as the code it generates sucks :p
you probably mean SDL instead of SQL in the readme ;)
also, SDL2.dll isn't part of vanilla Windows/.NET or is it? so you still have a 1MB+ intro in total then? :P
also, SDL2.dll isn't part of vanilla Windows/.NET or is it? so you still have a 1MB+ intro in total then? :P
@Maali: SDL will be replaced by Winform :-)
@porocyon: Thanks for your feedbacks ! I'll optimize my unpacker ...
@porocyon: Thanks for your feedbacks ! I'll optimize my unpacker ...
yeah, but the other Monogame abstractions (see opengl.cs) you borrowed also use SDL2.dll as lib for the GL procaddresses. correct me if i'm wrong, but shouldn't that be wrapped around opengl.dll then? (just curious/ignorant cos back then I used some automatically generated wrapper crap around glfw3 and called GL functionalities via that, which is also not vanilla. its DLL was smaller though! :P)
Yes I'll remove sdl and I need to rewrite opengl wrapper.
I'll look at others opengl wrappers (glsharp ....)
I'll look at others opengl wrappers (glsharp ....)
on the plus part of rewriting that, you probably don't need 50% of them :D
it's the work of my iloptimizer class, remove not used methods ... but it's a work in progress...
I've actually learned quite a lot by studying source code... So, thanks for sharing it!
Some one could look at my Intro02 example ?
https://github.com/procfxgen/NetPacker/tree/master/Examples/Intro02
glClearColor(1,0,0,1) doesn't work in C# .... my C++ version work.
https://github.com/procfxgen/NetPacker/tree/master/Examples/Intro02
glClearColor(1,0,0,1) doesn't work in C# .... my C++ version work.
Once you've seen, nay even bugfixed Mono you really don't want it to be your interpreter. Trust me, please ;)
superplek: Intro02 is an example without SDL but with winform ...
when this projet work, I'll look for Mono compatibility.
when this projet work, I'll look for Mono compatibility.
That work now.
For Intro02 I have an 7680 bytes executable size just for a simple OpenGL Red Screen.
For Intro02 I have an 7680 bytes executable size just for a simple OpenGL Red Screen.
The main problem is the launcher that take 5 ko ... I don't know how to reduce the size... If I edit executable in a binary editor, there's lot of 0x00 blocks ...
porocyon: an idea ?
Thanks
porocyon: an idea ?
Thanks