Mittwoch, 4. März 2015

New Blog: benedictinerklosterbruder.blogspot.com

It's a mess here since Wuala is "closed" for me.
Not to say that there was no mess before, but now it's absolutely chaotic here. All downloads are gone, if they were not gone before (just checked one on a really old post...that download link was expired for years..)

So I decided to open a new blog.

http://benedictinerklosterbruder.blogspot.com

All files will be uploaded to OneDrive and my home server. So, there will ever be a copy no matter if my server crashes or on the other side OneDrive "closes". Except for if both happens at the same time.

Also, every download will be explicitly linked on a special download page. If you search something, you don't have to search the whole blog for "that one" download.

Plus there is a sitemap wich links to the most important (or entry-)posts. Maybe more later.

Please be patient while I do the new layout and search for my downloads and stuff.

I decided to add ONE adsense Ad at the BOTTOM of the blog (here on the bottom of a blog entry). Please click this ad if you want to give me some credit. It would be awesome if I would make a dollar *out of the internet*. ;) Thanks.

Thanks to all of you for copying my code...ehr...reading my blog. That means something to me, I never thought more than 100 people would read that but...it's 25025 now. Nice Number. ThanksALot.

I know, It's not much for the internet, but in Switzerland it's a middle-big city, so....

Again: GOTO 100 -> http://benedictinerklosterbruder.blogspot.com
And here's my homeserver: http://ben0bi.homenet.org

Montag, 8. Dezember 2014

Rechtliche Situation: Schweiz

Nachdem wir nun alle wissen, dass es in Deutschland weder Gesetze noch Beamte (mit Hoheitsrechten) gibt, möchte ich nun wissen, wie das in der Schweiz ist.

Leider gibt es nur tonnenweise Informationen zu Deutschland und USA, andere Länder werden bei dieser Thematik leider ignoriert.

Betreffend Deutschland, siehe hier: http://newstopaktuell.wordpress.com/

Also, wie ist das in der Schweiz?

(Das Wort Bund bezieht sich nicht auf die (eingetragene!) Bezeichnung von Deutschland bei den UN Nichtregierungsorganisationen (!) (hier), sondern auf den "Bund der (schweizer) Eidgenossen".)

Also erstens: Ein Schweizer ist KEIN Eidgenosse, da er nie einen Eid geleistet hat. Ausser vielleicht beim Militär, aber sonst jedenfalls nicht.

Beamtenstatus: Seit 2002 aufgehoben. Diese *Angestellten* haben also KEINE Hoheitsrechte mehr.

Dies gilt NICHT für Polizei und Richter, diese sind immer noch *Beamte*.

Jedoch sind alle Polizeien und Gerichte eingetragene Firmen, welche man auf http://www.upik.de findet. Legitimation?

Wie kann ein *Beamter* für eine *private Firma* arbeiten, ist das rechtlich überhaupt möglich?
Hat dieser *Beamte* noch *Beamtenstatus* bzw. Hoheitsrechte, wenn er für diese *private Firma* arbeitet? Handelt er im Auftrag dieser Firma oder *im Auftrag des Bundes*?

Personenrecht: Die Schweizer Verfassung sagt: Jeder MENSCH ist rechtsfähig. Das kann man also nicht auf die *Person* abschieben. Man könnte jedoch sagen: "Ich bin zwar rechts-fähig, jedoch nicht rechts-pflichtig." (Oder?)

Doch auch wir werden *registriert* (Geburtsurkunde, etc.). Wer ist Eigentümer der Person? Ist es die Crown? Oder der Bund? Oder ist das bei uns anders?

Geltungsbereiche:
ZGB / OR: Schweiz
Verfassung: Schweizerische Eidgenossenschaft
Wurden also nicht *rausradiert*, wie im Deutschen GG.
(Ist "Schweiz" gleich "Schweizerische Eidgenossenschaft" ?)

Die "Eidgenossenschaft" WAR in www.upik.de bis c.a. 2013 (weiss nicht genau), danach habe ich sie nicht mehr gefunden. Was ist da passiert? Sind *wir* wieder ein *funktionsfähiger* Staat?

Auch seit 2002 ist die Schweiz Mitglied bei den Vereinten Nationen (UN).
Terranianer sind von der UN legitimiert und somit auch auf schweizer Boden.

http://terrania.org

Das ist der aktuelle Stand meiner Ermittlungen.

Bitte kommentieren. Bitte weitersagen. Bitte selber recherchieren und mir Feedback geben. Danke.

