seeseekey.net - Invictus Deus Ex Machina

Möchte man unter .NET/Mono das Schlie­ßen einer Kon­so­len­an­wen­dung abfan­gen so kann man dies mit eini­gen Metho­den lösen, wie zum Bei­spiel die Anwen­dung bestimm­ten pIn­voke Tech­ni­ken unter Win­dows. All­ge­mei­ner kann man das ganze mit dem „Can­cel­Key­Press“ Event gestal­ten was dann so aussieht:

Console.CancelKeyPress+=new ConsoleCancelEventHandler(Console_CancelKeyPress);
...
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
  WriteErrorToConsole("Programm wird abgebrochen...");
  e.Cancel=true; // Event abbrechen
}

Por­tie­run­gen sind eine schöne Sache wenn man sich die Zeit ver­trei­ben möchte ;) Bei der Por­tio­nie­run­gen von C/C++ nach C# wird dabei immer wie­der Dinge sehen die Schema F betref­fen wie z.B. bestimmte Datentypen:

unsigned int -> uint
unsigned -> uint
unsigned char -> byte
std:string -> string
size_t -> Int64

Andere sehr beliebte Sachen sind Kol­lek­tio­nen wie Lis­ten oder die Vek­tor­klasse. Aus Din­gen wie:

std::vector Things;
std::list Things();

wird dann meist immer ein:

List<Thing> Things;

Die Map:

std::map<unsigned short, unsigned> nodes;

wird dabei durch ein Dic­tio­nary ersetzt:

Dictonary<unsigned short, unsigned> nodes;

Immer wie­der schön sind die Typedefs wie z.B.

typedef std::vector<Account> Accounts;

wel­che bei mir dann auch in eine Liste umge­wan­delt wer­den, an den Stel­len an denen sie benutzt werden:

List<Account> Accounts;

Beim por­tie­ren von Klas­sen wer­den Hea­der und C Datei in eine gemein­same Datei gewor­fen und die Dop­pe­lun­gen ent­fernt. Aus den Klas­sen­funk­tio­nen aller:

void Thing::MakeFoo(int value)

wird dabei ein:

void MakeFoo(int value)

Bei While Schlei­fen wird aus einem:

while (message.getUnreadLength())

ein

while (message.getUnreadLength()!=0)

Aus einem Vergleich:

if(!receiver)

wird ein

if (receiver!=null)

Ite­ra­to­ren sind auch immer wie­der schöne Sachen. Aus

for (ChatChannels::const_iterator i = mChatChannels.begin(), i_end = mChatChannels.end());

wird ein:

foreach(ChatChannel channel in mChatChannels)

Sicher­lich gibt es auch noch andere Schema F Kon­strukte, dies sind aller­dings die bei mir am häu­figs­ten vorkommenden.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://stackoverflow.com/questions/3659044/comparison-of-c-stl-collections-and-c-sharp-collections
http://stackoverflow.com/questions/6274878/what-is-c-time-t-equivalent-for-c-sharp

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 der Por­tie­rung von C Quell­text ist man manch­mal am über­le­gen wie man eine bestimmte Stelle wohl syn­tak­tisch nach C# bringt. Möchte man eine auto­ma­ti­sche pro­to­ty­pi­sche Quell­text­kon­ver­tie­rung für sol­che Sachen so sollte man sich mal die Web­seite http://code2code.net/ anschauen.

Dort kann man C Quell­code ein­ge­ben und bekommt ihn in C# oder Visual Basic.NET zurück. Je nach Ein­ga­be­da­ten kann die Kon­ver­tie­rung dabei aller­dings unter­schied­lichs­ter Qua­li­tät sein. Um das Nach­den­ken kommt man also nicht herum ;)

Ich betreibe einen Mine­craft Ser­ver und ab und an kommt es vor das man ein paar neue Dinge zur Welt hin­zu­fügt. Manch­mal kommt es dabei zu unschö­nen Feh­lern, wel­che z.B. die Bed­rock­schicht beschä­di­gen. Da ich nun natür­lich nicht alles von Hand nach­bes­sern möchte habe ich ein klei­nes Tool geschrie­ben. Die­ses hört dabei auf den Namen „Mine­craft main­ten­ance tool“ und ist unter http://mcmt.googlecode.com zu fin­den. Das Tool steht dabei unter GPLv3 Lizenz und sollte unter Linux und Win­dows laufen.

Mit dem Tool sind im Moment fol­gende Dinge möglich:

  • Ent­fer­nen von Entities
  • Erset­zen von Blöcken
  • Erzeu­gen einer fla­chen Welt
  • Neu­be­rech­nung der Beleuchtung
  • Repa­rie­ren der Bedrockschicht

Wenn jemand Ideen hat was es noch alles kön­nen soll, kann diese in den Kom­men­ta­ren los­wer­den. Das Tool selbst setzt auf der Sub­strate Biblio­thek (unter MIT Lizenz) auf wel­che unter http://substrate-minecraft.googlecode.com zu fin­den ist.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://de.wikipedia.org/wiki/Minecraft
http://www.minecraftforum.net/topic/245996-sdk-substrate-map-editing-library-for-cnet-103/

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

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

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.

