├── .github └── FUNDING.yml ├── ADOverhaul ├── CHANGELOG.md └── README.md ├── ControllerEditor ├── Changelog.txt ├── Info_Images │ ├── AllConditions.gif │ ├── CleanupAssets.gif │ ├── CopyConditions.gif │ ├── CopySettings.gif │ ├── MakeTransitions.gif │ ├── MergeConditions.gif │ ├── RedirectTransitions.gif │ ├── RemakeTransitions.gif │ ├── ReverseTransitions.gif │ ├── SeparateConditions.gif │ ├── SharedConditions.gif │ ├── SwitchConditions.gif │ └── TransitionEdit.gif ├── Instructions.txt └── README.md ├── Duplicate With Materials ├── DuplicateWithMaterials.cs ├── Instructions.txt ├── README.md └── info_image │ ├── DupeWindow.png │ ├── newmats.gif │ └── settings.jpg ├── LICENSE ├── Other ├── DreadBanner.png ├── DreadHeart.png ├── DreadLogo.png ├── Info_Source │ ├── Hammy Follower │ │ ├── HowTo.md │ │ └── ToU.txt │ └── PhysBoneConverter │ │ ├── showcase.gif │ │ └── toolwindow.png ├── Privacy Policy.md └── Terms of Service.md ├── PasswordCreator ├── Changelog.txt ├── Info_Images │ ├── Input.png │ ├── Modules.png │ ├── PWSettings.gif │ └── PWSetup.gif └── README.md ├── README.md ├── Script Tracker ├── Default Settings.asset ├── Instructions.txt ├── README.md ├── ScriptTracker.cs └── ScriptTrackerSettings.cs └── Texture Utility ├── Editor.meta ├── Editor ├── TextureAutoPacker.cs ├── TextureAutoPacker.cs.meta ├── TextureAutoPackerData.cs ├── TextureAutoPackerData.cs.meta ├── TextureAutoPackerModule.cs ├── TextureAutoPackerModule.cs.meta ├── TextureUtility.cs └── TextureUtility.cs.meta ├── Info_images ├── PackWindow.png └── TextureWindow.png ├── README.md ├── Texture Auto-Packer Instructions.txt ├── Texture Auto-Packer Instructions.txt.meta ├── Texture Utility Instructions.txt └── Texture Utility Instructions.txt.meta /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: Dreadrith 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /ADOverhaul/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v0.11.1 2 | ------- 3 | - [Fix] Fixed 'Apply Changes' losing the reference to the root, ignoreTransforms and Colliders. 4 | - [Fix] Fixed 'Parameter' being grayed out if no controller parameter has an underscore. 5 | - [Fix] Fixed inability to use orbit view (Alt+Left Mouse) when in PB edit mode. 6 | - [Fix] Fixed Object Selector in Unity 2022 7 | - [UI] Added option to toggle animated foldouts 8 | - [Misc] Set a minimal Unity version so that it doesn't give you a popup in VCC 9 | 10 | v0.11.0 11 | ------- 12 | - [CRITICAL] Migrated to new licensing! Faster, more stable, and more features. 13 | - [Feature] Curve editing through the scene window! 14 | - [Feature] Added 'Apply Changes' button to testing to apply new testing settings. 15 | - [Feature] Added 'Restart' button to testing to reset transforms and apply new collider settings. 16 | - [Feature] Added an option to ignore scene-view clicks while editing through the scene-view. This is to handle mis-clicks when selecting or editing properties. 17 | - [Feature] On-scene tool selection and tooltips to minimize need for inspector. 18 | - [Feature] Go into editing with Ctrl+e while the ADO GUI is focused. 19 | - [Feature] Added an overlay to warn about disabled gizmos while editing. 20 | - [Feature] Added an option to hide native tools when testing physbones and colliders. 21 | - [Improvement] Added all the missing properties for Physbones. 22 | - [Improvement] Made testing physbones more seamless by keeping your selection on the duplicated objects. 23 | - [Improvement] Made it possible to add the physbone parameters to controllers individually rather than all at once. 24 | - [Fix] Fixed physbones not updating in runtime or testing when editing with ADO's inspector. 25 | - [Misc] Minor UI changes. 26 | 27 | v0.9.12 28 | ------- 29 | - [Feature] Added window DreadTools > Avatar Dynamics Overhaul. This is currently only for cosmetic options. Will be used for quick setup features in the future. 30 | - [Feature] Added "Global" option for PhysBone Gizmo. Disables and Enables whether all PhysBones should share Gizmo options. 31 | - [Feature] Added color fields in options to change the colors of the spheres for picking and selection 32 | - [Improvement] Handle size is now saved. 33 | 34 | v0.9.11 35 | ------- 36 | - [Feature] Context Menu options to transform Colliders and Contacts to the other AD types, excluding PhysBones. i.e: To Collider, To Sender, To Receiver. 37 | - [Fix] Gave more room for sliders so they don't disappear as often 38 | - [Fix] Removed the dumb float field at the top of the editor 39 | - [Misc] Added a helpbox that appears if not verified notifying confused users to delete the script if they somehow imported it without knowing 40 | - [Misc] Suppressed "Authorized" console message if Cache authorized 41 | 42 | v0.9.10 43 | ------- 44 | - [Feature] PhysBones affected parameters can now be instantly added to a chosen playable layer. 45 | - [Feature] Parameters can now be instantly added to a chosen playable layer. 46 | - [Improvement] PhysBones will now show the parameter values during playmode such as _IsGrabbed, _Angle and _Stretch. 47 | - [Improvement] Contact Receiver Parameter will now show the parameter value during playmode. 48 | - [Improvement] PhysBones parameter will now only show parameters that end with _IsGrabbed, _Angle or _Stretch. 49 | - [Improvement] Collision tag dropdown will no longer show default collision tags in the main list 50 | - [Improvement] Improved the "Target Avatar" field to be a dropdown 51 | - [Misc] Minor UI Changes 52 | 53 | v0.9.9 54 | ------ 55 | - [Fix] Updated ADO to include Immobile type & "Bones as Spheres". 56 | - [Fix] Made it possible to edit multiple AD components on the same object 57 | 58 | v0.9.8 59 | ------ 60 | - [Feature] Implemented Editor testing for PhysBones 61 | 62 | v0.9.7 63 | ------ 64 | - [Feature] Implemented Contact Sender and Receiver Editors 65 | - [Feature] Option to Change the size of selection handles when selecting or copying ignores and colliders 66 | - [GUI] Handles use a tint of color based on component 67 | - [UI] Minor Miscellanous UI Changer 68 | 69 | v0.9.0 70 | ------ 71 | Initial Pre-release 72 | -------------------------------------------------------------------------------- /ADOverhaul/README.md: -------------------------------------------------------------------------------- 1 | # Avatar Dynamics Overhaul 2 | ADO is almost ready but still under development. Read more on [Gumroad](https://www.dreadrith.com/l/ADOverhaul). 3 | 4 | ![](https://public-files.gumroad.com/ymzgjzvfakm6ooqsxtncenimxqa1) -------------------------------------------------------------------------------- /ControllerEditor/Changelog.txt: -------------------------------------------------------------------------------- 1 | (v3.4.0) 2 | -------- 3 | - [Feature] Template controllers can now be assigned and unassigned through the templates dropdown in the Animator window. 4 | - [Improvement] Motions used in Templates that exist in Packages will now be copied to the save location specified in the settings. This allows you to more easily export these motions. 5 | - [Fix] Fixed Controlled Editor requiring the Avatars SDK to run 6 | - [Fix] Fixed templates adding the original parameter when merging a template controller. 7 | - [Fix] Fixed layer view not refreshing properly on compact view change. 8 | - [UI] Minor UI tweaks, including version and license display. Can now hide your username. 9 | - [Misc] Template Motions will now have their "T_" cut from their name when copied. 10 | - [Misc] Modified some existing templates to have more dynamic naming. 11 | - [Misc] Due to changes with how Templates work, holding control or shift when adding a template will no longer auto-disable "Unique" parameter. Alternative is setting its default state through the Settings > Defaults > Other. 12 | 13 | (v3.3.2) 14 | -------- 15 | - [Fix] Animator Controller: Fixed base template parameters being included when merging template controllers even when renamed. 16 | - [Fix] Animator Controller: Made the "+" on States for quick anim clip work only on left click. This fixes it getting stuck on mouse if hovered when trying to drag the graph. 17 | - [Fix] Animator Controller: Fixed placeholder labels being aligned to the left instead of the right in the Quick Toggle window. 18 | 19 | (v3.3.1) 20 | -------- 21 | - [Critical Fix] Fixed Unity crashing when any 'Quick Input' window gets opened, such as Parameter Rename, Animator Selection, New Category Tag, and Quick Toggle. 22 | - [Fix] Fixed CE defaulting to "Verify On Display" instead of "Verify On Project Load", making it not patch unless opened. 23 | - [Known Issue] Compact layer view may require being unfocused, then focused again to fix the element height. Usually after recompiling. 24 | - [Known Issue] Some node styles may not apply completely correctly when patching. 25 | - [Known Issue] Some controller templates used may include clips that are in Packages. These clips normally don't get included in packages being exported. 26 | 27 | (v3.3.0) 28 | -------- 29 | - [CRITICAL] Controller Editor's source code has been heavily refactored and reorganized to allow easier updates. Due to the size of CE, this may have introduced a number of new bugs or unexpected changes. Please report such things if you encounter them. 30 | - [Feature] Animator Controller: Category View! Layers can now be viewed in Category based on Name Path such as Toggles/Head/Hat, or layer tags in the format of _category:path/name. Can category tag with context menu. Categories and layers are sorted alphabetically. 31 | - [Feature] Animator Controller: Compact View! Layers can now be viewed in a condensed way that only displays their index and name. 32 | - [Feature] Animator Controller: Can press a keyboard character to focus the next layer that starts with that character. 33 | - [Feature] Animator Controller: Can Drag N Drop Motions to BlendTrees to add them to it or replace a clip. 34 | - [Feature] Animator Controller: Added 'Animate' to Parameters to more easily add them to the activate animation in the animation window. 35 | - [Feature] Animator Controller: Selected states will have in and out transitions arrow animated. Toggleable in settings. 36 | - [Feature] Animator Controller: Arrows on transitions are now shifted to make it easier to see their direction. Adjustable in settings. 37 | - [Feature] Animator Controller: Pasted states are now auto-selected. 38 | - [Feature] Animator Controller: Implemented state styles. Right click a state to set a style for it. 39 | - [Feature] Animation Window: Material Shader Properties will now also show up when setting Property Name for a Renderer. Renderer must exist in the same path as the property from the root. 40 | - [Fix] Animation Window: Improved positioning of windows that appear in the animation window. May still appear way off. 41 | - [Fix] Animation Window: Fixed some bugs with animation window properties with children such as transform's 'Position' property. 42 | - [Fix] Animation Window: Minor tweaks and fixes with Drag&Drop to the animation window. 43 | - [Fix] Animator Controller: Fixed renaming with F2 showing the layer 0 name for rename start. 44 | - [Fix] Animator Controller: Fixed double transition getting created when making a transition to an empty sub-statemachine. 45 | - [Fix] Animator Controller: Fixed inability to edit anystate transitions in sub-statemachines 46 | - [Misc] Animator Controller: Auto-Frame will no longer frame the layer if it's the one already being inspected. 47 | - [Misc] Animator Controller: Holding shift when adding template will no longer insta-confirm it and will instead turn off "Unique parameter" and show the window anyway. 48 | - [UI] CE Window: The collapse button is now automatically set to the height of its part. It used to be hardcoded height. You may see some repaint delay when heights change due to this. 49 | - [UI] Rearranged and added options in the settings window. 50 | 51 | (v3.2.1) 52 | -------- 53 | - [Feature] Drag & Drop GameObjects to the animation window to add them as a new curve. Settings option included. 54 | - [Fix] Fixed an issue with selecting transitions. 55 | - [Fix] Fixed an issue with transition names expanding the window's width too much. (@gonsodany) 56 | 57 | (v3.2.0) 58 | -------- 59 | - [Feature] Added Context menu options to motions for embedding, extracting and renaming motions. 60 | - [Improvement] Quick Toggle (Drag & Drop GameObject to State) on a state with the default motion will always be set to "Replace" the motion by default. 61 | - [Fix] Fixed Animation Window suffering from erroneous resizing when the window is patched. 62 | - [Fix] Fixed condition and settings not working on sub-selected transitions (Selecting a transition from the transition count section). 63 | - [Fix] Disabled Harmony when VRCSDK is included. 64 | - [Misc] Added a warning to layer if machine is null. More warnings will be added in the future. 65 | - [Misc] Made conditions header buttons change cursor to link/index. 66 | 67 | (v3.1.1) 68 | -------- 69 | - [Feature] Animation Window: Right click to 'Set Property Name' for a property 70 | - [Feature] Animation Window: Right click to 'Set Type' for a property. 71 | - [Known Issue] Property and Type windows may sometimes appear far from the selected property 72 | 73 | (v3.1.0) 74 | -------- 75 | - [Feature] License Transfer is now done through e-mail verification! 'Security Details' have been scrapped due to being confusing and ineffective. 76 | - [Feature] Animation Window: Explicitly set the animator controller and relative root for pathing. 77 | - [Feature] Animation Window: Drag n Drop GameObjects to a property to change its path. 78 | - [Feature] Animation Window: Automatically switches to the animation clip in the selected animator state. 79 | - [Fix] Fixed a code issue that caused considerable lag whenever selecting anything. 80 | - [Fix] Fixed template controllers not duplicating animation clips with T_ as a prefix if no parameters were renamed 81 | - [UI] Modified window toolbar. Shows the tab when the corresponding object is selected OR when toolbar option is enabled. 82 | 83 | (v3.0.0) 84 | -------- 85 | - [CRITICAL] Implemented new licensing! Stabler. Much better response time. Less down time. Manual license transfer, bug reporting and feedback features! 86 | - [Improvement] Failed patches won't make other patches fail too and can now retry. 87 | - [Fix?] A patch may fail due to special characters in the project name. Retrying patching should fix it. 88 | 89 | (v2.9.4) 90 | -------- 91 | - [CRITICAL] Fixed an issue that causes CE to lockup when going into playmode with domain reload. 92 | - [Feature] Added 'Convert' to animator parameters for all types. Note: Converted parameters may not handle conditions the same way they did with their original type. 93 | - [Feature] Added 'Sample from Active StateMachine' to Layer node positions. 94 | - [Feature] Added 'Reverse Adjusts Values' to settings. This will modify the value/threshold of conditions with less/greater when reversing to properly reflect the opposite value. 95 | - [Fix] Parameter rename window will now appear in the middle of your animator window 96 | - [Fix] Fixed restoring default settings for 'Default State' setting name as blank. 97 | - [Misc] Moved 'Legacy Dropdown' to window's context menu 98 | 99 | (v2.9.2) 100 | -------- 101 | - [CRITICAL] Fixed an inconsistent bug that sometimes causes the HWID to be reported incorrectly or the authentication dropping randomly. 102 | - [Improvement] Massively improved the speed of renaming behaviour parameters when renaming through the parameters list. 103 | - [Fix] Transitions from state to itself will now always have 'Can Transition To Self' On regardless of default settings. 104 | - [UI] Clips with loop time On now have a loop icon on states. 105 | - [Misc] Update checker doesn't require you to open the settings anymore 106 | 107 | (v2.9.1) 108 | -------- 109 | - [Feature] Added ability to choose whether Quick Toggle merges with existing clips or replaces them. 110 | - [Fix] Fixed Quick Toggle window appearing tiny in the top left corner of the screen 111 | - [Fix] Fixed layer's default node positions not changing and saving 112 | 113 | (v2.9.0) 114 | -------- 115 | - [Feature] Implemented CE QuickToggle! Drag and Drop a gameobject to a state to use. 116 | - [Feature] Implemented Template dynamic renaming! 117 | - [Feature] Right click a condition's parameter to change it using keyboard. Write a non-existent parameter to add it quickly. 118 | - [Feature] Implemented custom condition matchin options. Click the cog icon on conditions to activate temporarily. 119 | - [Feature] Ability to set default Entry, Exit and AnyState positions for newly added layers. 120 | - [Feature] Added 'Add Root Tree' to Blendtree nodes. 121 | - [Improvement] If multiple states are selected, drag n drop of motion onto one of those states will set it for all of them 122 | - [Fix] Fixed new empty states not using custom default motion. 123 | - [Fix] Fixed inability to undo condition changes. 124 | - [Fix] Fixed Quick Clip ('+') opening your documents as path by default due to previously saving a clip in a location that doesn't exist in the current project. 125 | - [Fix] Fixed the ability to brick your controller by replicating an Exit transition from Entry. 126 | - [Fix] Fixed Replace Parameter only affecting the second parameter of 'Copy' parameter drivers. 127 | - [Fix] Fix clearing settings not working properly if settings window wasn't opened beforehand. 128 | - [UI] Fixed the 'Add' button for missing parameters going outside the alloted GUI area 129 | - [UI] Fixed minor GUI issue with Trigger conditions 130 | - [Patch] Renaming parameter will also reflect in parameter drivers 131 | - [Patch] Adding a parameter will now make the scrollbar go down to the bottom. 132 | - [Patch] Visual indicator to differentiate between float and integer parameters easier. 133 | - [Misc] Slight changes to saving and settings UI. Made need to set some settings again. 134 | - [Misc] States with (WD on/off) in their name will now be ignored when mass setting write defaults 135 | 136 | (v2.8.4) 137 | -------- 138 | - [Fix] Fixed Transitions to StateMachine not using custom default settings 139 | - [Fix] Fixed blend tree parameters not copying when using the controller tab copy function 140 | - [Fix] States alignment using 'Align Horizontal' and 'Align Vertical' can now undo 141 | - [Fix] Automatically refreshes graph when making multiple transitions from Entry 142 | - [Misc] Inverted 'Alternate Double Click''s Behaviour so that Off would be using Unity's native Double Click behaviour. Sorry for any confusion! 143 | - [Misc] Added 'Instructions' to CEditor's context menu and a help button next to settings button to open CEditor's manual. 144 | 145 | (v2.8.3) 146 | -------- 147 | - [Fix] Fixed inability to access SubStateMachines 148 | - [Misc] Replaced funky "X" button on lists with the usual reorderable list's '-' button 149 | - [Misc] Alternate Double Click is now on by default for first use 150 | 151 | (v2.8.2) 152 | -------- 153 | - [Feature] Added Copy, Paste and Remove for behaviours on States and Statemachines 154 | - [Fix] If using Ctrl for chain connecting, you now can still connect to and start connecting from target state with double click 155 | - [Fix] Fixed redirect transition not redirecting to Exit if only Exit is selected. 156 | - [Fix] Fixed Any and Entry requiring Ctrl to start chain connecting 157 | 158 | (v2.8.1) 159 | -------- 160 | - [Feature/Misc] Added "Fake Transition*". Read note below. 161 | - [Fix] Fixed pressing enter toggles 'Make Multiple Transitions' 162 | - [Fix] Removed debug from dev testing 163 | - [Misc] New empty states will now be named the same as the default state in settings. 164 | - [Misc] Re-enabled state name editing for selected states settings. 165 | - [Misc] Re-enabled state name editing for default state's settings. 166 | - [Misc] Changed main tabs toggle functionality. Ctrl/Shift click to enable multiple. 167 | 168 | Fake Transition: Do Ctrl+Shift+Click (x2) on any Node to do a fake transition. 169 | You can make a transition from ANY node to ANY other node including itself. These transitions are only for fun. They aren't functional and will not be saved. 170 | They may throw an error rarely but should be relatively safe. 171 | -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/AllConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/AllConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/CleanupAssets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/CleanupAssets.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/CopyConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/CopyConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/CopySettings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/CopySettings.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/MakeTransitions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/MakeTransitions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/MergeConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/MergeConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/RedirectTransitions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/RedirectTransitions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/RemakeTransitions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/RemakeTransitions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/ReverseTransitions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/ReverseTransitions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/SeparateConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/SeparateConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/SharedConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/SharedConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/SwitchConditions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/SwitchConditions.gif -------------------------------------------------------------------------------- /ControllerEditor/Info_Images/TransitionEdit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/ControllerEditor/Info_Images/TransitionEdit.gif -------------------------------------------------------------------------------- /ControllerEditor/Instructions.txt: -------------------------------------------------------------------------------- 1 | Made by Dreadrith#3238 2 | Server: https://discord.gg/ZsPfrGn 3 | Github: https://github.com/Dreadrith/DreadScripts 4 | Gumroad: https://gumroad.com/dreadrith 5 | Ko-fi: https://ko-fi.com/dreadrith 6 | 7 | Controller Editor now has an organized manual for instructions thanks to JustSleightly! 8 | Manual: https://notes.sleightly.dev/ceditor -------------------------------------------------------------------------------- /ControllerEditor/README.md: -------------------------------------------------------------------------------- 1 | ![Controller Editor](https://cdn.discordapp.com/attachments/750900715693539438/874198637289308180/AllTransitioning.gif) 2 | 3 | Utility Release. This ReadMe is somewhat outdated and requires updating. Various functions have been added since. 4 | 5 | # Controller Editor 6 | Controller Editor will make your work with anything controller related just a breeze! Save yourself the tediousness and the time wasted on repetitively doing the same thing with the convenience of this tool! 7 | 8 | ![TransitionsEdit](https://cdn.discordapp.com/attachments/750900715693539438/874447556950782072/ThumbTransitioning.gif) 9 | 10 | Controller Editor adds easy to use functions to the animator window and has many features to make it all easy. 11 | Some of the best features: 12 | 13 |

