A couple days ago I was doing my kitchen chores and realized I was out of food (or sealing) clips.
And I needed those ASAP.
So the choice was to either:
The latter option was so much more convenient and fun, that I obviously went with it. And by the time I was done, the clips were done as well, and I made use of them straight away.
Afterwards I realized that this provided a great opportunity for a brief post on the topic of 3D printing and my experience with it. As well as another look at the age-old question: "What is a consumer 3D printer actually useful for?"
I'll tell you all about it.
Unity prefabs are awesome. They are easy to create, easy to instantiate, and with the current versions of the Unity Editor can be used to create prefab variants and even nest prefabs within prefabs, allowing you to modularize the design of systems and scene objects.
But this simplicity comes at the cost of a higher risk of screwing things up the larger your project or the team grow...
All because of this little "Apply All" Inspector button, which is both a blessing and a curse:
You know what I'm talking about. Imagine having a prefab for an object or an important interactive actor, and scattering it all over the scenes in the project, each one — with its own unique overrides for the position, variable values or even MonoBehavior component scripts attached or removed. Obviously, they are all based on the same shared prefab asset on disk, which is expected to have a certain set of initial values and components, which are then either used "as is" or are changed slightly here and there in the scenes.
The problem is, it only takes one careless press of the "Apply All" button to screw up the prefab for every single instance of that prefab in all the scenes! And chances are, you or a member of your team will eventually press this button and completely change the base prefab on disk, which all scene instances are based upon. And the more prefabs in your project, or members in your team, the higher the chance of this event happening. Sometimes stealthily, which is even worse... Thank Heavens for version control!
Unfortunately, Unity doesn't provide a way to disable this button for certain prefabs (at least I wasn't able to find a way to do so). That's why when designing my previous game, even though I was the only developer and scene builder, I decided to save myself the headache and created a custom bare-bones "ActorLoader" prefab. I would then exclusively use this prefab to place interactive instantiatiables in the scenes. Such a prefab had just a handful of fields which were meant to always be overriden and not to use base properties stored in the shared prefab: a prefab type enum (used to determine which prefab to instantiate from the Resources folder), starting Transform parameters and a couple of modifiers, all overridden right away to ensure that no changes to the base prefab asset would ever break ActorLoaders anywhere in the project. And this approach worked wonderfully.
Such "loaders" are in fact considered standard practice in the industry in contrast to scattering actual prefabs in the scenes, for a lot of reasons, which I won't list here. But this still doesn't solve the original problem of prefabs being modifiable with a press of a button!
Unity prefab is just a serialized object. Which means we can tap into the serialization routine and do something when Unity serializes or deserializes a prefab in the Editor. All you need to do is extend one or several MonoBehavior components attached to the prefab from the ISerializationCallbackReceiver interface, and implement a couple of methods.
Here's how I did it in my current project: inherited a component from MonoBehavior and the interface:
// See: https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html
public class MyClass : MonoBehaviour, ISerializationCallbackReceiver
And then implemented a custom OnBeforeSerialize() routine, which is executed right before Unity commits any changes to the serialized object, which is a prefab in our case. I've commented it to help you understand how it works. Nothing special, but gets the job done:
#region ISerializationCallbackReceiver
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
// This can only be done inside UNITY_EDITOR since we can not check prefab status in a build!
#if UNITY_EDITOR
// IMPORTANT: EditorApplication checks must be done first.
// Otherise Unity may report errors like "Objects are trying to be loaded during a domain backup"
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isUpdating) return;
// Validate the type of your prefab. Useful pre-check.
if (UnityEditor.PrefabUtility.GetPrefabAssetType(this) != UnityEditor.PrefabAssetType.Regular) return;
// Override properties only if this is a prefab asset on disk and not any of its scene instances
if (UnityEditor.PrefabUtility.GetPrefabInstanceHandle(this)) return;
// Finally, re-set any fields to initial or specific values for the shared asset prefab on disk
// This protects these fields when "Apply Override" gets called from any of prefab's scene instances
// Example: enforce default position, rotation and scale values for the prefab
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
// Example: your variables here
// myFloat = 1f;
// myAssetRef = null;
// myClassInstance.myString = "Default string";
#endif
}
// OnAfterDeserialize can be left empty
void ISerializationCallbackReceiver.OnAfterDeserialize() { }
#endregion
As you can see, this method makes sure that each serialization call to the shared prefab asset on disk goes through a custom procedure which re-sets values for certain fields and references, and can even check whether specific components are attached to the prefab root or any of its children, and either add them if they're missing, or remove ones that shouldn't be there. This procedure is invoked any time prefab is serialized, which includes the aforementioned "Apply All" button or any other way to apply changes to the original asset.
And there you have it! With this approach each time you create a new prefab you can decide which shared asset fields and references should be protected from accidental overrides, and simply specify default/initial values for them within the ISerializationCallbackReceiver's OnBeforeSerialize() method.
Some time ago I bashed Unity Game Engine (the Editor in particular) for its instability and lots of quirks and questionable changes that took place over the years following the version 4 release of the Editor.
Fast forward to this September. I'm done with my microcontroller shenanigans and have mostly finished the Design Document for the game I talked about quite a while ago (which took a lot of planning, for I am a project manager after all).
What's the next step then? — Exactly!
So I've been playing with the latest "LTS" version of the Unity Editor 2021.3.7 and...
And I mean a good wow:
All in all, the time has come...
This post is not a comprehensive dive into the world of microcontrollers, but rather a brief introduction and a compilation of interesting facts I've collected over the months working on a couple projects that made use of contemporary microcontrollers to achieve real and practical goals.
I'm sure you're well aware of the situation with microelectronics prices. It's been getting worse for a couple years and doesn't look like it will improve any time soon due to the on-going crisis in several areas at once: semi-conductor component shortages, logistics issues, political games, socioeconomic factors and everything in between. For an average technically-minded person this means that one must look for creative ways to achieve their goals or alter those altogether.
We do live in the real world after all, and one must adapt or perish.
Remember "low-cost single-board PCs" we eagerly watched evolve and get cheaper over the years? All of those Raspberry/Orange/Rock Pi's and "Zeros", Tinker boards and Jetson Nanos? Oh they did evolve all right… Into overpriced 100+ USD boards. So now we're stuck in a reality where even the simplest single-board ARM PC in the form of a Pi Zero W is valued at 100 USD instead of expected $15-20.
There are practical alternatives to single-board PCs:
The first option is blatantly obvious if you're looking for a device with a real multitasking OS and a load of compute power. And used PCs nowadays? They are cheap. For a market price of about $150 for a Raspberry Pi 4 with 4GB RAM you can get a used mini-PC with a 4-core Pentium/Celeron CPU, 4 to 8 gigs of extendable RAM and a 128GB+ SSD system drive with an option of connecting a second drive via SATA or M.2.
Almost any PC will blow a Pi out of the water performance-wise. Sure, small PCs can't beat Pi boards' dimensions, power consumption and embedded IO-capabilities with over 20 I/O pins exposed for communicating with external devices. So if you're looking to set up a home web/file server, retro emulation station or use the machine as a simple desktop PC, opting for a used mini-PC today would be a no-brainer.
But what if you actually require rich I/O capabilities, small dimensions and low power-drain of a small single-board device?
Enter… Microcontrollers!
As one of millions of ZBrush perpetual license holders, today I received this gem of an offer from Maxxon:
With the following decription:
ZBrush has always stood for innovation and artistic empowerment. That is a philosophy that is shared by the Maxon creative community. We believe in empowering artists any way we can to help expand your capabilities and offer more to your clients. We are confident that having complete access to all Maxon tools, services and training will help you achieve your goals.
Just another bunch of corporate mumbo-jumbo with a poorly concealed attempt at selling a subscription to a perpetual license holder. Classic.
"...We are confident that having complete access to all Maxon tools, services and training will help you achieve your goals."
Allow me to fill in the blanks in this marketing pitch.
The full post is available now.
Not much to see here but a short announcement of the upcoming post about microcontrollers.
I've been dying to take a deep dive into this topic ever since I built my first PC, but was scared away by the complexly of both the programming and the hardware aspects of the whole endeavor. And now, 15+ years later, I finally built up some courage to try and program one of those and it turned out to be an incredible and very, very straightforward and rewarding experience! What helped motivate me to finally bite the bullet was the worsening availability of semiconductors and the price hike on almost all electronic components and devices that followed suit.
What must have also contributed was another project of mine where I modded a Panasonic RX-DT75 by adding audio over Bluetooth support via a new a voltage regulator with USB-level output, to which a Bluetooth USB module was then connected to gift this machine a new lease on life as a useful appliance and not just a relic of the past collecting dust on a shelf.
But boy would it still make one gorgeous dust-collector regardless!
Anyway, back to work!
Open-source community and the concept in general are mostly considered a good phenomena. Maintainers of the free Software are praised, as in most cases they are dedicating their own time and money to make sure the apps and modules they develop or look after can be used by the rest of the world. And they use this power to make the world a better place.
Except when they go a bit too far.
When was the last time you audited the code of the open-source Software you use on a daily basis?
Well, get used to doing that regularly from now on, since apparently RIAEvangelist, a maintainer of a popular node.js module named "node-ipc", came to a realization that he gets to decide the fate of some users' files as he recently submitted a new patch to the module which does something, that technically falls under the "malware" category: the update added new stealth functionality that would recursively go through the users' files and replace the contents of each one with the ❤️ (heart emoji) if it detected that the user was located in Russia or Belarus.
Apparently this was supposed (?) to help (?) stop (?) the on-going conflict between Russia and Ukraine? Don't ask... I don't get it either.