Letzte Einträge »

Operation Pandora Trigger

Nach wieder einmal langer langer Zeit, meine letztes Lebenszeichen hier ist etwas über ein Jahr her, finde ich die Zeit und auch die Motivation meinen Blog etwas zu pflegen.

Privat hat sich nicht all zu viel getan. Mit dem 5. Semester vor der Brust schreitet das Studium voran und somit macht man sich so langsam Gedanken was als nächstes kommt.
Nichtsdestotrotz liegen noch immer gute 1,5 Jahre vor mir.

Daher will ich heute etwas über ein Projekt erzählen an dem ich seit Anfang des Jahres mitarbeite.
Operation Pandora Trigger kurz OPT genannt ist eine in dem Spiel Armed Assault 2: Combined Operations stattfindende „Player versus Player“ Kampagne.
Hier treten alle 8 bis 9 Tage bis 100 Spieler in zwei Teams gegeneinander an, um auf der Karte Chernarus einen fiktiven Konflikt zwischen Russland und den USA um Macht, Geld und Öl auszutragen.
Neben der gut dreistündigen Schlacht sind die Spieler und vor allem die Heeresleitungen auch in den Pausen gefordert.
Krieg kostet Geld! Auch bei OPT!
So müssen zum Beispiel eingenommene Städte ausgebaut werden um Einnahmen zur Beschaffung von schwerem Gerät zu generieren.
Dazu kommen Trainings und die Planung der Schritte für die nächste Schlacht.

Ich selbst bin einer von zwei sogenannten Maintainer. Diese gehören keiner der beiden Fraktionen an und kümmern sich um den Betrieb der Community und fungieren in Streitfragen als Schlichter.

Mittlerweile befindet sich das Ganze in der zweiten Runde, welche Ende August gestartet ist. In den ersten der beiden gewerteten Schlachten kam es jeweils zu einem Unentschieden, was für die Ausgeglichenheit der Teams spricht.

Trotz der knapp 50 Anmeldungen auf beiden Seiten konnte wir unser Ziel von 100 Spielern während einer Schlacht noch nicht erreichen.
Diese Tatsache ist darauf zurück zu führen das nicht immer jeder zum Termin der Schlacht Zeit hat und man somit für 100 Spieler zur Schlacht gut 160 angemeldete Spieler benötigt.

Sofern ihr also ArmA Spieler seid oder eure spielerischen Interesse irgendwo zwischen Arcade und Simulation zu finden sind freue ich mich darauf euch auch bei OPT mal zu treffen.

Operation Pandora Trigger
Operation Pandora Trigger – Teilnehmen

Vor einiger Zeit habe ich in einem Artikel grob beschreiben wie sich in C# animierte Gifs erzeugen lassen.

Das dort erwähnte Tool namens MegaGifAnimator steht mittlerweile auf MegaDev zum Download bereit und hat erst vor kurzem noch ein kleines Update erhalten mit dem zwei Abstürze behoben wurden.

Bei entsprechendem Interesse werde ich hier auch einige Ausschnitte aus dem Quellcode genauer erläutern.

Wie Vielen sicherlich bekannt ist lassen die 64-Bit Versionen seit Windows 7 (vermutlich auch schon bei Windows Vista) keine unsignierten Treiber zu.

Die Variante beim Booten F8 zu drücken und unsignierte Treiber zu erlauben erschien mir da etwas umständlich, da sie bei jedem Systemstart wiederholt werden muss.

Alternativ gibt es einen Trick mit dem man einen Großteil unsignierter Treiber doch zum Laufen bringen kann.
Dazu gibt man unter Start -> Ausführen -> „cmd“ ein und fährt mit folgender Anweisung fort

bcdedit /set testsigning on

Nach einem Neustart müsste unten recht in der Ecke ein Text wie „Testversion“ erscheinen und damit den Erfolg der Aktion bestätigen.

Es ist jedoch Vorsicht geboten!
Bei meinen Versuchen führten die Treiber relativ häufig zu einem Bluescreen, was aber meiner Ansicht nach häufiger die Schuld des Systems als die der Treiber war.

Um den Vorgang wieder Rückgängig zu machen gibt man auf gleichem Wege

bcdedit /set testsigning off

ein und starte das System wiederum neu.

Buchtipp #2