Für ein Win­dows Forms Menü wollte ich einen Short­cut key (für die MFC kun­di­gen auch Acce­le­ra­tor genannt) set­zen. Das funk­tio­niert im Nor­mal­fall auch immer ohne Pro­bleme. Nur bei den Tas­ten Keys.NumPad0 - Keys.NumPad9 funk­tio­niert das nicht.

Auch eine manu­elle Zuweisung:

topToolStripMenuItem.ShortcutKeys = Keys.NumPad5;

schlägt mit einer Excep­tion fehl. Der Trick hier ist es die num­me­ri­schen Tas­ten des Num­pad immer mit Strg oder Alt zu benut­zen. So ist es ohne Pro­bleme mög­lich dem Menü­punkt den Short­cut key Alt + Num­pad 5 zuzu­wei­sen. Ich tippe mal das hängt bei die­sen Tas­ten mit der Dop­pel­be­le­gung (Num aus/an) zusammen.

Der freie Pass­wort­ma­na­ger Kee­Pass ist vor kur­zem in der neuen Ver­sion 2.16 erschie­nen. Im Gegen­satz zu 1er Serie ist die 2er Serie kom­plett neu­ge­schrie­ben wor­den und basiert auf .NET bzw. Mono. Sie läuft somit ohne Pro­bleme auch unter Linux. Damit kann der Mana­ger auch platt­form­über­grei­fend ein­ge­setzt wer­den. Die Soft­ware steht dabei unter GPLv2 und kann unter http://keepass.info/download.html bezo­gen werden.

Es gibt unter http://code.google.com/p/lib3ds/ ein Google Code Pro­jekt wel­ches eine Biblio­thek zum lesen und schrei­ben von 3DS imple­men­tiert. Lei­der gab es bis vor kur­zem keine freie 3DS Biblio­thek für .NET respek­tive Mono. Nun gibt es unter http://code.google.com/p/lib3dsnet/ eine Por­tie­rung der lib3ds, wel­che wie das Ori­gi­nal unter LGPL steht.

Die Biblio­thek unter­stützt dabei nicht nur das lesen und schrei­ben, son­dern auch alle mög­li­chen Arten von 3DS Nodes wie Kame­ras oder Mes­hes. Auch die Trans­for­ma­tion der Objekte zuein­an­der wird in die­ser Biblio­thek vor­ge­nom­men. In Gren­zen kommt lib3ds.Net auch mit defek­ten 3DS Dateien zurecht. Nach den ers­ten Tests funk­tio­niert die Biblio­thek tadel­los :)

Wei­tere Infor­ma­tio­nen gibt es unter:
http://en.wikipedia.org/wiki/.3ds

Unter .NET bzw. Win­dows Forms gibt es für das Abfra­gen von Tas­ten die Events Key­Down, KeyUp und Key­Press, wel­che am For­mu­lar hän­gen bzw. an den Con­trols. In mei­nem Fall hän­gen sie an einem For­mu­lar bei wel­chem die Key­Pre­view Eigen­schaft auf true gesetzt ist.

Mit die­sen Events kann man pro­blem­los fast alle Tas­ten abfan­gen. Pro­ble­ma­tisch wird es aber bei den Cur­sor­tas­ten. Hier bekomme ich nur ein KeyUp Event. Nun gibt es eine Mög­lich­keit diese Tas­ten trotz­dem abzu­fra­gen in dem die Funk­tion Pro­ces­sCmd­Key über­la­den wird:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    bool shift=(keyData&Keys.Shift)!=0;
    bool control=(keyData&Keys.Control)!=0;
    bool alt=(keyData&Keys.Alt)!=0;
    Keys unmodifiedKey=(keyData&Keys.KeyCode);

    if(unmodifiedKey==Keys.Up) DoFoobar(unmodifiedKey);

    return base.ProcessCmdKey(ref msg, keyData);
}

Aller­dings funk­tio­nierte diese Methode nicht wie gewünscht. Eine andere Methode ist die Über­la­dung der Funk­tion IsIn­put­Key. Dort wird dann fest­ge­legt das die Cur­sor­tas­ten wie nor­male Ein­ga­be­tas­ten behan­delt wer­den. Aller­dings brachte es nichts, diese Funk­tion im Haupt­for­mu­lar zu über­la­den, da sie dort nie erreicht wurde. Des­halb wurde sie in dem im For­mu­lar befind­li­chen OpenGL Con­trol überladen:

protected override bool IsInputKey(System.Windows.Forms.Keys keyData)
{
    if((keyData&Keys.KeyCode)==Keys.Up) return true;
    if((keyData&Keys.KeyCode)==Keys.Right) return true;
    if((keyData&Keys.KeyCode)==Keys.Left) return true;
    if((keyData&Keys.KeyCode)==Keys.Down) return true;

    return base.IsInputKey(keyData);
}

Damit kamen die Events für die Cur­sor­tas­ten ganz nor­mal bei den ent­spre­chen­den Events des Haupt­for­mu­la­res an.

Wei­tere Infor­ma­tio­nen gibt es unter:
http://stackoverflow.com/questions/2434834/processcmdkey-wait-for-keyup
http://familie-ottenhaus.de/simon/blog/2009/12/csharp-eigenes-control-keys-up-down-left-right-onkeydown-onkeypress-vs-processcmdkey/