Montag, 3. November 2014

Unity3D: 3D-Mesh LED HUD Healthbar

So, you want to achieve something like that?



Then stick to that tutorial.

I will NOT explain here, how to setup a second camera for the HUD, because you can make it your way. What I will explain here, is how to create a Healthbar (or other-bar) using "LEDs".

First, create a mesh with your LEDs in it. Every LED is an object (the mesh must have several parts in unity), wich is named after your LED-name wich you use later. I call them LED_x, where x is a number. Number has no zeroes before. (Not 01, just 1, and then 10)

You can make that mesh with Unity (empty gameObject with some spheres in it) or with your desired 3D-modeling software. Just remember, the LEDs must have all the same name with a number, defining wich LED on the bar it is. And remember for exporting that it must have several parts in unity. Don't merge the LEDs with the background-mesh...

Set all materials of the LEDs to the shader "VertexLit".

The first script we create has some static functions wich will be used later:

public class Static
{
    public const string TAG_HUDROOT = "HUDroot";

    // finds the gameobject tagged with text along the parents.
    public static Transform FindParentWithTag(Transform owner,string tag)
    {
        if (owner && owner.tag == tag)
            return owner;
        else if (!owner)
        {
            Debug.LogWarning("WARNING: No parent with tag " + tag + " found.");
            return null;
        }
        return FindParentWithTag(owner.transform.parent, tag);
    }

    // sets emmisive color on the renderer, if it has one.
    public static void SetRendererEmissiveColor(Renderer renderer, Color color,bool affectDiffuse=true)
    {
        if (!renderer)
            return;

        //renderer.material.SetColor(0, color);

        // maybe leave the diffuse color alone.
        if (affectDiffuse) 
            renderer.material.color = color;
        renderer.material.SetColor("_Emission", color);
        renderer.material.SetColor("_EmisColor", color);
    }

    // turns of the emissive color on the renderer, if it has one.
    public static void TurnOffRendererEmissiveColor(Renderer renderer,bool affectDiffuse=false)
    {
        if (!renderer)
            return;

        // maybe leave the diffuse color alone.
        if (affectDiffuse)
            renderer.material.color = Color.black;

        renderer.material.SetColor("_Emission", Color.black);
        renderer.material.SetColor("_EmisColor", Color.black);
    }
}

Now, we begin to build up our HUD.

Create a gameObject wich is centered on your HUD-cam (or has the same position or something like that). This is the HUDs root-node.

Tag it with "HUDroot" (create that tag, if it does not exist.)

Now add the script "TargetComponent" to the root node:

public class TargetComponent : MonoBehaviour
{ 
    public bool getCamTarget = true;
    public bool destroyIfNoTarget = true;
    public Transform target;
// Use this for initialization
void Start () {
        // get it every update so it changes when it changes.
        if (getCamTarget)
            GetCamTarget();  
}

// Update is called once per frame
void Update () 
    {
        if (destroyIfNoTarget && !target)
            GameObject.DestroyObject(gameObject);
    }

    public void GetCamTarget()
    {
        Camera mainCam = Camera.main;

        if (!mainCam)
            return;

        CameraController c= mainCam.GetComponent<CameraController>();

        if (!c)
        {
            Debug.LogError("ERROR: No CameraController-Script attached to the main camera.\nPlease attach it.");
            return;
        }

        target = c.target;
    }
}


This script contains the target for the whole HUD. It is mostly the player, but for
some HUD items, it could be e.g. the players target or info about some item.

I will not explain here about the CameraController.
It must have a target, wich is your player. That's all.

Add your mesh (gameObject) to this root node and positionate and rotate it like you desire.

Now add the script LEDBar to your HUDs root node:
public class LEDBar : MonoBehaviour 
{

    private void TESTFUNCTION() {;;}
    /*
    private void TESTFUNCTION()
    {
        // HULL HUD
        int posOrange = (int)(ArrayCount * 0.3333f) + 1; // 1/3 is orange
        // red is just the second LED
        int posRed = (int)(ArrayCount * 0.1f) + 1; // 1/10 is red

        // first green -> full range
        TurnOnLEDs(8, 15, new Color(0.0f, 1.0f, 0.0f));
        // then orange: 1/3 range
        TurnOnLEDs(new Color(1.0f, 1.0f, 0.0f), posRed + 1, posOrange, 8, 15);
        // then red: 1/5 range
        TurnOnLEDs(new Color(1.0f, 0.0f, 0.0f), 1, posRed, 8, 15);
    }
    */


