seeseekey.net - Invictus Deus Ex Machina

Nach eini­gen Mona­ten ist es Zeit den Zwi­schen­stand für den neuen Inver­tika Ser­ver und den Cli­ent vor­zu­stel­len. Inver­tika soll somit auf einer neuen tech­ni­schen Basis ste­hen. Diese neue tech­ni­sche Basis sieht so aus, das der Ser­ver in C# geschrie­ben wird und somit unter Mono und .NET läuft. Für den Cli­ent ist eine Imple­men­ta­tion als Webap­pli­ka­tion ange­dacht. Das ganze hatte dabei meh­rere Gründe:

  • die Pro­duk­ti­vi­tät ist in C# höher als in C/C++
  • es kön­nen keine Spei­cher­lö­cher entstehen
  • durch die auto­ma­ti­sche Spei­cher­ver­wal­tung wird der Ent­wick­ler entlastet
  • moder­nes und kon­sis­ten­tes Framework
  • Anpas­sung auf eigene Bedürfnisse
  • schnel­lere Entwicklung
  • IPv6 Unter­stüt­zung ist pro­blem­los möglich
  • bes­sere Unter­stüt­zung von mobi­len Geräten

Neben die­sen Grün­den sind es auch einige Dinge wie „typedefs“ wel­che nicht unbe­dingt zum Ver­ständ­nis bei­tru­gen oder meh­rere Klas­sen und Struk­tu­ren in einer Datei, wel­che das ganze ziem­lich unüber­sicht­lich machen. Auch die Abhän­gig­keit von zu vie­len Biblio­the­ken wurde verringert.

Der Inver­tika Code in der Entwicklung

Nach einer kur­zen Pla­nung­phase ging es dann am 3. Januar los mit der Ent­wick­lung. Zuerst wurde damit begon­nen den Account­ser­ver zu por­tier­ten. Dabei wur­den im Gegen­satz zum Ori­gi­nal einige Dinge verändern:

  • das Netz­werk setzt nun statt auf der Biblio­thek „enet“ direkt auf TCP auf
  • PhysFS wurde wegrationalisiert

Am 13. Januar (einem Frei­tag ;) ) waren die größ­ten Por­tie­rung­pro­bleme beim Account­ser­ver gelöst und es wurde begon­nen den Game­ser­ver zu por­tie­ren. Am Game­ser­ver ist die ein­zige grö­ßere Ände­rung die Anpas­sung der Skript­schnitt­stelle, damit diese mit den CLR Spra­chen kom­pa­ti­bel ist. Die Road­map für die Por­tie­rung sah dabei so aus:

  • Januar 2012: Imple­men­ta­tion des Inver­tika Server
  • Februar 2012 Imple­men­ta­tion des Inver­tika Clients
  • März 2012: Test der Software

Wie sich das für eine ordent­li­che Road­map gehört wurde sie nicht ein­ge­hal­ten. So ist eini­ges noch nicht fer­tig und auch am Cli­ent muss noch viel getan wer­den. Der Cli­ent sollte ursprüng­lich auch in C# geschrie­ben wer­den und es wurde damit auch begon­nen. Theo­re­tisch ließe sich diese Cli­ent­va­ri­ante auf die Platt­for­men Win­dows, Linux, Mac OS X, iOS und Android brin­gen, prak­tisch ist es mit klei­ne­ren und grö­ße­ren Pro­ble­men verbunden.

Ein gene­rel­les Pro­blem an einem sol­chen Cli­ent ist, das er auf der jewei­li­gen Ziel­platt­form erst instal­liert (oder auch kom­pi­liert) wer­den und außer­dem vom Nut­zer aktu­ell gehal­ten wer­den muss. Schö­ner wäre es, wenn man diese Hürde aus dem Weg geschafft wird. Mitt­ler­weile ist es dank Tech­ni­ken wie Webso­ckets, Web­wor­kern und Can­vas mög­lich, den Cli­ent kom­plett als Webap­pli­ka­tion zu schreiben.

