Author Topic: Shrugger! Unity!  (Read 152639 times)

Offline Hearteater

  • Core Member
  • *****
  • Posts: 2,334
Re: Shrugger! Unity!
« Reply #255 on: September 21, 2014, 03:44:19 pm »
I'm not sure if your issue is doing it in Unity, or doing it in general. Below is some code for testing whether the serialization of a custom generic collection class is working. The collection class itself is [Serializable] and implement ISerializable along with IDictionary. I have a constructor that takes "(SerializationInfo info, StreamingContext context)" which builds a new collection from the incoming stream. The TestClass is just [Serializable]. Really it's that simple. Ignore the xml extension, this serialization is binary (controlled by the formatter). I switched from XML to binary at some point apparently. There is a lot more you can do, this is just basic serialization (for the TestClass) and custom serialization (for the collection), using the BinaryFormatter which is part of C#. XML serialization is a touch different. Really, googling c# serialization gives you a lot of really useful info.

Variable c below is an instance of the collection in question.

Code: [Select]
            /*
             * Optional testing of ISerializable interface
             */
            if (c.GetType().IsSerializable)
            {
                Console.WriteLine("\n--- ISerializable ---");
                IDictionary<int, TestClass> c2;
                BinaryFormatter formatter = new BinaryFormatter();

                for (int id = 0; id <= range + 1; id += 10) c.Add(id, new TestClass(id));

                //Serialize
                using (FileStream fs = new FileStream("CollectionTest_ISerializable.xml", FileMode.Create))
                {
                    formatter.Serialize(fs, c);
                }

                //Deserialize
                using (FileStream fs = new FileStream("CollectionTest_ISerializable.xml", FileMode.Open))
                {
                    c2 = (IDictionary<int, TestClass>)formatter.Deserialize(fs);
                }
                File.Delete("CollectionTest_ISerializable.xml");

                Console.WriteLine("  Count comparison: {0}", c.Count == c2.Count ? "Ok" : "Failed");
                Console.Write("  Item comparison: ");
                result = true;
                foreach (KeyValuePair<int, TestClass> item in c)
                    if (!c2.ContainsKey(item.Key)) { result = false; break; }
                Console.WriteLine(result ? "Ok" : "Failed");
            }

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #256 on: September 21, 2014, 04:02:48 pm »
Serialization followed by FileIO.

Write the data to the file in any format you care to (raw XML, compressed XML, binary data, whatever floats your boat), the computer doesn't give two shits what the data is or what file extension you give it.

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #257 on: September 21, 2014, 07:08:34 pm »
We did the "huge world, at most X (1 per player) in RAM at once" thing with AVWW.  Well, sometimes more than X because the server could hold onto a chunk for a bit after it was empty in case it was re-entered very quickly, but not significantly more than X.

Basically each chunk got its own file on the server.  It was never stored on disk on the clients (outside the pagefile, anyhow, but that's outside our concern).

As for the actual serialization, as with other things we did our own custom string-based serialization.  Writing a series of primitive values (where everything non-primitive is expressed in terms of its own series of primitives) has continued to be the simplest and most efficient (in dev terms, at least) way for us.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #258 on: December 18, 2014, 09:47:15 am »
I've spent the last two or three months sluggishly working on my UI. And then came Unity and released their latest Update, with free UI components for everyone. Well, crap!

My code is nowhere near operational, so it seems that by just picking up the new Unity UI goodies, I can take a major shortcut. The new Unity UI seems to have pretty much anything that's necessary, apart from some gimmicks I was working on (3D UI elements, mostly). Unsurprisingly, it's also way prettier.

So I'm wondering right now - Should I put some more weeks to months into getting my UI to work, or just grab the Unity stuff and run with that?

What do youse think?
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #259 on: December 18, 2014, 09:57:21 am »
You can probably guess my approach: tell them to get their newfangled black-box-components off my lawn and make my own stupid GUI ;)

Mainly because in my experience I inevitably, inevitably, wind up having to make my own anyway because the provided ones don't allow sufficient flexibility, or have weird bugs, or some combination thereof.

On the other hand, there's a lot to be said for rapid prototyping and getting to a playable game without spending unnecessary amounts of time on the incidentalia like exactly how the interface is implemented.  That probably means having to go back and overhaul the UI later, but it can be a worthwhile tradeoff.