    public bool blackIfOff=false;
    public string arrayName = "LED_";

    private MeshRenderer[] LEDarray;
    // the ship wich the hud targets on.
    protected Transform target;
    // the huds root node.
    protected Transform root;


    protected void INITIALIZE()
    {
        //print("INITIALIZE");
        root = Static.FindParentWithTag(transform, Static.TAG_HUDROOT);
        if (!root)
        {
            Debug.LogError("ERROR: No HUDroot found for " + gameObject.name + "\nPlease tag the root object of your hud with " + Static.TAG_HUDROOT);
            return;
        }

        NotifyLEDs();

        // TEST TEST TEST
        TESTFUNCTION();
        // END TEST

        TargetComponent t = root.GetComponent<TargetComponent>();
        if (!t)
        {
            Debug.LogError("ERROR: No TargetComponent-Script attached to the HUDs root node.\nPlease attach it.\nIt searches for the HUDs target and sets it \"globally\" for the HUD.");
            return;
        }

        target = t.target;
// design flaw? target is null
        if (!target)
            print("WTF?");
    }

// ...so that is called in update...
    protected void FINDTARGET()
    {
        if (!target)
        {
            TargetComponent t = root.GetComponent<TargetComponent>();
            target = t.target;
        }
    }

    // Use this for initialization
    void Start () 
    {
        INITIALIZE();
    }

    // Update is called once per frame
    void Update () 
    {
        FINDTARGET();
    }

    public void NotifyLEDs()
    {
        if (!root)
        {
            Debug.LogError("ERROR: Cannot assign LEDs-Meshes because no HUD-root was found in "+gameObject.name+".\nPlease tag the root object of your HUD with " + Static.TAG_HUDROOT);
            return;
        }

        int c = RealCount;
        if (c <= 0)
        {
            Debug.LogWarning("WARNING: No HUD-Meshes found for " + arrayName + "x in " + gameObject.name+" in "+root.name+"\nHULLBar-Script needs to be in its own GameObject.");
            LEDarray = null;
            return;
        }

        // c > 0
        LEDarray = new MeshRenderer[c];

        var renderers = root.GetComponentsInChildren<MeshRenderer>();
        if (renderers.Length <= 0)
        {
            Debug.LogError("ERROR: @LEDBar.NotifyLEDs: No renderers found in " + root.name + ".");
            return;
        }

        int ii = 1;
        for (int i = 0; i < c; i++)
        {
            ii = i + 1;
            foreach (MeshRenderer r in renderers)
            {
                if(r.gameObject.name==arrayName+ii.ToString())
                    LEDarray[i]=r;
            }
        }

        BlackOut(blackIfOff);
        Debug.Log("HUD Mesh Notify: "+c+" HUD Meshes with name " + arrayName + "x found.");
    }

    // turn on leds first to last based on a range
    public void TurnOnLEDs(Color color,int lastLEDposition, float value, float maxValue)
    {
        //print("TURNON LEDS ALL VALUES");

        if (ArrayCount <= 0)
            return;

        if (lastLEDposition <= 0)
        {
            Debug.LogError("ERROR: LED range <= 0 @ LEDBar.TurnOnLEDs_#1 @" + gameObject.name);
            return;
        }

        // else count steps up and turn on each led < step.
        float LEDstep=0.0f;
        
        if(maxValue!=0)
            LEDstep = maxValue / ArrayCount;

        float rangedMaxValue = lastLEDposition * LEDstep;

        // maybe just turn on all the LEDs
        if (value >= rangedMaxValue)
        {
            //print("value > > > "+lastLEDposition);
            TurnOnLEDs(color, 1, lastLEDposition);
            return;
        }

        //print("value = " + value + " r=" + rangedMaxValue+" l="+lastLEDposition);

        float actual = 0.0f;
        for (int i = 0; i < lastLEDposition; i++)
        {
            // maybe we change index.
            int index = i+1;
            actual = i * LEDstep;
            if (value>0 && value >= actual)
                TurnOnLED(index,color);
        }
    }

    // turn on leds first to last.
    // range starts with 1!
    public void TurnOnLEDs(Color color,int first, int last)
    {
        if (ArrayCount <= 0)
            return;

        if (first <= 1)
            first = 1;

        // how many leds to light?
        int ledRange = last - first + 1;
        if (ledRange <= 0)
        {
            Debug.LogError("ERROR: LED range <= 0 @ LEDBar.TurnOnLEDs_#2 @" + gameObject.name);
            return;
        }

        for (int i = 0; i < ledRange; i++)
        {
            int index=first+i;
            TurnOnLED(index, color);
        }
    }