Die Anfänge des neuen Cli­ents basie­ren dabei auf der Tech­demo „mana.js“ wel­che unter https://github.com/bjorn/mana.js zu fin­den ist. Der Vor­teil der web­ba­sier­ten Lösung ist dabei die große Kom­pa­ti­bi­li­tät mit unter­schied­lichs­ten Gerä­ten solange sie über einen aktu­el­len Brow­ser verfügen.

Die Tech­demo des Cli­ents auf einem iPad

Wäh­rend der Ent­wick­lung beka­men die ein­zel­nen Teile auch Namen die wie folgt lauten:

  • inver­tika (Client)
  • invertika-account (Account­ser­ver)
  • invertika-game (Game­ser­ver)

Der Quell­text sollte in den nächs­ten Tagen im Repo­sitory (http://source.invertika.org) erschei­nen und zur Mit­ar­beit ein­la­den ;)

Wei­tere Infor­ma­tio­nen gibt es unter:
http://invertika.org

Wenn man ein Spiel in OpenGL rea­li­siert, hat man meist irgend­wann das Pro­blem das man auch Bedien­ele­mente wie Menüs, Check­bo­xen, Text­fel­der etc. im Spiel haben möchte. Diese sol­len dann natür­lich auch noch Events erhal­ten und mög­lichst auch in OpenGL gezeich­net wer­den (da nie­mand z.B. GDI Objekte im OpenGL haben möchte).

Die GWEN.NET Beispielanwendung

Für .NET/Mono gibt es hier­für eine Por­tie­rung von GWEN wel­che GWEN.NET heist und unter http://code.google.com/p/gwen-dotnet/ zu fin­den ist. Diese arbei­tet z.B. mit OpenTK zusam­men. Das ganze ist dabei unter der MIT Lizenz verfügbar.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://omeg.pl/blog/2011/07/the-quest-for-c-opengl-gui/

Bei OpenTK han­delt es sich um eine freie Tool­kit Bil­bio­thek. Aller­dings gibt es mit die­ser ein Pro­blem unter .NET 4. Dort stürzt das Con­trol beim initia­li­sie­ren eines OpenGL Kon­tex­tes ab. In die­sem Fall liegt es wohl an den ver­än­der­ten Sicher­heits­ein­stel­lun­gen unter .NET 4.

Sobald man die „AssemblyInfo.cs“ um die Zeile:

[assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)]

ergänzt, funk­tio­niert das ganze wie­der. In neue­ren Ver­sio­nen von OpenTK kann man dies über das Pro­jekt akti­vie­ren, indem man das Flag „NET40“ setzt.

Danach funk­tio­niert das Anle­gen des Kon­tex­tes wie­der ohne Probleme.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.opentk.com/node/1662
http://nl.wikipedia.org/wiki/OpenTK

Bei einem C# Pro­jekt von mir, wel­ches ich in Visual Stu­dio und Mono­De­ve­lop bear­beite, gab es einige Pro­bleme mit dem debug­gen. Unter Mono­De­ve­lop reichte es die Haupt­klasse anzu­ge­ben, so das er in diese sprin­gen konnte.

Bei Visual Stu­dio fruch­tete dies lei­der nicht. Dort stellt sich die Frage ob es even­tu­ell eine Inkom­pa­ti­bi­li­tät zwi­schen den Pro­jekt­da­teien gibt. Hier ist wohl wei­tere For­schung nötig.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/MonoDevelop
http://de.wikipedia.org/wiki/Visual_Studio

Man nehme eine .NET/Mono Biblio­thek wel­che als Ziel­f­rame­work .NET 4 benutzt. Nun erstelle man noch eine neue Anwen­dung und binde in diese Anwen­dung besagte Biblio­thek ein. Nun kann es vor­kom­men das man beim kom­pi­lie­ren der Anwen­dung fol­gende Feh­ler­mel­dung bekommt:

The type or namespace name 'FooBar' could not be found (are you missing a using directive or an assembly reference?)

Augen­schein­lich hat man eine Refe­renz ver­ges­sen. Zumin­dest könnte man genau dies bei der ent­spre­chen­den Mel­dung den­ken. Aller­dings ist das ganze in die­sem Fall ein Stück gemei­ner. Die neu erstellte .NET Anwen­dung hat als „Tar­get Frame­work“ nicht „.NET 4 Frame­work“ ein­ge­stellt, son­dern „.NET 4 Frame­work Cli­ent Profile“.