Transitions

14 | 20 | 21 |

States

22 | 27 | 28 |

Controller

29 | 33 | 34 | 35 | And a bunch more! 36 | Buy on the Gumroad! 37 | 38 |

Examples of some features and their use cases

39 | 40 | State MultiTransitioning 41 | Double Clicking an Animator State will enter MultiTransitioning mode. Single Click to connect and continue, Double Click to connect and transfer to destination. Click elsewhere to stop. 42 | 43 | ![State MultiTransitioning](https://cdn.discordapp.com/attachments/813830389033467904/874384002692304976/QuickTransitioning.gif) 44 | 45 | Make Multiple Transitions 46 | Available under the Animator State context menu 47 | (Toggle) Connect many previously selected Nodes with many currently selected Nodes. 48 | Toggle Off or Press Enter to confirm. Press Esc to cancel. 49 | 50 | ![Make Multiple Transitions](https://cdn.discordapp.com/attachments/813830389033467904/874384788532899920/ManyTransitions.gif) 51 | 52 | Reverse Transitions 53 | Available under the Transitions context menu. 54 | Makes a transition that switches the target's Source and Destination while maintaining settings and conditions. 55 | 56 | ![Reverse Transitions](https://cdn.discordapp.com/attachments/813830389033467904/874385287713796156/ReversingTransitions.gif) 57 | 58 | Replicate/Redirect Transitions 59 | Available under the Transitions context menu. 60 | (Toggle) Makes a transition that changes its Source (Replicate) Or Destination (Redirect) while maintaining settings and conditions. 61 | Toggle Off or Press Enter to confirm. Press Esc to cancel. 62 | 63 | ![Replicate/Redirect Transitions](https://cdn.discordapp.com/attachments/813830389033467904/874385891513229312/TrafickingTransitioning.gif) 64 | 65 | From/To Any Transition 66 | Available under the Transitions context menu. 67 | Switches the transition From or To an Any State transition while maintaining settings and conditions. 68 | If switching FROM AnyState, it replicates the transition from every other state. 69 | 70 | ![From/To Any Transition](https://cdn.discordapp.com/attachments/813830389033467904/874386993029726208/AnyTransitioning.gif) 71 | 72 | Select In / Out / Shared Transitions 73 | Available under the State context menu 74 | Selects ingoing (in) transitions. Outgoing (out) transitions. Or Shared transitions: transitions that have their Source and Destination currently selected. 75 | 76 | ![Select In / Out / Shared Transitions](https://cdn.discordapp.com/attachments/813830389033467904/874387508090241024/SelectingTransitions.gif) 77 | 78 | Pack/Unpack StateMachines 79 | Available under States/StateMachines context menu. 80 | Packs Selected Nodes into a new StateMachine and vice versa 81 | 82 | ![Pack/Unpack StateMachines](https://cdn.discordapp.com/attachments/813830389033467904/874390637934428250/PackingTransitioning.gif) 83 | 84 | Duplicate or Copy/Paste Layers 85 | Available under the Layer View context menu. 86 | Allows the recreation of a whole Layer and its StateMachines in 2 clicks. Can be used across Controllers. 87 | 88 | ![Duplicate or Copy/Paste Layers](https://cdn.discordapp.com/attachments/813830389033467904/874391450878627920/savedTransitioning.gif) 89 | 90 | Editing Transition Settings 91 | You can edit multiple transition's settings through the window. You can also Copy and Paste the settings. 92 | 93 | ![Editing Transition Settings](https://cdn.discordapp.com/attachments/813830389033467904/874428628635639879/EditingTransitions.gif) 94 | 95 | Editing Shared Conditions 96 | You can edit or add Conditions that are the same between the selected Transitions. You can also Copy and Paste the Conditions. 97 | 98 | ![Editing Shared Conditions](https://cdn.discordapp.com/attachments/813830389033467904/874429336088891412/sharingTransitioning.gif) 99 | 100 | **Editing All Conditions** 101 | You can edit all the Conditions that stack up based on the selection order. Press Up and Down arrow to move between Value fields. 102 | 103 | ![Editing All Conditions](https://cdn.discordapp.com/attachments/813830389033467904/874429789644161024/SpeedrunTransitioning.gif) 104 | 105 | **Editing VRC Parameter Drivers** 106 | You can edit or add Parameters to VRC P-Drivers that are the same. 107 | 108 | ![Editing VRC Parameter Drivers](https://cdn.discordapp.com/attachments/813830389033467904/874444928749563924/VRCTransitioning.gif) 109 | 110 | **Other Features** 111 | You can flip the mode of the conditions 112 | You can Merge multiple transitions into one transition that has all the previous transitions' conditions 113 | You can Separate a transition into multiple transitions that each have one of the previous conditions. 114 | 115 | ![Other Features](https://cdn.discordapp.com/attachments/813830389033467904/874445675046273034/FlexibleTransitioning.gif) 116 | 117 | **Other Settings** 118 | You can set the default settings of newly created Transitions and States. 119 | You can set the default layer weight of newly created layers. 120 | You can set Selected Transitions and Entry Transition Color. 121 | 122 | ![Other Settings](https://cdn.discordapp.com/attachments/813830389033467904/874446736494567485/defaultingTransitioning.gif) 123 | -------------------------------------------------------------------------------- /Duplicate With Materials/DuplicateWithMaterials.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace DreadScripts 9 | { 10 | public class DuplicateWithMaterials : EditorWindow 11 | { 12 | public static GameObject target; 13 | public static string targetPath; 14 | public static bool separateShared; 15 | 16 | 17 | public static void CreateVariant(GameObject targetObject) 18 | { 19 | string folderPath = PlayerPrefs.GetString("DupeWithMatsPath", "Assets/DreadScripts/Duplicate With Materials/Generated Materials"); 20 | bool separateSharedMaterials = PlayerPrefs.GetInt("DupeWithMatsSep", 1) == 1; 21 | Dictionary matDict = new Dictionary(); 22 | ReadyPath(folderPath); 23 | 24 | string assetPath = ""; 25 | string subFolderPath = ""; 26 | 27 | GameObject dupeObj = Instantiate(targetObject); 28 | List myRenderers = dupeObj.GetComponentsInChildren(true).ToList(); 29 | 30 | if (myRenderers.Count > 0) 31 | { 32 | assetPath = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + targetObject.name); 33 | AssetDatabase.CreateFolder(folderPath, assetPath.Substring(assetPath.LastIndexOf('/') + 1, assetPath.Length - assetPath.LastIndexOf('/') - 1)); 34 | 35 | for (int i = 0; i < myRenderers.Count; i++) 36 | { 37 | if (!AssetDatabase.IsValidFolder(assetPath + "/" + myRenderers.ElementAt(i).gameObject.name + " Materials")) 38 | { 39 | AssetDatabase.CreateFolder(assetPath, myRenderers.ElementAt(i).gameObject.name + " Materials"); 40 | subFolderPath = assetPath + "/" + myRenderers.ElementAt(i).gameObject.name + " Materials"; 41 | } 42 | 43 | Material[] newMaterials = myRenderers.ElementAt(i).sharedMaterials; 44 | for (int j = 0; j < myRenderers.ElementAt(i).sharedMaterials.Length; j++) 45 | { 46 | if (!myRenderers[i].sharedMaterials[j]) 47 | continue; 48 | if (!separateSharedMaterials && matDict.ContainsKey(myRenderers[i].sharedMaterials[j])) 49 | { 50 | newMaterials[j] = matDict[myRenderers[i].sharedMaterials[j]]; 51 | continue; 52 | } 53 | string matPath = AssetDatabase.GetAssetPath(myRenderers[i].sharedMaterials[j]); 54 | if (PrefabUtility.IsPartOfModelPrefab(myRenderers[i].sharedMaterials[j]) || matPath.IndexOf("Assets") != 0) 55 | { 56 | Material instantiatedMaterial = Instantiate(myRenderers[i].sharedMaterials[j]); 57 | string uniquePath = AssetDatabase.GenerateUniqueAssetPath(subFolderPath + "/" + myRenderers[i].sharedMaterials[j].name + ".mat"); 58 | AssetDatabase.CreateAsset(instantiatedMaterial, uniquePath); 59 | newMaterials[j] = AssetDatabase.LoadAssetAtPath(uniquePath); 60 | } 61 | else 62 | { 63 | newMaterials[j] = CopyAssetAndReturn(matPath, AssetDatabase.GenerateUniqueAssetPath(subFolderPath + "/" + myRenderers[i].sharedMaterials[j].name + ".mat")); 64 | } 65 | if (!separateSharedMaterials) 66 | matDict.Add(myRenderers[i].sharedMaterials[j], newMaterials[j]); 67 | } 68 | myRenderers[i].sharedMaterials = newMaterials; 69 | } 70 | } 71 | 72 | string[] subDirectories = System.IO.Directory.GetDirectories(assetPath); 73 | foreach (string s in subDirectories) 74 | { 75 | if (!System.IO.Directory.EnumerateFileSystemEntries(s).Any()) 76 | { 77 | FileUtil.DeleteFileOrDirectory(s); 78 | FileUtil.DeleteFileOrDirectory(s + ".meta"); 79 | } 80 | } 81 | 82 | AssetDatabase.Refresh(); 83 | EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(assetPath)); 84 | 85 | } 86 | 87 | [MenuItem("DreadTools/Utilities/Dupe With Mats")] 88 | public static void showWindow() 89 | { 90 | DuplicateWithMaterials win = GetWindow(false, "Dupe With Mats", true); 91 | win.minSize = new Vector2(400, 120); 92 | win.maxSize = new Vector2(400, 120); 93 | } 94 | private void OnGUI() 95 | { 96 | target = (GameObject)EditorGUILayout.ObjectField("Target", target, typeof(GameObject), true); 97 | 98 | separateShared = EditorGUILayout.Toggle(new GUIContent("Separate Shared Materials", "Force each material slot to have its own material."), separateShared); 99 | 100 | if (GUILayout.Button("Create Variant", "toolbarbutton")) 101 | CreateVariant(target); 102 | EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); 103 | AssetFolderPath(ref targetPath, "New Materials Path", "DupeWithMatsPath"); 104 | using (new GUILayout.HorizontalScope()) 105 | { 106 | GUILayout.FlexibleSpace(); 107 | if (GUILayout.Button("Made By Dreadrith#3238","boldlabel")) 108 | Application.OpenURL("https://linktr.ee/Dreadrith"); 109 | } 110 | } 111 | 112 | private void OnEnable() 113 | { 114 | targetPath = PlayerPrefs.GetString("DupeWithMatsPath", "DreadScripts/Duplicate With Materials/Generated Materials"); 115 | } 116 | 117 | private static void ReadyPath(string path) 118 | { 119 | if (!Directory.Exists(path)) 120 | Directory.CreateDirectory(path); 121 | } 122 | private static T CopyAssetAndReturn(string path, string newpath) where T : Object 123 | { 124 | if (path != newpath) 125 | AssetDatabase.CopyAsset(path, newpath); 126 | return AssetDatabase.LoadAssetAtPath(newpath); 127 | 128 | } 129 | private static void AssetFolderPath(ref string variable,string title, string playerpref) 130 | { 131 | using (new GUILayout.HorizontalScope()) 132 | { 133 | EditorGUI.BeginDisabledGroup(true); 134 | EditorGUILayout.TextField(title, variable); 135 | EditorGUI.EndDisabledGroup(); 136 | if (GUILayout.Button("...", GUILayout.Width(30))) 137 | { 138 | var dummyPath = EditorUtility.OpenFolderPanel(title, AssetDatabase.IsValidFolder(variable) ? variable : string.Empty, string.Empty); 139 | if (string.IsNullOrEmpty(dummyPath)) 140 | return; 141 | 142 | if (!dummyPath.StartsWith("Assets")) 143 | { 144 | Debug.LogWarning("New Path must be a folder within Assets!"); 145 | return; 146 | } 147 | 148 | variable = FileUtil.GetProjectRelativePath(dummyPath); 149 | PlayerPrefs.SetString(playerpref, variable); 150 | } 151 | } 152 | } 153 | 154 | } 155 | } 156 | #endif -------------------------------------------------------------------------------- /Duplicate With Materials/Instructions.txt: -------------------------------------------------------------------------------- 1 | Made by Dreadrith#3238 2 | Server: https://discord.gg/ZsPfrGn 3 | 4 | Version: v1.0.2 5 | Link: https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/DupeWithMats.unitypackage 6 | 7 | Duplicate with Materials is made for the purpose of creating Variants of an Object/Avatar quickly by Duplicating the target and replacing its materials with a new copy of them. 8 | 9 | Steps: 10 | 1- Open the window (DreadTools > Utilities > Dupe with Mats) 11 | 2- Place your target in the Game Object field 12 | 3- Press "Create Variant". 13 | 14 | This tool will duplicate your Target, replace all its materials and create a folder in the chosen path which contains the newly created materials. 15 | 16 | Separate Shared Materials option: Materials that are reused accross multiple renderers will instead have a separate material for each material slot. 17 | -------------------------------------------------------------------------------- /Duplicate With Materials/README.md: -------------------------------------------------------------------------------- 1 | # Duplicate With Materials 2 | Latest Version: v1.0.2 3 | Download Duplicate With Materials 4 | 5 | Duplicate With Materials was made to instantly allow you to make new variations of an Avatar without having to go through each Renderer and replace its materials. 6 | Using this tool will make a duplicate of your Object and replaces all its Materials with a duplicate of each one. 7 | 8 | ![Window](https://github.com/Dreadrith/DreadScripts/blob/main/Duplicate%20With%20Materials/info_image/DupeWindow.png) 9 | ![Creation](https://github.com/Dreadrith/DreadScripts/blob/main/Duplicate%20With%20Materials/info_image/newmats.gif) 10 | 11 | # Settings 12 | You can choose where to save the generated materials using its Settings Window. 13 | There is also an option to force each material slot to have its own unique Material rather than Maintaining common materials by checking "Separate Shared Materials". 14 | 15 | # Extra 16 | Duplicate With Materials will: 17 | - Create a Unique folder for the new Duplicate in the path chosen. 18 | - Separate Materials into folders named by the objects they reside on. 19 | - Automatically Re-create folders for its path if needed. 20 | - Automatically maintain common materials between Renderers that have been Duplicated. 21 | - Automatically handle duplicating built-in Materials. 22 | - Automatically handle model-embedded Materials. 23 | -------------------------------------------------------------------------------- /Duplicate With Materials/info_image/DupeWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Duplicate With Materials/info_image/DupeWindow.png -------------------------------------------------------------------------------- /Duplicate With Materials/info_image/newmats.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Duplicate With Materials/info_image/newmats.gif -------------------------------------------------------------------------------- /Duplicate With Materials/info_image/settings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Duplicate With Materials/info_image/settings.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dreadrith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Other/DreadBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Other/DreadBanner.png -------------------------------------------------------------------------------- /Other/DreadHeart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Other/DreadHeart.png -------------------------------------------------------------------------------- /Other/DreadLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Other/DreadLogo.png -------------------------------------------------------------------------------- /Other/Info_Source/Hammy Follower/HowTo.md: -------------------------------------------------------------------------------- 1 | # Hammy The Follower [](https://dreadrith.com/links/ "Dreadrith") [](https://dreadrith.com/kofi/ "Store") [](https://dreadrith.com/discord/ "Discord") [](https://www.dreadrith.com/ "Store") 2 | 3 | ## Setup 4 | 5 | 1. Find the prefab 'Hammy Follower' in Assets > DreadScripts > Prefabs > Hammy Follower 6 | 2. Drag and Drop 'Hammy Follower' onto the Root* of your Avatar 7 | 3. (Optional) Move the new GameObject*, 'Hammy Follower', to where you want him to follow. 8 | 4. Tell Hammy that he's very cute. 9 | 5. Done! 10 | 11 | Root: Usually the top most object of your Avatar's hierarchy. Always the GameObject with the 'Avatar Descriptor' component.
12 | GameObject: The names you can click on under the 'Hierarchy' window. Each name represents a GameObject. 13 | 14 | Treat Hammy nicely! 15 | 16 | ## Extra 17 | Adding a Toggle: An Icon for your menu toggle is included in DreadScripts > Prefabs > Hammy Follower > Mat + Textures. 18 | As well as animations for toggling Hammy On or Off in DreadScripts > Prefabs > Hammy Follower > Animations. 19 | 20 | Hue Shifting (PC ONLY): A Mask Texture is included in DreadScripts > Prefabs > Hammy Follower > Mat + Textures. 21 | Use this to only hue shift the parts with color in them with your shader of choice. 22 | 23 | ## Optimization 24 | The following is for those that want to meet Quest Specifications and avoid reaching Very Poor performance rating or just want to optimize further. 25 | Not everything will be explained as this is for slightly advanced users. 26 | 27 | ### Hammy's Standalone Stats: 28 | | Stat | Count | 29 | | --- | --- | 30 | | Animators | 1 | 31 | | Materials | 1 | 32 | | Skinned Mesh Renderers | 1 | 33 | | Polygons | 7434 | 34 | | Bones | 33 | 35 | | PhysBone Components | 2 | 36 | | PhysBone Affected Transforms | 39 | 37 | | PC Rating | Good | 38 | | Quest Rating | Poor | 39 | 40 |
41 | 42 | The biggest rank tanker is the PhysBone Affected Transforms. This is due to having a second PhysBone component on Hammy that affects his entire skeleton. 43 | If you expand Hammy Follower enough, you'll find Container > Hammy PhysSettings. Deleting this will remove the 2nd PhysBone component and redude the affected transforms count a lot. 44 | However, this would make Hammy be very stiff (not cute!). Only way to improve this is to take Hammy to a 3D software and merge/reduce his bone count. 45 | 46 | Hammy has a cute idle animation built-in, hence the 1 animator count. This is the easiest to optimize as you can move the contents of the animator, to your main avatar descriptor and delete the animator component. 47 | You'll have to repath the animation's root, you can do it manually or use a tool like [this one](https://github.com/Dreadrith/Unity-Animation-Hierarchy-Editor). 48 | The animation contains transforms properties, and may need to be handled like you'd handle animations for non-human parts like tails and wings. Good luck! 49 | 50 | Of course, you can always optimize the mesh to reduce the polygons using a 3D modeling software. 51 | But why should Hammy be any less cute than you? 52 | 53 | ## Advanced 54 | Spazzing Issues / Scaling: Generally, scaling the prefab is ok but you may notice that things may be acting a bit weird if you scale it down too much. 55 | This is because the follower system has a limited reach and it may be hitting the limit. This is visible with the follower no longer following smoothly and instead snaps or the balloon moves 1:1 with you. 56 | If this happens, it may help to scale the system up without scaling the pet itself. 57 | To do this, you can follow these steps: 58 | 1. Unpack the follower prefab. 59 | 2. Go down the chain to 'Container' and drag it out of the system. 60 | 3. Scale up the follower prefab's root, not too much! 61 | 4. Drag and Drop 'Container' Back to where it was ('Chain 5'). 62 | 5. Done! 63 | -------------------------------------------------------------------------------- /Other/Info_Source/Hammy Follower/ToU.txt: -------------------------------------------------------------------------------- 1 | Terms of Use: 2 | ------------- 3 | - Do not use this package for any purpose if you did not purchase it from Dreadrith's Gumroad store. 4 | - Do not claim as your own. 5 | - Do not redistribute or resell this package or any of its parts on their own or an unfinished avatar. 6 | - Do not use on free or nitro Avatars or packages. 7 | - You may use this package for commercial purposes. 8 | - You may use this package on publicly and privately uploaded Avatars. 9 | - Do not mistreat Hammy! Breaking this ToU will make Hammy sad. 10 | -------------------------------------------------------------------------------- /Other/Info_Source/PhysBoneConverter/showcase.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Other/Info_Source/PhysBoneConverter/showcase.gif -------------------------------------------------------------------------------- /Other/Info_Source/PhysBoneConverter/toolwindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Other/Info_Source/PhysBoneConverter/toolwindow.png -------------------------------------------------------------------------------- /Other/Privacy Policy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Only information provided through the product's purchase is collected. 4 | [License protected products](https://dreadrith.com/license-tos) will provide the database with a Hash* from hardware identifiers to proceed with Activation and Authorization. 5 | No other information or data is sent or collected. 6 | All information collected is for the sake of the product's functionality and customer support. 7 | 8 | *Hash: A unique combination of text with one way generation from a given input. A hash can't be reverted back to its input.* 9 | -------------------------------------------------------------------------------- /Other/Terms of Service.md: -------------------------------------------------------------------------------- 1 | # Terms of Service 2 | By purchasing a product, you agree to the Terms of Service & [Privacy Policy](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Privacy%20Policy.md).
3 | **Violation of these terms will result in [blacklisting](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#blacklist)**. 4 | 5 | ## Store Rules 6 | 1. If purchasing for someone else, put the giftee's information and give them the license key (if any) for them to activate the product. 7 | 2. Refunds are viable for [licensed products](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#license-protected-product) if it has not yet been activated. No refunds otherwise due to the nature of digital products. 8 | 3. Do **NOT** [chargeback](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#tools). 9 | 4. For any questions/issues, read [here](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#contact). 10 | 11 | ## Product rules: 12 | 1. Do **NOT** attempt to disassemble or de-obfuscate any script or source code, according to DMCA Code 1201 regarding circumvention of copyright protection systems. 13 | 2. Do **NOT** use HWID Spoofers when using [licensed products](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#license-protected-product). This wouldn't be a violation in of itself but it may cause you issues with license verification and transfer guidelines. 14 | 3. Do **NOT** redistribute any file without permission or appropriate license. Follow export instructions if provided. 15 | 4. Do **NOT** claim or resell as your own. 16 | 5. The following rules apply to **ALL** products except '[Tools](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#tools)': 17 | - Do **NOT** use commercially without permission or an appropriate license, such as selling on an avatar or offering the product as a service or upsell in an upload or commission. 18 | - Do **NOT** sell on an avatar usually costing below $10. 19 | - Do **NOT** use on public releases or uploads without permission. 20 | - Credit **@Dreadrith#3238** and provide a link to my [Store](https://dreadrith.gumroad.com/). 21 | 22 | ## Other Rules 23 | **I reserve the right to refuse/refund and ban/blacklist users without appeal. Reasons for such may include but are not limited to:** 24 | 1. Affiliation with leaking/ripping/theft. 25 | 2. Affiliation with malicious parties. 26 | 3. Suspicious activity or account history/age/mutuals. 27 | 4. Demonstrating or promoting toxic behavior. 28 | 29 | ## My Part 30 | 1. Products will be updated and supported for as long as possible, but I am not liable for any changes made by Unity or VRChat that deprecate any features or functionality via software/game updates. 31 | 2. I am not liable for damage or harm caused by manipulation or misuse of the script. 32 | 3. If I quit, license protection systems will be removed from relevant products. 33 | 34 | ## License Transfer Guidelines 35 | In the event of hardware change, you may request a license transfer [by contacting me](https://github.com/Dreadrith/DreadScripts/blob/main/Other/Terms%of%Service.md#contact). License transfers will follow these guidelines: 36 | 1. License transfer is only allowed after 30 days from license activation. 37 | 2. License transfer to another user is not allowed. 38 | 3. License transfer to a device from which you've already transferred from, is not allowed. 39 | 40 | --- 41 | # Definitions 42 | ## License Protected Product 43 | License producted products are scripts that require activation using a license key. License keys are acquired after purchase and can be found in the Gumroad library content view or the receipt e-mail. 44 | ## Tools 45 | Tools are scripts that are typically used for simplifying and/or speeding up workflow, such as Avatar Dynamics Overhaul, rather than adding whole new features such as Carbon Copy. In most cases, the product's type will be listed on the product's information. 46 | ## Blacklist 47 | Users that have been blacklisted will have product and server access revoked. Any active licenses/subscriptions and services terminated without refund. In severe cases, legal action may be taken. 48 | ## Chargeback 49 | Chargeback is attempting to get a refund for a purchase without or against my discretion. 50 | 51 | --- 52 | # Contact 53 | For any questions/issues, contact me via Discord using #Support or opening a ticket on my [Discord server](https://discord.gg/ZsPfrGn) or [contacting me directly](https://discord.com/users/196328481460584448) @Dreadrith#3238 54 | -------------------------------------------------------------------------------- /PasswordCreator/Changelog.txt: -------------------------------------------------------------------------------- 1 | (v2.8.2) 2 | -------- 3 | - [CRITICAL FIX] Fixed re-lock issue when the local avatar loads after already loading the original avatar, such as with mirrors and cameras. 4 | - [Fix] Fixed some miscellaneous issues that I forgot to note down. 5 | - [Misc] Lowered time to lock the avatar from 1.5s to 0.5s 6 | 7 | (v2.8.1) 8 | -------- 9 | - [Fix] Fixed Password ReCreator (Commercial Feature) 10 | - [Fix] Name obfuscation will now only use letters and numbers as not to cause weird issues with the avatar and its animator. 11 | - [Fix] Fixed a bug that may have been causing Menu and Parameters to generate with missing references causing various weird issues. 12 | 13 | (v2.8.0) 14 | -------- 15 | - [Feature] License transfer is now done through e-mail verification! 'Security Details' have been scrapped due to being confusing and ineffective. 16 | - [Feature] Most settings are now saved! 17 | - [Feature] There's now a password history in case you forgot your password! 18 | - [Modification] Modified name obfuscation to use an explicit set of characters rather than random bytes. 19 | - [Fix] Fixed an obscure security flaw that allowed indefinite unlock time if submenu locking is used 20 | - [Fix] Fixed an issue that caused exclusively submenu locking to not work. 21 | - [Fix] Handled some cases where path generation may fail due to inconventional avatar names 22 | - [UI] Fixed rich text with 'Commercialize' 23 | - [Misc] Fixed rich text - if any - in license info 24 | - [Misc] Preset dropdown is now removed due to introduction of saved settings 25 | - [Known Issue] Some people are experience re-locking in certain situations such as world teleportation or FBT calibration. If you're experiencing this, please contact me for support and debug to hopefully resolve this issue for everyone. 26 | 27 | (v2.7.0) 28 | -------- 29 | - [CRITICAL] Implemented new licensing! Stabler. Much better response time. Less down time. Manual license transfer, bug reporting and feedback features! 30 | - [Feature] Implemented HoloBadge support! Flaunt your HoloBadge by JustSleightly on the protected avatar! 31 | - [Improvement] Password Creator can now take 0 memory! Thanks to local parameters! 32 | - [Fix] Fixed the stupid bug with the scrollbar flashing while resizing window. 33 | - [Fix?] Might've improved some sync stuff, maybe? *I don't know. I'm not sure. I'm not a developer. I'm just a monkey with a keyboard. (*: Copilot completion lmao) 34 | 35 | (v2.6.6) 36 | -------- 37 | - [Fix] Changed something that otherwise may be a security flaw 38 | 39 | (v2.6.5) 40 | -------- 41 | - [Fix] Fixed error thrown if memory would be above 128 rather than 256 42 | - [Misc] Renamed "Avatar is locking up randomly" to "Disable Obfuscation" 43 | 44 | (v2.6.4) 45 | -------- 46 | - [Fix] Fixed Avatar re-locking itself in-game after unlocking 47 | - [Fix] Max memory cost is now calculated properly according to current SDK 48 | - [Improvement] If Remember Me is disabled. Password Parameters will be forced reset on avatar load. 49 | - [Improvement] Removed the Mistake Counter if Mistake Events is not enabled. 50 | - [Improvement] Updated licensing. Can cache verify and compatible with windows 11. 51 | - [Misc] Changed default lock animation 52 | - [Misc] Changed context menu order priorty 53 | 54 | (2.6.3) 55 | ------- 56 | [Feature] Added "Simple Mode". Only displays the minimal settings to setup password on an avatar. 57 | [Misc] Changed default settings and Low/Medium Protection presets: 58 | - Name Obfuscation defaults Enabled 59 | - Strict Identifiers defaults Enabled 60 | - Low & Medium has strict identifiers disabled. 61 | 62 | (2.6.2) 63 | ------- 64 | [Feature] Commercialize Module and Password Recreator feature.* 65 | [Fix] Fixed Full Lock Animations sometimes getting stuck at frame 0. 66 | 67 | *: This Feature is a Commercial Exclusive feature. 68 | This module will add "Password Recreator" monobehaviour to the Avatar and create Deobfuscation Data appropriately. 69 | This Monobehaviour can change the password credentials on the avatar when used with the Deobfuscation Data. 70 | This feature is to allow package sales where package users can change the password of the avatar easily. 71 | -------------------------------------------------------------------------------- /PasswordCreator/Info_Images/Input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/PasswordCreator/Info_Images/Input.png -------------------------------------------------------------------------------- /PasswordCreator/Info_Images/Modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/PasswordCreator/Info_Images/Modules.png -------------------------------------------------------------------------------- /PasswordCreator/Info_Images/PWSettings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/PasswordCreator/Info_Images/PWSettings.gif -------------------------------------------------------------------------------- /PasswordCreator/Info_Images/PWSetup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/PasswordCreator/Info_Images/PWSetup.gif -------------------------------------------------------------------------------- /PasswordCreator/README.md: -------------------------------------------------------------------------------- 1 | Showcase: 2 | 3 | [![Password Creator](http://img.youtube.com/vi/D8H2ZRW3mfI/0.jpg)](http://www.youtube.com/watch?v=D8H2ZRW3mfI "Password Creator") 4 | 5 | Feature Release 6 | 7 | # Password Creator 8 | 9 | Password Creator is made to limit access to the Avatar or its Features however you see fit. You can: 10 | - Lock the Avatar, not allowing it to move nor track. 11 | - Lock the Layers, stop certain things from working or changing. 12 | - Lock the SubMenus, disallow access to certain menus and features 13 | 14 | Password Creator Can: 15 | - Save its state, only needs to be entered once 16 | - Count mistakes to fully lock case there were too many failed attempts 17 | - Have a Pre-Timer and a Post-Timer, to lock when chosen to or fully lock if not entered in time. 18 | - Other minor features: Lock Animation, Manual Confirm, Integrated Menu, Input Open Animation, maybe more to come! 19 | 20 | Password Creator is great for Creators! 21 | - You can use it as protection, with the existence of Re-Uploader and it being more common recently, this will help fend it off. 22 | - You can use it to showcase a Demo/Trial Avatar, whose use time is limited or access to features is blocked, unless they know the password. 23 | - You can use it to limit the access to friends, supporters, patrons, or whoever you'd like by giving them the access code. If the Avatar gets cloned, they won't get to use it depending on how you lock it unless they know the code. 24 | 25 | Buy on the Gumroad: https://dreadrith.gumroad.com/l/PWCreator 26 | If you want to read more about this, check it out on my Discord server: https://discord.gg/ZsPfrGn 27 | 28 | ![Setup](https://github.com/Dreadrith/DreadScripts/blob/main/PasswordCreator/Info_Images/PWSetup.gif) 29 | ![Modules](https://github.com/Dreadrith/DreadScripts/blob/main/PasswordCreator/Info_Images/PWSettings.gif) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

DreadScripts

3 |

DreadScripts are highly focused on simplifying the workflow and effort needed for Unity, mostly focused on VRChat.

4 | 5 | 6 |

Paid

7 | 8 | ## [Carbon Copy (VRChat)](https://github.sleightly.dev/carboncopy) 9 |
10 | Carbon Copy is a feature-rich constraint-based clone system built for VRChat users. 11 | 12 | - Easy to Use one click setup script! 13 | - Supports Mimic and 3 different types of Mirror 14 | - Scale, Bind, Freeze, Lag, Swap, Hide and More! 15 | - On-Screen HUD to visualize active features and settings. 16 | - Highly optimized for Memory with most features fitting into just 9 Memory! 17 |
18 | 19 | ## [Password Creator (VRChat)](https://github.com/Dreadrith/DreadScripts/tree/main/PasswordCreator) 20 |
21 | Password Creator is made to limit access to the Avatar or its Features however you see fit 22 | 23 | - Lock the Avatar, not allowing it to move nor track. 24 | - Lock the Layers, stop certain things from working or changing. 25 | - Lock the SubMenus, disallow access to certain menus and features 26 |
27 | 28 | ## [DBone Editor Overhaul](https://dreadrith.gumroad.com/l/DBEditor) 29 |
30 | DynamicBone Editor Overhaul will make it much simpler and quicker for you to setup your Character's Dynamic Bones! 31 | 32 | - New Dynamic Bones automatically set their selves as the Root. 33 | - Select or Copy Colliders/Exclusions through the scene, no more drag & drop! 34 | - Very intuitive Collider handles for easy placement! 35 | - Easily set DBones Radius and End Offset through the scene. 36 | - Cleaned and more organized layout. 37 |
38 | 39 | ## [Controller Editor](https://github.com/Dreadrith/DreadScripts/tree/main/ControllerEditor) 40 |
41 | Controller Editor will hasten and simplify your work with Controllers as much as possible, reducing tedious time wasting clicks and typing to barely a few clicks 42 | 43 | - Multi-Edit and Copy/Paste Transitions Settings and Conditions. 44 | - (VRChat) Multi-Edit Avatar Parameter Drivers Parameters. 45 | - Variety of functions: Reverse/Remake/Redirect Transitions, Flip Conditions Mode, Separate/Merge Conditions. 46 | - Duplicate Layers or Copy them to another controller 47 |
48 |

Free

49 | 50 | ## [Limb Control](https://github.com/Dreadrith/LimbControl) 51 | (VRChat) Control your limbs through Puppet Control whether you're on PC or Half Body! 52 | ## [Asset Organizer](https://github.com/Dreadrith/AssetOrganizer) 53 | Reorganizes Prefab, Scene or Folder's dependency assets into their own sorted folders 54 | ## [Script Tracker](https://github.com/Dreadrith/DreadScripts/tree/main/Script%20Tracker) 55 | Scan imported packages and assets for potentially malicious scripts 56 | ## [Text2Texture](https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/Text2Texture.unitypackage) 57 | Easily generate a Normal Map, a Mask, a Custom Text Texture or a Material from given text input! 58 | ## [Texture Utility](https://github.com/Dreadrith/DreadScripts/tree/main/Texture%20Utility) 59 | Various Tools and Scripts to speed up your workflow when it comes to Textures 60 | ## [Quick Toggle](https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/QuickToggle.unitypackage) 61 | Quickly generate clips that Enable or Disable GameObjects in your hierarchy. 62 | ## [Dupe With Mats](https://github.com/Dreadrith/DreadScripts/tree/main/Duplicate%20With%20Materials) 63 | Instantly make new variations of an Avatar by duplicating and replacing each material. 64 | ## [Selection Helper](https://github.com/Dreadrith/SelectionHelper) 65 | Unity Editor package to make selecting certain objects easier and less tedious. 66 | ## [Export PostProcessor](https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/ExportPostProcessor.unitypackage) 67 | Removes the mundane and repetitive things you have to do when exporting packages. 68 | ## [Reset Avatar](https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/Reset.Avatar.unitypackage) 69 | Reset your Avatar's pose as long as it's humanoid case you break it somehow, usually by recording animation. 70 | ## [Dreadomizer](https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/Dreadomizer.unitypackage) 71 | (VRChat) Quickly create a new layer which has a randomizing state, and filled with the possible state cases of the parameter. 72 | 73 | ## [Discord](https://discord.gg/ZsPfrGn) 74 | There are a bunch of other stuff on my Discord, including more free scripts, prefabs and others. 75 | My Discord also Contains more information about the Bigger Big Boy Paid Scripts. 76 | -------------------------------------------------------------------------------- /Script Tracker/Default Settings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 65d1728145d2f1b4498640fcd2940b54, type: 3} 13 | m_Name: Default Settings 14 | m_EditorClassIdentifier: 15 | HighRisk: 16 | - UnitypackageRussianRoulett 17 | - System.Security 18 | - Environment.SpecialFolder.DesktopDirectory 19 | - GenerateRandomSalt 20 | - Cryptography 21 | - DownloadRansomware 22 | - ScriptTracker 23 | - ransomware 24 | - discord 25 | NormalRisk: 26 | - Networking 27 | - System.Net 28 | - UnityWebRequest 29 | - WebClient 30 | - http 31 | LowRisk: [] 32 | promptDLL: 1 33 | alwaysDLL: 0 34 | -------------------------------------------------------------------------------- /Script Tracker/Instructions.txt: -------------------------------------------------------------------------------- 1 | Made by Dreadrith#3238 2 | Server: https://discord.gg/ZsPfrGn 3 | 4 | Version: v1.2.0 5 | Link: https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/ScriptTracker.unitypackage 6 | 7 | Script Tracker was made to offer protection against potentially malicious scripts and warn about possible hidden activities. 8 | Malicious coders may attempt to steal your info, such as credentials or auth tokens. They may also attempt to cause damage to your device through the scripts. 9 | 10 | The Script Tracker scans code based on Keywords written in the Script Tracker Settings. (Create > DreadScripts > Script Tracker Settings). 11 | You can change the settings in the Editor Window (DreadTools > Scripts Settings > Script Tracker). 12 | WARNING: DLLS CANNOT BE SCANNED OR REVISED! Always be warry of DLLs and only get them from trustworthy sources! 13 | 14 | On first import of the Script Tracker, it's recommended to allow your current project's scripts if you trust them by clicking "Allow Current Project Scripts and DLLs" 15 | to avoid getting prompted about scripts already present in the project. 16 | 17 | When a script gets prompted you can: 18 | - Allow: Imports the script normally, and adds it to the whitelist. 19 | - Revise: Imports the script as a .txt file, and adds "Flags" to the lines that have triggered flags. After revision, you may either turn it back to .cs or delete it. To turn it back to a script .cs file, Right Click > Show in explorer. Right Click Script > Rename > Replace extension with .cs. 20 | - Delete: Deletes the script and its meta data, disallowing it from compiling or running anything. 21 | 22 | 23 | Script Tracker Settings: Created through Assets > Create > DreadScripts > Script Tracker Settings 24 | Contains Keywords that should be scanned for, Case-Insensitive. 25 | - Low Risk Flag: Flagged if any Low Risk keyword is found, ignores flag if allowed previously. 26 | - Normal Risk Flag: Flagged if any Normal Risk keyword is found, ignores flags if allowed previously and after verifying integrity*. 27 | - High Risk Flag: Flagged if any High Risk keyword is found, prompts any time it gets flagged. 28 | 29 | *Verifying Integrity: Script Tracker will save a Hash of the allowed script and will compare the script to it when reimporting. So it will prompt if anything in the script was changed. 30 | -------------------------------------------------------------------------------- /Script Tracker/README.md: -------------------------------------------------------------------------------- 1 | # Script Tracker 2 | 3 | Download Here 4 | Instructions in Assets > DreadScripts > Script Tracker > Instructions.txt 5 | Settings in DreadTools > Scripts Settings > Script Tracker 6 | 7 | ![Flag](https://cdn.discordapp.com/attachments/898498998527197224/898544716478574722/unknown.png) 8 | 9 | ![Settings](https://cdn.discordapp.com/attachments/898498998527197224/944407784546512906/scriptSettings.png) 10 | 11 | This script is for security purposes. It will attempt to protect you against scripts that have the potential to be malicious. 12 | For any imported Script, this script will read it preemptively and warn you if it contains any "Keywords" defined in the script's settings. 13 | When warned, you are prompted to Allow, Delete or Revise the file. Revising the file turns it into a txt file, which will stop it from running and allow you to open it to read it. 14 | 15 | You can also make it prompt for all Scripts, in case you want to import a package without worrying about what Scripts it contains. 16 | This will also prompt for imported DLLs, the script cannot read the DLL so it will prompt for all or none of them, and you can only allow or delete them. 17 | Once imported, it is recommended to open DreadTools > Scripts Settings > Script Tracker then pressing "Allow Current Project Scripts and DLLs". 18 | 19 | **This is not foolproof!** 20 | It is still possible to cause damage through other script means and this may not cover all possibilities, so be cautious of what you're importing! 21 | -------------------------------------------------------------------------------- /Script Tracker/ScriptTracker.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using UnityEngine; 3 | using UnityEditor; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | using System.Security.Cryptography; 7 | using System.Text; 8 | using UnityEditor; 9 | 10 | namespace DreadScripts.ScriptTracker 11 | { 12 | internal sealed class ScriptTracker : AssetPostprocessor 13 | { 14 | internal const string PREFS_SETTINGSGUID = "ScriptTrackerSettingsGUID"; 15 | private static readonly string warnDLL = "\nWARNING: This is a DLL and can't be scanned! Only Import DLLs from trusted sources!"; 16 | private static bool check = true; 17 | private static bool flagged = true; 18 | private static bool checkDLL = true; 19 | 20 | private static string GetPath() 21 | { 22 | string myPath = AssetDatabase.GUIDToAssetPath(AssetDatabase.FindAssets("ScriptTracker")[0]); 23 | myPath = myPath.Substring(0, myPath.LastIndexOf('/')); 24 | return myPath; 25 | } 26 | 27 | private static bool KeywordMatch(string content, string match) 28 | { 29 | return content.IndexOf(match, System.StringComparison.OrdinalIgnoreCase) >= 0; 30 | } 31 | 32 | static string StringToHash(string s) 33 | { 34 | using (HashAlgorithm hashing = SHA256.Create()) 35 | { 36 | byte[] hash = null; 37 | 38 | hash = hashing.ComputeHash(Encoding.UTF8.GetBytes(s)); 39 | 40 | StringBuilder sb = new StringBuilder(); 41 | foreach (byte b in hash) 42 | { 43 | sb.Append(b.ToString("X2")); 44 | } 45 | 46 | return sb.ToString(); 47 | } 48 | } 49 | 50 | static void OnPostprocessAllAssets(string[] importedAssets, string[] unused1, string[] unused2, string[] unused3) 51 | { 52 | if (importedAssets.Length == 0) 53 | return; 54 | ScriptTrackerSettings settings = LoadScriptTrackerSettings(); 55 | 56 | check = EditorPrefs.GetBool("ScriptTrackerCheck", true); 57 | flagged = EditorPrefs.GetBool("ScriptTrackerFlagged", true); 58 | 59 | if (!check && !checkDLL) return; 60 | try 61 | { 62 | AssetDatabase.StartAssetEditing(); 63 | 64 | foreach (string path in importedAssets) 65 | { 66 | bool isScript = Path.GetExtension(path) == ".cs"; 67 | bool isDLL = Path.GetExtension(path) == ".dll"; 68 | string pathGUID = AssetDatabase.AssetPathToGUID(path); 69 | bool hasKey = EditorPrefs.HasKey("ScriptTracker-" + pathGUID); 70 | 71 | if (isScript && check) 72 | { 73 | bool isLow = false, isNormal = false, isHigh = false; 74 | Dictionary triggers = new Dictionary(); 75 | 76 | string[] scriptLines = File.ReadAllLines(path); 77 | 78 | string key = hasKey ? EditorPrefs.GetString("ScriptTracker-" + pathGUID) : ""; 79 | string scriptHash = StringToHash(string.Join("", scriptLines)); 80 | bool isChanged = key != scriptHash; 81 | 82 | bool IterateSettings(int lineIndex, List keywords, string flagMessage, ref bool riskBool) 83 | { 84 | foreach (var k in keywords) 85 | { 86 | if (string.IsNullOrEmpty(k)) continue; 87 | if (!KeywordMatch(scriptLines[lineIndex], k)) continue; 88 | 89 | triggers.Add(lineIndex, k); 90 | scriptLines[lineIndex] += flagMessage; 91 | riskBool = true; 92 | return true; 93 | } 94 | 95 | return false; 96 | } 97 | 98 | for (int i = 0; i < scriptLines.Length; i++) 99 | { 100 | if (IterateSettings(i, settings.HighRisk, " //[ST] FLAGGED HIGH RISK", ref isHigh)) break; 101 | if (IterateSettings(i, settings.NormalRisk, " //[ST] FLAGGED NORMAL RISK", ref isNormal)) break; 102 | IterateSettings(i, settings.LowRisk, " //[ST] FLAGGED LOW RISK", ref isLow); 103 | } 104 | 105 | string warnMessage = "Importing Script: " + Path.GetFileNameWithoutExtension(path); 106 | if (isHigh) warnMessage += "\nWARNING: FLAGGED AS HIGH RISK!"; 107 | else if (isNormal) warnMessage += "\nWarning: Flagged as Normal Risk!"; 108 | else if (isLow) warnMessage += "\nWarning: Flagged as Low Risk!"; 109 | 110 | foreach (var p in triggers) 111 | { 112 | warnMessage += $"\n Line {p.Key} - {p.Value}"; 113 | } 114 | 115 | if ((!hasKey && (isNormal || isLow)) 116 | || (hasKey && isNormal && isChanged) 117 | || isHigh 118 | || !flagged) 119 | switch (EditorUtility.DisplayDialogComplex("Importing Script", warnMessage, "Allow", "Delete", "Revise")) 120 | { 121 | case 0: 122 | EditorPrefs.SetString("ScriptTracker-" + pathGUID, scriptHash); 123 | Debug.Log(Path.GetFileNameWithoutExtension(path) + " added to whitelist."); 124 | break; 125 | case 1: 126 | File.Delete(path); 127 | File.Delete(path + ".meta"); 128 | break; 129 | case 2: 130 | string newFilePath = path.Substring(0, path.Length - 2) + "txt"; 131 | File.Move(path, newFilePath); 132 | File.WriteAllLines(newFilePath, scriptLines); 133 | File.Delete(path + ".meta"); 134 | break; 135 | } 136 | } 137 | else 138 | { 139 | if (isDLL) 140 | { 141 | if ((!hasKey && settings.promptDLL) || (settings.promptDLL && settings.alwaysDLL) || !flagged) 142 | if (EditorUtility.DisplayDialog("Importing DLL", "Importing DLL: " + Path.GetFileNameWithoutExtension(path) + warnDLL, "Allow", "Delete")) 143 | { 144 | EditorPrefs.SetString("ScriptTracker-" + AssetDatabase.AssetPathToGUID(path), "Set"); 145 | } 146 | else 147 | { 148 | File.Delete(path); 149 | File.Delete(path + ".meta"); 150 | } 151 | } 152 | } 153 | } 154 | } 155 | finally 156 | { 157 | AssetDatabase.StopAssetEditing(); 158 | } 159 | 160 | PostPackageImport(); 161 | AssetDatabase.Refresh(); 162 | 163 | } 164 | 165 | private static bool wasCompiling; 166 | private static bool wasImporting; 167 | 168 | [InitializeOnLoadMethod] 169 | private static void HookPackageImport() 170 | { 171 | AssetDatabase.importPackageStarted -= PrePackageImport; 172 | AssetDatabase.importPackageStarted += PrePackageImport; 173 | } 174 | 175 | private static void PrePackageImport(string name) 176 | { 177 | wasImporting = true; 178 | wasCompiling = (bool)GetType("UnityEditor.EditorApplication, UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").GetMethod("CanReloadAssemblies", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, null); 179 | EditorApplication.LockReloadAssemblies(); 180 | } 181 | 182 | private static void PostPackageImport() 183 | { 184 | if (wasImporting) 185 | { 186 | if (wasCompiling) EditorApplication.UnlockReloadAssemblies(); 187 | wasImporting = false; 188 | } 189 | } 190 | 191 | internal static ScriptTrackerSettings LoadScriptTrackerSettings() 192 | { 193 | var settings = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(PlayerPrefs.GetString(PREFS_SETTINGSGUID))); 194 | if (settings) return settings; 195 | 196 | string defaultGUID = "9f5f97932281c834bbcc8e130bd396ce"; 197 | settings = AssetDatabase.LoadAssetAtPath(defaultGUID); 198 | if (settings) 199 | { 200 | PlayerPrefs.SetString(PREFS_SETTINGSGUID, defaultGUID); 201 | return settings; 202 | } 203 | 204 | settings = ScriptableObject.CreateInstance(); 205 | string folderPath = "Assets/DreadScripts/Script Tracker"; 206 | ReadyPath(folderPath); 207 | string filePath = $"{folderPath}/Default Settings.asset"; 208 | AssetDatabase.CreateAsset(settings, filePath); 209 | AssetDatabase.ImportAsset(filePath); 210 | AssetDatabase.TryGetGUIDAndLocalFileIdentifier(settings, out string guid, out long id); 211 | PlayerPrefs.SetString(PREFS_SETTINGSGUID, guid); 212 | return settings; 213 | } 214 | 215 | private static void ReadyPath(string folderPath) 216 | { 217 | string[] folderNames = folderPath.Split('/'); 218 | string[] folderPaths = new string[folderNames.Length]; 219 | 220 | for (int i = 0; i < folderNames.Length; i++) 221 | { 222 | folderPaths[i] = folderNames[0]; 223 | for (int j = 1; j <= i; j++) 224 | folderPaths[i] += $"/{folderNames[j]}"; 225 | } 226 | 227 | for (int i = 1; i < folderPaths.Length; i++) 228 | if (!AssetDatabase.IsValidFolder(folderPaths[i])) 229 | AssetDatabase.CreateFolder(folderPaths[i - 1], folderNames[i]); 230 | } 231 | 232 | private static System.Type GetType(string typeName) 233 | { 234 | var myType = System.Type.GetType(typeName); 235 | if (myType != null) 236 | return myType; 237 | foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies()) 238 | { 239 | myType = assembly.GetType(typeName); 240 | if (myType != null) 241 | return myType; 242 | } 243 | return null; 244 | } 245 | 246 | } 247 | 248 | [CustomEditor(typeof(ScriptTrackerSettings))] 249 | internal sealed class ScriptTrackerEditor : Editor 250 | { 251 | private static Vector2 scroll; 252 | 253 | private static GUIContent[] riskTabs = 254 | { 255 | new GUIContent("Low Risk", "Scripts flagged as Low Risk need to be allowed only once."), 256 | new GUIContent("Normal Risk", "Scripts flagged as Normal Risk need to be allowed once or each time they are changed"), 257 | new GUIContent("High Risk", "Scripts flagged as High Risk need to be allowed any time they are imported") 258 | }; 259 | 260 | private static int tabIndex; 261 | 262 | SerializedObject settings; 263 | SerializedProperty lowProp; 264 | SerializedProperty normalProp; 265 | SerializedProperty highProp; 266 | SerializedProperty dllProp; 267 | SerializedProperty alwaysdllProp; 268 | private void OnEnable() 269 | { 270 | settings = new SerializedObject((ScriptTrackerSettings)target); 271 | lowProp = settings.FindProperty("LowRisk"); 272 | normalProp = settings.FindProperty("NormalRisk"); 273 | highProp = settings.FindProperty("HighRisk"); 274 | dllProp = settings.FindProperty("promptDLL"); 275 | alwaysdllProp = settings.FindProperty("alwaysDLL"); 276 | } 277 | public override void OnInspectorGUI() 278 | { 279 | scroll = EditorGUILayout.BeginScrollView(scroll); 280 | settings.Update(); 281 | dllProp.boolValue = EditorGUILayout.Toggle("Warn for DLLs", dllProp.boolValue); 282 | if (dllProp.boolValue) 283 | alwaysdllProp.boolValue = EditorGUILayout.Toggle("Always Warn for DLLs", alwaysdllProp.boolValue); 284 | 285 | tabIndex = GUILayout.Toolbar(tabIndex, riskTabs, "toolbarbutton"); 286 | 287 | void DisplayRiskProperty(SerializedProperty prop) 288 | { 289 | for (int i = 0; i < prop.arraySize; i++) 290 | { 291 | using (new GUILayout.HorizontalScope("box")) 292 | { 293 | if (GUILayout.Button("X", GUI.skin.label, GUILayout.Width(17), GUILayout.Height(17))) 294 | { 295 | prop.DeleteArrayElementAtIndex(i); 296 | continue; 297 | } 298 | prop.GetArrayElementAtIndex(i).stringValue = EditorGUILayout.TextField(prop.GetArrayElementAtIndex(i).stringValue); 299 | } 300 | } 301 | if (GUILayout.Button("Add", "toolbarbutton")) 302 | prop.InsertArrayElementAtIndex(prop.arraySize); 303 | } 304 | 305 | switch (tabIndex) 306 | { 307 | case 0: 308 | DisplayRiskProperty(lowProp); 309 | break; 310 | case 1: 311 | DisplayRiskProperty(normalProp); 312 | break; 313 | case 2: 314 | DisplayRiskProperty(highProp); 315 | break; 316 | } 317 | 318 | settings.ApplyModifiedProperties(); 319 | EditorGUILayout.EndScrollView(); 320 | } 321 | } 322 | 323 | internal sealed class ScriptTrackerWindow : EditorWindow 324 | { 325 | ScriptTrackerSettings settings; 326 | private enum CST 327 | { 328 | AllScripts, 329 | Flagged, 330 | Disable 331 | } 332 | private static CST checkScriptType = CST.Flagged; 333 | 334 | [MenuItem("DreadTools/Scripts Settings/Script Tracker")] 335 | private static void showWindow() 336 | { 337 | GetWindow(false, "Script Tracker Settings", true); 338 | } 339 | private void OnGUI() 340 | { 341 | EditorGUI.BeginChangeCheck(); 342 | checkScriptType = (CST)EditorGUILayout.EnumPopup("Prompt Scripts", checkScriptType); 343 | if (EditorGUI.EndChangeCheck()) 344 | { 345 | switch ((int)checkScriptType) 346 | { 347 | case 0: 348 | EditorPrefs.SetBool("ScriptTrackerFlagged", false); 349 | EditorPrefs.SetBool("ScriptTrackerCheck", true); 350 | break; 351 | case 1: 352 | EditorPrefs.SetBool("ScriptTrackerFlagged", true); 353 | EditorPrefs.SetBool("ScriptTrackerCheck", true); 354 | break; 355 | case 2: 356 | EditorPrefs.SetBool("ScriptTrackerFlagged", false); 357 | EditorPrefs.SetBool("ScriptTrackerCheck", false); 358 | break; 359 | } 360 | } 361 | 362 | if (checkScriptType== CST.Flagged) 363 | { 364 | ScriptTrackerSettings dummy; 365 | EditorGUI.BeginChangeCheck(); 366 | dummy = (ScriptTrackerSettings)EditorGUILayout.ObjectField("Settings", settings, typeof(ScriptTrackerSettings), false); 367 | if (EditorGUI.EndChangeCheck()) 368 | { 369 | if (dummy!=null) 370 | { 371 | settings = dummy; 372 | PlayerPrefs.SetString(ScriptTracker.PREFS_SETTINGSGUID, AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(settings))); 373 | } 374 | } 375 | } 376 | 377 | if (GUILayout.Button("Allow Current Project Scripts and DLLs")) 378 | { 379 | string[] paths = AssetDatabase.FindAssets("t:Script"); 380 | foreach (var p in paths) 381 | { 382 | EditorPrefs.SetBool(p, true); 383 | } 384 | Debug.Log("All Scripts in projects added to whitelist"); 385 | } 386 | } 387 | 388 | private void OnEnable() 389 | { 390 | bool Flagged = EditorPrefs.GetBool("ScriptTrackerFlagged", true); 391 | bool Check = EditorPrefs.GetBool("ScriptTrackerCheck", true); 392 | checkScriptType = Check ? (Flagged ? CST.Flagged : CST.AllScripts) : CST.Disable; 393 | settings = ScriptTracker.LoadScriptTrackerSettings(); 394 | } 395 | 396 | } 397 | } 398 | #endif -------------------------------------------------------------------------------- /Script Tracker/ScriptTrackerSettings.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace DreadScripts.ScriptTracker 6 | { 7 | [System.Serializable] 8 | [CreateAssetMenu(fileName = "New Tracker Settings", menuName = "DreadScripts/Script Tracker Settings")] 9 | internal sealed class ScriptTrackerSettings : ScriptableObject 10 | { 11 | public List HighRisk; 12 | public List NormalRisk; 13 | public List LowRisk; 14 | public bool promptDLL; 15 | public bool alwaysDLL; 16 | 17 | ScriptTrackerSettings() 18 | { 19 | HighRisk = new List(){ 20 | "UnitypackageRussianRoulett", 21 | "System.Security", 22 | "Environment.SpecialFolder.DesktopDirectory", 23 | "GenerateRandomSalt", 24 | "Cryptography", 25 | "DownloadRansomware", 26 | "ScriptTracker", 27 | "ransomware", 28 | "discord" 29 | }; 30 | 31 | NormalRisk = new List(){ 32 | "Networking", 33 | "System.Net", 34 | "UnityWebRequest", 35 | "WebClient", 36 | "http" 37 | }; 38 | LowRisk = new List() 39 | { 40 | 41 | }; 42 | promptDLL = true; 43 | alwaysDLL = false; 44 | } 45 | 46 | } 47 | } 48 | #endif -------------------------------------------------------------------------------- /Texture Utility/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d65e81b5d6447b74a85dc00b5bdfc8a5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPacker.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using UnityEditor.Animations; 6 | using System.Linq; 7 | using UnityEngine.Networking; 8 | 9 | namespace DreadScripts 10 | { 11 | public class TextureAutoPackerWindow : EditorWindow 12 | { 13 | private static TextureAutoPackerData data; 14 | private static SerializedObject serializedObject; 15 | private static SerializedProperty _active; 16 | private static SerializedProperty _activeModules; 17 | private static UnityEditorInternal.ReorderableList modulesList; 18 | private static Texture2D titleTexture; 19 | 20 | [MenuItem("DreadTools/Utilities/Texture Auto-Packer")] 21 | public static void ShowWindow() 22 | { 23 | EditorWindow w = GetWindow(false, "Texture Auto-Packer", true); 24 | if (!titleTexture) 25 | { 26 | titleTexture = TextureUtility.GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _); 27 | titleTexture.Apply(); 28 | } 29 | w.titleContent.image = titleTexture; 30 | } 31 | private void OnEnable() 32 | { 33 | data = TextureAutoPackerData.GetInstance(); 34 | serializedObject = new SerializedObject(data); 35 | _active = serializedObject.FindProperty("active"); 36 | _activeModules = serializedObject.FindProperty("activeModules"); 37 | modulesList = new UnityEditorInternal.ReorderableList(serializedObject, _activeModules, true, true, true, false) 38 | { 39 | drawElementCallback = DrawElement, 40 | drawHeaderCallback = DrawHeader 41 | }; 42 | } 43 | 44 | private void DrawHeader(Rect rect) 45 | { 46 | EditorGUI.LabelField(rect, "Active Modules"); 47 | } 48 | 49 | private void DrawElement(Rect rect, int index, bool isActive, bool isFocused) 50 | { 51 | if (!(index < _activeModules.arraySize && index >= 0)) 52 | return; 53 | rect.y += 2; 54 | rect.height = EditorGUIUtility.singleLineHeight; 55 | if (GUI.Button(new Rect(rect.x, rect.y, 20, rect.height), "X")) 56 | { 57 | _activeModules.DeleteArrayElementAtIndex(index); 58 | return; 59 | } 60 | rect.x += 20; 61 | rect.width -= 20; 62 | _activeModules.GetArrayElementAtIndex(index).objectReferenceValue = (TextureAutoPackerModule)EditorGUI.ObjectField(rect, _activeModules.GetArrayElementAtIndex(index).objectReferenceValue, typeof(TextureAutoPackerModule), false); 63 | } 64 | 65 | private void OnGUI() 66 | { 67 | serializedObject.Update(); 68 | Color og = GUI.backgroundColor; 69 | GUI.backgroundColor = _active.boolValue ? Color.green : Color.grey; 70 | _active.boolValue = GUILayout.Toggle(_active.boolValue, new GUIContent("Active","Determine whether the Auto-Packer should initiate on texture import"), "Toolbarbutton"); 71 | GUI.backgroundColor = og; 72 | 73 | EditorGUI.BeginDisabledGroup(!_active.boolValue); 74 | modulesList.DoLayoutList(); 75 | if (GUILayout.Button(new GUIContent("Force Check", "Initiate the Auto-Packer without having to trigger a texture import"))) 76 | { 77 | TextureAutoPacker.InitiateAutoPacking(); 78 | TextureAutoPackerProcessor.OnAutoPackingEnd(); 79 | } 80 | EditorGUI.EndDisabledGroup(); 81 | 82 | serializedObject.ApplyModifiedProperties(); 83 | } 84 | } 85 | 86 | [CustomEditor(typeof(TextureAutoPackerModule))] 87 | public class TextureAutoPacker : Editor 88 | { 89 | static GUIContent removeIcon; 90 | TextureAutoPackerModule module; 91 | SerializedProperty packingList; 92 | GUIStyle freeButtonStyle; 93 | public override void OnInspectorGUI() 94 | { 95 | freeButtonStyle = new GUIStyle("toolbarbutton") { padding = new RectOffset(1, 1, 1, 1) }; 96 | serializedObject.Update(); 97 | 98 | if (GUILayout.Button(new GUIContent("Add","Create a new Auto-Packed texture"), "toolbarbutton")) 99 | { 100 | module.packedTextures.Add(new AutoPackedTexture()); 101 | serializedObject.Update(); 102 | } 103 | 104 | for (int i = packingList.arraySize - 1; i >= 0; i--) 105 | DrawPackingProperty(i); 106 | 107 | 108 | serializedObject.ApplyModifiedProperties(); 109 | } 110 | private void OnEnable() 111 | { 112 | module = (TextureAutoPackerModule)target; 113 | packingList = serializedObject.FindProperty("packedTextures"); 114 | removeIcon = EditorGUIUtility.IconContent("winbtn_win_close"); 115 | } 116 | 117 | static bool Running; 118 | public static bool InitiateAutoPacking() 119 | { 120 | bool HasPacked=false; 121 | if (Running) 122 | return true; 123 | Running = true; 124 | TextureAutoPackerData data = TextureAutoPackerData.GetInstance(); 125 | if (!data.active) 126 | return false; 127 | data.activeModules.ForEach(m => 128 | { 129 | if (!m) 130 | goto Skip; 131 | 132 | SerializedObject module = new SerializedObject(m); 133 | module.Update(); 134 | for (int i = 0; i < m.packedTextures.Count; i++) 135 | { 136 | if (m.packedTextures[i].WasModified()) 137 | { 138 | HasPacked = true; 139 | string newTexturePath = m.packedTextures[i].Pack(); 140 | 141 | if (string.IsNullOrEmpty(newTexturePath)) 142 | goto Skip; 143 | 144 | SerializedProperty packedTexture = module.FindProperty("packedTextures").GetArrayElementAtIndex(i); 145 | SerializedProperty hashes = packedTexture.FindPropertyRelative("channelsHashes"); 146 | for (int j = 0; j < 4; j++) 147 | { 148 | hashes.GetArrayElementAtIndex(j).stringValue = string.Empty; 149 | if (m.packedTextures[i].channels[j].texture) 150 | hashes.GetArrayElementAtIndex(j).stringValue = m.packedTextures[i].channels[j].texture.imageContentsHash.ToString(); 151 | } 152 | packedTexture.FindPropertyRelative("forceModified").boolValue = false; 153 | AssetDatabase.ImportAsset(newTexturePath, ImportAssetOptions.ForceUpdate); 154 | TextureAutoPackerProcessor.PathToProperty.Add(new System.Tuple(newTexturePath, packedTexture.FindPropertyRelative("packed"))); 155 | } 156 | } 157 | module.ApplyModifiedPropertiesWithoutUndo(); 158 | 159 | Skip:; 160 | }); 161 | Running = false; 162 | 163 | return HasPacked; 164 | } 165 | 166 | public void DrawPackingProperty(int index) 167 | { 168 | SerializedProperty t = packingList.GetArrayElementAtIndex(index); 169 | SerializedProperty _name = t.FindPropertyRelative("name"); 170 | SerializedProperty _expanded = t.FindPropertyRelative("expanded"); 171 | SerializedProperty _channels = t.FindPropertyRelative("channels"); 172 | SerializedProperty _packed = t.FindPropertyRelative("packed"); 173 | SerializedProperty _encoding = t.FindPropertyRelative("encoding"); 174 | SerializedProperty _quality = t.FindPropertyRelative("jpgQuality"); 175 | SerializedProperty _modified = t.FindPropertyRelative("forceModified"); 176 | AutoPackedTexture autoTexture = ((TextureAutoPackerModule)t.serializedObject.targetObject).packedTextures[index]; 177 | using (new GUILayout.VerticalScope("box")) 178 | { 179 | using (new GUILayout.HorizontalScope()) 180 | { 181 | using (new GUILayout.HorizontalScope("toolbarbutton", GUILayout.Width(12))) 182 | _expanded.boolValue = GUILayout.Toggle(_expanded.boolValue, GUIContent.none, "foldout", GUILayout.Width(10)); 183 | 184 | using (new GUILayout.HorizontalScope("toolbarbutton")) 185 | _name.stringValue = EditorGUILayout.TextField(GUIContent.none, _name.stringValue, GUI.skin.label); 186 | 187 | if (GUILayout.Button(removeIcon, freeButtonStyle, GUILayout.Width(17))) 188 | { 189 | packingList.DeleteArrayElementAtIndex(index); 190 | return; 191 | } 192 | } 193 | if (_expanded.boolValue) 194 | { 195 | using (new GUILayout.HorizontalScope("box")) 196 | { 197 | _encoding.enumValueIndex = (int)(TextureUtility.TexEncoding)EditorGUILayout.EnumPopup((TextureUtility.TexEncoding)_encoding.enumValueIndex, GUILayout.Width(95)); 198 | 199 | EditorGUI.BeginDisabledGroup(_encoding.enumValueIndex != 1); 200 | EditorGUIUtility.labelWidth = 50; 201 | _quality.intValue = EditorGUILayout.IntSlider("Quality", _quality.intValue, 1, 100); 202 | EditorGUIUtility.labelWidth = 0; 203 | EditorGUI.EndDisabledGroup(); 204 | } 205 | using (new GUILayout.HorizontalScope()) 206 | { 207 | for (int i = 0; i < _channels.arraySize; i++) 208 | { 209 | if (DrawChannelProperty(_channels.GetArrayElementAtIndex(i))) 210 | _modified.boolValue = true; 211 | } 212 | GUILayout.Label("", GUI.skin.verticalSlider, GUILayout.Height(133)); 213 | using (new GUILayout.VerticalScope("box")) 214 | { 215 | using (new GUILayout.HorizontalScope()) 216 | { 217 | GUILayout.FlexibleSpace(); 218 | GUILayout.Label("Packed", "boldlabel"); 219 | GUILayout.FlexibleSpace(); 220 | } 221 | GUILayout.Label(GUIContent.none); 222 | using (new GUILayout.HorizontalScope()) 223 | { 224 | GUILayout.FlexibleSpace(); 225 | _packed.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField("", _packed.objectReferenceValue, typeof(Texture2D), false, GUILayout.Width(66)); 226 | GUILayout.FlexibleSpace(); 227 | } 228 | using (new GUILayout.HorizontalScope()) 229 | { 230 | if (GUILayout.Button("Force Pack", "toolbarbutton")) 231 | { 232 | string newTexturePath = autoTexture.Pack(); 233 | if (!string.IsNullOrEmpty(newTexturePath)) 234 | { 235 | AssetDatabase.ImportAsset(newTexturePath); 236 | _packed.objectReferenceValue = AssetDatabase.LoadAssetAtPath(newTexturePath); 237 | } 238 | } 239 | } 240 | } 241 | } 242 | } 243 | } 244 | } 245 | 246 | public bool DrawChannelProperty(SerializedProperty channel) 247 | { 248 | bool edited = false; 249 | SerializedProperty _name = channel.FindPropertyRelative("name"); 250 | SerializedProperty _texture = channel.FindPropertyRelative("texture"); 251 | SerializedProperty _invert = channel.FindPropertyRelative("invert"); 252 | SerializedProperty _mode = channel.FindPropertyRelative("mode"); 253 | 254 | 255 | GUIStyle buttonGroupStyle = new GUIStyle(GUI.skin.GetStyle("toolbarbutton")) { padding = new RectOffset(1, 1, 1, 1), margin = new RectOffset(0, 0, 1, 1) }; 256 | using (new GUILayout.VerticalScope("box")) 257 | { 258 | using (new GUILayout.HorizontalScope()) 259 | { 260 | GUILayout.FlexibleSpace(); 261 | GUILayout.Label(_name.stringValue, "boldlabel"); 262 | GUILayout.FlexibleSpace(); 263 | } 264 | using (new GUILayout.HorizontalScope()) 265 | { 266 | EditorGUI.BeginChangeCheck(); 267 | 268 | GUILayout.FlexibleSpace(); 269 | bool dummy; 270 | EditorGUI.BeginChangeCheck(); 271 | dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Red, "R", buttonGroupStyle, GUILayout.Width(16)); 272 | if (EditorGUI.EndChangeCheck()) 273 | if (dummy) 274 | _mode.enumValueIndex = 0; 275 | 276 | EditorGUI.BeginChangeCheck(); 277 | dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Green, "G", buttonGroupStyle, GUILayout.Width(16)); 278 | if (EditorGUI.EndChangeCheck()) 279 | if (dummy) 280 | _mode.enumValueIndex = 1; 281 | 282 | EditorGUI.BeginChangeCheck(); 283 | dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Blue, "B", buttonGroupStyle, GUILayout.Width(16)); 284 | if (EditorGUI.EndChangeCheck()) 285 | if (dummy) 286 | _mode.enumValueIndex = 2; 287 | 288 | EditorGUI.BeginChangeCheck(); 289 | dummy = GUILayout.Toggle(_mode.enumValueIndex == (int)ChannelTexture.ColorMode.Alpha, "A", buttonGroupStyle, GUILayout.Width(16)); 290 | if (EditorGUI.EndChangeCheck()) 291 | if (dummy) 292 | _mode.enumValueIndex = 3; 293 | GUILayout.FlexibleSpace(); 294 | 295 | if (EditorGUI.EndChangeCheck()) 296 | if (_texture.objectReferenceValue) 297 | edited = true; 298 | } 299 | using (new GUILayout.HorizontalScope()) 300 | { 301 | GUILayout.FlexibleSpace(); 302 | _texture.objectReferenceValue = (Texture2D)EditorGUILayout.ObjectField("", _texture.objectReferenceValue, typeof(Texture2D), false, GUILayout.Width(66)); 303 | GUILayout.FlexibleSpace(); 304 | } 305 | 306 | EditorGUI.BeginChangeCheck(); 307 | _invert.boolValue = GUILayout.Toggle(_invert.boolValue, "Invert", "toolbarbutton"); 308 | if (EditorGUI.EndChangeCheck()) 309 | if (_texture.objectReferenceValue) 310 | edited = true; 311 | } 312 | return edited; 313 | } 314 | } 315 | 316 | public class TextureAutoPackerProcessor : AssetPostprocessor 317 | { 318 | public static List> PathToProperty = new List>(); 319 | public static bool TextureImported = false; 320 | void OnPostprocessTexture(Texture2D texture) 321 | { 322 | TextureImported = true; 323 | } 324 | public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) 325 | { 326 | if (TextureImported) 327 | { 328 | TextureImported = false; 329 | if (!TextureAutoPacker.InitiateAutoPacking()) 330 | OnAutoPackingEnd(); 331 | } 332 | } 333 | public static void OnAutoPackingEnd() 334 | { 335 | PathToProperty.ForEach(t => 336 | { 337 | t.Item2.serializedObject.Update(); 338 | t.Item2.objectReferenceValue = AssetDatabase.LoadAssetAtPath(t.Item1); 339 | t.Item2.serializedObject.ApplyModifiedPropertiesWithoutUndo(); 340 | }); 341 | PathToProperty.Clear(); 342 | } 343 | } 344 | 345 | public abstract class TAPDreadData : ScriptableObject where T : ScriptableObject 346 | { 347 | private static T _instance = null; 348 | private static string _SavePath; 349 | 350 | protected static T GetInstance(string SavePath) 351 | { 352 | _SavePath = SavePath; 353 | if (!_instance && Exists()) 354 | { 355 | _instance = AssetDatabase.LoadAssetAtPath(SavePath); 356 | } 357 | if (!_instance) 358 | { 359 | _instance = CreateInstance(); 360 | string directoryPath = System.IO.Path.GetDirectoryName(SavePath); 361 | if (!System.IO.Directory.Exists(directoryPath)) 362 | System.IO.Directory.CreateDirectory(directoryPath); 363 | 364 | AssetDatabase.CreateAsset(_instance, _SavePath); 365 | } 366 | return _instance; 367 | } 368 | 369 | public static bool Exists() 370 | { 371 | return System.IO.File.Exists(_SavePath); 372 | } 373 | 374 | } 375 | 376 | } 377 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPacker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4ec2ba90c6362ef45a22d7d4a61e49a3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPackerData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace DreadScripts 6 | { 7 | [System.Serializable] 8 | public class TextureAutoPackerData : TAPDreadData 9 | { 10 | public bool active; 11 | public List activeModules = new List(); 12 | private static readonly string SavePath = "Assets/DreadScripts/SavedData/TextureUtility/TextureAutoPackerData.asset"; 13 | public static TextureAutoPackerData GetInstance() 14 | { 15 | return GetInstance(SavePath); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPackerData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6abd492e1c018b04aa7334b21f8d3e64 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPackerModule.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | namespace DreadScripts 7 | { 8 | [System.Serializable] 9 | [CreateAssetMenu(fileName = "New Auto-Packer Module", menuName = "DreadScripts/Auto-Packer Module")] 10 | public class TextureAutoPackerModule : ScriptableObject 11 | { 12 | public List packedTextures; 13 | 14 | public TextureAutoPackerModule() 15 | { 16 | packedTextures = new List(); 17 | } 18 | } 19 | 20 | [System.Serializable] 21 | public class AutoPackedTexture 22 | { 23 | public bool expanded; 24 | public bool forward=true; 25 | public string name; 26 | public ChannelTexture[] channels; 27 | public string[] channelsHashes; 28 | public bool forceModified; 29 | 30 | public Texture2D packed; 31 | 32 | public TextureUtility.TexEncoding encoding; 33 | public int jpgQuality = 75; 34 | public AutoPackedTexture() 35 | { 36 | name = "New Packed Texture"; 37 | channels = new ChannelTexture[] {new ChannelTexture("Red",0), new ChannelTexture("Green", 1), new ChannelTexture("Blue", 2), new ChannelTexture("Alpha", 0) }; 38 | channelsHashes = new string[] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty }; 39 | encoding = TextureUtility.TexEncoding.SaveAsPNG; 40 | } 41 | 42 | public bool WasModified() 43 | { 44 | if (forceModified) 45 | { 46 | return true; 47 | } 48 | for (int i = 0; i < 4; i++) 49 | { 50 | string textureHash = string.Empty; 51 | if (channels[i].texture) 52 | textureHash = channels[i].texture.imageContentsHash.ToString(); 53 | if (textureHash != channelsHashes[i]) 54 | return true; 55 | } 56 | return false; 57 | } 58 | 59 | public string Pack() 60 | { 61 | string newTexturePath; 62 | if (packed) 63 | newTexturePath = TextureUtility.PackTexture(channels, AssetDatabase.GetAssetPath(packed), packed.width, packed.height, encoding, false, true, false); 64 | else 65 | newTexturePath = TextureUtility.PackTexture(channels, encoding, true, false); 66 | return newTexturePath; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureAutoPackerModule.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 246a916bd716d6d4ba61ee90fc9090de 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEngine; 4 | using System.Linq; 5 | 6 | //Made by Dreadrith#3238 7 | //Server: https://discord.gg/ZsPfrGn 8 | //Github: https://github.com/Dreadrith/DreadScripts 9 | //Gumroad: https://gumroad.com/dreadrith 10 | 11 | namespace DreadScripts 12 | { 13 | public class TextureUtility : EditorWindow 14 | { 15 | private readonly string[] DimensionPresets = { 16 | "128x128", 17 | "256x256", 18 | "512x512", 19 | "1024x1024", 20 | "2048x2048", 21 | "4096x4096", 22 | }; 23 | 24 | private static GUIContent resetIcon; 25 | private static Texture2D titleTexture; 26 | 27 | private static Texture2D mainTexture; 28 | private static Texture2D maskTexture; 29 | 30 | private static int jpgQuality = 75; 31 | private static int texWidth, texHeight; 32 | private static bool copyImport = true; 33 | private static bool pingTexture = true; 34 | 35 | private static bool rotating; 36 | private static TexRotation rotationType; 37 | 38 | private static bool inverting; 39 | private static bool maskInvert=true; 40 | private static bool invertRedS = true, invertGreenS = true, invertBlueS = true, invertAlphaS; 41 | 42 | private static bool unpacking=true,packing; 43 | private static bool editingTab=true, packingTab,creatingTab; 44 | 45 | 46 | private static readonly ChannelTexture redChannel = new ChannelTexture("Red", 0); 47 | private static readonly ChannelTexture greenChannel = new ChannelTexture("Green", 1); 48 | private static readonly ChannelTexture blueChannel = new ChannelTexture("Blue", 2); 49 | private static readonly ChannelTexture alphaChannel = new ChannelTexture("Alpha", 0); 50 | private static readonly ChannelTexture[] channelTextures = { redChannel, greenChannel, blueChannel, alphaChannel }; 51 | 52 | private static bool hueShifting; 53 | private static bool maskHueShift=true; 54 | private static float hueShiftFloat; 55 | 56 | private static bool saturating; 57 | private static bool maskSaturate=true; 58 | private static float saturationFloat; 59 | 60 | private static bool colorizing; 61 | private static bool maskColorize=true; 62 | private static bool textureColorize; 63 | private static bool alphaColorize; 64 | private static float colorizeFloat=0.5f; 65 | private static Color colorizeColor = Color.black; 66 | private static Texture2D colorizeTexture; 67 | 68 | private static Color originalGUIColor; 69 | 70 | private static TexEncoding encoding = TexEncoding.SaveAsPNG; 71 | public enum TexEncoding 72 | { 73 | SaveAsPNG, 74 | SaveAsJPG, 75 | SaveAsTGA 76 | } 77 | 78 | public enum TexRotation 79 | { 80 | Clockwise90, 81 | CClockwise90, 82 | Rotate180, 83 | FlipHorizontal, 84 | FlipVertical 85 | } 86 | 87 | #region Creating Tab Variables 88 | private static bool creatingCustomSize; 89 | private static bool creatingReverse; 90 | private static string creatingPath; 91 | private static Color solidColor=Color.black; 92 | private static Gradient gradientColor = new Gradient() { colorKeys = new GradientColorKey[] { new GradientColorKey(Color.white, 0), new GradientColorKey(Color.black, 1) } }; 93 | 94 | private static TextureCreatingMode creatingMode = TextureCreatingMode.SolidColor; 95 | 96 | private enum TextureCreatingMode 97 | { 98 | SolidColor, 99 | HorizontalGradient, 100 | VerticalGradient 101 | } 102 | #endregion 103 | 104 | [MenuItem("DreadTools/Utilities/Texture Utility")] 105 | private static void showWindow() 106 | { 107 | EditorWindow w = GetWindow(false, "Texture Utility", true); 108 | if (!titleTexture) 109 | { 110 | titleTexture = GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _); 111 | titleTexture.Apply(); 112 | } 113 | 114 | w.titleContent.image = titleTexture; 115 | w.minSize = new Vector2(423, 253); 116 | } 117 | 118 | private void OnGUI() 119 | { 120 | originalGUIColor = GUI.backgroundColor; 121 | using (new GUILayout.HorizontalScope()) 122 | { 123 | bool c = editingTab; 124 | 125 | SetColorIcon(editingTab); 126 | editingTab = GUILayout.Toggle(editingTab, "Editing", "toolbarbutton"); 127 | if (!c && editingTab) 128 | { 129 | packingTab = false; 130 | creatingTab = false; 131 | } 132 | 133 | c = creatingTab; 134 | 135 | 136 | SetColorIcon(creatingTab); 137 | creatingTab = GUILayout.Toggle(creatingTab, "Creating", "toolbarbutton"); 138 | if (!c && creatingTab) 139 | { 140 | packingTab = false; 141 | editingTab = false; 142 | } 143 | 144 | c = packingTab; 145 | 146 | SetColorIcon(packingTab); 147 | packingTab = GUILayout.Toggle(packingTab, "Packing", "toolbarbutton"); 148 | if (!c && packingTab) 149 | { 150 | editingTab = false; 151 | creatingTab = false; 152 | } 153 | GUI.backgroundColor = originalGUIColor; 154 | } 155 | 156 | if (editingTab) 157 | DrawEditingTab(); 158 | 159 | 160 | if (creatingTab) 161 | DrawCreatingTab(); 162 | 163 | if (packingTab) 164 | DrawPackingTab(); 165 | 166 | Credit(); 167 | } 168 | 169 | 170 | private void DrawEditingTab() 171 | { 172 | using (new GUILayout.HorizontalScope()) 173 | { 174 | using (new GUILayout.VerticalScope()) 175 | { 176 | using (new GUILayout.HorizontalScope("box")) 177 | DrawDimensionsGUI(); 178 | 179 | using (new GUILayout.HorizontalScope("box")) 180 | { 181 | encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding, GUILayout.Width(95)); 182 | 183 | EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG); 184 | EditorGUIUtility.labelWidth = 50; 185 | jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100); 186 | EditorGUIUtility.labelWidth = 0; 187 | EditorGUI.EndDisabledGroup(); 188 | } 189 | 190 | using (new GUILayout.HorizontalScope("box")) 191 | { 192 | copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport); 193 | pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture); 194 | } 195 | 196 | using (new GUILayout.HorizontalScope("box")) 197 | { 198 | if (!rotating) 199 | { 200 | SetColorIcon(rotating); 201 | rotating = GUILayout.Toggle(rotating, "Rotate", "toolbarbutton"); 202 | GUI.backgroundColor = originalGUIColor; 203 | } 204 | else 205 | { 206 | SetColorIcon(rotating); 207 | rotating = GUILayout.Toggle(rotating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 208 | GUI.backgroundColor = originalGUIColor; 209 | 210 | EditorGUI.BeginDisabledGroup(true); 211 | GUILayout.Toggle(true, "M", EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); 212 | EditorGUI.EndDisabledGroup(); 213 | 214 | GUILayout.Label("Rotate"); 215 | rotationType = (TexRotation)EditorGUILayout.EnumPopup(GUIContent.none, rotationType); 216 | } 217 | } 218 | 219 | using (new GUILayout.HorizontalScope("box")) 220 | { 221 | if (!inverting) 222 | { 223 | SetColorIcon(inverting); 224 | inverting = GUILayout.Toggle(inverting, "Invert", "toolbarbutton"); 225 | GUI.backgroundColor = originalGUIColor; 226 | } 227 | else 228 | { 229 | SetColorIcon(inverting); 230 | inverting = GUILayout.Toggle(inverting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 231 | GUI.backgroundColor = originalGUIColor; 232 | 233 | maskInvert = GUILayout.Toggle(maskInvert, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); GUILayout.Label("Invert"); 234 | invertRedS = EditorGUILayout.ToggleLeft("R", invertRedS, GUILayout.Width(30)); 235 | invertGreenS = EditorGUILayout.ToggleLeft("G", invertGreenS, GUILayout.Width(30)); 236 | invertBlueS = EditorGUILayout.ToggleLeft("B", invertBlueS, GUILayout.Width(30)); 237 | invertAlphaS = EditorGUILayout.ToggleLeft("A", invertAlphaS, GUILayout.Width(30)); 238 | 239 | } 240 | } 241 | 242 | using (new GUILayout.HorizontalScope("box")) 243 | { 244 | if (!saturating) 245 | { 246 | SetColorIcon(saturating); 247 | saturating = GUILayout.Toggle(saturating, "Saturate", "toolbarbutton"); 248 | GUI.backgroundColor = originalGUIColor; 249 | } 250 | else 251 | { 252 | SetColorIcon(saturating); 253 | saturating = GUILayout.Toggle(saturating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 254 | GUI.backgroundColor = originalGUIColor; 255 | maskSaturate = GUILayout.Toggle(maskSaturate, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); 256 | EditorGUIUtility.labelWidth = 65; 257 | saturationFloat = EditorGUILayout.Slider("Saturate", saturationFloat, -1, 1); 258 | EditorGUIUtility.labelWidth = 0; 259 | } 260 | } 261 | using (new GUILayout.HorizontalScope("box")) 262 | { 263 | if (!hueShifting) 264 | { 265 | SetColorIcon(hueShifting); 266 | hueShifting = GUILayout.Toggle(hueShifting, "Hue Shift", "toolbarbutton"); 267 | GUI.backgroundColor = originalGUIColor; 268 | } 269 | else 270 | { 271 | SetColorIcon(hueShifting); 272 | hueShifting = GUILayout.Toggle(hueShifting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 273 | GUI.backgroundColor = originalGUIColor; 274 | 275 | maskHueShift = GUILayout.Toggle(maskHueShift, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); 276 | EditorGUIUtility.labelWidth = 65; 277 | hueShiftFloat = EditorGUILayout.Slider("Hue Shift", hueShiftFloat, 0, 1); 278 | EditorGUIUtility.labelWidth = 0; 279 | } 280 | } 281 | 282 | using (new GUILayout.HorizontalScope("box")) 283 | { 284 | if (!colorizing) 285 | { 286 | SetColorIcon(colorizing); 287 | colorizing = GUILayout.Toggle(colorizing, "Colorize", "toolbarbutton"); 288 | GUI.backgroundColor = originalGUIColor; 289 | } 290 | else 291 | { 292 | SetColorIcon(colorizing); 293 | colorizing = GUILayout.Toggle(colorizing, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 294 | GUI.backgroundColor = originalGUIColor; 295 | 296 | maskColorize = GUILayout.Toggle(maskColorize, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); 297 | EditorGUIUtility.labelWidth = 65; 298 | colorizeFloat = EditorGUILayout.Slider("Colorize", colorizeFloat, 0, 1); 299 | EditorGUIUtility.labelWidth = 0; 300 | if (!textureColorize) 301 | colorizeColor = EditorGUILayout.ColorField(new GUIContent(""), colorizeColor, true, alphaColorize, false, GUILayout.Width(70), GUILayout.Height(17)); 302 | else 303 | colorizeTexture = (Texture2D)EditorGUILayout.ObjectField(colorizeTexture, typeof(Texture2D), false, GUILayout.Width(70), GUILayout.Height(17)); 304 | textureColorize = GUILayout.Toggle(textureColorize, new GUIContent("T", "Use Texture"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16)); 305 | alphaColorize = GUILayout.Toggle(alphaColorize, new GUIContent("A", "Use Alpha"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16)); 306 | } 307 | } 308 | 309 | } 310 | using (new GUILayout.VerticalScope()) 311 | { 312 | using (new GUILayout.VerticalScope("box")) 313 | { 314 | EditorGUIUtility.labelWidth = 1; 315 | GUILayout.Label("Main", GUILayout.Width(65)); 316 | EditorGUI.BeginChangeCheck(); 317 | mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(65)); 318 | if (EditorGUI.EndChangeCheck()) 319 | ResetDimensions(); 320 | EditorGUIUtility.labelWidth = 0; 321 | } 322 | EditorGUI.BeginDisabledGroup(!(hueShifting || saturating || inverting || colorizing)); 323 | using (new GUILayout.VerticalScope("box")) 324 | { 325 | EditorGUIUtility.labelWidth = 1; 326 | GUILayout.Label("Mask", GUILayout.Width(65)); 327 | maskTexture = (Texture2D)EditorGUILayout.ObjectField("", maskTexture, typeof(Texture2D), false, GUILayout.Width(65)); 328 | EditorGUIUtility.labelWidth = 0; 329 | } 330 | EditorGUI.EndDisabledGroup(); 331 | } 332 | } 333 | EditorGUI.BeginDisabledGroup(!mainTexture); 334 | if (GUILayout.Button("Apply")) 335 | { 336 | ApplyTexture(); 337 | } 338 | EditorGUI.EndDisabledGroup(); 339 | } 340 | 341 | private void DrawCreatingTab() 342 | { 343 | using (new GUILayout.HorizontalScope("box")) 344 | { 345 | if (!creatingCustomSize) 346 | { 347 | SetColorIcon(creatingCustomSize); 348 | creatingCustomSize = GUILayout.Toggle(inverting, "Custom Dimensions", "toolbarbutton"); 349 | GUI.backgroundColor = originalGUIColor; 350 | } 351 | else 352 | { 353 | SetColorIcon(creatingCustomSize); 354 | creatingCustomSize = GUILayout.Toggle(creatingCustomSize, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17)); 355 | GUI.backgroundColor = originalGUIColor; 356 | 357 | DrawDimensionsGUI(false); 358 | } 359 | } 360 | 361 | using (new GUILayout.HorizontalScope("box")) 362 | { 363 | encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding); 364 | 365 | EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG); 366 | EditorGUIUtility.labelWidth = 50; 367 | jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100); 368 | EditorGUIUtility.labelWidth = 0; 369 | EditorGUI.EndDisabledGroup(); 370 | } 371 | 372 | using (new GUILayout.HorizontalScope("box")) 373 | { 374 | pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture); 375 | 376 | EditorGUI.BeginDisabledGroup(creatingMode != TextureCreatingMode.HorizontalGradient && creatingMode != TextureCreatingMode.VerticalGradient); 377 | creatingReverse = EditorGUILayout.Toggle("Reverse Texture", creatingReverse); 378 | EditorGUI.EndDisabledGroup(); 379 | } 380 | 381 | using (new GUILayout.HorizontalScope("box")) 382 | { 383 | creatingMode = (TextureCreatingMode)EditorGUILayout.EnumPopup("Texture Mode", creatingMode); 384 | } 385 | 386 | switch ((int)creatingMode) 387 | { 388 | case 0: 389 | solidColor = EditorGUILayout.ColorField(solidColor); 390 | break; 391 | case 1: 392 | case 2: 393 | gradientColor = EditorGUILayout.GradientField(gradientColor); 394 | break; 395 | } 396 | if (GUILayout.Button("Create")) 397 | { 398 | CreateTexture(); 399 | } 400 | AssetFolderPath(ref creatingPath, "Save To", "TextureUtilityCreatingPath"); 401 | } 402 | 403 | private void DrawPackingTab() 404 | { 405 | 406 | using (new GUILayout.HorizontalScope("box")) 407 | { 408 | encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding); 409 | EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG); 410 | EditorGUIUtility.labelWidth = 50; 411 | jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100); 412 | EditorGUIUtility.labelWidth = 0; 413 | EditorGUI.EndDisabledGroup(); 414 | } 415 | using (new GUILayout.HorizontalScope("box")) 416 | { 417 | copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport); 418 | pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture); 419 | } 420 | using (new GUILayout.HorizontalScope()) 421 | { 422 | bool p = unpacking; 423 | SetColorIcon(unpacking); 424 | unpacking = GUILayout.Toggle(unpacking, "Unpack", "toolbarbutton"); 425 | if (!p && unpacking) 426 | packing = false; 427 | 428 | p = packing; 429 | SetColorIcon(packing); 430 | packing = GUILayout.Toggle(packing, "Pack", "toolbarbutton"); 431 | if (!p && packing) 432 | unpacking = false; 433 | 434 | GUI.backgroundColor = originalGUIColor; 435 | } 436 | if (packing) 437 | { 438 | using (new GUILayout.HorizontalScope()) 439 | { 440 | EditorGUIUtility.labelWidth = 1; 441 | redChannel.DrawGUI(); 442 | greenChannel.DrawGUI(); 443 | blueChannel.DrawGUI(); 444 | alphaChannel.DrawGUI(); 445 | EditorGUIUtility.labelWidth = 0; 446 | } 447 | EditorGUI.BeginDisabledGroup(!channelTextures.Any(c => c.texture)); 448 | if (GUILayout.Button("Pack")) 449 | { 450 | PackTexture(channelTextures); 451 | } 452 | } 453 | if (unpacking) 454 | { 455 | 456 | using (new GUILayout.VerticalScope("box")) 457 | { 458 | using (new GUILayout.HorizontalScope()) 459 | { 460 | GUILayout.FlexibleSpace(); 461 | GUILayout.Label("Main Texture"); 462 | GUILayout.FlexibleSpace(); 463 | } 464 | 465 | using (new GUILayout.HorizontalScope()) 466 | { 467 | GUILayout.FlexibleSpace(); 468 | EditorGUIUtility.labelWidth = 1; 469 | mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(66)); 470 | EditorGUIUtility.labelWidth = 0; 471 | GUILayout.FlexibleSpace(); 472 | } 473 | } 474 | EditorGUI.BeginDisabledGroup(!mainTexture); 475 | if (GUILayout.Button("Unpack")) 476 | { 477 | UnpackTexture(); 478 | } 479 | EditorGUI.EndDisabledGroup(); 480 | } 481 | 482 | 483 | EditorGUI.EndDisabledGroup(); 484 | } 485 | 486 | private void DrawDimensionsGUI(bool drawReset=true) 487 | { 488 | GUIStyle iconStyle = new GUIStyle(GUI.skin.label) { padding = new RectOffset(), margin = new RectOffset(), imagePosition = ImagePosition.ImageOnly }; 489 | 490 | EditorGUI.BeginDisabledGroup(!mainTexture && !creatingTab); 491 | if (drawReset) 492 | { 493 | if (GUILayout.Button(resetIcon, iconStyle, GUILayout.Height(16), GUILayout.Width(16))) 494 | ResetDimensions(); 495 | } 496 | EditorGUIUtility.labelWidth = 20; 497 | texWidth = EditorGUILayout.IntField(new GUIContent("W","Width"), texWidth); 498 | texHeight = EditorGUILayout.IntField(new GUIContent("H", "Height"), texHeight); 499 | EditorGUIUtility.labelWidth = 0; 500 | 501 | int dummy = -1; 502 | EditorGUI.BeginChangeCheck(); 503 | dummy = EditorGUILayout.Popup(dummy, DimensionPresets,GUILayout.Width(17)); 504 | if (EditorGUI.EndChangeCheck()) 505 | { 506 | string[] dimensions = ((string)DimensionPresets.GetValue(dummy)).Split('x'); 507 | texWidth = int.Parse(dimensions[0]); 508 | texHeight = int.Parse(dimensions[1]); 509 | } 510 | 511 | EditorGUI.EndDisabledGroup(); 512 | 513 | } 514 | 515 | public static Texture2D GetColors(Texture2D texture, out Color[] Colors, bool unloadTempTexture = false) 516 | { 517 | return GetColors(texture, texture.width, texture.height, out Colors, unloadTempTexture); 518 | } 519 | 520 | public static Texture2D GetColors(Texture2D texture, int width, int height, out Color[] Colors,bool unloadTempTexture = false) 521 | { 522 | //Thanks to 523 | //https://gamedev.stackexchange.com/questions/92285/unity3d-resize-texture-without-corruption 524 | texture.filterMode = FilterMode.Point; 525 | RenderTexture rt = RenderTexture.GetTemporary(width, height); 526 | 527 | rt.filterMode = FilterMode.Point; 528 | RenderTexture.active = rt; 529 | Graphics.Blit(texture, rt); 530 | Texture2D newTexture = new Texture2D(width, height); 531 | newTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0); 532 | Color[] myColors = newTexture.GetPixels(); 533 | RenderTexture.active = null; 534 | ///////////////////// 535 | Colors = myColors; 536 | if (unloadTempTexture) 537 | { 538 | DestroyImmediate(newTexture); 539 | return null; 540 | } 541 | return newTexture; 542 | } 543 | 544 | private static void SaveTexture(byte[] textureEncoding, string path, bool refresh=false, bool ping=false) 545 | { 546 | System.IO.FileStream stream = System.IO.File.Create(path); 547 | stream.Write(textureEncoding, 0, textureEncoding.Length); 548 | stream.Dispose(); 549 | if (refresh) 550 | { 551 | AssetDatabase.Refresh(); 552 | if (ping) 553 | { 554 | Ping(path); 555 | } 556 | } 557 | 558 | } 559 | private static void Ping(string path) 560 | { 561 | EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(path)); 562 | } 563 | 564 | private void ApplyTexture() 565 | { 566 | if (colorizing && !colorizeTexture && textureColorize) 567 | { 568 | Debug.LogError("Cannot Colorize using a texture without a texture!"); 569 | return; 570 | } 571 | 572 | string destinationPath = GetDestinationFolder(mainTexture); 573 | string texPath = AssetDatabase.GetAssetPath(mainTexture); 574 | 575 | Texture2D newTexture = GetColors(mainTexture, texWidth, texHeight, out Color[] myColors); 576 | 577 | if (rotating) 578 | { 579 | List rotatedColors = new List(); 580 | switch (rotationType) 581 | { 582 | case TexRotation.Clockwise90: 583 | for (int i = texWidth-1; i >=0; i--) 584 | { 585 | rotatedColors.AddRange(newTexture.GetPixels(i, 0, 1, texHeight)); 586 | } 587 | myColors = rotatedColors.ToArray(); 588 | newTexture = new Texture2D(texHeight, texWidth); 589 | break; 590 | 591 | case TexRotation.CClockwise90: 592 | for (int i = 0; i < texWidth; i++) 593 | { 594 | rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(i, 0, 1, texHeight))); 595 | } 596 | myColors = rotatedColors.ToArray(); 597 | newTexture = new Texture2D(texHeight, texWidth); 598 | break; 599 | 600 | case TexRotation.Rotate180: 601 | myColors = ReverseArray(myColors); 602 | break; 603 | 604 | case TexRotation.FlipHorizontal: 605 | for (int i = 0; i < texHeight; i++) 606 | { 607 | rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(0, i, texWidth, 1))); 608 | } 609 | myColors = rotatedColors.ToArray(); 610 | break; 611 | 612 | case TexRotation.FlipVertical: 613 | for (int i = texHeight - 1; i >= 0; i--) 614 | { 615 | rotatedColors.AddRange(newTexture.GetPixels(0, i, texWidth, 1)); 616 | } 617 | myColors = rotatedColors.ToArray(); 618 | break; 619 | } 620 | 621 | } 622 | 623 | bool colorInverting = (invertRedS || invertGreenS || invertBlueS || invertAlphaS) && inverting; 624 | bool HSVEditing = hueShifting || saturating; 625 | bool colorEditing = HSVEditing || colorizing; 626 | bool editing = colorEditing || colorInverting || unpacking; 627 | bool masking = ((maskColorize && colorizing) || (maskInvert && colorInverting) || (maskSaturate && saturating) || (maskHueShift && hueShifting)) && maskTexture; 628 | 629 | Color[] maskColors; 630 | if (masking) 631 | { 632 | GetColors(maskTexture, texWidth, texHeight, out maskColors, true); 633 | } 634 | else 635 | maskColors = null; 636 | 637 | Color[] colorizeTextureColors; 638 | if (colorizing && textureColorize) 639 | { 640 | GetColors(colorizeTexture, texWidth, texHeight, out colorizeTextureColors, true); 641 | } 642 | else 643 | colorizeTextureColors = null; 644 | 645 | 646 | Color[] newColors = new Color[myColors.Length]; 647 | if (editing) 648 | { 649 | for (int i = 0; i < myColors.Length; i++) 650 | { 651 | Color currentColor = myColors[i]; 652 | 653 | if (colorEditing) 654 | { 655 | if (HSVEditing) 656 | { 657 | Color.RGBToHSV(currentColor, out float h, out float s, out float v); 658 | currentColor = Color.HSVToRGB(hueShifting ? (Mathf.Repeat(h + (hueShiftFloat * (maskTexture && maskHueShift ? maskColors[i].r : 1)), 1)) : h, saturating ? (Mathf.Clamp01(s + (saturationFloat * (maskTexture && maskSaturate ? maskColors[i].r : 1)))) : s, v); 659 | currentColor.a = myColors[i].a; 660 | } 661 | if (colorizing) 662 | { 663 | float oga = currentColor.a; 664 | currentColor = Color.Lerp(currentColor, textureColorize ? colorizeTextureColors[i] : colorizeColor, colorizeFloat * (maskColorize && maskTexture ? maskColors[i].r : 1)); 665 | 666 | if (!alphaColorize) 667 | currentColor.a = oga; 668 | } 669 | } 670 | 671 | float r = colorInverting && invertRedS ? currentColor.r - ((currentColor.r - (1 - currentColor.r)) * (maskInvert && maskTexture ? maskColors[i].r : 1)) : currentColor.r; 672 | float g = colorInverting && invertGreenS ? currentColor.g - ((currentColor.g - (1 - currentColor.g)) * (maskInvert && maskTexture ? maskColors[i].g : 1)) : currentColor.g; 673 | float b = colorInverting && invertBlueS ? currentColor.b - ((currentColor.b - (1 - currentColor.b)) * (maskInvert && maskTexture ? maskColors[i].b : 1)) : currentColor.b; 674 | float a = colorInverting && invertAlphaS ? currentColor.a - ((currentColor.a - (1 - currentColor.a)) * (maskInvert && maskTexture ? maskColors[i].a : 1)) : currentColor.a; 675 | 676 | newColors[i] = new Color(r, g, b, a); 677 | } 678 | } 679 | newTexture.SetPixels(editing ? newColors : myColors); 680 | newTexture.Apply(); 681 | 682 | GetEncoding(newTexture, encoding, out byte[] data, out string ext); 683 | 684 | string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name 685 | + (colorInverting ? " Inverted" : "") + ext); 686 | 687 | SaveTexture(data, newTexturePath, true, pingTexture); 688 | 689 | if (copyImport) 690 | { 691 | CopyTextureSettings(texPath, newTexturePath); 692 | } 693 | } 694 | 695 | private static void GetEncoding(Texture2D texture, TexEncoding encodingType, out byte[] data, out string ext) 696 | { 697 | switch ((int)encodingType) 698 | { 699 | default: 700 | ext = ".png"; 701 | data = texture.EncodeToPNG(); 702 | break; 703 | case 1: 704 | ext = ".jpg"; 705 | data = texture.EncodeToJPG(jpgQuality); 706 | break; 707 | case 2: 708 | ext = ".tga"; 709 | data = texture.EncodeToTGA(); 710 | break; 711 | } 712 | } 713 | 714 | 715 | private void CreateTexture() 716 | { 717 | Texture2D newTexture = null; 718 | int w = creatingCustomSize ? texWidth : 0; 719 | int h = creatingCustomSize ? texHeight : 0; 720 | 721 | Color[] myColors = null; 722 | switch ((int)creatingMode) 723 | { 724 | case 0: 725 | if (!creatingCustomSize) 726 | { 727 | w = h = 4; 728 | } 729 | newTexture = new Texture2D(w, h); 730 | 731 | myColors = CreateFilledArray(solidColor, w * h); 732 | newTexture.SetPixels(0, 0, w, h, myColors); 733 | break; 734 | case 1: 735 | { 736 | if (!creatingCustomSize) 737 | { 738 | w = 256; 739 | h = 4; 740 | } 741 | newTexture = new Texture2D(w, h); 742 | 743 | int i = creatingReverse ? w - 1 : 0; 744 | int istep = creatingReverse ? -1 : 1; 745 | 746 | float xstepValue = (1f / w); 747 | float xcurrentStep = 0; 748 | for (; i < w && i >= 0; i += istep) 749 | { 750 | newTexture.SetPixels(i, 0, 1, h, CreateFilledArray(gradientColor.Evaluate(xcurrentStep), h)); 751 | xcurrentStep += xstepValue; 752 | } 753 | } 754 | break; 755 | case 2: 756 | { 757 | if (!creatingCustomSize) 758 | { 759 | w = 4; 760 | h = 256; 761 | } 762 | newTexture = new Texture2D(w, h); 763 | 764 | int i = creatingReverse ? h - 1 : 0; 765 | int istep = creatingReverse ? -1 : 1; 766 | 767 | float ystepValue = 1f / h; 768 | float ycurrentStep = 0; 769 | for (; i < h && i >= 0; i += istep) 770 | { 771 | newTexture.SetPixels(0, i, w, 1, CreateFilledArray(gradientColor.Evaluate(ycurrentStep), w)); 772 | ycurrentStep += ystepValue; 773 | } 774 | } 775 | break; 776 | } 777 | 778 | GetEncoding(newTexture, encoding, out byte[] data, out string ext); 779 | 780 | RecreateFolders(creatingPath); 781 | SaveTexture(data, AssetDatabase.GenerateUniqueAssetPath(creatingPath +"/Generated Texture"+ext), true, pingTexture); 782 | } 783 | 784 | private void UnpackTexture() 785 | { 786 | string destinationPath = GetDestinationFolder(mainTexture); 787 | string texPath = AssetDatabase.GetAssetPath(mainTexture); 788 | int x = mainTexture.width, y = mainTexture.height; 789 | Texture2D newTexture = GetColors(mainTexture, x, y, out Color[] myColors); 790 | List> copyFromTo = new List>(); 791 | 792 | bool isRedPass = true, isGreenPass, isBluePass, isAlphaPass; 793 | isGreenPass = isBluePass = isAlphaPass = false; 794 | try 795 | { 796 | AssetDatabase.StartAssetEditing(); 797 | 798 | do 799 | { 800 | Color[] newColors = new Color[myColors.Length]; 801 | 802 | bool hasAlpha = false; 803 | for (int i = 0; i < myColors.Length; i++) 804 | { 805 | Color currentColor = myColors[i]; 806 | 807 | float r = currentColor.r; 808 | float g = currentColor.g; 809 | float b = currentColor.b; 810 | float a = currentColor.a; 811 | 812 | if (isRedPass) 813 | { 814 | g = b = r; 815 | a = 1; 816 | } 817 | if (isGreenPass) 818 | { 819 | r = b = g; 820 | a = 1; 821 | } 822 | if (isBluePass) 823 | { 824 | r = g = b; 825 | a = 1; 826 | } 827 | if (isAlphaPass) 828 | { 829 | r = g = b = a; 830 | if (a != 1) 831 | hasAlpha = true; 832 | } 833 | 834 | newColors[i] = new Color(r, g, b, a); 835 | } 836 | 837 | if (isAlphaPass && !hasAlpha) 838 | { 839 | isAlphaPass = false; 840 | goto Skip; 841 | } 842 | 843 | newTexture.SetPixels(newColors); 844 | newTexture.Apply(); 845 | 846 | GetEncoding(newTexture, encoding, out byte[] data, out string ext); 847 | 848 | string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name 849 | + (isRedPass ? "-Red" : isGreenPass ? "-Green" : isBluePass ? "-Blue" : "-Alpha") + ext); 850 | 851 | SaveTexture(data, newTexturePath); 852 | 853 | if (copyImport) 854 | { 855 | copyFromTo.Add(new System.Tuple(texPath, newTexturePath)); 856 | } 857 | 858 | if (isAlphaPass) 859 | isAlphaPass = false; 860 | if (isBluePass) 861 | { 862 | isBluePass = false; 863 | isAlphaPass = true; 864 | } 865 | if (isGreenPass) 866 | { 867 | isGreenPass = false; 868 | isBluePass = true; 869 | } 870 | if (isRedPass) 871 | { 872 | isRedPass = false; 873 | isGreenPass = true; 874 | } 875 | 876 | if (unpacking) 877 | newTexture = new Texture2D(x, y); 878 | 879 | Skip:; 880 | 881 | } while (isRedPass || isGreenPass || isBluePass || isAlphaPass); 882 | } 883 | finally 884 | { 885 | AssetDatabase.StopAssetEditing(); 886 | } 887 | AssetDatabase.Refresh(); 888 | if (copyImport) 889 | { 890 | for (int i = 0; i < copyFromTo.Count; i++) 891 | { 892 | CopyTextureSettings(copyFromTo[i].Item1, copyFromTo[i].Item2); 893 | } 894 | } 895 | } 896 | 897 | public void PackTexture(ChannelTexture[] channels) 898 | { 899 | int firstIndex = 0; 900 | for (int i = 3; i >= 0; i--) 901 | { 902 | if (channels[i].texture) 903 | firstIndex = i; 904 | } 905 | ChannelTexture firstChannel = channels[firstIndex]; 906 | int w = firstChannel.texture.width; 907 | int h = firstChannel.texture.height; 908 | PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encoding); 909 | } 910 | 911 | public static string PackTexture(ChannelTexture[] channels, TexEncoding encodingType, bool refresh=true, bool copyImportSettings=true) 912 | { 913 | int firstIndex = -1; 914 | for (int i = 3; i >= 0; i--) 915 | { 916 | if (channels[i].texture) 917 | firstIndex = i; 918 | } 919 | if (firstIndex < 0) 920 | return string.Empty; 921 | ChannelTexture firstChannel = channels[firstIndex]; 922 | int w = firstChannel.texture.width; 923 | int h = firstChannel.texture.height; 924 | return PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encodingType,refresh,false,copyImportSettings); 925 | } 926 | 927 | public static string PackTexture(ChannelTexture[] channels, string destination,int width, int height, TexEncoding encodingType, bool refresh=true,bool overwrite=false, bool copyImportSettings=true) 928 | { 929 | int firstIndex = -1; 930 | for (int i = 3; i >= 0; i--) 931 | { 932 | if (channels[i].texture) 933 | firstIndex = i; 934 | } 935 | if (firstIndex < 0) 936 | return string.Empty; 937 | 938 | ChannelTexture firstChannel = channels[firstIndex]; 939 | 940 | 941 | Texture2D newTexture = new Texture2D(width, height); 942 | channels[0].GetChannelColors(width, height, out float[] reds, true); 943 | channels[1].GetChannelColors(width, height, out float[] greens, true); 944 | channels[2].GetChannelColors(width, height, out float[] blues, true); 945 | channels[3].GetChannelColors(width, height, out float[] alphas, true); 946 | Color[] finalColors = new Color[width*height]; 947 | 948 | for (int i=0;i< finalColors.Length;i++) 949 | { 950 | finalColors[i].r = (reds!=null) ? reds[i] : 0; 951 | finalColors[i].g = (greens != null) ? greens[i] : 0; 952 | finalColors[i].b = (blues != null) ? blues[i] : 0; 953 | finalColors[i].a = (alphas != null) ? alphas[i] : 1; 954 | } 955 | newTexture.SetPixels(finalColors); 956 | newTexture.Apply(); 957 | 958 | GetEncoding(newTexture, encodingType, out byte[] data, out string ext); 959 | 960 | string newTexturePath = GetDestinationFolder(destination)+"/"+System.IO.Path.GetFileNameWithoutExtension(destination)+ext; 961 | if (!overwrite) 962 | newTexturePath = AssetDatabase.GenerateUniqueAssetPath(newTexturePath); 963 | SaveTexture(data, newTexturePath); 964 | DestroyImmediate(newTexture); 965 | if (refresh) 966 | AssetDatabase.Refresh(); 967 | 968 | 969 | if (copyImportSettings) 970 | { 971 | CopyTextureSettings(AssetDatabase.GetAssetPath(firstChannel.texture), newTexturePath); 972 | } 973 | return newTexturePath; 974 | } 975 | 976 | private static void CopyTextureSettings(string from, string to) 977 | { 978 | TextureImporter source = (TextureImporter)AssetImporter.GetAtPath(from); 979 | TextureImporterSettings sourceSettings = new TextureImporterSettings(); 980 | source.ReadTextureSettings(sourceSettings); 981 | 982 | TextureImporter destination = (TextureImporter)AssetImporter.GetAtPath(to); 983 | destination.SetTextureSettings(sourceSettings); 984 | destination.maxTextureSize = source.maxTextureSize; 985 | destination.textureCompression = source.textureCompression; 986 | destination.crunchedCompression = source.crunchedCompression; 987 | destination.SaveAndReimport(); 988 | } 989 | 990 | private static string GetDestinationFolder(Object o) 991 | { 992 | string path = AssetDatabase.GetAssetPath(o); 993 | return GetDestinationFolder(path); 994 | } 995 | private static string GetDestinationFolder(string path) 996 | { 997 | return path.Substring(0, path.LastIndexOf('/')); 998 | } 999 | 1000 | private void ResetDimensions() 1001 | { 1002 | if (mainTexture) 1003 | { 1004 | texHeight = mainTexture.height; 1005 | texWidth = mainTexture.width; 1006 | } 1007 | } 1008 | 1009 | private void SetColorIcon(bool value) 1010 | { 1011 | if (value) 1012 | GUI.backgroundColor = Color.green; 1013 | else 1014 | GUI.backgroundColor = Color.grey; 1015 | } 1016 | 1017 | private void OnEnable() 1018 | { 1019 | resetIcon = new GUIContent(EditorGUIUtility.IconContent("d_Refresh")) { tooltip = "Reset Dimensions" }; 1020 | creatingPath = PlayerPrefs.GetString("TextureUtilityCreatingPath", "Assets/DreadScripts/Texture Utility/Generated Assets"); 1021 | 1022 | foreach (var channel in channelTextures) 1023 | { 1024 | channel.SetMode(EditorPrefs.GetInt("TextureUtilityChannel" + channel.name, (int)channel.mode)); 1025 | } 1026 | } 1027 | 1028 | private static T[] CreateFilledArray(T variable,int length) 1029 | { 1030 | T[] myArray = new T[length]; 1031 | for (int i=0;i< myArray.Length;i++) 1032 | { 1033 | myArray[i] = variable; 1034 | } 1035 | return myArray; 1036 | } 1037 | 1038 | private static T[] ReverseArray(T[] array) 1039 | { 1040 | T[] reversed = new T[array.Length]; 1041 | int index = array.Length - 1; 1042 | for (int i = 0; i < reversed.Length; i++) 1043 | { 1044 | reversed[i] = array[index]; 1045 | index--; 1046 | } 1047 | return reversed; 1048 | } 1049 | 1050 | #region Extracted From DS_CommonMethods 1051 | public static void AssetFolderPath(ref string variable, string title, string playerpref) 1052 | { 1053 | EditorGUILayout.BeginHorizontal(); 1054 | EditorGUI.BeginDisabledGroup(true); 1055 | EditorGUILayout.TextField(title, variable); 1056 | EditorGUI.EndDisabledGroup(); 1057 | if (GUILayout.Button("...", GUILayout.Width(30))) 1058 | { 1059 | string dummyPath = EditorUtility.OpenFolderPanel(title, variable, ""); 1060 | if (string.IsNullOrEmpty(dummyPath)) 1061 | return; 1062 | 1063 | if (!dummyPath.Contains("Assets")) 1064 | { 1065 | Debug.LogWarning("New Path must be a folder within Assets!"); 1066 | return; 1067 | } 1068 | variable = FileUtil.GetProjectRelativePath(dummyPath); 1069 | PlayerPrefs.SetString(playerpref, variable); 1070 | } 1071 | EditorGUILayout.EndHorizontal(); 1072 | } 1073 | 1074 | public static void RecreateFolders(string fullPath) 1075 | { 1076 | string[] folderNames = fullPath.Split('/'); 1077 | string[] folderPaths = new string[folderNames.Length]; 1078 | for (int i = 0; i < folderNames.Length; i++) 1079 | { 1080 | folderPaths[i] = folderNames[0]; 1081 | for (int j = 1; j <= i; j++) 1082 | { 1083 | folderPaths[i] = folderPaths[i] + "/" + folderNames[j]; 1084 | } 1085 | } 1086 | for (int i = 0; i < folderPaths.Length; i++) 1087 | { 1088 | if (!AssetDatabase.IsValidFolder(folderPaths[i])) 1089 | { 1090 | AssetDatabase.CreateFolder(folderPaths[i].Substring(0, folderPaths[i].LastIndexOf('/')), folderPaths[i].Substring(folderPaths[i].LastIndexOf('/') + 1, folderPaths[i].Length - folderPaths[i].LastIndexOf('/') - 1)); 1091 | } 1092 | 1093 | } 1094 | } 1095 | #endregion 1096 | 1097 | private static void Credit() 1098 | { 1099 | GUIStyle creditLabelStyle = new GUIStyle(GUI.skin.label) { richText = true }; 1100 | using (new GUILayout.HorizontalScope()) 1101 | { 1102 | GUILayout.FlexibleSpace(); 1103 | if (GUILayout.Button("Made by Dreadrith#3238",creditLabelStyle)) 1104 | { 1105 | Application.OpenURL("https://github.com/Dreadrith/DreadScripts"); 1106 | } 1107 | 1108 | } 1109 | } 1110 | } 1111 | 1112 | [System.Serializable] 1113 | public class ChannelTexture 1114 | { 1115 | public string name; 1116 | public Texture2D texture; 1117 | public bool invert; 1118 | public Color defaultColor; 1119 | public ColorMode mode = ColorMode.Red; 1120 | public enum ColorMode 1121 | { 1122 | Red, 1123 | Green, 1124 | Blue, 1125 | Alpha 1126 | } 1127 | public ChannelTexture(string n, int mode) 1128 | { 1129 | name = n; 1130 | SetMode(mode, true); 1131 | if (n == "Alpha") 1132 | defaultColor = Color.white; 1133 | } 1134 | 1135 | public void SetMode(int i, bool ignoreSave = false) 1136 | { 1137 | switch (i) 1138 | { 1139 | case 0: 1140 | mode = ColorMode.Red; 1141 | break; 1142 | case 1: 1143 | mode = ColorMode.Green; 1144 | break; 1145 | case 2: 1146 | mode = ColorMode.Blue; 1147 | break; 1148 | case 3: 1149 | mode = ColorMode.Alpha; 1150 | break; 1151 | } 1152 | if (!ignoreSave) 1153 | { 1154 | EditorPrefs.SetInt("TextureUtilityChannel" + name, i); 1155 | } 1156 | } 1157 | 1158 | public Texture2D GetChannelColors(int width, int height, out float[] colors, bool unloadTempTexture) 1159 | { 1160 | Texture2D textureToUse; 1161 | if (texture) 1162 | textureToUse = texture; 1163 | else 1164 | { 1165 | textureToUse = new Texture2D(1, 1, TextureFormat.RGBA32, false, true); 1166 | textureToUse.SetPixel(0, 0, defaultColor); 1167 | textureToUse.Apply(); 1168 | } 1169 | 1170 | Texture2D newTexture = TextureUtility.GetColors(textureToUse, width, height, out Color[] myColors, unloadTempTexture); 1171 | colors = myColors.Select(c => 1172 | { 1173 | switch (mode) 1174 | { 1175 | case ColorMode.Red: 1176 | return c.r; 1177 | case ColorMode.Green: 1178 | return c.g; 1179 | case ColorMode.Blue: 1180 | return c.b; 1181 | default: 1182 | return c.a; 1183 | } 1184 | }).ToArray(); 1185 | if (invert) 1186 | { 1187 | for (int i = 0; i < colors.Length; i++) 1188 | { 1189 | colors[i] = 1 - colors[i]; 1190 | } 1191 | } 1192 | 1193 | if (!texture && unloadTempTexture) 1194 | Object.DestroyImmediate(textureToUse); 1195 | 1196 | return newTexture; 1197 | 1198 | } 1199 | 1200 | public void DrawGUI() 1201 | { 1202 | GUIStyle buttonGroupStyle = new GUIStyle(GUI.skin.GetStyle("toolbarbutton")) { padding = new RectOffset(1, 1, 1, 1), margin = new RectOffset(0, 0, 1, 1) }; 1203 | using (new GUILayout.VerticalScope("box")) 1204 | { 1205 | using (new GUILayout.HorizontalScope()) 1206 | { 1207 | GUILayout.FlexibleSpace(); 1208 | GUILayout.Label(name, "boldlabel"); 1209 | GUILayout.FlexibleSpace(); 1210 | } 1211 | using (new GUILayout.HorizontalScope()) 1212 | { 1213 | GUILayout.FlexibleSpace(); 1214 | bool dummy; 1215 | EditorGUI.BeginChangeCheck(); 1216 | dummy = GUILayout.Toggle(mode == ColorMode.Red, "R", buttonGroupStyle, GUILayout.Width(16)); 1217 | if (EditorGUI.EndChangeCheck()) 1218 | if (dummy) 1219 | SetMode(0); 1220 | 1221 | EditorGUI.BeginChangeCheck(); 1222 | dummy = GUILayout.Toggle(mode == ColorMode.Green, "G", buttonGroupStyle, GUILayout.Width(16)); 1223 | if (EditorGUI.EndChangeCheck()) 1224 | if (dummy) 1225 | SetMode(1); 1226 | 1227 | EditorGUI.BeginChangeCheck(); 1228 | dummy = GUILayout.Toggle(mode == ColorMode.Blue, "B", buttonGroupStyle, GUILayout.Width(16)); 1229 | if (EditorGUI.EndChangeCheck()) 1230 | if (dummy) 1231 | SetMode(2); 1232 | 1233 | EditorGUI.BeginChangeCheck(); 1234 | dummy = GUILayout.Toggle(mode == ColorMode.Alpha, "A", buttonGroupStyle, GUILayout.Width(16)); 1235 | if (EditorGUI.EndChangeCheck()) 1236 | if (dummy) 1237 | SetMode(3); 1238 | GUILayout.FlexibleSpace(); 1239 | } 1240 | using (new GUILayout.HorizontalScope()) 1241 | { 1242 | GUILayout.FlexibleSpace(); 1243 | Rect myTextureRect = GUILayoutUtility.GetRect(66, 66); 1244 | Rect myColorRect = new Rect(myTextureRect) { x = myTextureRect.x + 1, y = myTextureRect.y + 45, width = 20, height = 20 }; 1245 | 1246 | if (!texture) 1247 | defaultColor = EditorGUI.ColorField(myColorRect, GUIContent.none, defaultColor, false, false, false); 1248 | texture = (Texture2D)EditorGUI.ObjectField(myTextureRect, texture, typeof(Texture2D), false); 1249 | if (!texture) 1250 | defaultColor = EditorGUI.ColorField(myColorRect, GUIContent.none, defaultColor, false, false, false); 1251 | 1252 | 1253 | GUILayout.FlexibleSpace(); 1254 | } 1255 | invert = GUILayout.Toggle(invert, "Invert", "toolbarbutton"); 1256 | } 1257 | } 1258 | } 1259 | } -------------------------------------------------------------------------------- /Texture Utility/Editor/TextureUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb8d94d5a72732e4b8b754b8138f95d8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Texture Utility/Info_images/PackWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Texture Utility/Info_images/PackWindow.png -------------------------------------------------------------------------------- /Texture Utility/Info_images/TextureWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dreadrith/DreadScripts/e4d005cc423fc5007b4b20066f28bcf4ff8efba8/Texture Utility/Info_images/TextureWindow.png -------------------------------------------------------------------------------- /Texture Utility/README.md: -------------------------------------------------------------------------------- 1 | # Texture Utility 2 | 3 | Utility Release 4 | ---------------------- 5 | Download Here 6 | Texture Utility and Auto-Packer's purpose is to speed up the workflow by negating the need to use other softwares for mundane texture edits and achieve the desired results directly in Unity. 7 | 8 | Features: 9 | - Resize, Rotate, Invert, Saturate, Hueshift and Colorize textures with Support for Masks. 10 | - Quickly Create a Solid or Gradient colored texture. 11 | - Unpack or Pack textures with color channels. 12 | - Includes an Auto-Packing system to automatically pack a texture from its channels. 13 | 14 | ![Window](https://github.com/Dreadrith/DreadScripts/blob/main/Texture%20Utility/Info_images/TextureWindow.png) 15 | ![Pack](https://github.com/Dreadrith/DreadScripts/blob/main/Texture%20Utility/Info_images/PackWindow.png) 16 | -------------------------------------------------------------------------------- /Texture Utility/Texture Auto-Packer Instructions.txt: -------------------------------------------------------------------------------- 1 | Made by Dreadrith#3238 2 | Server: https://discord.gg/ZsPfrGn 3 | Github: https://github.com/Dreadrith/DreadScripts 4 | Gumroad: https://gumroad.com/Dreadrith 5 | Ko-fi: https://ko-fi.com/dreadrith 6 | 7 | Version: v2.0.1 8 | Download: https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/TextureUtility.unitypackage 9 | 10 | Texture Auto-Packer is made to negate the need to have to go through texture packing by automatically detecting channels modifications and update the resulting texture 11 | 12 | How Auto-Packer works: 13 | ---------------------- 14 | Auto-Packer will usually initiate whenever a Texture gets imported, whether it's new, modified or re-imported. 15 | It checks the settings in the Auto-Packer window, and checks for changes in each module, and packs each texture that's marked as modified. 16 | 17 | An Auto-Packed Texture is marked as modified when: 18 | - The Channel Textures doesn't match the hash of the textures the last time it got packed. 19 | - The Channel selector was changed 20 | - Invert toggle was clicked. 21 | 22 | Module Settings: 23 | ---------------- 24 | Used to determine what Auto-Packed Textures to check for channel modification 25 | Found under Assets > Create > DreadScripts > Auto-Packer Module 26 | 27 | An Auto-Packed Texture consists of 4 Channel Textures (RGBA) and a Packed Texture (Result) 28 | 29 | Add: Creates a new Auto-Packed Texture 30 | Save As: Determines the extension of the Packed Texture. 31 | Quality: Only for JPG, determines the quality of the Packed Texture. 32 | 33 | RGBA: Determines which channel should be sampled for the respective color 34 | Invert: Inverts the sampled colors from the color texture. 35 | 36 | Force Pack: Packs the resulting texture regardless of modification. (Overwrites result texture). 37 | 38 | Window Settings 39 | --------------- 40 | Used to modify the settings of the Auto-Packer. 41 | Found under DreadTools > Utilities > Texture Auto-Packer 42 | 43 | Active: Determines whether the Auto-Packer should check for channel modifications and pack the result if needed. 44 | Active Modules: The Modules that the Auto-Packer should lookup for textures to pack 45 | 46 | Force Check: Initiates the Auto-Packer without having to trigger a texture import. 47 | -------------------------------------------------------------------------------- /Texture Utility/Texture Auto-Packer Instructions.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cf8d7973ce3e7bc48a90402d42b774cc 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Texture Utility/Texture Utility Instructions.txt: -------------------------------------------------------------------------------- 1 | Made by Dreadrith#3238 2 | Server: https://discord.gg/ZsPfrGn 3 | Github: https://github.com/Dreadrith/DreadScripts 4 | Gumroad: https://gumroad.com/Dreadrith 5 | Ko-fi: https://ko-fi.com/dreadrith 6 | 7 | Version: v2.0.1 8 | Download: https://github.com/Dreadrith/DreadScripts/releases/download/Scripts/TextureUtility.unitypackage 9 | 10 | Texture Utility is made to make mundane and simple edits easier and quicker by doing it straight through Unity 11 | Found under DreadTools > Utilities > Texture Utility 12 | 13 | General Settings: 14 | ----------------- 15 | Dimensions (W and H): - Width and Height of the newly created Textures. Refresh Icon resets the dimensions to the currently set Main Texture. 16 | - Popup button is to select hardcoded preset dimensions. 17 | - You can add your own in the script in Texture Utility > Editor > TextureUtility.cs. Simply add a new line to "DimensionPresets" with the same format. 18 | 19 | Save As: - Choose whether to save as PNG or JPG. JPG is typically smaller than but doesn't support Transparency. 20 | - If using JPG, use the slider to set the quality of it. Less quality is smaller size but smaller color range. 21 | 22 | Copy Import Settings: - Newly Created Texture will derive its import settings from the referenced texture. Settings such as Max Size, Crunch, Compression, etc... 23 | Highlight Texture: - Project / Assets window will automatically navigate to the folder where the new texture was created. 24 | 25 | 26 | Editing Tab: For Resize and Edits. 27 | ------------ 28 | Main: - The Main texture the edits will be applied to. 29 | Mask: - Defines the parts and factor of how and where the edits will be applied. Black is a factor of 0. White is a factor of 1. 30 | 31 | "M" Toggle: - Chooses whether the module should be affected by the Mask. 32 | 33 | Rotate: - Rotates the texture or flips it. 34 | Invert: - Inverts the Colors of the selected channels on the texture. R > Red, G > Green, B > Blue, A > Alpha. an R G B invert is the typical color invert. 35 | Saturate: - (Very Wonky) Increases / Decreases the saturation of the texture. -1 will guarantee all colors are grayscale. +1 is Hell. 36 | Hue Shift: - Shifts the Hue of the texture. +1 is a full round hue shift back to the same color. 37 | Colorize: - Lerps the colors between the main texture and the target Texture / Color. 0 is no change. +1 is full on target colors. 38 | - "T" Toggle switches the mode between Color and Texture. "A" Toggle chooses whether the Alpha of the target should be used. 39 | 40 | Press "Apply" to apply the edits. This will create a new texture with the same name in the same folder as the main texture with the desired edits. 41 | 42 | 43 | Creating Tab: For creating simple textures 44 | ------------- 45 | Custom Dimensions: - Choose to specify the dimensions of the newly created texture 46 | - By default, Dimensions will be 4x4 for Solid Color, 256x4 for Horizontal Gradient, 4x256 for Vertical Gradient. 47 | 48 | Reverse Texture: - The colors of the created texture will be flipped. 49 | 50 | Texture Mode: - Choose whether the texture is a solid color or a horizontal/vertical gradient. 51 | Color/Gradient: - Choose your colors for the new texture. 52 | 53 | Save To: - The folder where the textures will be created. 54 | 55 | Press "Create" to create the new texture. It will save the texture under the path specified in "Save To". 56 | 57 | 58 | Packing Tab: For Unpacking/Packing texture's channels (RGBA) 59 | ------------ 60 | Unpack: - Choose the main texture then Press "Unpack". 61 | - This will create 3-4 textures (RGB(A)) in the same folder as the main texture with their appropriate channel colors. 62 | 63 | Pack: - Insert your channel colors that you wish to merge under their appropriate channels 64 | - The Colored box is the default solid color to use if not using a texture. 65 | - Choose the color that you wish to extract from the Channel's texture or color 66 | - Invert Toggle will invert the colors of the channel before packing it. 67 | - Press "Pack" to pack the textures into 1 texture. -------------------------------------------------------------------------------- /Texture Utility/Texture Utility Instructions.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d36c365e711ee448a0f1132f787d572 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------