    // turn on ALL leds based on a range.
    // switching colors here for not messing up with the parameters (int and float above)
    public void TurnOnLEDs(float value, float maxValue,Color color)
    {
        //print("TurnOnLEDs range");
        if(ArrayCount<=0)
            return;
        TurnOnLEDs(color,ArrayCount, value, maxValue);
    }

    // index must start with 1!
    public void TurnOnLED(int index, Color color)
    {
        index -= 1;
        if (index >= ArrayCount)
            return;
        if (LEDarray[index])
            Static.SetRendererEmissiveColor(LEDarray[index], color);
        else
            Debug.LogWarning("WARNING: HUD item #" + (index + 1) + " is not assigned.\nLED name: " + arrayName + "x in " + gameObject.name);
    }


    // turn all the leds off.
    public void BlackOut(bool affectDiffuse = false)
    {
        if (ArrayCount<=0)
            return;
        foreach (MeshRenderer r in LEDarray)
            Static.TurnOffRendererEmissiveColor(r,affectDiffuse);
    }

    public int ArrayCount { get { return LEDarray.Length; } }

    // (re)count the items in the gameObject
    public int RealCount
    {
        // count all leds in the in the root node, with the same name.
        get
        {
            var renderers = root.GetComponentsInChildren<MeshRenderer>();
            if (renderers.Length<=0)
            {
                Debug.LogError("ERROR: @LEDBar.RealCount: No renderers found in "+root.name+".");
                return 0;
            }

            bool done = false;
            bool found = false;
            string arname = "";
            int count = 0;
            
            while (!done)
            {
                int c = count + 1;
                arname = arrayName + c.ToString();

                found = false;
                foreach (MeshRenderer r in renderers)
                {
                    if (r.gameObject.name == arname)
                    {
                        Debug.Log("Registering HUD object "+r.gameObject.name);
                        count++;
                        found = true;
                    }
                }

                if (!found)
                    done = true;
            }
            return count;
        }
    }
}



That's a big one. You can add as much of them to your root node as you want.
The important thing here is "arrayName", where you put the name of your LEDs WITHOUT any number. ("LED_")

You can now use BlackOut, TurnOnLEDs and TurnOnLED as you wish.

BlackOut(makeBlack=false) - turns Off all LEDs.
TurnOnLED(index) - turns on a single LED.
TurnOnLEDs(value, maxValue, Color) - turns on the LEDs based on the value and maxValue.
TurnOnLEDs(Color, first, last) - turns on the LEDs from # first to last.
-> And the other function combines that both.
ArrayCount returns the Length of the LED-array.
(RealCount counts the LEDs in the mesh-construction.)

You can now use that as base class for your HUD, and stuff the values/maxValues-scripting-stuff into the derived class, using the "target"-value.

Example class to add to your HUD:
public class HealthHUD : HUDBar
{
    void Start()
    {
         INITIALIZE();
         // ...
    }
 
     void Update()
    {
        FINDTARGET(); // there is a bug with finding the target in Start. I dunno...

        if (!target)
            return;

        BlackOut(true);  // Set all LEDs to black.

        // HULL HUD

         //Destructable is a class with health values.
        // ...make your own...
        Destructable d = target.GetComponent<Destructable>();
        if (d)
        {
            int posOrange = (int)(ArrayCount * 0.3333f) + 1; // 1/3 is orange
            // red is just the second LED
            float posRed = (int)(ArrayCount * 0.1f) + 1; // 1/10 is red

            // first green -> full range
            TurnOnLEDs(d.currentHealthPoints, d.maxHealthPoints, new Color(0.0f, 1.0f, 0.0f));
            // then orange: 1/3 range
            TurnOnLEDs(new Color(1.0f, 1.0f, 0.0f),posOrange, d.currentHealthPoints, d.maxHealthPoints);
            // then red: 1/10 range
            TurnOnLEDs(new Color(1.0f, 0.0f, 0.0f), (int)posRed, d.currentHealthPoints, d.maxHealthPoints);
        }
    }
}

Hope that helps. It's tested but not this blog entry. If you miss something, tell me.

Samstag, 25. Oktober 2014

NEW CLOUD

Wuala will close all free accounts per December. 31. 2014, so I moved all the stuff from there to the Microsoft-Cloud.