Und die­sem Pro­fil feh­len ein paar Assem­bly­re­fe­ren­zen und wenn man Pech hat benö­tigt eine Biblio­thek genau diese. Hier hilft es dann ein­fach das „Tar­get Frame­work“ auf „.NET 4 Frame­work“ zu stel­len. Danach sollte es dann ohne Pro­bleme funktionieren.

Manch­mal kann einen die Soft­ware­ent­wick­lung schon in den Wahn­sinn trei­ben, vor allem wenn es um tri­viale Dinge geht. So sollte es ja eigent­lich selbst­ver­ständ­lich sein, das der Debug­ger an einem Hal­te­punkt hält. Mein ers­ter Gedanke war, das es daran liegt das ich das Pro­jekt im Debug­mo­dus auf „Any CPU“ ein­ge­stellt habe. Sobald ich es auf „x86“ oder „x64“ gestellt habe, hielt der Debug­ger an der gewünsch­ten Stelle. Aller­dings hatte ich ein ähnli­ches Pro­jekt mit fast den sel­ben Ein­stel­lun­gen (auch „Any CPU“), doch dort funk­tio­nierte es mit dem Debug­ger. Also sollte es ein Ver­gleich der Pro­jekt­da­teien rich­ten. Nach eini­ger Zeit war hier auch kein Erfolg zu melden.

Beim Star­ten des Pro­jek­tes fiel mir aller­dings auf das die Hal­te­punkte aus­ge­blen­det wurden:

Im Tool­tip zu den Hal­te­punk­ten stand dann:

No sym­bols have been loa­ded for this document

Dies brachte mich dazu in das „bin/Debug“ Ver­zeich­nis zu schauen und siehe da, es gab keine pdb Dateien für das Pro­jekt. Um die pdb Dateien für das Pro­jekt anzu­le­gen, geht man in die Pro­jekt­ein­stel­lun­gen, dort auf „Build“ und dann auf „Advanced“.

In dem sich dar­auf öffnen­den Dia­log stellt man die „Debug info“ auf „full“. Damit soll­ten die PDB Dateien erzeugt wer­den und das debug­gen wie­der funktionieren.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://en.wikipedia.org/wiki/Program_database
http://msdn.microsoft.com/en-us/library/yd4f8bd1%28v=vs.71%29.aspx
http://geekswithblogs.net/dbutscher/archive/2007/06/26/113472.aspx
http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx

Eine gewöhn­li­che .NET Anwen­dung benö­tigt keine Admi­nis­tra­tor­rechte und bekommt diese meist auch nicht. Doch was wenn man doch mal sol­che Rechte benö­tigt um z.B. die Zuord­nun­gen zu einem Datei­for­mat in der Regis­try vor­neh­men zu kön­nen? Unter XP ist dies kein Pro­blem da der Nut­zer dort meist mit Admi­nis­tra­tor­rech­ten unter­wegs ist. Unter Win­dows Vista und höher muss man diese Rechte aller­dings anfordern.

Lei­der ist es nicht mög­lich, sich diese Rechte nur für eine bestimmte Funk­tion anzu­for­dern. Ent­we­der man holt sie sich die Rechte (per Mani­fest Datei) für die ganze Anwen­dung oder gar nicht. Bei der Anfor­de­rung der Rechte für die ganze Anwen­dung wird man von Win­dows jedes­mal gefragt ob man die ent­spre­chende Anwen­dung mit Admi­nis­tra­tor­rech­ten star­ten möchte, was natür­lich unschön ist.

Eine wei­tere Mög­lich­keit ist es für die Fälle wel­che admi­nis­tra­tive Rechte benö­ti­gen eine extra Anwen­dung zu schrei­ben, wel­che dann z.B. die Datei­er­wei­te­run­gen regis­triert. Der Vor­teil die­ser Vari­ante ist es, das man nur nach den ent­spre­chen­den Rech­ten gefragt wird, wenn es nötig ist. Diese Vari­ante kann man nun auch aus­bauen, indem man keine Fremd­an­wen­dung auf­ruft, son­dern sich sel­ber mit ein paar Kommandozeilenparametern:

ProcessStartInfo processInfo=new ProcessStartInfo();
processInfo.Verb="runas";
processInfo.FileName=FileSystem.ApplicationPathWithFilename;
processInfo.Arguments="-reg:.bat;.xml";
Process.Start(processInfo);

In der Program.cs wer­tet man diese Argu­mente dann in der

static void Main(string[] args)

aus und führt die ent­spre­chende Aktion aus. Danach been­det man die Anwen­dung gleich wie­der. Somit kann man die Teile wel­che sol­che Rechte benö­ti­gen in der eige­nen Anwen­dung „auslagern“.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://www.vbarchiv.net/workshop/workshop_115.html
http://victorhurdugaci.com/using-uac-with-c-part-1/
http://victorhurdugaci.com/using-uac-with-c-part-2/
http://victorhurdugaci.com/using-uac-with-c-part-3/

Wenn man in Mono­De­ve­lop eine GTK# Anwen­dung schreibt und sie zwingt auf „jeder CPU“ zu lau­fen so wird diese Anwen­dung beim Start abstürz­ten. Meist sieht das dann so aus:

Unbehandelte Ausnahme: System.TypeInitializationException:
Der Typeninitialisierer für "Gtk.Application" hat eine Ausnahme verursacht.
System.BadImageFormatException: Es wurde versucht, eine Datei mit einem falschen Format zu laden.
(Ausnahme von HRESULT: 0x8007000B)

 bei GLib.Thread.glibsharp_g_thread_supported()
 bei GLib.Thread.get_Supported()
 bei Gtk.Application..cctor()

--- Ende der internen Ausnahmestapelüberwachung ---
 bei Gtk.Application.Init()
 bei testapp.MainClass.Main(String[] args) in d:\testapp\Main.cs:Zeile 10.

Das Pro­blem ist wohl das es noch keine x64 GTK# Biblio­thek für Win­dows gibt. Aus die­sem Grund sollte man seine Assem­blys auf x86 stel­len, dann klappt es auch mit Win­dows 7.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://mono.1490590.n4.nabble.com/windows-7-x64-and-gtk-app-td1516626.html

