The game's skater loader builds each recipe slot with that slot's own function, which puts the
item's appearance preset on a material named for the slot's kind ("Outfit_Top_mat"). An item worn
on top sits in another kind's slot, so its mesh found nothing under its own material ("Bottom_mat")
and drew white. The preset lookup guard's addEsShaderPreset hook now also puts the preset of an item
on top on its own kind's material (layer_materials.h: which presets those are, from each item's
catalog folder and AssetPaths; the five native functions checked by their first bytes).
The outfit service logs what goes on top and where, the slot trials, why an item is not worn and
what it waits for.
Scrolling shirts onto Yudi-Yuddispack's philippleinshirt_ap crashed the game (Skate.exe+0x3dc07ed):
one of the preset's set parameters has a type of 0x0c07010304040502 (null in another crash). The
game type-checks every set parameter when it next applies a preset to a material, reading the
type unchecked, and catching that crash inside addEsShaderPreset was too late: the preset was on
the material already and the next update crashed on it.
addEsShaderPreset's guard now checks the preset first, as that type check reads it: the TypeInfo,
its data, a word at +4. A preset with a parameter whose type cannot be read is left out as a
preset that is not loaded is (the item shows without it), and named in the log once with that
parameter's key. Many of the game's own types are built at run time, so the test is that the
type reads, not that it lies in the game's image.
Costume crash: the skater scripts' item:addEsShaderPreset uses the
preset it is handed without checking that it is loaded, and the game
crashed in the material's construction shortly after arriving on a
server's map while wearing a modded costume. The call is now checked
first: an item whose preset is not there is shown without it, and the
log says so.
Stuck close: once the player closes the game, a watch starts. If the
window has gone or stopped answering and the process is still there
8 seconds later, the process is ended. A window that still answers
(the close was turned down) is left alone, and the watch stands down
after two minutes.
Level unload guard: switched off. Skipping the entry that crashed left
its reference registered, so leaving the level never finished and the
game hung with the world unloaded. The crash it covered is back until
the reference is released properly.