All my old links (to my stuff) are invalid then. You can find the stuff here:

https://onedrive.live.com/redir?resid=99C1BC740CDB8B8B!107&authkey=!ANM6mz0AeC7Ri5g&ithint=folder%2cpdf

Sorry for that.

Sonntag, 28. September 2014

XBox360: Make Destiny run with D-Link-Router

Ok, first I followed this tutorial:

http://www.crashwiki.com/fix-destiny-error-codes/

But I did not find out the DNS-adresses of my ISP.

I gave up and made an automatic connection on the XBox - and then, there popped up some DNS adresses.

I wrote them down and then made a manual connection with the given DNS adresses.

Destiny ran for a few seconds longer now. ;)

You need to make your NAT open for the XBox360.

With a D-LINK-Router, this is done like that:

1. Login to your router.
2. Go to DMZ (Demilitarized Zone)
3. Enable DMZ
4. Set the IP of the DMZ host to your XBox-IP.

Restart your router and modem.

Since then, it runs properly.

If you cannot get the DNS-adresses, use the ones from google: 8.8.8.8 and 8.8.4.4

Hope that helps.

Freitag, 22. August 2014

C#: Object Factory with XML Data and Library

I am rebuilding a trading card game (TCG) to make it available on PC.
(NetRunner / Android: Netrunner)

For that I need several card types (classes) and some data associated with them.
First I wanted to make a class for EVERY new card. But then I thought, that there can be the same card class wich just has some other values. So, I made an XML-File with the cards values.

The XML values will be read into a card library. Because a card can have any card-class, the class name is included in the XML-Data. The "right" instance will be created and added to the library.

(I use the short "NM" for the (working title) word "NetMage".)

You can finally use: NMCardFactory.Clone("My_Card_Id") to copy a card from the library.

Now to the code:
First, here is a sample XML file.
<CardList>
<Card id="MyBaseCard">
    <Class>Base_Default</Class>
    <Title>My Base Card</Title>
    <StoryText>Some story text.</StoryText>
    <Cost>2</Cost>
</Card>
 <Card id="MyExtendedCard">
   <Class>Extended_Default</Class>
   <Title>Extended Card</Title>
   <StoryText>Some other story text.</StoryText>
   <Cost>3</Cost>
   <MyValue>Value</MyValue>
   ....
</Card>
</CardList>

I everytime have a class called "Globals" with global methods and a class called "Values" with important values to gather them together.

So, first the NMGlobals class, there are three static methods:
namespace CardGame.Source
{
    public class NMGlobals
   {
        // find the first xml node with a given name in a parent node.
        public static XmlNode FindFirstXMLNode(XmlNode parent, string name)
        {
            foreach (XmlNode node in parent)
            {
                if (node.Name.ToLower().Equals(name.ToLower()))
                    return node;
            }
            return null;
        }

        // find the first innertext from node NodeName in parent.
        public static string FirstXMLInnerText(XmlNode parent, string NodeName)
        {
            // get the text
            string t = "";
            XmlNode xmlText = NMGlobals.FindFirstXMLNode(parent, NodeName);
            if (xmlText != null)
            {
                t = xmlText.InnerText;
                Log.Write(NodeName+": " + t);
            }
            else
            {
                Log.Write("XML Warning: No <"+NodeName+"> found.");
            }
            return t;
        }

        // find first inner int from node NodeName in parent.
        public static int FirstXMLInnerInt(XmlNode parent, string NodeName)
        {
            // get the int
            int i = 0;
            XmlNode xmlText = NMGlobals.FindFirstXMLNode(parent, NodeName);
            if (xmlText != null)
            {
                i = Convert.ToInt32(xmlText.InnerText);
                Log.Write(NodeName + ": " + i);
            }
            else
            {
                Log.Write("XML Warning: No <" + NodeName + "> found.");
            }
            return i;
        }
   }
}

These three methods are used for processing XML Data.

Now to the Values:
namespace CardGame.Source
{
   public class NMValues
   {
      public const string CardClassNamespace = "NetRunner.Cards";
   }
}

This is the namespace for all your card classes, wich you want to use with XML.

Now we need the base card. It has an ID, a Title and a StoryText. (Only the ID will be needed but I want to explain the loading stuff...) This base card class can be used for ANY game. I will derive a base card class from that for "the game itself" in the NetRunner.CardType namespace - and from that the card-type-classes - and then I will derive the actual cards in the NetRunner.Cards namespace. This is to show you how I approached it. Remember the namespaces: For the base stuff, it is "CardGame", for the (my) game, it is "NetRunner".

