Useful C# Features (or “Cool Things You Didn’t Know You Could Use in Unity”)

1. Tuples & Discards!

Tuples is something more dynamic languages like JavaScript have been holding over the more static languages for a while. It allows you to do more with less action (higher level ones, that is). While tuples have existed in C# before as a class of their own, they are now getting a proper implementation. It basically makes a complex variable/object without having to predefine it using a class or a struct.

var alphabetStart = (Alpha: "a", Beta: "b");
Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");

You can even use it to return more than one element from a method(!!!). Unfortunately, the Unity editor doesn’t support handling those kinds of returns yet but they are still useful inside your scripts.

Discards are those underscores you see in the example below. It allows you to deconstruct a tuple and discard the data you don’t want, only keeping what you actually need in its own named variable.

using System;

public class Example
{
    public string NewYorkCityName
    {
        get
        {
            var (_, name, _) = QueryCityData("New York City");
            return name;
        }
    }

    private static (string name, int pop, double size) QueryCityData(string name)
    {
        if (name == "New York City")
        { return (name, 8175133, 468.48); }

        return ("", 0, 0);
    }
}

2. Pattern Matching!

Pattern matching allows you to test a runtime type in an if or switch statement and then convert it to that specific type all in a single statement!

if (input is int count)
{ sum += count; }

It also increases the power of switch, allowing you to do a lot more with less and create much more complex testing blocks.

public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
    int sum = 0;
    foreach (var i in sequence)
    {
        switch (i)
        {
            case 0: break;
            case IEnumerable<int> childSequence:
            {
                foreach(var item in childSequence)
                { sum += (item > 0) ? item : 0; }
                break;
            }
            case int n when n > 0: sum += n; break;
            case null: throw new NullReferenceException("Null found in sequence");
            default: throw new InvalidOperationException("Unrecognized type");
        }
    }
    return sum;
}

3. Local functions

Local functions is currently one of my favorite features in C#. You could already create functions inside functions by assigning a block into an Action or Func variable but now you can just define an anonymous function and not worry about what returns or not returns a value or where exactly you defined which variable. So, if you need a complex block or calling the same function multiple times but you don’t want it available outside, Local Functions are here for you.