So on balance I'd suggest keeping your UI stuff in a safe place so you can get back to it later, but then spend a day or two trying to get your game working with the provided components and see if it really is a shortcut.  If it takes longer than that then you may be better off just forging ahead with the PanzerUI or whatever you'd call such a thing ;)
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #260 on: December 18, 2014, 10:13:02 am »
The GUI tools for 4.6 are massively improved from what I hear.

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #261 on: December 19, 2014, 04:53:56 am »
Well, now it is called the PanzerUI alright  :D

When I first touched the Unity UI stuff, I dropped it again because it wasn't obvious to me which components I would have to generate to get it running (since I do everything from code, refusing to go through the editor). But I guess I'll be doing some science after all, and see how quickly I can get it to work.

Thanks for your advice, gents!
The beatings shall continue
until morale improves!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #262 on: December 28, 2014, 08:17:01 am »
So I told them to get their newfangled black-box-components off my lawn and made my own stupid GUI. PUI. It is called the Panzer User Interface now.

Not pretty, not optimal, and using quite a few workarounds. But it works! Displays text and simple rectangular shapes, reacts to clicks, activates, deactivates, hides, unhides, destroys and constructs nicely, all without being much of a performance drain. Key combos also work now, with any combination of Shift, Alt and Control and any key being detected correctly.

Still needs drag'n'drop, mouseover, text entry, grouping and other more or less important features, but the basic UI is functional.
I'll also have to learn a few things about working with text and making procedural textures, so I can stop using Unity's 2D-only GUIText class and slap my strings straight onto the UI's 3D meshes.

Anyways, things are finally ready for interactivity. May the user input and data output commence!  :D
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #263 on: December 28, 2014, 10:29:25 am »
Congratulations!  May your UI flatten the enemy ;)
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #264 on: January 27, 2015, 04:45:43 am »
Quick'un: How much of a performance-hog are things like Mathf.Log10 / System.Math.Log10?

As per the usual, I'm pretty bad at maths, so I can't really judge it.

Oh, and for when I'm just trying to figure out how many digits a number has - is there a faster way?
The beatings shall continue
until morale improves!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #265 on: January 27, 2015, 09:14:17 am »
Oh, and for when I'm just trying to figure out how many digits a number has - is there a faster way?

Couple of options I see, if you're only interested in the whole number value (ie. 900 -> 3)

1) For-loop that divides by 10 and checks for > 1 and a counter.
2) Convert to a string and check for string length.

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #266 on: January 27, 2015, 09:52:05 am »
Quick'un: How much of a performance-hog are things like Mathf.Log10 / System.Math.Log10?
I didn't know a number (before the later experiment, at least), but a few thoughts:


1) Off the cuff, raising x to y where y is not an integer is simply bound to be painful cpu-wise.  And taking the log of an arbitrary number is likely to involve something similar: i.e. no simple conversion to multiplication or division.


2) If all you want is the number of digits (of an integer, or the integer part of a real number, right?  Not talking places after the decimal?), realize that Log10 is doing a lot more work than telling you that (note that its result is a floating point value).  Doing more work = taking more time.  Generally, at least.  So it's a matter of asking "how do I answer only the question I'm actually asking?"  In which case the for-loop-dividing-by-10 that Draco18s suggested is pretty much your go-to method.  I wouldn't suggest the ToString() method as that involves heap allocation and, again, doing a lot more work than is actually necessary.


3) On the other hand, depending on how often you're doing this, it may not matter _at all_ how inefficient you make this particular computation.  Is it just for, say, 20 numbers on the GUI, once per frame?  Probably not going to notice the difference, and it's not going to get worse in more-intense gamestates (a key point).  But if it's multiple times per ship per frame and there could be thousands of ships in the more-intense gamestates, then some attention may be worthwhile.


4) If you really want to know the answer to "how fast is method XYZ" one of the best ways is simply to measure it yourself, by putting something like this in your program's startup code:

Code: [Select]
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        int iterations = 100000000;
        stopwatch.Start();
        for ( int i = 0; i < iterations; i++ )
            Mathf.Log10( i );
        stopwatch.Stop();
        Debug.Log( "stopwatch reported " + stopwatch.ElapsedMilliseconds + "ms for " + iterations + " iterations, average of " +
            ( (float)stopwatch.ElapsedMilliseconds / (float)iterations ) + "ms per iteration" );

In my case, the result was:

Quote
stopwatch reported 4932ms for 100000000 iterations, average of 4.932E-05ms per iteration

Of course, if your compiler is feeling cheeky it may simply optimize out those Log10 calls since the result is not used.  So I tried an alternate version:

Code: [Select]
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        int iterations = 100000000;
        double dummyResult = 0;
        stopwatch.Start();
        for ( int i = 0; i < iterations; i++ )
        {
            float thisResult = Mathf.Log10( i );
            dummyResult += thisResult;
        }
        stopwatch.Stop();
        Debug.Log( "stopwatch reported " + stopwatch.ElapsedMilliseconds + "ms for " + iterations + " iterations, average of " +
            ( (float)stopwatch.ElapsedMilliseconds / (float)iterations ) + "ms per iteration (dummyResult=" + dummyResult + ")" );

Which should force the computation of Log10 since the compiler can't say "well, he doesn't really need to see that value in the console log".

And that gave:

Quote
stopwatch reported 5426ms for 100000000 iterations, average of 5.426E-05ms per iteration (dummyResult=-Infinity)

So the first result looks pretty accurate for the cost of the actual Log10 call (the cost went up from 4.9 somethings to 5.4 somethings when I added in that += nonsense).  Unless it was feeling really cheeky and put something in like "if it's infinity, then we don't need thisResult for this iteration, which means we don't need the Log10 call from here on out", but I think that's kind of unlikely.

So 0.00004932ms, or 0.04932 microseconds, or 49.32 nanoseconds per call.  50ns is a fairly good chunk for a single mathematical operation.  Even Sqrt, which is semi-mythical in how long it can take, only came up as about 20ns per call in a similar test on my machine.  That said, it's all a question of how many calls we're talking.

I also tried a version that made sure the parameter to Log10 was a non-integer (by replacing it with "(float)i + ( (float)i * 0.001f )") but the result was very similar.  Just checking to see if maybe Log10 was using a more efficient branch for integer cases.

Amusingly, however, I found that the for-loop-dividing-by-10 situation took 90ns per iteration on float inputs, and 56ns on int inputs (fdiv being much worse than div on an ALU level).

So it actually looks like Log10 isn't bad here :)


So to sum up:
- Ask yourself: "does it matter?"
- If it matters, then don't guess.  Measure.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #267 on: January 27, 2015, 11:03:15 am »
- If it matters, then don't guess.  Measure.

I was going to mention as such, then forgot.
(Speaking of x^y math, somewhere I had a version that was very fast as it only handled integer values).
Ah, thanks Google.

Code: [Select]
int ipow(int base, int exp)
{
    int result = 1;
    while (exp)
    {
        if (exp & 1)
            result *= base;
        exp >>= 1;
        base *= base;
    }

    return result;
}

It basically takes a shortcut due to a mathemagic.

Code: [Select]
x^15 = (x^7)*(x^7)*x
x^7 = (x^3)*(x^3)*x
x^3 = x*x*x

Basically, as long as the exponent is greater than 1 you can square the input and divide the exponent by 2.

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #268 on: January 27, 2015, 11:23:36 am »
Some additional info: I generally do need it to return valid results for values < 1, with a round integer return sufficing in most cases. It'll be called between maybe 30 and 300 time per frame, depending on which UI elements are being shown...at least that goes for that particular application.

- Ask yourself: "does it matter?"
- If it matters, then don't guess.  Measure.

I'll remember that one  :D
I already built a little profiler-esque thingy, and although it's a bit primitive right now, I guess I could improve it to the point where it'll be usable for answering such questions.

And thanks for all the other info, too!

mathemagic
I actually didn't get that. At all  :o
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #269 on: January 27, 2015, 11:34:45 am »
Some additional info: I generally do need it to return valid results for values < 1, with a round integer return sufficing in most cases. It'll be called between maybe 30 and 300 time per frame, depending on which UI elements are being shown...at least that goes for that particular application.
Ok, so something like a max of 30,000ns, or 30 microseconds per frame.  100 microseconds would be a tenth of a millisecond (and you want your frames to take no more than 16ms if you're going for 60fps).  Not something to worry about speed on in this case, I'd say.

If you need it to work for places past the decimal too, then I'd say just use the ToString().Length approach since 300 small heap allocs per frame isn't a big deal.

But more to the point: why do you actually need to count the digits?  Are you computing the visual size of the number on the GUI, or are you checking whether it should switch to (value/1000)kilowhatevers or (value/1000000)megawhatevers, or what?  Depending on the actual use case there are often performance tricks you can do that have nothing to do with the actual work itself (and thus no make thog do math).  Not that there's really any point in optimizing this in this case, but just for kicks.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!