namespace CardGame.Source
{
     public class NMCard
     {
          protected string _ID; // the ID is an UNIQUE identifier for the card-class-value-pair.
          public string ID {get{return _ID;}}
          public void __setID(string id) {_ID=id;}  // we set the ID outside, in the card factory.

          protected string _Title; // Title of the card, set with CopyValuesFrom or LoadFromXML
          public string Title {get{return _Title;}}

          protected string _StoryText; // some story text for the setting of the game.
          public string StoryText {get{return _StoryText;}}

          public NMCard()
          {
               // Initialize the (new) values.
                __setID("# No ID #");
                _Title= "# No Title #";
                _StoryText="";
          }

          // This is a main feature and MUST be overriden if there are new values.
          // It is used while CLONING a card.
           public virtual void CopyValuesFrom(NMCard card)
          {
              __setID(card.ID);
               _Title=card.Title;
               _StoryText=card.StoryText;
          }

          // This also is a main feature and MUST be overriden if there are new values.
          // It is used while creating the card library.
          public virtual void LoadFromXML(XmlNode xmlCard)
          {
                _Title=NMGlobals.FirstXMLInnerText(xmlCard,"Title");
                _StoryText=NMGlobals.FirstXMLInnerText(xmlCard,"StoryText");
          }
     }
}
As you can see, there are two methods, "CopyValuesFrom" and "LoadFromXML". LoadFromXML will be called while creating the card library. It gets the XML node containing all card values. From that, we can extract our values. CopyValuesFrom makes the same - but it copies the values from a card. So, every new value needs to be "registered" in these two methods.

Now we derive the base NetRunner card class from that card in NetRunner.CardTypes:

namespace NetRunner.CardTypes
{
   public class NetRunnerBaseCard : NMCard
   {
      // Every Netrunner card has a cost.
      protected int _Cost;
      public int Cost  {get{return _Cost;}}

      // Overriden functions.
      public override void CopyValuesFrom(NMCard card)
      {
             base.CopyValuesFrom(card); // DO NOT FORGET THAT!
            if(card is NetRunnerBaseCard)
                  _Cost=((NetRunnerBaseCard)card).Cost;
      }

       public override void LoadFromXML(XmlNode xmlCard)
       {
            base.LoadFromXML(xmlCard); // DO NOT FORGET THAT!
            _Cost=NMGlobals.FirstXMLInnerInt(xmlCard,"Cost");
       }
    }
}

Now you can derive your card types from that NetRunnerBaseCard in the namespace NetRunner.CardTypes. Everytime you have new values wich need to be loaded or copied, overwrite the two methods like in the example above. (Cost)

Finally you create actual cards in the namespace NetRunner.Cards. That is to prevent the XML-creator from using the base class/es wich are also in the CardTypes namespace but cannot directly be played.. 
namespace NetRunner.Cards
{
    public class Base_Default : NetRunnerBaseCard {}
    public class Base_Special : NetRunnerBaseCard
    {
       ///  ..add values like strength or something like above ..
     }
    public class Extended_Default : NetRunnerEventCard {} // That's an example.
}

We have now an XML file with some cards and some card classes. Let's finally get on to the actual card factory class wich we are all waiting for. It has a list (_cardClasses) wich contains the names of all registered classes (all classes in the given namespace) and a dictionary (_cardLibrary) wich contains all the different cards with their values.

When you use the Clone-Method, it searches the library for the given ID and clones that object.

The classes-list is only needed for security reasons while loading from XML.

namespace CardGame.Source
{
    public class NMCardFactory
    {
        // all registered card classes in the "Cards" namespace
        // (see NMValues for the namespace)
        protected static IEnumerable<Type> _cardClasses=null;

        // all the cards there are available
        // This cards will be loaded per XML and then created by the classname.
        // Then card.LoadFromXML will be called.
        protected static Dictionary<string,NMCard> _cardLibrary = null;

        // library stuff
        public static Dictionary<string,NMCard> Library { get { return _cardLibrary; } }
        public static int LibrarySize { get { return _cardLibrary.Count; } }
        public static void ClearLibrary() {_cardLibrary.Clear();}

