• Hi Guest!

    We are extremely excited to announce the release of our first Beta1.1 and the first release of our Public AddonKit!
    To participate in the Beta, a subscription to the Entertainer or Creator Tier is required. For access to the Public AddonKit you must be a Creator tier member. Once subscribed, download instructions can be found here.

    Click here for information and guides regarding the VaM2 beta. Join our Discord server for more announcements and community discussion about VaM2.
  • Hi Guest!

    VaM2 Resource Categories have now been added to the Hub! For information on posting VaM2 resources and details about VaM2 related changes to our Community Forums, please see our official announcement here.
Decal Maker

Plugins + Scripts Decal Maker

Download [3 MB]
Chokaphi updated Decal Maker with a new update entry:

Roses are red, Violets are red, Bushes are red...shit I broke the colorpicker again

Update the ColorPicker UI and fix reported bugs.

Fix: Adds check to skip Genital texture clipping when a male character is selected.
Fix: Color Picker will correctly sync with selected textures values.
Fix: Color Picker slider now has the texture path and value entry box.
Fix: Set DynamicStorables to not save to JSON

Read the rest of this update entry...
 
A fantastic plugin that addresses one of the biggest shortcomings of VAM's native skin functionality.

However, I have a suggestion:

SuperController.LogError is conventionally used for reporting actual errors. For messages indicating successful plugin loading, unloading, or other informational events, it might be better to use an info-level log instead.

The red error messages can be distracting and may even cause unnecessary confusion—especially for regular players.

Moreover, VAM pops up a UI window every time LogError is triggered, which can be quite unnecessary in these cases.
 
A fantastic plugin that addresses one of the biggest shortcomings of VAM's native skin functionality.

However, I have a suggestion:

SuperController.LogError is conventionally used for reporting actual errors. For messages indicating successful plugin loading, unloading, or other informational events, it might be better to use an info-level log instead.

The red error messages can be distracting and may even cause unnecessary confusion—especially for regular players.

Moreover, VAM pops up a UI window every time LogError is triggered, which can be quite unnecessary in these cases.

I try to use SuperController.LogError for user facing errors I want reported even if it does not crash the plugin, and Debug.Log/Error/warning for internal logs.

I did find a few that should be changed Please Add any others you think should not be alerted on.
Next release these will not be on or use internal logs:
  • Decal Maker assetbundle loaded and ready " + DateTime.Now
  • Decal Maker assetbundle unloaded " + DateTime.Now)
  • A JSON printout when old saves were loaded/converted
 
I try to use SuperController.LogError for user facing errors I want reported even if it does not crash the plugin, and Debug.Log/Error/warning for internal logs.

I did find a few that should be changed Please Add any others you think should not be alerted on.
Next release these will not be on or use internal logs:
  • Decal Maker assetbundle loaded and ready " + DateTime.Now
  • Decal Maker assetbundle unloaded " + DateTime.Now)
  • A JSON printout when old saves were loaded/converted

Thank you for your response. I think these would make more sense in an info-level log rather than an error log. In fact, aside from errors caused by the failure of a specific operation or function, it might be worth considering moving most error logs to info logs, as people who truly care about this information usually know how to find and interpret it. For most casual users, error logs only cause unnecessary alarm. :ROFLMAO:

JSON:
        void CharacterEvents(object o, CharEventArgs e)
        {
            SuperController.LogError(DateTime.Now +" PluginState CharacterEvent " + e.eventName);
            switch (e.eventName)
            {
                case "GpuTextureData":
                    //texture data for character has been stored
                    Data.InitRenderers(CharacterState);
                    break;

                case "_isMale":
                    PluginSettings.IsMale = e._isMale;
                    break;

                case "_uvSetName":
                    PluginSettings.UVSetName = e._uvSetName;
                    break;
            }
        }

JSON:
            this.request = request;
            loaded = true;
            SuperController.LogError("Decal Maker assetbundle loaded and ready " +DateTime.Now);
        }

