Now for some mobile networking

Now for some mobile networking

Early taxi app screenshotNot the face to face type but actual networking. This is needed because I’m working on a game server. My mobile game (Manana Banana) will become networked enabled and thus multiplayer.  C# is ideal for this type of thing but I’m not using the networking capability of MonoGame instead managing the whole lot myself.

Back a few years ago when I was a full-time mobile developer I wrote an app that was used by taxi drivers. It was a conversion of an Android App (I wrote it from scratch running on an iPhone based on the Android source code).  There’s a curious architecture with such apps because not only is the a user interface but in the background the app was “chatting” over 3G to a central server (written in VB6 I kid you not) which sent an “are you alive?” message every six seconds to every driver’s phone.

It was not a traditional client-server architecture but the kind of system where the driver could send a message to the server or the server could send a message to the driver. 

What this meant was the app was always keeping one eye on the 3G, getting messages and then it might for instance popup a screen saying “There’s a job from x to y. Do you want it?”. If the driver said yes then the app would receive details and show the driver the route to the pickup point. If the driver didn’t respond within 30 seconds or said no then the program would pass that back to the server,

What is a ConcurrentQueue?

C# has an advanced data structure called a ConcurrentQueue<t> which is a thread safe generic queue. I used two of these, one for a receive queue and one for a transmit queue in conjunction with a thread that never finished. All the 3G stuff was done using C# TCP/IP clients and ran in this thread. Messages that came in were put on the receive queue and could be popped off and processed in the main program. Messages to send out from the main program were put on the transmit queue and sent out in the thread. It was a very clean way of separating the main application running in the main thread from the 3G running in a background thread. 

Compared to the Android program which was all running in one thread and polled the 3G, I was told by my drivers that my app felt much more responsive!   The screenshot above was a very early image of it. It had a very simple UI where each screen of controls (Views in iOS parlance) was built up dynamically.  

Also C#/Xamarin has a way of getting from a thread to the main thread on iOS. You cannot update any controls from any thread only from the main UI thread.  There’s a method called InvokeOnMainThread for the Xamarin iOS controls. See this Microsoft/Xamarin documentation on how to use it. So that’s what I’ll be doing in my networked game.  

Interestingly because I’m managing everything, the TCP/IP messages can be very small, under 20 bytes each. This allows a very high throughput. 

Some awesome listings

Some awesome listings

Awesome stamp
Image by Pete Linforth from Pixabay

It has become a thing to label a big collection (usually open source) as awesome and there are several such collections around for many programming languages. In fact the C code collection’s first entry is to one of them.

That said they are pretty awesome, often having links to many related and useful open source projects. My only problem with the likes of GitHub and SourceForge etc. is the sheer quantity of excellent stuff on there. These awesome links are one way to “tame” them.

So now there’s a new link up top for C# and MonoGame links and a couple of entries to start it off.

 

MonoGame – How to make a clickable button

MonoGame – How to make a clickable button

Clear Button with one card clickedI’m using this in Android games but the principle applies to any MonoGame game. Here clickable and touchable mean the same.

You need three things to make something clickable.

  1. The area. For simplicity sake this will always be rectangular.
  2. The Action. When you touch (or click it), you want it to run code.
  3. An id of sorts. If you have multiple buttons etc, you meed to distinguish them.

We’ll use an int for 3. Use const ints to give it a name rather than being a magic number.

 

When you click whatever, the Event should include the ide so let’s define the event Type first.

public class ButtonClickedEventArgs : EventArgs
{
    public int Id { get; set; }
}

Not rocket science is it!

Now lets define a ClickButton class.

public class ClickButton
{
    public int Id { get; set; }
    public Rectangle TouchArea { get; set; }
    public Action<object, ButtonClickedEventArgs> AnAction { get; set; } = null;

    public ClickButton(int id)
    {
        Id = id;
        TouchArea = new Rectangle(0, 0, 0, 0);
    }
}

Again nothing too complicated. There’s an int Id which which is set in the Constructor, a Rectangle TouchArea and an Action which is defined to include our ButtonClickedEventArgs.

Here;’s some example code. I’ve defined a graphic for a Clear button in my game and this is loaded as usual in the LoadContent().  I’ve also defined the button in Class declaration.

ClickButton ClearButton;

In LoadControl(), this is also initialised. Here’s it’s two line. It could be done in one, by altering the constuctor.

ClearButton = new ClickButton(1);  // 1 is the id
ClearButton.AnAction += ClearCards;

ClearCards is a method that does something when the button is cleared. This matches our Event handler as it has the usal two parameters for an Event except the args is our ButtonClickedEventArgs.

private void ClearCards(object sender, ButtonClickedEventArgs args)  {
   // all the code here, not shown
}

Where is the TouchArea defined?