Auf Sourcef­orge gibt es das Pro­jekt Midi Sheet Music (http://sourceforge.net/projects/midisheetmusic/, http://midisheetmusic.sourceforge.net/). Dabei han­delt es sich um eine Soft­ware in wel­che man eine MIDI Datei ein­la­den kann und anschlie­ßend eine Noten­an­sicht bekommt. Beim Abspie­len zeigt die Soft­ware dann an wel­che Tasten(kombinationen) für wel­che Noten gespielt wer­den müs­sen. Die Soft­ware läuft dabei auf Win­dows, Linux und MacOS, ist in C# geschrie­ben und steht unter der GPL.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/MIDI

Wenn man grö­ßere Anwen­dun­gen schreibt, so haben diese meist eine Undo & Redo­funk­tion. Damit man das Rad nicht neu erfin­den muss, gibt es soge­nannte Undo Frame­works. Ein schö­nes Frame­work für .NET ist das Undo Frame­work wel­ches unter http://undo.codeplex.com/ zu fin­den ist. Es basiert dabei auf dem Ent­würfs­mus­ter Kom­mando (http://de.wikipedia.org/wiki/Kommando_%28Entwurfsmuster%29) und ist rela­tiv ein­fach zu benutzen.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://blogs.msdn.com/b/kirillosenkov/archive/2009/06/29/new-codeplex-project-a-simple-undo-redo-framework.aspx
http://blogs.msdn.com/b/kirillosenkov/archive/2009/07/02/samples-for-the-undo-framework.aspx

Man nehme fol­gen­des Stück C# Quelltext:

HashSet test=new HashSet();

Das Pro­blem an einem sol­chen Hash­Set ist, das man nicht mit­tels eines Indi­cies auf die­ses zugrei­fen kön­nen. Die Zeile:

string tmp=test[5];

würde also nicht funk­tio­nie­ren. Abhilfe schafft hier die Klasse Sor­ted­Set:

SortedSettest=new SortedSet();

Nun kann man mit­tels Ele­men­tAt über einen Indice selek­tiert werden:

string tmp=test.ElementAt(5);

Wich­tig ist dabei das der Namess­pace System.Linq ein­ge­bun­den ist da diese Funk­tio­na­li­tät über eine Exten­sion imple­men­tiert wird.

In .NET/Mono kann man ja eine Varia­ble nach ihrem Typ fragen:

bool test=true;
test.GetType().FullName;

Die Full­Name Eigen­schaft gibt dabei einen String mit der Bezeich­nung des Daten­ty­pes zurück. Da ich ab und an eine Liste die­ser „Full­na­mes“ benö­tigt, gibt es das ganze nun hier:

  • bool -> Boolean-> System.Boolean
  • byte -> Byte -> System.Byte
  • DateTime -> DateTime -> System.DateTime
  • dou­ble -> Dou­ble -> System.Double
  • int -> Int32 -> System.Int32
  • long -> Int64 -> System.Int64
  • short -> Int16 -> System.Int16
  • string -> String -> System.String
  • uint -> UInt32 -> System.UInt32
  • ulong -> UInt64 -> System.UInt64
  • ushort -> UInt16 -> System.UInt16

Es han­delt sich dabei jeweils um den C# Alias, die .NET Bezeich­nung und den Fullname.

Obfu­sca­to­ren für .NET gibt es einige, die teu­ers­ten kos­ten bis zu 4000 $, die güns­ti­ge­ren so um die 300 - 700 $. Es gibt aber auch die Preis­klasse Null. In der Open Source Liga gibt es dabei zwei (soweit ich das ent­deckt habe) Anwendungen:

Das Pro­blem an die­sen bei­den Pro­gram­men ist das sie mit mei­nem .NET 4 Assem­blies nicht funk­tio­nie­ren. Also schaute ich mich nach einer Alter­na­tive um und bin auf EazFuscator.net gesto­ßen. Diese Soft­ware ist Free­ware, ein­fach zu bedie­nen, exzel­lent doku­men­tiert und sie funk­tio­niert ein­fach. Zu fin­den ist die Soft­ware dabei unter http://www.foss.kharkov.ua/g1/projects/eazfuscator/dotnet/Default.aspx. Sie lässt sich auch in Visual Stu­dio Pro­jekt integrieren.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/Obfuscator
http://stackoverflow.com/questions/805549/free-obfuscation-tools-for-net

Ich stelle vor ein paar Tagen ein .NET Pro­jekt von .NET 2 auf .NET 4 um. An dem Pro­jekt hin­gen einige Biblio­the­ken wel­che wei­ter­hin auf .NET 2 basier­ten (und dies auch wei­ter­hin tun sol­len). Nach der Umstel­lung ergab sich nun das Pro­blem, das ich die Anwen­dung nicht mehr mit dem Debug­ger star­ten konnte.

Das Pro­blem hängt dabei damit zusam­men das das Visual Stu­dio für .NET 1 bis .NET 3.5 sowie für .NET 4 jeweils eine eigene Debu­gen­gine benutzt. Um das Pro­blem zu umge­hen schal­tete ich in den Pro­jekt­ei­gen­schaf­ten unter Debug den Ein­trag Enable the Visual Stu­dio hos­ting pro­cess aus. Danach konnte ich auch mit dem gemisch­ten Pro­jekt wie­der debuggen.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://blogs.msdn.com/b/debugger/archive/2010/04/30/can-t-hit-breakpoints-in-a-plug-in-or-can-t-debug-net-2-0-3-0-3-5-from-a-mixed-mode-exe-project-with-visual-studio-2010.aspx

Wenn man ein Zahl unter .NET spei­chern (bzw. mit ihr arbei­ten) möchte kann man einen Int benut­zen. Sollte die Zahl grö­ßer wer­den könnte man einen Int64 neh­men. Doch was wenn die Zah­len noch grö­ßer wer­den? Für die­sen Fall gibt es seid .NET 4 eine Klasse namens Big­In­te­ger wel­che sich im Name­space System.Numerics befindet:

BigInteger bigNumber=BigInteger.Parse("998877665544332211");
bigNumber+=1001;
bigNumber*=2;
MessageBox.Show(bigNumber.ToString());

Damit sind dann auch sehr große Zah­len kein Pro­blem :)