At some point in August, the slowly-increasing desire to work on the Stiletto reached it’s final point, and I broke my hiatus. I talked with Haven and he promised me that he fully intended for this map to still be produced. So, I threw out an @everyone in the SRP Dev discord to see who was still interested in the project and, surprisingly, most everyone was still on-board with the idea.
So, with the advent of VRChat’s update to Unity 2019, we cracked the project back open, bashed off the rust, got the project up to date, and got back to work.
Restructuring the Hull
The old hull we were using was literally just the Scharnhorst’s hull with no edits other than paint and removing some low-poly detail greebling. In the interest of making the ship “more fantasy-like”, which is a point of criticism and/or advice I hear frustratingly often from Haven, we eventually harassed Haven enough to give us a big pile of reference images for how he actually wanted the ship to look. One of the reference images looked rather interesting to me, a much fatter, sloping hull rather than one that starts narrow and fans upwards and outwards.
So I set about redoing the entire hull over the course of the next couple of weeks. I started with a crap ton of Bezier Curves in Blender, shaping them around how the midships would slope first, and then duplicating and transposing them along the hull, tweaking control points along the way until, finally, I had something resembling the “skeleton” of the hull.
From there, I took the Bezier Curves, hit “Convert to Mesh”, and then took the top two vertices between two ribs and connected them. From there, using the wondrously useful Mesh: F2 plugin that comes with Blender (seriously, turn that on if you do a lot of retopo or poly-fill construction), I just had to select that new edge and hold F to fill in each strip of the hull’s skin.
However, this process was admittedly imperfect. Notably around transition points where the Curves had fewer control points and, thus, fewer vertices than their neighbor, and especially around the prow and stern of the ship. I could have spent many hours tweaking the output mesh to smooth it down, but just then I had a potentially very bad idea: throw the lot into the Sculpt mode of Blender, and smooth it out like a big clay ball. Also, stay WAAYYY the hell away from the DynTopo button, as I really did not want to add a retopo pass onto this admittedly-slow project. After a lot of fussing, realignment, redoes, and discovery that Sculpt is not great at smoothing out cylinders for the propeller shaft alleys, I finally had the new hull.
Rethinking Textures
As the project was progressing, the map size just kept creeping up and up and up, at one point hitting somewhere around 240 MB even though we don’t even have a single bit of proper interior yet. This was very much not good for our target of keeping the map under half-a-gig for the players with slow internet. The main culprit of our extraneous file size? All those 4096×4096 bespoke textures I’ve been having to manually paint all over the ship. This downside was two-fold: not only did it bloat the map size a LOT for nothing other than a lot of very similar looking textures, but painting details like rivets, scratches, seams, and the like takes an absolutely hellish amount of time. And pixels! The midship smokestack we had before had to be an 8192×8192 base texture to make the rivets look like rivets and not jpeg artifacts. The normal map alone was 80 MB uncompressed!
The fix for all this entailed two main prongs of attack. First, I had to go back through and replace all the bespoke textures with the Stiletto_White and Stiletto_Blue generic tileable materials. It cost a few percentage points more triangles to achieve, but the Aft Mast was already using this method instead of bespokes, so it was already proven to work well. Also, a few hundred or thousand more polygons doesn’t affect too much in the grand scheme of the map, especially with today’s video cards and their obscene fill rates. This served really well to limit the size of the map, eventually pushing the map size way the hell down from 200+ MB to 94 MB for the whole thing. Unfortunately, this made everything look really flat and bland, since it was all just base painted metal with no variations. Gone were the bespoke rivets, and gone were the auto-generated edge scarring from Substance Painter.
That’s where the second prong came in: Adding another feature to the PBR Metal Rough shader. The ability to add in an overlay or “detail” texture on top of the base material. This procedure is nothing new, really, even the Standard shader does it. But in any case, as you can see from the above, I can now take a tileable “rivet” texture and plaster it everywhere I please. Seen prominently, the same pattern the Midships Smokestack uses for its rivets, but on the Stiletto_White base instead of Stiletto_Blue.
As seen in the header image, the Hull also has some painted-over weld lines, warping, and wear and tear bits. Esarai provided about 16 variants of overlay textures to the project for fleshing out details like this.
Just as well, I was able to leverage a feature that’s been in my PBR Metal Rough shader for some time: On-Demand Color Remapping. I baked out the “paint” layer from Stiletto_White (in order to preserve scratches) to the Colormap texture, and then was able to reuse Stiletto_White for the various colors of hull paint with almost no increase in map size.
Das (Little) Boat
I’m going to expedite this section a bit, because, even though it’s taken me a couple weeks to implement, this article is getting quite long. Simply put, we now have life rafts, row boats, and the motorized patrol boats to fill out the Midships section. Also notable, the patrol boats or “Captain’s Yachts” have two hinged hatches, the one in the rear opening to a “mana cell” compartment, which would power the boat’s “Motus Core” (working title, no model yet) in the engine bay under the forward hatch (note the brass pipes leading from aft to fore). The collisions have been set up so mechanic RP can work without having to Playspace Move your model into the floor, which Desktop users cannot do.
Now have some screenshots:
Administration At Your Fingertips
I’m going to throw it on over to Kaderen for this next section, as this was their baby for the past month and change:
Kaderen here, talking a little bit about the Admin Menu I put together for the project. The menu was a pretty large undertaking, and required at least 3 individual rewrites to get to the point it is. While the (mostly) finished product is seen above, a lot of hackery to work around Udon’s limitations was required, which complicated things significantly. But before we start jumping into the details of how things work, lets discuss what inspired me to make the Menu in the first place.
The main drive for me to create the Menu was two major factors; firstly, trying to create a cleaner, less intrusive solution for the way we interact with the environment. As you can see above, having a number of individual buttons, through either of the popular methods of using a bunch of GameObjects or using a simple UI setup requires a lot of real estate. This ends up being clunky to interact with, and is tedious and time consuming for us to maintain if we want to make changes. The second main drive behind the Menu is to prevent Players, Admins, or us Devs from having to move from the current location we’re in in order to do things. Aside from simply the convenience standpoint, this helps in scenarios where an Admin needs to change the time, get a pickup, or change their speed, and they can do so easily without having to haphazardly teleport somewhere to do it, and prevents interrupting any scenario they might be taking part in.
Now that why the menu exists has been laid out, time to get into the details of how. Firstly, there are two major components that make it tick; individual menus, and the thing that controls it all. Lets start with the individual menus, so we know what the Controller has to do to tie everything together. Each individual menu is isolated and only contains only the information for its own items. These items can point to various things, like another menu, a button for an UdonBehaviour’s event, or outright modify the variables of an UdonBehaviour. Other than containing this information, individual menus keep track of what index the cursor is at, and scrolling their own items when they go off screen. Importantly, not a single menu exists until the menu is opened. All menus are dynamically created by the Controller at runtime.
So, what is the controller doing, then? The responsibilities of the controller are as follows;
- Handle inputs from the user.
- Create menus as they’re opened.
- Clean up menus that have been closed and are no longer needed.
- Store information for all menus so that they can be properly constructed.
That last one is the most important, as that’s the biggest hitch we run into dealing with Udon here. Udon doesn’t let us write constructors, so the only way to store data is to have within a GameObject with an UdonBehaviour that exists within the scene. This means to properly be able to store all the data for every menu that would ever need to be created, the controller uses multiple jagged arrays (arrays of arrays). This is the part that made the menu so time consuming to get working correctly, and brought along a number of other issues that complicated things, not the least of which being the fact that Unity does not serialize jagged arrays.
With all that out of the way, however, we end up with a pretty slick product. Along with the fact that it’s been set up to allow for outside scripts to hook into it, it allows for self-populating menus such as the player list seen above. A number of modules have already been implemented, including utilities for pickup management, dice rolling, teleports, and more. The hope with all of this is to make things as easy as possible for Admins and Players once we get around to this map’s trial by fire in actual roleplay.
Collab’s Treachery
In the middle of all of the above, something sinister was happening in the background that nobody had noticed for the month and a half since we rebooted SRP Dev. Collab, something that CLAIMS to be a version control system for Unity, something that COSTS MONEY IF YOU HAVE MORE THAN THREE PEOPLE, decided it’d be a dandy idea to just pretend to do its job.
For a bit of background: for those who don’t know how team development works, you need some way to get the latest files to all of your team members. Usually, this is done via something called “Version Control”, and usually takes the form of technologies named Git, SVN, or (god forbid) Dropbox. What all these have in common is a central online storage of files that everyone can pull updates from. Enter Collab, Unity’s in-built answer to team-based development and version control. Collab 1.6.5, the base version that comes with Unity 2018 and 2019, refuses to work properly for Kaderen for whatever reason. So, we decided, “let’s try updating, 2.0.0 is supposed to have some good stuff behind it, and it actually works for everyone!”
The most immediately noticeable pain was that Collab 2.0.0 likes VERY MUCH to just not fully scan the project, necessitating multiple pushes to the cloud in order to get ALL the files synced (my record is 5 attempts before finally working fully). The other noticeable thing was that it now seemed to support syncing files outside the Assets/ directory, where everything is processed and loaded by Unity for placement into the game. Now, I’ve been keeping all my Blender and Photoshop files around for ongoing maintenance, updates, upgrades, fixes, etc., and Unity will attempt to load these files as usable assets. This process is quite slow, especially when my development files reach in excess of 100mb (lookin’ at you, Photoshop), and every time I save, Unity reimports these as assets, taking a lot of my time. So noting the new syncing of outside files, we decided that we could save a lot of time by moving all those raws out to an external folder. And save time it did! Initially!
Fast forward a month and a half. I need to open up the Aft Housing Blender file to remove the life raft hooks to make them into their own props. What’s this? Aft_housing.blend seems to have been deleted by mistake! No matter, Collab has a version history like every other version control software out there, I’ll just downgrade to the version it was last seen and copy it out. That all completed after quite some time, and I managed to recover aft_housing.blend without much fuss.
The problems started when I tried to get back up to the current version. Collab just…wouldn’t let me. Every time I tried to Restore, I got “Could not pull entry!” and the process would error out. So I deleted my local copy and pulled it fresh off their servers. Hours of Collab fuckery later, I finally was back on the latest version. Popping back into the project directory to copy aft_housing.blend back into place, however, revealed a terrible truth. DevFiles/ was missing. Where had it gone? Why wasn’t Collab pulling it? Is it just being a shit? I asked Kaderen and Esarai if they could sync me their versions of the folder. That’s when the full gravity of the situation landed on my head, Kaderen’s versions had not been updated by Collab since August, and Esarai never even got the DevFiles/ directory at all!
Collab, in it’s infinite stupidity, consistently claimed that changes were being sent to the server and pushed, and EVEN HAS RECORDS OF THESE FILES BEING CHANGED ON THE TIMELINE. BUT! Where were these files? FUCKING NOWHERE!! Even after fully exporting the project through Unity’s web interface, the entire DevFiles folder was just never saved out. There were no warnings about files failing to save or push, there were no errors about putting stuff in the wrong directory, by all messaging everything was running FINE.
After this all went down, I was able to partially recover a bunch of my work (and losing yet more) by scraping my Dropbox for files shared with people not on the Collab seat list (like the Stiletto_Only.blend file I sent to EnDjinn for use in drawing out the interior floor plans). I was able to salvage the new hull and redone texturing for the entire exterior, but lost the Propeller and a couple other minor props.
So I’ve given the middle finger to Collab, bit the bullet, and learned how to spin up my own Gitlab server using the Dell R710 I happen to own in my living room. I would have used Gitlab.com itself, but they have a 10GB repository size limit, whereas I can have as many terabytes as I have storage on my local instance. With help from my friend Hobnob, I was able to get this functional within the weekend. The tricky bit is going to be getting the non-technically-savvy onto the project, since it requires more than just clicking an Upload Now button to use.
Rant Over, Here’s A Preview
So that’s one of the longer posts I’ve had so far on my blog. It’s been a very busy couple of months, and I still didn’t even document everything that happened. On top of all of this, Haven and Sprixer (mostly Sprixer) have spun up a new, more immediate project known as Actium RP, which takes place in the canon of Battletech and Haven’s own community shenanigans.
I was just brought onto the project last night, but I can show you one WIP sneak peek before I buckle down and get cracking on everything else I have to do today.