        // initialize the card factory
        // You must call that once in the game.
        // Load all card classes into the _cardClasses list.
        public static void Initialize()
        {
            if(_cardClasses==null)
                _cardClasses = GetTypesFromNamespace(Assembly.GetExecutingAssembly(), NMValues.CardNamespaceName);
            if (_cardLibrary == null)
                _cardLibrary = new Dictionary<string,NMCard>();
        }

        // Load a card library from a given XML file.
        public static bool LoadLibraryFromXML(string filename)
        {
            Log.Write("Loading card library from " + filename+"...");

            if (File.Exists(filename))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(filename);

                string root=xmlDoc.DocumentElement.Name.ToLower();
                if(root.Equals("cardlist"))
                {
                    foreach (XmlNode xmlCard in xmlDoc.DocumentElement.ChildNodes)
                    {
                        if (xmlCard.Name.ToLower().Equals("card"))
                        {
                            Log.Write("--- Card --------------------------------------------------------------------------------------------------");
                            // Load the ID
                            XmlAttribute ID = xmlCard.Attributes["id"];
                            // Load it again, with "ID"
                            if (ID == null)
                                ID = xmlCard.Attributes["ID"];
                            // Load it again, with "Id"
                            if (ID == null)
                                ID = xmlCard.Attributes["Id"];

                            if (ID!=null)
                            {
                                Log.Write("ID: " + ID.Value);
                                // check if id already exists.
                                if (!_cardLibrary.ContainsKey(ID.Value))
                                {
                                    // get the class of the card
                                    XmlNode xmlClass = NMGlobals.FindFirstXMLNode(xmlCard, "class");
                                    if (xmlClass != null)
                                    {
                                        // does the class name exist in the namespace?
                                        if (ClassExists(xmlClass.InnerText))
                                        {
                                            // create the card and load values.
                                            NMCard card = CreateByClass(xmlClass.InnerText);
                                            card.__setID(ID.Value);
                                            card.LoadFromXML(xmlCard);
                                            _cardLibrary.Add(ID.Value, card);
                                        }else{
                                            Log.Write("XML Error: Card class \"" + xmlClass.InnerText + "\" for card (ID) \"" + ID.Value + "\" does not exist. Ignoring.");
                                        }
                                    }else{
                                        Log.Write("XML ERROR: No <Class> found! Ignoring.");
                                    }
                                }else{
                                    Log.Write("XML ERROR: ID \"" + ID.Value + "\" does already exist. Ignoring.");
                                }
                            }else{
                                Log.Write("XML ERROR: No ID on the <card> found. Ignoring.");
                            }
                        }else{
                            Log.Write("--- WARNING -----------------------------------------------------------------------------------------------");
                            Log.Write("XML Warning: First sub-node of root must be  <Card>. It's \""+xmlCard.Name+"\". Ignoring.");
                        }
                    }
                    Log.Write("-----------------------------------------------------------------------------------------------------------");
                    return true;
                }else{
                    Log.Write("XML Error: Root node must be named <CardList> in "+filename+". Aborting.");
                }
            }
            return false;
        }

        // checks if a card class exists in the
        public static bool ClassExists(string name)
        {
            foreach (Type t in ClassTypes)
            {
                if (t.Name.Equals(name))
                    return true;
            }
            return false;
        }

        // get the count of registered card classes.
        public static int ClassCount
        {
            get
            {
                if (_cardClasses == null)
                    return 0;
                else
                    return _cardClasses.Count();
            }
        }

        // return the card class list.
        public static IEnumerable<Type> ClassTypes { get { return _cardClasses; } }

        /* Create a card from its class name.
         * The card class must be in the namespace wich is defined in
         * the NMValues class.
         * Returns the raw card with default values (mostly 0 ;) )
         * TODO: protected
         */
        protected static NMCard CreateByClass(string classname)
        {
            NMCard c = null;

            // Factory generating card with string from classname.
            Type hai = Type.GetType(NMValues.CardClassNamespace + "." + classname, true);
            c = (NMCard)(Activator.CreateInstance(hai));

            return c;
        }

        /* This is the main function of the factory.
         * It clones a card wich is in the library and returns it.
         * You can clone by card ID.
         */
        public static NMCard Clone(string ID)
        {
            NMCard card = GetCardByID(ID);
            NMCard clone = null;
            if (card != null)
            {
                clone = CreateByClass(card.GetType().Name);
                clone.CopyValuesFrom(card);
            }
            return clone;
        }

        /* Get a card from the library by its ID */
        protected static NMCard GetCardByID(string ID)
        {
            NMCard card = null;
            if (_cardLibrary.ContainsKey(ID))
            {
                card = _cardLibrary[ID];
            }else{
                Log.Write("Library Error: (id)"+ID+" does not exist.");
            }
            return card;
        }