Gestern ist mir an meinem Bücherregal aufgefallen das ich nach meinem letzten (und ersten) Buchtipp ganz vergessen habe euch mit den Daten zum angesprochenen zweiten Teil der Gerald Saga, „Das Schwert der Vorsehung“, zu versorgen.

Angesichts der Tatsache das mit „The Witcher 2″ die erneute „Versoftung“ der Geschichten nicht mehr in all zu weiter Ferne liegt scheint mir der Zeitpunkt auch günstig.

In „Das Schwert der Vorsehung“ ist als der zweite Band mit Kurzgeschichten rund um die Figur Gerald von Riva. Der Zusammenhang wie auch die zeitliche Abfolge ist wie im ersten Band ziemlich vage, was aber nicht weiter störend wirkt.
Querverweise zwischen den Geschichten beider Bände sind nicht vorhanden bzw. fallen einem nicht auf, sofern man nicht gezielt und gründlich sucht.
Somit ist „Der letzte Wunsch“ keine Voraussetzung für „Das Schwert der Vorsehung“.

Für Interessierte die sich einige Informationen zum Autor verschaffen wollen verweise ich an dieser Stellen an Wikipedia.

Abschließend noch einige Fakten die Amazon zu „Das Schwert der Vorsehung“ anbietet.

  • Broschiert: 464 Seiten
  • Verlag: Deutscher Taschenbuch Verlag (1. Juni 2008)
  • Sprache: Deutsch
  • ISBN-10: 3423210699
  • ISBN-13: 978-3423210690
  • Größe und/oder Gewicht: 19,2 x 12 x 2,8 cm

C# Animierte Gifs erstellen

Es ist mehr oder weniger bekannt das man mit Bordmitteln des .Net Frameworks keine Animierten Gif Bilder erstellen kann.

Nun stand ich aber vor dem Problem genau das zu realisieren.
Was macht man also?
Man benutzt Google und begibt sich auf die Suche nach jemandem der das Problem schon mehr oder weniger gelöst hat.

Als erstes stieß ich auf einen Ansatz der sich sehr nahe am technischen Hintergrund orientierte.

Technische Lösung

Leider waren die Ergebnisse qualitativ nicht ausreichen.
Hinzu kommt das ich es nicht sehr schön finde Byte-Array aufzubauen und diese mit kryptischen Zahlen zu füllen, bei denen ich mir sicher bin das ich schon in zwei Tagen nicht mehr weiß welche was bedeutet.

Die Suche ging also weiter und ich stieß schnell auf NGif.
Da es sich schon mal um eine Bibliothek handelte und ich nicht wieder mit irgendwelche Byte-Arrays hantieren musste war mein Eindruck gleich wesentlich besser.
Dieser bestätigte sich dann auch im weiteren Verlauf meiner Tests, so das nach und nach ein Tool zum Erstellen von animierten Gif Bildern entstand.

Einige kleine Schwierigkeiten traten dennoch auf.

  1. Füttert man NGif zum Beispiel nicht mit JPG Dateien sondern nicht-animierten Gif Bildern so lässt die Qualität stark nach.
  2. Das festlegen von Transparenz funktioniert nicht immer.

NGif bietet auch die Möglichkeit bestehende Bilder zu bearbeiten. In wie weit diese funktioniert und auch zu ansehnlichen Ergebnissen führt muss noch getestet werden. Momentan reicht die Version 1 mit der Möglichkeit zum Erstellern besagter Bilder aus.

Das fertige Tool wird übrigens in den nächsten Tagen unter dem Namen MegaGifAnimator (klingt gut oder?) auf MegaDev veröffentlicht werden.

LANSIN(N) 19

Ich besuche nicht viele Veranstaltungen im Jahr aber ein Termin hat sich in der Vergangenheit durchgesetzt.
Die Lansin ist eine Lanparty der etwas anderen Art.
Nicht zuletzt weil sich die halbe Halle nun schon über mehrere Jahre persönlich kennt und man auch bei der OPT-Community aktiv ist.

Ort ist wie in den letzten Jahren die Werner Bruckmeier Halle in 73527 Täferrot.
Zeitpunkt der 05.-07.11.2010
Preis: 22€
Max. Teilnehmerzahl: 172

Wer sich also noch etwas informieren will folge bitte diesem Link
LANSIN(N)