private static string GetText(string path, string filename)
{
     string AppendPathSeparator(string filepath)
     { return filepath.EndsWith(@"\") ? filepath : filepath + @"\"; }

     var reader = File.OpenText($"{AppendPathSeparator(path)}{filename}");
     var text = reader.ReadToEnd();
     return text;
}

4. Switch Expressions!

You can now rephrase your Switch blocks into something much nicer and readable.

public static RGBColor FromRainbow(Rainbow colorBand) =>
    colorBand switch
    {
        Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
        Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
        Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
        Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
        Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
        Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
        Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
        _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
    };

5. Property Patterns

This is another wonderful extension to the switch statement allowing you to switch on a structure and get output depending on its internal properties rather easily.

public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
    location switch
    {
        { State: "WA" } => salePrice * 0.06M,
        { State: "MN" } => salePrice * 0.075M,
        { State: "MI" } => salePrice * 0.05M,
        // other cases removed for brevity...
        _ => 0M
    };

6. Tuple Patterns

This is another cool extension to the switch statement, allowing you to match a case based on individual items inside a tuple breakdown.

public static string RockPaperScissors(string first, string second)
    => (first, second) switch
    {
        ("rock", "paper") => "rock is covered by paper. Paper wins.",
        ("rock", "scissors") => "rock breaks scissors. Rock wins.",
        ("paper", "rock") => "paper covers rock. Paper wins.",
        ("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
        ("scissors", "rock") => "scissors is broken by rock. Rock wins.",
        ("scissors", "paper") => "scissors cuts paper. Scissors wins.",
        (_, _) => "tie"
    };

7. Using Declarations

One of the really nice things in C# over C and C++ is that it is a managed language. Yes, there are performance differences (which Unity has almost 100% taken care of) but it is a huge load of responsibility off the developer. The Using declaration is a great way to take advantage of it. When you need to open a file or create a web request but just for a short time and you want to dispose of it properly… you can go through the whole rigmarole or just enclose the code in a Using block that takes care of everything for you.

static int WriteLinesToFile(IEnumerable<string> lines)
{
    using (var file = new System.IO.StreamWriter("WriteLines2.txt"))
    {
        int skippedLines = 0;
        foreach (string line in lines)
        {
            if (!line.Contains("Second"))
            { file.WriteLine(line); }
            else
            { skippedLines++; }
        }
        return skippedLines;
    } // file is disposed here
}

8. Indices and Ranges

First of all, you can now define a range in C#.

Range phrase = 1..4;

And you can use those numbers or that Range to access a sub-range or a sub-group of another variable. However, be careful because range accessors are beginning inclusive and ending exclusive.

var words = new string[] { "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog" };

var quickBrownFox = words[1..4]; // "quick", "brown", "fox" and no "jumped"

var lazyDog = words[^2..^0];
 // The from-end index accessor. ^0 is the end and not included
var allWords = words[..]; // contains "The" through "dog".
var firstPhrase = words[..4]; // contains "The" through "fox"
var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"
var text = words[phrase]; // is like quickBrownFox

9. Null Coalescing Assignment

The Null Coalescing Operators are some of my favorite features in new C#. It allows you to check for Nullls and then do things accordingly. The null-coalescing assignment operator checks if the left side is null. If it isn’t, it’s returned. If it is, the right side is assigned to it and then it’s returned. It’s a great way to do lazy resource assignment and/or creation. 

List<int> numbers = null;
int? i = null;

numbers ??= new List<int>();
numbers.Add(i ??= 17);
numbers.Add(i ??= 20);

Console.WriteLine(string.Join(" ", numbers));  // output: 17 17
Console.WriteLine(i);  // output: 17

Posted in IT, Life, Programming by with no comments yet.

News: Average User has no Concept of How Much Game Dev Costs

Recently, some clueless joe on Twitter said he will pay 10,000$ to the person who adds a multiplayer aspect to Zelda: Breath of the Wild. If he was going to donate to a modder who was working on it, that would have been fine but it seems like he was thinking that he could hire someone to do something like that for that kind of money.

Here is a long, detailed response to this which you should read but here’s the summary: 10,000$ would pay for about two work months of the average+ programmer. Also, networking is hard. The hardest networking challenges in gaming usually arise in fighting games because they usually need to be exactly per pixel and per frame accurate and, probably over distances where network traffic takes more time to go back and forth than it takes pro players twitch reflexes to react. You can see how important this is if you go back and read about the network woes of Street Fighter V.

Now, the demands of a PvE, open world, action RPG would probably be a lot less strict but these are still difficult problems. Especially if you’re talking about tacking on something like this onto a game that was definitely not designed for it.

You want a more current example? On the one hand, Battlefield 2042 is out now and it’s buggy as hell. On the other hand, Halo Infinite’s multiplayer is also out and it’s much better. Probably because the team is backed and overseen by a very strict corporate overland. On the other other hand, Halo’s campaign will come out in a week but the Co-Op campaign will only come out in May 2022. MAY!!!

343 Industries have been working on the Halo games for over 10 years! They are backed by one of the biggest corporations in the world! [According to Wikipedia] They are 750 strong! And it’ll take them — yes, assuming they have more going on than just Halo Co-Op — five months from campaign release to co-op campaign release.

And some people think you can just add co-op mode on a massive game for 10,000$.


Posted in Gaming, Less Interesting News, Practice, Programming, Thinking Out Loud by with no comments yet.

How to Make a Unity Package (For the Unity Package Manager)

Let’s say you have a bunch of code you want to drag around with you to every new Unity project, or maybe just the next project you’re doing for the same company. Don’t just copy and paste the same directory over and over again forcing you to also copy changes and updates. Create a package instead!

Unity has switched over to a package model for a lot of the engine’s capabilities. And it also allows you to import non-Asset Store packages straight from GitHub or even locally. So how do you take what you have and make it an easily distributable package? Follow these steps.

  1. In your Project window, below all your regular files is a Packages folder. Right click on it and select Show in Explorer.
  2. In that Packages folder, create a new directory and name it however you like. This will be the root of your package.
    1. Do remember that the folder name can not contain spaces.
  3. Create a new “package.json” file.
    1. This page right here explains everything about the structure of the file.
    2. And here is an example file.
  4. Back in Unity, your new package should be visible with the name you gave it.
  5. Clicking on package file will open it in the Editor UI, allowing you to edit it more conveniently so you don’t have to go back to the JSON.
  6. In that Inspector window, you can also easily add Dependencies if your package requires it which is a much easier workflow than typing them out.
  7. After this basic set up, you’ll want to add your content, this link here will show you the folder and file structure required of a package.
    1. You need the package.json file.
    2. Adding a “README.md”, “CHANGELOG.md”, and “LICENSE.md” files is general practice and provides a better user experience.
    3. The “Editor” folder should contain your editor scripts.
    4. The “Runtime” folder should contain your runtime scripts.
    5. And you can add additional “Tests” and “Documentation~” under their respective folders.
      1. Under “Tests” you do have to add “Editor” and/or “Runtime” sub-folders depending on what you’re testing.
    6. You may also add additional folders and files as you wish.
  8. Just drop your scripts, assets, and whatever else you want from your current project into the correct folder in the package (Regular scripts into “Runtime”, editor scripts into “Editor”, and test scripts into “Tests”).
  9. Then, for every folder you have files in, right click it and select “Create\Assembly Definition”.
    1. It is recommended to name them in reverse web notation in a way that is easy to understand.
    2. For tests, you need to add a reference to your relevant assembly definition file (The runtime file for runtime tests and editor file for editor tests) and to the Unity TestRunner assemblies (Yes, both).
      1. Also, make sure that Editor is the only platform selected.
  10. That’s it, your done defining.
  11. If you move the package anywhere else for safe keeping, you can add it from the Package Manager by pressing the ‘+’ sign, selecting “Add from Disk” and finding your package.json file.
  12. But it is recommended that you upload the contents of your package (Not the folder itself but everything in it) to some Git repository and then you can always add it from Git and your users will be much happier for a constantly updated package.

Posted in Practice, Programming, Thinking Out Loud by with comments disabled.

Temp Logs into Documentation

Here’s an idea I had while writing a server application I needed to test on a remote computer with limited debugging abilities…

I insert debug logs, temporary logs, before and/or after important sections of flow so I could see in the console what is going on and what is failing. But I wouldn’t want them there when the app rolls into production.

And then I thought, people hate writing in-line documentation but it’s quite important. And here I have all these debug logs explaining what is going on. So, instead of deleting them, comment them out. Then I have them for later, if I want, and they pretty much function like in-line documentation.

Win-Win!


Posted in IT, Life, Practice, Programming, Thinking Out Loud, Work by with comments disabled.

קצת גאה בעצמי

היה לי יום טוב היום.

זאת אומרת, הוא התחיל בזה שחשבתי שיש לי שעון ואז גיליתי שיש לי אבל, משום מה, הוא לא העיר אותי. אז היפלתי על מעין לטפל במוצארט בבוקר ומיהרתי החוצה.

סיימתי עוד פרויקט בעבודה והראיתי אותו לבוס. קיבלתי כמה תיקונים עליהם אני עדיין עובד. בסדר. אבל אני כן גאה בזה שבשביל להשיג כל מיני אפקטים הייתי צריך להשתמש בחבילת תוכנה שכולם משתמשים בה אבל לא הצלחתי לגרום לה לעשות בדיוק מה שאני רוצה. כששאלתי, התשובה שקיבלתי היא ‘יש דרך אבל היא לא כל כך טובה אבל ככה כולם עושים’. אז לא רציתי לעשות את זה ככה. כתבתי גרסה משל עצמי.

לא שכתבתי ספריה פופלארית מאפס אבל, אם היא מסוגלת לעשות א’ ועד ת’, אני צריך ח’ וחצי, אולי שני ח’. והיא לא הייתה יכולה לתת לי את זה. אז לקחתי שעה וחצי וכתבתי משהו שעושה שלושה וחצי ח’, כדי שיהיה וזה כבר היה על הדרך.

וחזרתי הביתה ועשיתי התעמלות. יום בטן. לא הצלחתי להגיע לגבול הנוכחי אבל הצלחתי לסיים את הקודם בהצלחה. לפחות זה. אני כבר מרגיש יותר טוב. בהחלט יותר ערני ואנרגטי.

😉


Posted in IT, Life, Me, Programming by with comments disabled.

Tidbits of Experience: Unity App on Android Not Showing Permission Request Dialog

It happened to me that an app I was creating required some Android permissions and while it did show the permission dialogs when I first installed it, subsequent builds, with more or different permissions, didn’t pop the dialog. Even after uninstalling and reinstalling the app, nothing happened.

Digging through the AndroidManifest.xml file Unity was generating, I found this line:

<meta-data android:name=”unityplayer.SkipPermissionsDialog” android:value=”true” />

So, to override, make sure you have an AndroidManifest.xml file in your Plugins\Android directory (you can copy the generated file from Temp\StagingArea as a start) and make sure you have the line:

<meta-data android:name=”unityplayer.SkipPermissionsDialog” android:value=”false” />

Under your Application tag.

It will ask for permissions every time you reinstall the app but it should be good from then on out.


Posted in Life, Practice, Programming, Thinking Out Loud by with comments disabled.

The Push Forward Extensions

Here is a package of several extensions I’ve created that I use in my Unity projects. I thought they would be useful and would appreciate any feedback.

Push Forward Extensions.


Posted in Programming, Work by with comments disabled.

I Made a Game!

It’s here.

You need a phone and at least four people to play it.

Have fun. I’m tired. Good night.


Posted in From the Writing Desk, Gaming, Life, Programming by with comments disabled.

Success!

So, I’m working on a dice roller for Android…

And today, after much mucking about with HTTP packages and a little mucking about with System.Net (after I got tired and decided to do it bare bones) and a little bit of https wrangling, I finally got my first real response from Random.org. And it was pretty quick.

Yay! I’m out.


Posted in High-Tech, Life, Programming by with 5 comments.

Fuck You, Xamarin

After messing around with tutorials and trying to put something together for about a month and finally running into huge building/libraries/references issues that I couldn’t solve for a few days, I decided to quit Xamarin development. At least, for now.

Even planned as a simple 2D application, I’m willing to accept the splash screen and loading times so I can do this handily in Unity GUI. And I know it will compile very easily to Android and, slightly less easily, to iOS. It will definitely be quicker and easier to build.


Posted in IT, Life, Programming by with comments disabled.