The development of the
v3.0 milestone has started this weekend and so far, I'm 34 commits and three closed issues in. This won't be a pace that I'll be able to keep up, but it's a start! Also, really enjoy having a bigger goal towards improvement of Duality as a whole again, which isn't just "more stuff" in some regard.
So far, it's been mostly removing obsolete API and functionality, cleaning up the legacy bits of Font resource (and simplifying them internally in the process), and some renaming. The biggest improvement so far happend to the logging system.
The big old
Log class has been split up into
Log, the actual log instance,
LogFormat, a static class with all the formatting helpers, and
Logs, a static class that manages global log instances.
Code:
// The old way
Log.Game.Write("Hey! Here, have a beer: {0}", Log.Type(typeof(Beer)));
// The new way
Logs.Game.Write("Hey! Here, have a beer: {0}", LogFormat.Type(typeof(Beer)));
All logs have now been made thread-safe, so you can safely write from whichever amount of threads you like and be sure that your messages will arrive safely at their destination.
It is now also possible to define your own custom global logs, which can be especially useful in bigger or infrastructure plugin projects. To define one, implement a class deriving from
CustomLogInfo like this:
Code:
// Optional: Tag your log info with an icon to use in the editor
[EditorHintImage("YourMainNamespace.EmbeddedResources.LogIcon.png")]
public class TestLog : CustomLogInfo
{
// Provide an empty constructor that sets the logs name and ID
public TestLog() : base("Test Log", "Test") { }
// If you want to tag your log instance with additional info, define it here.
}
This is done once anywhere in your project, or any of the dependencies of your project. Afterwards, you can use your custom global log like this:
Code:
// Your custom log
Logs.Get<TestLog>().Write("Test");
// For reference: One of the default logs
Logs.Game.Write("Test");
By using a class definition for identifying your custom log, we can solve multiple problems at once: The log info class can provide configuration parameters for the log, we get all the advantages of type safety for our log identifiers and don't have to deal with strings that will fail silently when the identifier changes. If you're trying to access a custom log that doesn't exist, your code will simply not compile. No chance for errors to creep in!
Additionally, the static generic getter uses
an internal trick to achieve static binding performance, rather than doing a dictionary
TryGetValue. There simply is no lookup - the compiler knows exactly where to look for your log instance based on the type.
To complete the custom log support, the editor log view has been extended to recognize custom logs and provide source filter buttons for them, just the same as it does for the three predefined logs:

Finally, the API for
Logs and
VisualLogs has been adjusted to mimic each other, so the learning curve should be a little easier on the two.