Nachdem mein „MarqueeControl“ nun langsam aber sicher Formen annimmt (Ich werde es nach Fertigstellung hier im Blog veröffentlichen) wird es Zeit einige Worte über den Abruf eines RSS Feeds zu verlieren.
Besonders seit der Einführung von Linq in .Net ist das Ganze zu einem Kinderspiel geworden.
Der folgende Abschnitt übernimmt dabei die gesamte Arbeit.
Einzig und alleine um eine etwas schönere Behandlung von Fehler, Timeouts, etc muss sich nochmal gekümmert werden ;)

public static class Rss
    {
        public static RssItem[] GetItems(Uri feedUrl)
        {
            RssItem[] rssItems = null;

            try
            {
                XDocument doc = XDocument.Load(feedUrl.OriginalString);

                rssItems = (from x in doc.Descendants("channel").Descendants("item")
                            select new RssItem()
                            {
                                Title = x.Descendants("title").Single().Value,
                                Message = x.Descendants("description").Single().Value,
                                Url = new Uri(x.Descendants("link").Single().Value),
                                PublishedOn = DateTime.Parse(x.Descendants("pubDate").Single().Value, CultureInfo.InvariantCulture)
                            }).ToArray<RssItem>();

            }
            catch (WebException) { }

            return rssItems;
        }
    }

Zu guter Letzt nur noch die Struktur in der die Daten gehalten werden.

public class RssItem
    {

        #region fields

        private string _title;
        private string _message;
        private Uri _url;
        private DateTime _publishedOn;

        #endregion fields

        #region properties

        public string Title
        {
            get { return this._title; }
            set { this._title = value; }
        }

        public string Message
        {
            get { return this._message; }
            set { this._message = value; }
        }

        public Uri Url
        {
            get { return this._url; }
            set { this._url = value; }
        }

        public DateTime PublishedOn
        {
            get { return this._publishedOn; }
            set { this._publishedOn = value; }
        }

        #endregion properties

    }

Ich hätte es nicht gedacht aber es ist doch relativ kompliziert wenn man versucht z.B. einen RSS Feed als Lauftext/Newsticker auf einer Windows Form darzustellen.

Mein erster Ansatz bestand darin ein Label zu platzieren und dann mit einer „ausgeklügelten“ Routine (in einem extra Thread um die GUI nicht zu blocken) den Text entsprechen zu „bewegen“.

Ausschnitt:

private int _feedIndex = 0;
private int _feedOffset = 0;

private void Worker(string feedString)
{
    while (true)
    {
        // Check if this method is running on a different thread
        // than the thread that created the control.
        if (this._lbFeed.InvokeRequired)
        {
            // It's on a different thread, so use Invoke.
            SetFeedTextCallback d = new SetFeedTextCallback(SetFeedText);
            this._ctrl.Invoke(d, new object[] { feedString.Substring(_feedIndex, _feedOffset) });
        }
        else
        {
            this._lbFeed.Text = feedString.Substring(_feedIndex, _feedOffset); ;
        }

        if (_feedOffset + _feedIndex + 1 <= feedString.Length)
        {
            if (this._lbFeed.InvokeRequired)
            {
                SetFeedAlignmentCallback d = new SetFeedAlignmentCallback(SetFeedAlignment);
                this._ctrl.Invoke(d, new object[] { ContentAlignment.MiddleRight });
            }
            else
            {
                this._lbFeed.TextAlign = ContentAlignment.MiddleRight;
            }

            if (_feedOffset < 95)
            {
                _feedOffset++;
            }
            else
            {
                _feedIndex++;
            }
         }
         else
         {
             if (this._lbFeed.InvokeRequired)
             {
                 SetFeedAlignmentCallback d = new SetFeedAlignmentCallback(SetFeedAlignment);
                 this._ctrl.Invoke(d, new object[] { ContentAlignment.MiddleLeft });
             }
             else
             {
                 this._lbFeed.TextAlign = ContentAlignment.MiddleLeft;
             }

             _feedIndex++;
             _feedOffset--;

             if (_feedIndex == feedString.Length)
             {
                 _feedIndex = 0;
                 _feedOffset = 0;
             }
         }

         Thread.Sleep(125);
     }
}

Leider braucht das Ganze nicht nur Speicher sondern auch ne Menge CPU Zeit.
Hinzu kommt das naturgemäß ein „i“ kürzer ist als ein „m“ und so ein gewisses Ruckeln auftrat.