So are we all setup ready to rock’n’roll? Well not quite. We haven’t said exactly where the TouchArea is. That of course depends on where we draw the button. In my game, the ClearButton moves across. It’s absent when all six cards are present but as soon as one has been touched and a back card touched to move it, the Clear Card appears. In the top image you can see it to the right of the five top cards. I had clicked the seven of clubs when it was in the top row then the first back on the top row of the three rows.

For my next move I clicked the ten of diamonds and the second back on that first row where the ten of diamonds no wit. It now looks like this and the Clear Button has moved over.  If I click the Clear button it will move the seven clubs and ten diamonds back to the top row and replace them in the first row with backs.

Second clickTo set the TouchArea of the ClearButton, I do it in the Draw method. It’s as simple as this:

if (hand.Count < 6) // Draw ClearButton on end
  {
    spriteBatch.Draw(clearButton, new Rectangle(x, y, cardWidth, cardHeight), 
        new Rectangle(0, 0, cardWidth, cardHeight), Color.White);
    ClearButton.TouchArea = new Rectangle(x, y, cardWidth, cardHeight);
  }

There’s actually a small bug visible. When you click a top row card, the game highlights it by reducing its opacity to 0.5. If you look at the ten of diamonds, you can see it still has that reduced opacity; it should have been restored to 1.0 when it was moved to the first row. The same is true in the top picture for the seven clubs! Easily overlooked but just a one-line fix.

Some Touchy Code

The very last bit is to fire touch detection and this is done in the Update() method. When you touch the screen, calling Touchpanel.GetState() returns a collection of touches. This is my code. It cycles through the touches collection, gets the X, Y position of each touch and adjusts it to match the virtual screen coordinates. (Drawing to a virtual screen means this looks the same on every Android irrespective of its physical screen sizes and resolution).

touchState = TouchPanel.GetState();
foreach (var touch in touchState)
{
   if (touch.State == TouchLocationState.Pressed)
    {
         var x = touch.Position.X / xRatio; // adjust for virtual screen
         var y = touch.Position.Y / yRatio;
         CheckClickedTop(x, y, hand);
         if (pickedCard == null) return; // no point checking further...
         for (var i = 0; i < 3; i++)
            CheckClickedBottom(x, y, commonCards[i], true);
            if (hand.Count == 6) continue; // All top cards so no ClearButton visible
            // Check if Clear button
            if (ClearButton.TouchArea.Contains(x, y))
              {
                  ClearButton.AnAction(ClearButton, new ButtonClickedEventArgs() { Id = ClearButton.Id }); 
              }
      }
}

The top cards are held in a class called hand and the bottom three rows are held in CommonCards[3] each of which is a hand. The CheckClicked.. methods cycle through the cards in the hand comparing coordinates to see which card if at all has been clicked. If it has it calls the AnAction Event for the one clicked. The very last if shows how this works to check if the ClearButton was clicked. I’ll simplify this code by moving it into a ClickButton method.

In praise of Hyper-V

In praise of Hyper-V

Hyper-V Manager screen I’ve been using virtual machines for years. Originally I started with VirtualBox, the free VM manager from Oracle. I’m not sure why I switched to Hyper-V, about five or six years ago but I’ve been on Hyper-V since then. You need to be on Windows Pro and have at least 8 GB though the more RAM the better. I have 64 GB and the most I’ve ever had in use at one time is 29 GB. I always try to keep RAM use below 50% as there’s less disk swapping.

VMs are an excellent way to try out other Operating systems, install software and venture outside the comfort zone of a Windows PC and Windows 10.  Many of the screenshots published here in earlier posts have come from Ubuntu 18.04 LTS running in Hyper-V. It takes a minute to fire it up and connect then login.

I learnt to use Linux that way, both via the Ubuntu GUI and terminal commands and much of my 2nd Ebook has been tested on a Raspberry Pi OS running in a VM. Of course it lacks the hardware of the real Pi, so I have to test programs on both, but it’s quite a bit quicker doing a screen grab using the commercial Snagit on my Windows 10 PC.

I can do screen grabs on a PI using scrot, but then I have to upload the image using WinSCP or Putty. It’s not the end of the world but when you are doing a lot, having the image in the Snagit editor ready to copy/paste is a time saver. Also in a similar way, make sure you can do copy/paste via the clipboard and can resize the guest OS (as it’s called). It makes a difference.

I have mine configured so its uses RDP and you can just see the corner of the RDP bar in the Ubuntu image below where I’ve just launched Visual Studio Code.

Ubuntu 18.04 LTS running in an RDP session on Windows 10 in Hyper-V

