Below is a small list of tips and tricks for scene and plugin creation that I've learned while working with VAM and creating plugins. Many of these are probably already well known to old experienced users, but some may not have heard of them, so I'm sharing it here.
— Tricks
- CUA with the Standard Unity shader in Fade or Transparent render mode can be hidden using the built-in VAM UIImage atom - set it Background Alpha = 0.004 (strict), Image Alpha = 0, both Colors = 0-0-0 and RenderQueue = 2999 (strict) - as a result, when you look at such CUA through this UIImage, it will be "cut off" (hidden) exactly in those places where they visually intersect.
- If you have VAM Glass atom onto which Directional Light shines, turn off Glass "Pixel Light" checkbox to prevent it from flickering.
- To prevent the arms/legs from passing through the Person body when abruptly rewinding the Timeline to the beginning, switch the animation to frame 0, then go to the "Pose Tab" and click "Use Current Pose". It's important to uncheck "Include Morphs" before, otherwise data from Naturalis or other plugins that modify morphs will be retained. The idea is that the animation will "jump" to this pose when resetting without taking physics into account, which will completely eliminate (or at least significantly reduce) collision and clothing issues.
- If Light (especially Directional) passes through headwear/clothing and does not cast a shadow and/or illuminates objects it should not reach, use VAMTweaks and set Shadow Cascads = 4.
- If when you move Main camera on Y axis there is an effect that the Skybox also moves, it needs to be scaled via PhysicsObject -> Scale (usually by 5-10 times).
- You can use BlurCube atom with Pexilization = 0.0001 (strict) and RenderQueue = 3000 to create X-Ray effect on any clothing which is visually located behind it (while its scaling and rotation along the axes will be taken into account).
— For plugins developers
- Get ALL components of the specified type (FindObjectsOfType works unreliably and often does not return even active atoms)
Button[] AllButtons = Resources.FindObjectsOfTypeAll(typeof(Button)) as Button[];
- Remove current plugin
manager.RemovePluginWithUID(storeId.Substring(0, storeId.IndexOf("_")));
- Get the current plugin index (works with any numbers)
int CurrentPluginIndex = int.Parse(storeId.Substring(7, storeId.IndexOf("_") - 7))
- Create a UVTemplate of some clothing itme and get it as a Texture2D (with subsequent deletion of temporary file)
public override void Init () {
DAZSkinWrap[] dressedСlothe = containingAtom.GetComponentsInChildren<DAZSkinWrap>();
MaterialOptions neededVAMMaterial = dressedСlothe[#NeededClothIndex].gameObject.GetComponents<DAZSkinWrapMaterialOptions>()[#NeededMaterialIndex] as MaterialOptions;
string customTextureFolderBackup = neededVAMMaterial.customTextureFolder;
neededVAMMaterial.customTextureFolder = "Custom";
neededVAMMaterial.CreateUVTemplateTexture();
neededVAMMaterial.customTextureFolder = customTextureFolderBackup;
StartLoadingTexture("Custom\\" + (neededVAMMaterial.storeId.Substring(neededVAMMaterial.storeId.IndexOf(":") + 1) + "UVTemplate.png"));
}
public void StartLoadingTexture (string texturePath) {
ImageLoaderThreaded.QueuedImage queuedImage = new ImageLoaderThreaded.QueuedImage();
queuedImage.imgPath = texturePath;
queuedImage.forceReload = false;
queuedImage.createMipMaps = false;
queuedImage.isNormalMap = false;
queuedImage.isThumbnail = false;
queuedImage.linear = true;
queuedImage.createAlphaFromGrayscale = false;
queuedImage.compress = false;
queuedImage.callback = new ImageLoaderThreaded.ImageLoaderCallback(ApplyLoadedTexture);
ImageLoaderThreaded.singleton.QueueImage(queuedImage);
}
public void ApplyLoadedTexture (ImageLoaderThreaded.QueuedImage queuedImage) {
SomeTexture2DVariable = queuedImage.tex;
FileManagerSecure.DeleteFile(queuedImage.imgPath);
}
- Public (available) Timeline functions
public const string Animation = "Animation";
public const string Segment = "Segment";
public const string NextAnimation = "Next Animation";
public const string PreviousAnimation = "Previous Animation";
public const string NextAnimationInMainLayer = "Next Animation (Main Layer)";
public const string PreviousAnimationInMainLayer = "Previous Animation (Main Layer)";
public const string NextSegment = "Next Segment";
public const string PreviousSegment = "Previous Segment";
public const string Scrubber = "Scrubber";
public const string Time = "Set Time";
public const string Play = "Play";
public const string PlayIfNotPlaying = "Play If Not Playing";
public const string IsPlaying = "Is Playing";
public const string Stop = "Stop";
public const string StopIfPlaying = "Stop If Playing";
public const string StopAndReset = "Stop And Reset";
public const string NextFrame = "Next Frame";
public const string PreviousFrame = "Previous Frame";
public const string Speed = "Speed";
public const string Weight = "Weight";
public const string Locked = "Locked";
public const string Paused = "Paused";
- Paths where the plugin can create files (those with "true" do not require user manual confirmation)
FileManager.RegisterPluginSecureWritePath("Saves", false);
FileManager.RegisterPluginSecureWritePath("Custom", false);
FileManager.RegisterPluginSecureWritePath("Saves/PluginData", true);
FileManager.RegisterPluginSecureWritePath("Custom/PluginData", true);
- setCallbackFunction is not called if Set is equal to the current value
- Open the current plugin UI (only works if it was opened manually at least once before)
manager.pluginListPanel.GetChild(int.Parse(storeId.Substring(7, storeId.IndexOf("_") - 7))).GetChild(7).GetChild(0).GetChild(1).GetComponent<Button>().onClick.Invoke();
- Get all wearable cloth (returns arrays only for the current Person "main" gender, male or female)
DAZClothingItem[] AllAvailableCloth = personAtom.transform.GetChild(2).GetChild(2).GetComponent<DAZCharacterSelector>().clothingItems
DAZClothingItem[] AllDressedCloth = System.Array.FindAll(personAtom.transform.GetChild(2).GetChild(2).GetComponent<DAZCharacterSelector>().clothingItems, item => item.active)
- Getting the Atom parent of any GameObject (access the topmost object in the hierarchy, which is a child of "SceneAtoms", which never has parents)
public Atom GetGameObjectAtom (GameObject targetGameObject) {
Transform iterableTransform = targetGameObject.transform;
while (iterableTransform.parent.parent != null) {
iterableTransform = iterableTransform.parent;
}
return iterableTransform.parent.GetComponent<JSONStorable>().containingAtom;
}
- Get the full name of the VAR in which the current plugin is located (will return SomeCreator.SomeName.SomeVersion)
string containingVARNameFull = System.Text.RegularExpressions.Regex.Match(manager.GetJSON()["plugins"][name.Substring(0, name.IndexOf('_'))].Value, @"^(.*?/.*?/)").Value;
- Create plugin UI button, set its text and customize his size, style, and color, finaly add a click event in one line of code
CreateButton("<b><size=28><color=#ff0000ff>Some button text</color></size></b>").button.onClick.AddListener(() => { someJSONStorableFloat.val++; });
- An atom follows another atom - no extra calculations are needed and everything works smoothly on VAM physics
containingAtom.freeControllers[0].follow = SuperController.singleton.GetAtomByUid("Cube").freeControllers[0].control;
containingAtom.freeControllers[0].SetPositionStateFromString("Following");
containingAtom.freeControllers[0].SetRotationStateFromString("Following");
- Determine whether the current plugin is a Session Plugin or a Scene Plugin
if (containingAtom.type == "SessionPluginManager" || containingAtom.type == "CoreControl")
- Accessing other plugins
- If the order is known :
MVRScript[] plugins = someAtom.GetChild(0).GetChild(0).GetChild(1).GetChild(0).GetComponentsInChildren<MVRScript>();
plugins[X].SetFloatParamValue("someFloat", 5f);
plugins[X].SetBoolParamValue("someBool", false);
- If the order is known and within the Atom on which the plugin is located :
transform.parent.GetChild(X).GetComponent<MVRScript>().SetFloatParamValue("someFloat", 5f);
X is plugin index in the atom plugins list (if a plugin has multiple scripts (loaded via .cslist), then each individual script is +1 to the index)
- By name
public static MVRScript GetPluginByName (this Atom currentAtom, string pluginName) {
Transform pluginsContainer = currentAtom.reParentObject.GetChild(0).GetChild(1).GetChild(0);
for (int a = 0; a < pluginsContainer.childCount; a++) {
if (pluginsContainer.GetChild(a).name.Length - pluginName.Length > 0 && pluginsContainer.GetChild(a).name.Substring(pluginsContainer.GetChild(a).name.Length - pluginName.Length, pluginsContainer.GetChild(a).name.Length) == pluginName) {
return pluginsContainer.GetChild(a).GetComponent<MVRScript>();
break;
}
}
}
The advantages of this method are that it doesn't matter whether the plugin has a namespace or what it is. If there are several scripts in one plugin using .cslist, it will still work because a new object is created for each individual script.
- Get access to all UI elements of the current plugin
Note that the entire plugin UI is only available after Init() - from the Start() function or further down the functions hierarchy
public MVRPluginUI PluginControls;
public MVRScriptControllerUI PluginControls2;
public MVRScriptUI PluginControls3;
string pluginIndexString = storeId.Substring(0, storeId.IndexOf("_"));
for (int a = 0; a < manager.pluginListPanel.childCount; a++) {
if (manager.pluginListPanel.GetChild(a).GetChild(5).GetComponent<Text>().text == pluginIndexString) {
PluginControls = manager.pluginListPanel.GetChild(a).GetComponent<MVRPluginUI>();
PluginControls2 = PluginControls.scriptControllerContent.GetChild(0).GetComponent<MVRScriptControllerUI>();
break;
}
}
PluginControls3 = UITransform.GetComponent<MVRScriptUI>();
= PluginControls
public Text uidText;
public Button fileBrowseButton;
public Button clearButton;
public Button reloadButton;
public Text urlText;
public Button removeButton;
public RectTransform scriptControllerContent;
= PluginControls2
public Text label;
public Toggle enabledToggle;
public Button openUIButton;
public InputField userLabelInputField;
public InputFieldAction userLabelInputFieldAction;
= PluginControls3
public RectTransform rightUIContent;
public RectTransform leftUIContent;
public RectTransform fullWidthUIContent;
public Button closeButton;
- Open any available Tab on any atom (instead of XXX - copy of the Tab text with spaces)
someAtom.manager.scriptUIParent.parent.GetComponent<UITabSelector>().SetActiveTab("XXX");
- Unity layers in VAM
Layer 0: Default (LayerMask: 1)
Layer 1: TransparentFX (LayerMask: 2)
Layer 2: Ignore Raycast (LayerMask: 4)
Layer 4: Water (LayerMask: 16)
Layer 5: UI (LayerMask: 32)
Layer 8: ControlColliders (LayerMask: 256)
Layer 9: PlayerBlock (LayerMask: 512)
Layer 10: DefaultAndPlayerBlock (LayerMask: 1024)
Layer 11: Select (LayerMask: 2048)
Layer 12: Tongue (LayerMask: 4096)
Layer 13: TongueOnly (LayerMask: 8192)
Layer 14: PhysicsMesh1 (LayerMask: 16384)
Layer 15: PhysicsMesh2 (LayerMask: 32768)
Layer 16: WaterSurface (LayerMask: 65536)
Layer 17: Invisible (LayerMask: 131072)
Layer 20: LookAtTrigger (LayerMask: 1048576)
Layer 21: Glow (LayerMask: 2097152)
Layer 22: LoadUI (LayerMask: 4194304)
Layer 23: ScreenUI (LayerMask: 8388608)
Layer 24: GUI (LayerMask: 16777216)
Layer 25: Ignore CharacterCore (LayerMask: 33554432)
Layer 26: CharacterExtremities (LayerMask: 67108864)
Layer 27: Player (LayerMask: 134217728)
Layer 28: 1Hair (LayerMask: 268435456)
Layer 29: Character (LayerMask: 536870912)
Layer 30: Ignore Collision (LayerMask: 1073741824)
Layer 31: Ignore Character (LayerMask: -2147483648)
- Add custom Tab to the Atom left menu (copyright an existing Tab and removes unnecessary content)
TabbedUIBuilder tempTabbedUIBuilder = someAtom.transform.GetChild(1).GetChild(0).GetComponent<TabbedUIBuilder>();
TabbedUIBuilder.Tab newUITab = new TabbedUIBuilder.Tab();
newUITab.name = "SomeTabName"; //New Tab button Text
newUITab.prefab = Instantiate(SuperController.singleton.mainHUD.GetChild(1).GetChild(0).GetChild(2).GetChild(12), tempTabbedUIBuilder.selector.transform);
newUITab.color = new Color (0.05f, 0.05f, 0.05f, 1f); //New Tab button color
Destroy(newUITab.prefab.GetChild(0).gameObject);
Destroy(newUITab.prefab.GetChild(1).gameObject);
tempTabbedUIBuilder.AddTab(newUITab);
newUITab.prefab.GetComponent<Image>().color = Color.red; //New Tab background color
someAtom.transform.GetChild(1).GetChild(0).GetChild(0).GetChild(1).GetComponent<RectTransform>().sizeDelta += new Vector2 (0f, 80f);
A big thank you to all the other amazing creators out there that help amateurs like me enjoy VAM so much. Standing on the shoulders of giants!
— Tricks
- CUA with the Standard Unity shader in Fade or Transparent render mode can be hidden using the built-in VAM UIImage atom - set it Background Alpha = 0.004 (strict), Image Alpha = 0, both Colors = 0-0-0 and RenderQueue = 2999 (strict) - as a result, when you look at such CUA through this UIImage, it will be "cut off" (hidden) exactly in those places where they visually intersect.
- If you have VAM Glass atom onto which Directional Light shines, turn off Glass "Pixel Light" checkbox to prevent it from flickering.
- To prevent the arms/legs from passing through the Person body when abruptly rewinding the Timeline to the beginning, switch the animation to frame 0, then go to the "Pose Tab" and click "Use Current Pose". It's important to uncheck "Include Morphs" before, otherwise data from Naturalis or other plugins that modify morphs will be retained. The idea is that the animation will "jump" to this pose when resetting without taking physics into account, which will completely eliminate (or at least significantly reduce) collision and clothing issues.
- If Light (especially Directional) passes through headwear/clothing and does not cast a shadow and/or illuminates objects it should not reach, use VAMTweaks and set Shadow Cascads = 4.
- If when you move Main camera on Y axis there is an effect that the Skybox also moves, it needs to be scaled via PhysicsObject -> Scale (usually by 5-10 times).
- You can use BlurCube atom with Pexilization = 0.0001 (strict) and RenderQueue = 3000 to create X-Ray effect on any clothing which is visually located behind it (while its scaling and rotation along the axes will be taken into account).
— For plugins developers
- Get ALL components of the specified type (FindObjectsOfType works unreliably and often does not return even active atoms)
Button[] AllButtons = Resources.FindObjectsOfTypeAll(typeof(Button)) as Button[];
- Remove current plugin
manager.RemovePluginWithUID(storeId.Substring(0, storeId.IndexOf("_")));
- Get the current plugin index (works with any numbers)
int CurrentPluginIndex = int.Parse(storeId.Substring(7, storeId.IndexOf("_") - 7))
- Create a UVTemplate of some clothing itme and get it as a Texture2D (with subsequent deletion of temporary file)
public override void Init () {
DAZSkinWrap[] dressedСlothe = containingAtom.GetComponentsInChildren<DAZSkinWrap>();
MaterialOptions neededVAMMaterial = dressedСlothe[#NeededClothIndex].gameObject.GetComponents<DAZSkinWrapMaterialOptions>()[#NeededMaterialIndex] as MaterialOptions;
string customTextureFolderBackup = neededVAMMaterial.customTextureFolder;
neededVAMMaterial.customTextureFolder = "Custom";
neededVAMMaterial.CreateUVTemplateTexture();
neededVAMMaterial.customTextureFolder = customTextureFolderBackup;
StartLoadingTexture("Custom\\" + (neededVAMMaterial.storeId.Substring(neededVAMMaterial.storeId.IndexOf(":") + 1) + "UVTemplate.png"));
}
public void StartLoadingTexture (string texturePath) {
ImageLoaderThreaded.QueuedImage queuedImage = new ImageLoaderThreaded.QueuedImage();
queuedImage.imgPath = texturePath;
queuedImage.forceReload = false;
queuedImage.createMipMaps = false;
queuedImage.isNormalMap = false;
queuedImage.isThumbnail = false;
queuedImage.linear = true;
queuedImage.createAlphaFromGrayscale = false;
queuedImage.compress = false;
queuedImage.callback = new ImageLoaderThreaded.ImageLoaderCallback(ApplyLoadedTexture);
ImageLoaderThreaded.singleton.QueueImage(queuedImage);
}
public void ApplyLoadedTexture (ImageLoaderThreaded.QueuedImage queuedImage) {
SomeTexture2DVariable = queuedImage.tex;
FileManagerSecure.DeleteFile(queuedImage.imgPath);
}
- Public (available) Timeline functions
public const string Animation = "Animation";
public const string Segment = "Segment";
public const string NextAnimation = "Next Animation";
public const string PreviousAnimation = "Previous Animation";
public const string NextAnimationInMainLayer = "Next Animation (Main Layer)";
public const string PreviousAnimationInMainLayer = "Previous Animation (Main Layer)";
public const string NextSegment = "Next Segment";
public const string PreviousSegment = "Previous Segment";
public const string Scrubber = "Scrubber";
public const string Time = "Set Time";
public const string Play = "Play";
public const string PlayIfNotPlaying = "Play If Not Playing";
public const string IsPlaying = "Is Playing";
public const string Stop = "Stop";
public const string StopIfPlaying = "Stop If Playing";
public const string StopAndReset = "Stop And Reset";
public const string NextFrame = "Next Frame";
public const string PreviousFrame = "Previous Frame";
public const string Speed = "Speed";
public const string Weight = "Weight";
public const string Locked = "Locked";
public const string Paused = "Paused";
- Paths where the plugin can create files (those with "true" do not require user manual confirmation)
FileManager.RegisterPluginSecureWritePath("Saves", false);
FileManager.RegisterPluginSecureWritePath("Custom", false);
FileManager.RegisterPluginSecureWritePath("Saves/PluginData", true);
FileManager.RegisterPluginSecureWritePath("Custom/PluginData", true);
- setCallbackFunction is not called if Set is equal to the current value
- Open the current plugin UI (only works if it was opened manually at least once before)
manager.pluginListPanel.GetChild(int.Parse(storeId.Substring(7, storeId.IndexOf("_") - 7))).GetChild(7).GetChild(0).GetChild(1).GetComponent<Button>().onClick.Invoke();
- Get all wearable cloth (returns arrays only for the current Person "main" gender, male or female)
DAZClothingItem[] AllAvailableCloth = personAtom.transform.GetChild(2).GetChild(2).GetComponent<DAZCharacterSelector>().clothingItems
DAZClothingItem[] AllDressedCloth = System.Array.FindAll(personAtom.transform.GetChild(2).GetChild(2).GetComponent<DAZCharacterSelector>().clothingItems, item => item.active)
- Getting the Atom parent of any GameObject (access the topmost object in the hierarchy, which is a child of "SceneAtoms", which never has parents)
public Atom GetGameObjectAtom (GameObject targetGameObject) {
Transform iterableTransform = targetGameObject.transform;
while (iterableTransform.parent.parent != null) {
iterableTransform = iterableTransform.parent;
}
return iterableTransform.parent.GetComponent<JSONStorable>().containingAtom;
}
- Get the full name of the VAR in which the current plugin is located (will return SomeCreator.SomeName.SomeVersion)
string containingVARNameFull = System.Text.RegularExpressions.Regex.Match(manager.GetJSON()["plugins"][name.Substring(0, name.IndexOf('_'))].Value, @"^(.*?/.*?/)").Value;
- Create plugin UI button, set its text and customize his size, style, and color, finaly add a click event in one line of code
CreateButton("<b><size=28><color=#ff0000ff>Some button text</color></size></b>").button.onClick.AddListener(() => { someJSONStorableFloat.val++; });
- An atom follows another atom - no extra calculations are needed and everything works smoothly on VAM physics
containingAtom.freeControllers[0].follow = SuperController.singleton.GetAtomByUid("Cube").freeControllers[0].control;
containingAtom.freeControllers[0].SetPositionStateFromString("Following");
containingAtom.freeControllers[0].SetRotationStateFromString("Following");
- Determine whether the current plugin is a Session Plugin or a Scene Plugin
if (containingAtom.type == "SessionPluginManager" || containingAtom.type == "CoreControl")
- Accessing other plugins
- If the order is known :
MVRScript[] plugins = someAtom.GetChild(0).GetChild(0).GetChild(1).GetChild(0).GetComponentsInChildren<MVRScript>();
plugins[X].SetFloatParamValue("someFloat", 5f);
plugins[X].SetBoolParamValue("someBool", false);
- If the order is known and within the Atom on which the plugin is located :
transform.parent.GetChild(X).GetComponent<MVRScript>().SetFloatParamValue("someFloat", 5f);
X is plugin index in the atom plugins list (if a plugin has multiple scripts (loaded via .cslist), then each individual script is +1 to the index)
- By name
public static MVRScript GetPluginByName (this Atom currentAtom, string pluginName) {
Transform pluginsContainer = currentAtom.reParentObject.GetChild(0).GetChild(1).GetChild(0);
for (int a = 0; a < pluginsContainer.childCount; a++) {
if (pluginsContainer.GetChild(a).name.Length - pluginName.Length > 0 && pluginsContainer.GetChild(a).name.Substring(pluginsContainer.GetChild(a).name.Length - pluginName.Length, pluginsContainer.GetChild(a).name.Length) == pluginName) {
return pluginsContainer.GetChild(a).GetComponent<MVRScript>();
break;
}
}
}
The advantages of this method are that it doesn't matter whether the plugin has a namespace or what it is. If there are several scripts in one plugin using .cslist, it will still work because a new object is created for each individual script.
- Get access to all UI elements of the current plugin
Note that the entire plugin UI is only available after Init() - from the Start() function or further down the functions hierarchy
public MVRPluginUI PluginControls;
public MVRScriptControllerUI PluginControls2;
public MVRScriptUI PluginControls3;
string pluginIndexString = storeId.Substring(0, storeId.IndexOf("_"));
for (int a = 0; a < manager.pluginListPanel.childCount; a++) {
if (manager.pluginListPanel.GetChild(a).GetChild(5).GetComponent<Text>().text == pluginIndexString) {
PluginControls = manager.pluginListPanel.GetChild(a).GetComponent<MVRPluginUI>();
PluginControls2 = PluginControls.scriptControllerContent.GetChild(0).GetComponent<MVRScriptControllerUI>();
break;
}
}
PluginControls3 = UITransform.GetComponent<MVRScriptUI>();
= PluginControls
public Text uidText;
public Button fileBrowseButton;
public Button clearButton;
public Button reloadButton;
public Text urlText;
public Button removeButton;
public RectTransform scriptControllerContent;
= PluginControls2
public Text label;
public Toggle enabledToggle;
public Button openUIButton;
public InputField userLabelInputField;
public InputFieldAction userLabelInputFieldAction;
= PluginControls3
public RectTransform rightUIContent;
public RectTransform leftUIContent;
public RectTransform fullWidthUIContent;
public Button closeButton;
- Open any available Tab on any atom (instead of XXX - copy of the Tab text with spaces)
someAtom.manager.scriptUIParent.parent.GetComponent<UITabSelector>().SetActiveTab("XXX");
- Unity layers in VAM
Layer 0: Default (LayerMask: 1)
Layer 1: TransparentFX (LayerMask: 2)
Layer 2: Ignore Raycast (LayerMask: 4)
Layer 4: Water (LayerMask: 16)
Layer 5: UI (LayerMask: 32)
Layer 8: ControlColliders (LayerMask: 256)
Layer 9: PlayerBlock (LayerMask: 512)
Layer 10: DefaultAndPlayerBlock (LayerMask: 1024)
Layer 11: Select (LayerMask: 2048)
Layer 12: Tongue (LayerMask: 4096)
Layer 13: TongueOnly (LayerMask: 8192)
Layer 14: PhysicsMesh1 (LayerMask: 16384)
Layer 15: PhysicsMesh2 (LayerMask: 32768)
Layer 16: WaterSurface (LayerMask: 65536)
Layer 17: Invisible (LayerMask: 131072)
Layer 20: LookAtTrigger (LayerMask: 1048576)
Layer 21: Glow (LayerMask: 2097152)
Layer 22: LoadUI (LayerMask: 4194304)
Layer 23: ScreenUI (LayerMask: 8388608)
Layer 24: GUI (LayerMask: 16777216)
Layer 25: Ignore CharacterCore (LayerMask: 33554432)
Layer 26: CharacterExtremities (LayerMask: 67108864)
Layer 27: Player (LayerMask: 134217728)
Layer 28: 1Hair (LayerMask: 268435456)
Layer 29: Character (LayerMask: 536870912)
Layer 30: Ignore Collision (LayerMask: 1073741824)
Layer 31: Ignore Character (LayerMask: -2147483648)
- Add custom Tab to the Atom left menu (copyright an existing Tab and removes unnecessary content)
TabbedUIBuilder tempTabbedUIBuilder = someAtom.transform.GetChild(1).GetChild(0).GetComponent<TabbedUIBuilder>();
TabbedUIBuilder.Tab newUITab = new TabbedUIBuilder.Tab();
newUITab.name = "SomeTabName"; //New Tab button Text
newUITab.prefab = Instantiate(SuperController.singleton.mainHUD.GetChild(1).GetChild(0).GetChild(2).GetChild(12), tempTabbedUIBuilder.selector.transform);
newUITab.color = new Color (0.05f, 0.05f, 0.05f, 1f); //New Tab button color
Destroy(newUITab.prefab.GetChild(0).gameObject);
Destroy(newUITab.prefab.GetChild(1).gameObject);
tempTabbedUIBuilder.AddTab(newUITab);
newUITab.prefab.GetComponent<Image>().color = Color.red; //New Tab background color
someAtom.transform.GetChild(1).GetChild(0).GetChild(0).GetChild(1).GetComponent<RectTransform>().sizeDelta += new Vector2 (0f, 80f);
A big thank you to all the other amazing creators out there that help amateurs like me enjoy VAM so much. Standing on the shoulders of giants!