Ich machte mich also daran eine bessere Lösung zu suchen und begann ein neues Control zu entwerfen mit dessen Hilfe ich den Text zeichnen wollte. Das klappte soweit dann auch erstaunlich gut. Etwas mehr Speicher wurde belegt aber Last auf der CPU sank deutlich.
Leider gab es dann doch einen Stolperstein.
Zumindest bei meiner Implementierung gibt es Probleme bei „BackColor = Color.Transparent“ und zwar deshalb weil man mit einer transparenten Farbe den bereits gezeichneten Text natürlich nicht überdecken kann.
Hier musste ich etwas in Trickkiste greifen und bin erst einmal wie folgt verblieben.

1) Ist der Hintergrund Farbe des Controls nicht transparent so wird ganz normal gezeichnet.

  • Control mit Farben füllen -> Teil des Textes zeichnen
  • Control mit Farben füllen -> Teil des Textes zeichnen
  • usw.

2) Ist die Hintergrundfarbe des Controls transparent so gibt es zwei Möglichkeiten

2.1) Das Parent-Control hat ein Hintergrundbild
In diesem Fall hole ich mir den Ausschnitt des des Bildes auf dem mein Control liegt und verwende diesen als „Farbe“ zum Überdecken des bisher Gezeichneten.

2.2) Das Parent-Control hat kein Hintergrundbild
In diesem Fall leihe ich mir dann dessen Hintergrundfarbe aus.

Problem: Hat auch das Parent-Control auch einen transparenten Hintergrund kommt es zum Fehler. In wie weit ich das für meine Zwecke abdecken muss wird sich noch herausstellen.

collapse="true"

Gestern habe ich euch berichtet das ich nun statt direkt die Windows API aufzurufen die SoundPlayer Klasse des .Net Frameworks benutzte, um Audioausgaben zu verwirklichen.

Leider scheint bei beiden Methoden ein und das selbe Problem aufzutreten.

Wird ein Soundfile sehr oft nacheinander asynchron abgespielt (z.B. wenn eine Taste nicht nur kurz sondern sehr lange gedrückt wird) erfolgt irgendwann keine Ausgabe mehr bis die Anwendung neu gestartet wird.
Das Betriebssystem und andere Programme werden davon nicht beeinflusst.

Eine Art „cool down“ scheidet als Lösung aus, da auch relativ schnelle Tastendrücke erkannt werden müssen.

Besonders verwunderlich ist das gleichartige Verhalten beider Methoden eigentlich nicht!
Schließlich Kapselt der SoundPlayer fast ausschließlich die API Calls in eine managed Bibliothek.

Ob und wie ich eine Lösung finde steht noch in den Sternen aber ich werde die nächsten tage vermutlich viel Zeit damit verbringen.
Wenn alles nichts hilft werde ich wohl wieder einen Schritt zurück gehen und versuchen müssen wieder direkt mit der Windows API zu kommunizieren, um auf diesem Weg eine Lösung zu finden.

SoundPlayer in C#

Nachdem ich nun schon länger daran arbeite Sounds mittels C# in einer Anwendung abzuspielen und bisher dazu direkt die Windows API genutzt habe bin ich auf die SoundPlayer Klasse gestoßen.
Diese befindet sich im System.Media namespace.
Im Prinzip wird dort auch nichts anderes gemacht als die bisher von mir genutzt Windows API synchron oder asynchron aufzurufen aber man hat irgendwie ein besseres Gefühl dabei.


Vorher (pinvoke.net)

[DllImport("winmm.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PlaySound(string pszSound, UIntPtr hmod, UInt32 fdwSound);
...
private const UInt32 SND_ASYNC = 0x0001;
private const UInt32 SND_FILENAME = 0x20000;
...
public void Play (string strFileName)
{
    PlaySound (strFileName, UIntPtr.Zero, (SND_FILENAME | SND_ASYNC));
}
...


Nachher

...
System.Media.SoundPlayer soundPlayer = new SoundPlayer(filepath);
soundplayer.Play() // asynchron
...


Wer trotzdem gerne mal bisschen in der Windows API stöbern und diese auch mit C# nutzen will sollte sich mal auf folgender Seite umsehen.
pinvoke.net

Follow

Get every new post delivered to your Inbox.