        // get all types (classes) in a specific namespace and assembly.
        // used to get all card types (classes) into the _cardTypes list.
        // You can then create cards by index. (!)
        protected static IEnumerable<Type> GetTypesFromNamespace(Assembly assembly, String desiredNamespace)
        {
            return assembly.GetTypes().Where(type => type.Namespace == desiredNamespace);
        }
    }
}

That's it. You can now use the following commands:
NMCardFactory.Initialize() // Initialize the card factory.
NMCardFactory.LoadFromXML("c:\\myFile.xml"); // load a card set.

NMCard card = NMCardFactory.Clone("My_Card_ID");


Here are the missing classes:

namespace CardGame.Source
{
    public class Log
    {
        public static void Write(string text) {Console.WriteLine(text);} // you can also save it to file here...
    }
}

namespace NetRunner.CardTypes
{
   public class NetRunnerEventCard : NetRunnerBaseCard
   {
      // A value like in the example xml.
      protected string _MyValue;
      public string MyValue  {get{return _MyValue;}}

      // Overriden functions.
      public override void CopyValuesFrom(NMCard card)
      {
             base.CopyValuesFrom(card); // DO NOT FORGET THAT!
            if(card is NetRunnerEventCard)
                  _MyValue=((NetRunnerEventCard)card).MyValue;
      }

       public override void LoadFromXML(XmlNode xmlCard)
       {
            base.LoadFromXML(xmlCard); // DO NOT FORGET THAT!
            _MyValue=NMGlobals.FirstXMLInnerString(xmlCard,"MyValue");
       }
   }
}


Hope that helps. Have Fun!

Samstag, 26. April 2014

PLOG - a Picture Log

I created a PLOG with PHP wich can use a MySQL Database. You can also use it without the Database.

An Android Smartphone App for it is included, with full source code!.

To use it without Database, there ist the file php/values.php where you can set your DB connection variables or turn the DB off with

$db_use_Database = false;

The code is built on six (6) files. (excluding the Android App)

index.php -> assembles the webpage with the php commands below and some divs around it.
_android.php -> communicates with the Android app. (returns the result of $plogapp->validate_android() to the device. That is one line of text.)
css.css -> general style definitions for index.php and some tags from php/plogclass.php
php/_install.php -> Call that one ONCE after you created the MySQL-Database. It creates the necessary Table on the Database.
php/values.php -> The values that you MUST set before using the PLOG.
php/plogclass.php -> All the code for the PLOG and the Android app goes here.

You can alter index.php, css.css and php/values.php for your PLOG. The _android.php, php/plogclass.php and php/_install.php files should not be altered, except the SQL syntax may be wrong on your server.

There is a bonus file asciiimage.php wich creates a coloured text image from a given file.
I am to lazy to remove the link every time I make it public, so you get it all.

The HTML code is right at the bottom of php/plogclass.php, if you want to change the file-list appereance.

To delete uploaded files/comments, just call index.php in your browser with the flag "enabledeletion".

http://.../index.php?enabledeletion

To alter a comment on an already uploaded file, just call index.php in your browser with the flag "changecomment".

http://.../index.php?changecomment

You can create whatever file you want for index.php, it should only contain this stuff in php:
include "php/plogclass.php";
$plogapp=new PLOG(); // -> create a PLOG-instance.
$plogapp->validate_html(); // -> uploads or deletes some files. (This was previously in the constructor.)
$plogapp->show_uploadform() // -> shows the upload form, you could also create your own.
$plogapp->show_files() // -> this "is" the PLOG itself.
$plogapp->show_feedback() // -> shows some feedback from the code like "File uploaded".

Your _android.php file should only return the result of $plogapp->validate_android(); and contain NO html tags. The WHOLE file looks like this:
<?php
 include("php/plogclass.php");
$plogapp=new PLOG();
return $plogapp->validate_android();
?>

..and should not contain something other than that because the Android device reads everything as plain text.

Here is MY PLOG:
http://ben0bi.homenet.org/PLOG

Last but  not least, here is the download of the .zip file with all six files and all Android-app stuff in it.
http://wuala.com/ben0bi/Shared/CODE/PLOG.zip

And last but not least, a direct link to the (debug version of the) Android App:
https://wuala.com/ben0bi/Shared/Android/PLOGultra_debug.apk

Have Fun!