From a terminal I did ifconfig and got

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.21.212.121  netmask 255.255.240.0  broadcast 172.21.223.255
        inet6 fe80::2b71:6d6b:9a09:9aae  prefixlen 64  scopeid 0x20
        ether 00:15:5d:38:01:03  txqueuelen 1000  (Ethernet)
        RX packets 47317  bytes 69248755 (69.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27622  bytes 1791175 (1.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

and on Windows

C:\Users\David>ping 172.21.212.121

Pinging 172.21.212.121 with 32 bytes of data:
Reply from 172.21.212.121: bytes=32 time<1ms TTL=64
Reply from 172.21.212.121: bytes=32 time<1ms TTL=64
Reply from 172.21.212.121: bytes=32 time<1ms TTL=64
Reply from 172.21.212.121: bytes=32 time<1ms TTL=64

This makes it very handy for testing network servers or if you do web development running a web server locally.

A simple Rock, Paper, Scissors game

A simple Rock, Paper, Scissors game

Rock, Paper, Scissors
Image by OpenClipart-Vectors from Pixabay

One of the easiest games to program is Rock, Paper, Scissors. All you are doing is a simple comparison, but programming it so the computer player can win more games than the player is not quite so easy.

The easiest strategy is always guess paper as Rock is apparently the most often chosen. That might work for the first couple of games but after that… A better strategy is count what the player plays each time to try and detect a bias. Guess randomly but make the %age of guesses favour the move that defeats the players most common move. If the player pays paper 50% of the time, guess scissors 50% of the time.

Then there’s variations on this, try and analyse past moves to give an edge. That could get quite complicated. You have to program it for pattern recognition. If the player favours scissors after losing with rock etc.

Here is a simple implementation of RPS in C.

 

How to use indexed sequential files

How to use indexed sequential files

Files
Image by Pontep Luangon from Pixabay

This was a big thing long before PCs existed but you don’t see it so much nowadays.  Say we have a lot of static data, perhaps text strings which can vary in length from a few bytes to hundreds of bytes long. What is an efficient method to store them, i.e. in both space and time?

The answer is ISAM (Indexed Sequential Access Method)  which sounds more complicated than it is. We will use two binary files- one is the data file and one is the index file. The data file holds the raw text strings. We’ll write the raw strings using the C file write. At the same time as write them, we also build up an array of structs. This struct will look something like this:

typedef struct {
  int id;
  unsigned long offset;
  unsigned long length;
} indexRec;

The id could be a char * string. It’s just a way to search for and find the data.

As each text string is written to the data file we populate a struct with the file offset and length. Eventually after all strings are written you can write the arrays of structs to the  index file.

Then anytime you wish to read text strings back, load the structs into an array in ram and scan for the matching id then call fgetpos with offset (this moves the file pointer to the specified byte offset) and read in the length number of bytes from the data file.

An even simpler approach

If you just use an index number then you can scrap the id field and instead store the index file as a collection of offset and length fields. To read string #100 just do a fgetpos to byte at 100 * 8 (four for the size of offset plus four for the size of length)  in the index file, read the eight bytes for offset and length then do a fgetpos in the data file to the offset and read in length bytes as before. Very efficient and very fast. Just two reads in two files and one of those is only eight bytes.

If you wish to change the text strings in the data file, use the same method to retrieve them. If the new string is smaller then just write it and change the length field of the index record and rewrite it. If the new string is longer than the old, write it on to the end of the data file and change the index offset and length fields and rewrite them in the index file.

Both of these edit methods (shorter or longer string edits) will ‘lose’ bytes in the data file. When replacing with a shorter string and adjusting the length, the extra bytes that were in the previous string are no longer referenced. With a longer edit the entire previous string is no longer referenced.

Reclaim lost bytes

However it’s very easy to compact the data file and reclaim these lost bytes. Just process the index file and read each string and write them on the end of a new initially-empty file.  You also change each index file record to have the new offset and length of each string in the new data file. Once it’s rewritten just delete or backup the old data file and rename the new data file to be the one used from now on. Depending on how often the data file is edited, you will need to “compact it” every few days or weeks. But compacting is a pretty quick process, even for mega byte or larger sized files.

I used this technique albeit in Turbo Pascal not C to store game data for postal games I wrote back in the late 1980s. Games that are still run today but on the internet, not by post. For example in a map location there can be several parties of adventurers. The file record for that location has a file pointer to the start of a chain of party file ptr records. Each index file of adventurer parties has a binary file offset to the party in a binary file and a file ptr (or -1 if the end) of the next party’s file pointer. Like a pointer linked list but using file pointers instead of real pointers. Similarly the map location has a file pointer to a dungeon if one exists in this location (or -1 if it doesn’t).

This technique kept the map file fairly small but there were lots of binary file pairs for parties, dungeon, characters (in parties), and towns and shops in towns. Who needed a database? I didn’t… (That’s cos databases didn’t really exist back in the day. Had they existed I might have used them… maybe).

The minus one problem

In the struct definition, you’ll notice that I use unsigned longs for file pointers and length. There is no -1 for unsigned longs. It’s 4294967295. Using this as an end of chain pointer is ok because it is never going to be used as an offset. If I had used signed numbers then I could have used -1 but remember when I wrote this, it ran on a 16 bit computer so I used 65535 instead of -1. I could easily get binary files 40 Kb or 50 KB in size, so a signed number would have overflowed after 32767 bytes.

How to use some advanced data structures in C

How to use some advanced data structures in C

Linked Lists
From Wikimedia Commons

In my eBook, I used only structs and arrays. In fact the commonest “structure” was an array of structs. That was used for bullets, asteroids and aliens ships.The benefits of that are it’s easy to process; I started out by using it as an array and eventually switched to using a pointer to each struct “walking” the pointer through the array, jumping it if you like from struct to struct. Very simple and ideal for a game like asteroids.

You don’t need complexity because that slows things down and the only constraint in the design was making sure I could run everything at 60 frames per second..

C doesn’t come with anything more complex, yet computer science has determined many many advanced data structures that have their uses.

If you were programming a dungeon exploration game, an array might not be the best way to store the dungeon. You’d have multiple levels where each level consist mainly of rooms and corridors. How might you store that? Also there’d be monsters, treasures, traps, transporters and so on in the dungeon.  How would you traverse this structure, guaranteeing there’s a path so that every room can be reached?

Coirridor
Image by Rudy and Peter Skitterians from Pixabay

You might use an array to hold each level but how would you connect levels? Thinking about it I probably wouldn’t. I’d have staircases connecting corridors, traps that let you fall through to a room or corridor below, a transporter that lets you appear in a room or corridor above.

C is flexible enough to support a structure like this but you would have to code all the storage yourself. One way round it is to find an open source library like SGLIB. One reason I chose this is because it lets you create container data structures.

Sglib is fairly low level. It includes code for sorting arrays, for manipulating singe, double and sorted linked lists, red-black trees and hashed containers. As they say “A hashed container is a table of fixed size containing another (we say base) container in each cell. Once an object is going to be inserted into the hashed container, the hash function is used to determine the cell where it belongs and then the object is inserted into the base container stored in this cell. The base container is usually a list, however it can be a sorted list, double linked list or a red-black tree as well. Sglib’s hashed container is parameterised by the name of the base container.”

There are examples provided in the documentation as how to use each type of data structure.

 

What is the best way to include text?

What is the best way to include text?

Words
Image by Free-Photos from Pixabay

One of the games I’m working on needs to include a 1.9 MB text file (200,000 words). Now it’s not that big a deal but using 7zip I can compress it down to 400 KB and that’s 20% of the uncompressed size. So I’m thinking of including some C# code to decompress it.

But I did wonder if there was any kind of built in decompression, so you could add it to say Resources and have it decompressed automatically when read. I haven’t seen anything like that but it would be cool if if existed.

 

A free C Book – “C Programming Notes for Professionals”

A free C Book – “C Programming Notes for Professionals”

C Notes for Professionals Book coverThis has nothing to do with my ebook and was produced entirely by the Goalkicker.com project which produces free and very professional looking ebooks, I came across it just a few days ago.

The C Programming Note for Professionals is currently 327 pages long, a 2.4 MB download. It’s nicely laid out and professionally done. I’ve only flicked through it but it looks an excellent piece of work with 63 chapters currently. You can leave your email address and they’ll notify you of any changes.

There are almost 50 ebooks in total covering topics like Android, .NET, Xamarion Forms, Perl, PHP, MySQL, PostgreSQL and may other topics. This is an excellent library.  I don’t know who is behind this project but they deserve to be bought a lot of coffees…

An irritating bug with MonoGame/Android

An irritating bug with MonoGame/Android

Android Phone
Image by Iván Tamás from Pixabay

Bugs happen, it’s a way of life but when the bug affects you as a developer, it can be a tad annoying. I’ve found a bug and mentioned it in the MonoGame forums.

The bug occurs intermittently. I do a build then run the program on an Android phone. It starts loading, shows the splash screen then splat “The Content file was not found” message appears in Visual Studio.

This may be a bug in Xamarin or MonoGame. No doubt it will eventually get fixed but still a bit annoying. About the main workround I’ve found is rebuild everything. Start with the Pipeline tool- do a Build/Clean then a Build/Build. Then in the Project (in Visual Studio) do a Build/Clean then Build/Deploy which recompiles everything.

If the error still persists then it’s possible you have a typo; say a lowercase i instead of I in a filename. (I’ve done that once). Another fix though rather unsatisfactory is in the Project Properties, on the Options tab, right at the top is a checkbox Use Shared Runtime. If you untick that, deployment takes a bit longer. Instead of copying 3 MB which takes a second or so, it copies about 60 MB instead which takes a bit longer. I tried it but went back to the Clean and Deploy approach as copying was taking 10-15 seconds.