JSON:
        public void Destroy()
        {
            AssetLoader.DoneWithAssetBundleFromFile(path);
            //request = null;
            loaded = false;
            SuperController.LogError("Decal Maker assetbundle unloaded " + DateTime.Now);
           
            foreach (GameObject obj in InstancedObjects)
            {
                GameObject.Destroy(obj);
            }
            InstancedObjects = new List<GameObject>();
        }

JSON:
        void CharacterEvents(object o, CharEventArgs e)
        {
            SuperController.LogError(DateTime.Now + " BaseREnderer CharacterEvent " + e.eventName);
            switch (e.eventName)
            {
                case "GpuTextureData":
                    //texture data for character has been stored
                    //Debug.LogError(DateTime.Now+" BaseRender GpuTextureData " + e.daskin?.name + " " + e.dAZCharacter?.name);
                    IsDirty = true;
                    break;

                case "_uvSetName":
                    SetClipAction();
                    break;
            }
        }

JSON:
        public void Update()
        {
            SuperController.LogError("OnLateUpdate()");
            if (IsDirty)
            {
                SuperController.LogError("IS DIRTY!" + _MaterialSlot + " " + _TextureSlot);
                if (!Processing)
                {
                    dirtyTimeStart = dirtyTime;
                    Processing = true;
                    StartCoroutine(ApplyChanges());
                }
            }
        }
 
Last edited:
Thank you for your response. I think these would make more sense in an info-level log rather than an error log. In fact, aside from errors caused by the failure of a specific operation or function, it might be worth considering moving most error logs to info logs, as people who truly care about this information usually know how to find and interpret it. For most casual users, error logs only cause unnecessary alarm. :ROFLMAO:

JSON:
        void CharacterEvents(object o, CharEventArgs e)
        {
            SuperController.LogError(DateTime.Now +" PluginState CharacterEvent " + e.eventName);
            switch (e.eventName)
            {
                case "GpuTextureData":
                    //texture data for character has been stored
                    Data.InitRenderers(CharacterState);
                    break;

                case "_isMale":
                    PluginSettings.IsMale = e._isMale;
                    break;

                case "_uvSetName":
                    PluginSettings.UVSetName = e._uvSetName;
                    break;
            }
        }
Not active in Beta 2.5

JSON:
            this.request = request;
            loaded = true;
            SuperController.LogError("Decal Maker assetbundle loaded and ready " +DateTime.Now);
        }

JSON:
        public void Destroy()
        {
            AssetLoader.DoneWithAssetBundleFromFile(path);
            //request = null;
            loaded = false;
            SuperController.LogError("Decal Maker assetbundle unloaded " + DateTime.Now);
          
            foreach (GameObject obj in InstancedObjects)
            {
                GameObject.Destroy(obj);
            }
            InstancedObjects = new List<GameObject>();
        }

JSON:
        void CharacterEvents(object o, CharEventArgs e)
        {
            SuperController.LogError(DateTime.Now + " BaseREnderer CharacterEvent " + e.eventName);
            switch (e.eventName)
            {
                case "GpuTextureData":
                    //texture data for character has been stored
                    //Debug.LogError(DateTime.Now+" BaseRender GpuTextureData " + e.daskin?.name + " " + e.dAZCharacter?.name);
                    IsDirty = true;
                    break;

                case "_uvSetName":
                    SetClipAction();
                    break;
            }
        }
These asset load/unloads were using SuperController log by mistake and will be fixed next release.

JSON:
        public void Update()
        {
            SuperController.LogError("OnLateUpdate()");
            if (IsDirty)
            {
                SuperController.LogError("IS DIRTY!" + _MaterialSlot + " " + _TextureSlot);
                if (!Processing)
                {
                    dirtyTimeStart = dirtyTime;
                    Processing = true;
                    StartCoroutine(ApplyChanges());
                }
            }
        }
Also not active in Beta2.5
 
Hi.
tried yesterday a little bit. I noticed one thing.
When I scale a "normal" texture, it doesn't work. You can move and rotate the "normal" texture, but the scaling doesn't work.
thanks and keep up the good work.
 
Back
Top Bottom