Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Unusably slow

A topic by Neon Specter created 38 days ago Views: 954 Replies: 37
Viewing posts 1 to 26

I just purchased Super Text Mesh and it's bringing the editor to a crawl.  The slowdown depends on the number of characters in the text field.  It's not too bad with just a few words, but it gets quite slow after a few sentences and after a few paragraphs it's completely unusable (takes over a minute just to change the text color or load a prefab with Super Text).

I'm using Unity 6000.0.27f1.  All Super Text settings are default and I'm using newly created Super Text objects.  I'm using a single Screen Space Overlay canvas and don't have any slowdown issues with TMP.

Developer

Hello,


This is something I've wanted to optimize for a while - but STM was originally made for flashy dialogue boxes and small UI elements, leaving large paragraphs a bit of an afterthought - I already have a working fix though! Look for STMPagination in the sample scenes - you can use this to have one STM object automatically flow into the next - even with reading effects. Splitting up the work between multiple meshes (e.g. one per line for a page) seems to work well for keeping performance up in this circumstance.

So... will keep thinking on more optimizations to my code, but the pagination script works for this scenario!

-Kai

Hi,

Thanks for the quick response.  So I would have to have a bunch of separate texts then to work around this issue?  I'm afraid that's not really a great solution, even if I only have to manage the text property of one of them.

My use case here is tutorials - where it would be quite helpful to have rich text formatting for headers, lists, and etc.  This is a really heavy performance hit for a text object... would it be possible to add a toggle to disable whatever is causing the slowdown in the editor for this use case (no animations needed)?

I bought this asset to replace my own buggy rich text system (as well as for some other features), so I know that this is feasible without noticeably affecting editor performance.  Ideally you'd want to avoid ExecuteInEditMode entirely (there are more than performance concerns with this) and rely on OnInspectorGUI instead - making playing animations in edit mode optional.

Developer

I really should make an auto-pagination prefab for this already now that I think about it... Or extend the pagination component so there's a button that easily adds an STM object and automatically adjusts line spacing/size... Adding that to the to-do list for sure!


And yes, there is a "disableAnimatedText" boolean that can be checked, which will disable all animated effects., and a mesh shouldn't update in the way it does for animations without any applied. That's why I'm suggesting splitting it up into lines, that way you can have some effects without needing the entire mesh to rebuild.

A toggle for animations in edit mode is a great idea actually, I can add that to the settings for the next update! The inspector itself has a lot of overhead for large blocks of text too, sometimes performance can increase by inspecting something else. (Will need to look into this again, but I could swear this was something I couldn't work around short of a toggle to hide the text field)

On paper this asset solves all of my text problems, so I'd really like to make it work - but it starts chugging with as few as 100 characters; essentially meaning I'd need a new object for every sentence or two.  I don't really consider that to be usable.

I don't mean to criticize your code (I haven't even looked at it yet), but I feel like something is being done very wrong for it to perform this badly and you either need to find out what that something is, or separate out some of the more expensive functionality - enabling it only if it's used.  I understand that Unity's own editor code is often very poorly optimized, but there are definitely ways to work around that.

Now, as for a prefab:  if it's something that allows me to set a single text area (rect where text appears) and then automatically creates STM objects as needed, I would consider that to be a satisfactory workaround.  I don't want to have to micro-manage a bunch of separate text areas though.

If you could do that relatively soon (next few weeks), it would work for me - ideally also committing to fix the underlying performance issues at some point.  If not, I don't think the asset will work for me and I'd need a refund, as I don't think it currently meets the lightweight performance claims.

Developer

Unity's own inspector doesn't even support RTL text, ligatures, or Emoji, (I've already made packages for fixing these in-editor, but the inspector's text areas seem untouchable... Look up any "how to type RTL text in Unity Editor" question and every answer involves typing LTR and fixing it in post) so I don't think any optimization has been done on it in the last 10 years either... I'm thinking of ways to optimize this right now and everything just hits a roadblock besides hiding the text field itself. The unity editor just introduces a lot of overhead typically.


I'll write the multiline auto-pagination script asap (that would be a really good sample script for a common use-case, I want to make it) and see what can be done in terms of optimization for large fields of text on their own, but there's only so much that can be done with hundreds of Vector3s being updated on a CPU-bound mesh every frame. Splitting it into separate coroutines like the multi-mesh solution could be a good hint towards that though, if I get a free week sometime I would love to mess around with that. (e.g. instead of one coroutine for reading a mesh/maintaining animations, maybe a coroutine for each character could perform better...? Will need to test)


I originally developed STM on a 2009 macbook pro, then a 2017 mid-range windows laptop, so I'll admit I'm a bit curious about your system specs! I really do enjoy optimization, but it was consuming my life years ago, so my approach is now "if this ran fine on a 2017 iPhone, it'll be fine on anything now", haha. That said, it's been a while since I've done a peer code review, so I may pay a friend to look over my code to see if I missed anything. A couple features were added in the last few years, so maybe something got left out.


I'll take no offence to a refund, all that matters is getting your game done in a timely matter... I spent the better part of this last decade developing STM to save other developers' time, but I just can't pour quite as much into it anymore between contract work and personal life... but I will see what I can do over the weekend! STM is my baby, I want to make sure it 's still working as it should.

I'm running on a Ryzen 5600X and CPU utilization is low with none of the cores maxed out - so it's clearly a bottleneck somewhere.  On further testing I've found that it only becomes unusable when working with prefabs.

If I drop a prefab into the scene and unpack it, I can have over 1000 characters and it's super laggy but doesn't lock up the editor.  If I leave it as a prefab every change takes 15-60 seconds (Unity pops up the "Hold on" window with STM's OnInspectorGUI and Unity's save scene and import assets taking the the longest).  Multiple changes also get queued (like dragging to select a color from the color palette), which can lock up unity for several minutes at a time.

I tried creating completely new prefabs to test this and got the exact same behavior - it's at least 20x slower when working with prefabs.  It doesn't matter if I'm working with a prefab in the scene or in prefab mode.

Developer

Huh okay that's interesting - not at all the issue I thought that was happening at all if there's a difference inside and outside of prefabs.


It could be something with a newer version of Unity forcing some editor code to be called more than it should (There shouldn't be a difference at all when editing the color value of a mesh inside and outside of a prefab), so will have to look into that for sure. I'm getting a few ideas already but will need to test them myself to see if they make a difference and don't break anything else. (Marking the textMesh variable as nonserialized is the first thing I'm going to try, but it should not be taking 15-60 seconds to save a 4k vert mesh on any CPU from the last decade regardless...?)

One guess I have that you can try is... is auto-save enabled in the prefab editor? Not sure if it would make a huge difference if it's somehow taking 15-60 seconds at any point, but that would force a save every time a value updates and force other instances to update too which could be a lot if done every single frame.

So will experiment with this soon! Sorry for the trouble.

(3 edits)

I tried turning off auto save and it doesn't really make a difference (it happens both in prefab mode and in scene mode when working with prefabs).  I made two more strange observations:

1.  The slowdown seems to heavily depend on the text content.  If I copy/paste "Hello World!" over and over it performs better and I can get about twice as many characters before it slows down to the same level as my tutorial text (which is ~900 characters).  The tutorial text is just plain English text, nothing fancy.

2.  With the repeated text prefab, If I save the prefab and then drop it into the scene I get the laggy, but still usable behavior; however, the moment I touch the actual text, it turns bold (in the inspector window) and starts locking up unity.

Note that when I say "usable", I mean I can edit the text settings. It's still pretty unusable for typing text into the text box.

EDIT:  I'm also noticing that after recompiling Unity takes over a minute to import any prefabs that have a STM object (but only if they're in the scene).  I also tried making the text mesh non-serialized and it made no difference.

Developer

Ok, update...


First, Is this the type of setup you're describing? I'm trying this in an old Unity version (My main development project for STM) so it could be something unique to a newer version, but I just want to see if I'm on the same page or not:



The bit of lag I see here seems typical for multiple prefabs getting edited, but from what you described you're seeing something a bit more than this, so is this type of setup correct, but just with a *lot* more text? Additionally, I tried this both inside and outside of Unity UI and didn't see a difference in UI text - if anything, the UI text had better performance than the above gif? So will try in Unity 6 soon.


Second, I went ahead and wrote the auto pagination script, but I don't actually see a visible performance boost on my end vs. just editing a normal text mesh, but I'm going to share it regardless:

https://pastebin.com/UReTwUEf

You just attach this as a component to an STM object and it sets up others like this:


There's an option to automatically grab the amount of lines from the text mesh, redo the layout if the amount of lines changes, and the amount of lines each STM object will render. It's useful, but I unfortunately don't think it'll be the answer to this problem just yet. Worth a shot, though.


So I will try it in Unity 6 soon, but I want to make sure I'm understanding the problem correctly as I'm not seeing any locking up on my end just yet? I feel like I must be missing something obvious, sorry I've been bouncing between so many different projects and I might be getting stuff mixed up.

I'm getting strange results when testing.  If I drop a prefab with a moderate amount of text into the scene, I get "normal" lag until I edit the text, at which point it starts locking up.  Then if I unpack the prefab, it's back to normal.  The more text I add to the prefab (beyond the amount initially there), the slower it gets.  I recorded a video demonstrating this - do you have a support email I can send it to?

The one consistent thing is:  whenever the text in the STM text box turns bold, it starts locking up unity.  When I edit the text as described above, it turns bold and this happens.  For my tutorial prefab, I notice it's already bold when I try to edit it, meaning everything is super slow right from the start (even just opening it in prefab mode).

As for the auto pagination script: I couldn't get it to work.  If I set it to auto it does nothing.  If I click manual setup, it creates one empty STM object.  I couldn't get it to overflow text into other objects no matter how much text I added.

When I add the script it doesn't automatically add STM pagination.  If I add it manually or click Manual Set Up it adds one that is disabled and throws null errors because overflow text isn't assigned.  Clicking Manual Set Up again sometimes assigns the overflow text, sometimes not.  At that point, it creates a second STM clone with an exact copy of the first one's text.  After this happens, the original's text is stale and doesn't update when I change the text in the text box.

I copied your settings and wasn't able to get it to automatically create/destroy/assign text to STM objects.

Developer

It's not supposed to do it automatically on being added, but it will do it after any default value is changed or text is changed on the mesh - (The default assigned values on a new instance of the script will no nothing - autoLineCount is set to false, lineCount is set to 1) I did it this way because the code called upon OnEnable() and OnDisable() wouldn't hook into STM properly if run on the same frame- so I figured two birds one stone - if the script when created is in a non-automatic state and requires set up, the action of setting it up will finish the enable process once the text mesh is edited. So... it's by design!


There shouldn't be any null errors though, I can give that another look after dinner...


Your "lines per text mesh" value is 31, try changing that, if it's higher than the amount of lines, no additional meshes will be created.

Here's what I'm doing:

  1. Create Super Text via UI --> Super Text
  2. Change text to "Test"
  3. Add STM Auto Split to Super Text
  4. Click Manual Set Up --> null error

At this point, the text field is stale and doesn't update the rendered text when changed.  I tried manually assigning overflow text in the STM Pagination component and clicking Manual Set Up again, but it's completely unresponsive to text changes at this point.

Developer

Following these steps, and I cannot reproduce that... can you send me the text from the error you're getting?

NullReferenceException: Object reference not set to an instance of an object STMPagination.Awake () (at Assets/Extensions/Clavian/SuperTextMesh/Sample/Pagination/STMPagination.cs:13) UnityEngine.GameObject:AddComponent() STMAutoSplit:SetUp() (at Assets/Scripts/STMAutoSplit.cs:108) STMAutoSplitEditor:OnInspectorGUI() (at Assets/Scripts/STMAutoSplit.cs:30) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
NullReferenceException: Object reference not set to an instance of an object STMPagination.OnDisable () (at Assets/Extensions/Clavian/SuperTextMesh/Sample/Pagination/STMPagination.cs:38) UnityEngine.GameObject:AddComponent() STMAutoSplit:SetUp() (at Assets/Scripts/STMAutoSplit.cs:108) STMAutoSplitEditor:OnInspectorGUI() (at Assets/Scripts/STMAutoSplit.cs:30) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
Developer

Oh right, I forgot I updates STMPagination with some safeties for this... sorry! Ok here's the updated script for that: https://pastebin.com/TDAy7Fc0
If *this* doesn't work, it's probably something with script execution order so will need another way around that.

(1 edit)

OK, no more errors or stale text, but pagination still doesn't work.  No STM objects are created.  Tried with both manual and auto line counts.  Overflow text still isn't assigned.  Am I supposed to manually assign it to something?

Developer

Once the script is added, clicking "Manual Set Up" should create more STM objects as siblings of the first and automatically attach and set up STMPagination scripts on them - Keep in mind, if "autoLineCount" is on and the amount of text is only enough for one line, no text meshes will be created. If "linesPerTextMesh" is too high, no text meshes will be created. If "lineCount" is 1, no text meshes will be created. The script just formats STM objects and assigns STMPagination scripts automatically, so please send me a screenshot of the inspector if you're still having issues with it.

(1 edit)

Alright, I got it to work by turning on auto line count and then clicking manual set up.  I'm confused by the line count field... if it's just a total count of the number of lines of text, shouldn't it be read-only?

Unfortunately it seems to be even slower when using the auto pagination.  I'm not sure it's working correctly - the behavior I see doesn't make sense to me:  it creates a bunch of STM objects and each one has progressively fewer words than the last.  So the rendered text only appears once, but the overall text seems to be duplicated a bunch across several STM objects.

To give a non-concrete example:  if the original text is "One Two Three", then the first clone would have "Two Three", the second has "Three", and then there's a few empty ones as well.

Developer

It's just a script for setting up pagination - if you assign the value yourself it'll make that many text meshes - if it's setto auto it'll make as many as needed.


But OK good to know, this means it's got to be something with editing a prefab STM object for sure... I will dig into this more tomorrow!

Developer (1 edit)

Been looking into it and yes, in Unity 6 at least, in this specific scenario, something is going wrong... Long text on a prefab causes a huge delay - Tried it both with a prefab that had a small amount of text and a big amount of text too - the small one was extremely bad, the big one still bad vs non-prefab text but still noticeably slower.


Found a thread here about the issue: https://discussions.unity.com/t/extreme-slowdown-traced-to-serializedobject-appl...

Seems like it's not specifically my fault, and the solution here is to not actually store any text on the mesh, just send it when it needs to be sent.


Still digging into this more though... The problem code I'm seeing is absolutely editor-only, a call from stm.OnInspectorGUI() triggering SerializedObject.ApplyModifiedProperties()... Both of these are only called in-editor and specifically if the inspector for the currently inspected object is open.


So... until Unity provides a way to work around this or a deep profiler that will actually tell me something I can fix, my advice is to not type a ton of text on the asset directly in the editor and instead have something else that will send text to the object. The prefab can be set up in advance, but the issue seems to just be editing a large amount of data in the inspector of a prefab in newer versions of Unity for whatever reason.

A dialogue manager would work for this, but if you want to edit text in the editor, here's a super-basic sample script to work around the issue... I'm not 100% sure why this works while the default inspector itself causes lag, but please try putting this on the same GameObject, and collapsing the inspector for SuperTextMesh. I seem to be able to edit text very smoothly with this method:

https://pastebin.com/fNFGPiNV

I'll keep thinking about how to work around this though as the issue is clearly something with the inspector for SuperTextMesh, since collapsing it and using this component instead has everything run smoothly... Will keep looking into that!


EDIT: more findings, it's for sure linked to serializedObject.ApplyModifiedProperties() - if I tell the STM inspector to return after the text field and call it immediately - there's still a delay. If I remove it... no delay, but the text of course doesn't update since ApplyModifiedProperties is needed to... apply the properties. So I think the extra code I wrote above just gets around this by... not using a custom inspector...? Doing even more digging...

Interesting.  I use ApplyModifiedProperties in my own rich text editor and have no performance issues whatsoever even with very large amounts of text.

I built this system a while ago (and in a hurry), but I recall running into some major issue - not sure if it was a performance issue, but looking at my code I see I have delta checks and dirty flags for the text and comments saying to only call ApplyModifiedProperties when necessary.

I took a brief glance at your editor and it seems like you might be saving a lot of different properties in OnInspectorGUI and I don't see anything that checks if calling ApplyModifiedProperties is actually necessary (though I think it should just return if there's no changes, but according to your testing it seems like just the call itself is the issue).  This would mean you're calling ApplyModifiedProperties every frame while the editor is visible (unless I'm mistaken).

I did try adding a HasModifiedProperties check before your ApplyModifiedProperties calls, but it didn't help - maybe it's just the number of properties you're trying to save every frame (or maybe HasModifiedProperties has the same issue).  I can confirm, however that commenting those calls out solves the performance problem.

Developer

Right, even though I tried changing it so ApplyModifiedProperties() calls and returns if text is being edited, it is still happening every frame. I tried making it call it only if text is currently being edited and stop rendering the rest of the inspector, but that also makes it happen every frame for that... And just tried wrapping ApplyModifiedProperties() in both a hasModifiedProperties and GUI.changed check, and it didn't make a difference, either. So yes, I suppose it's just trying to save too many properties...? I'd expect ApplyModifiedProperties to only apply what was actually modified, but I guess it must be going through everything if both putting a check for hasModifiedProperties and calling it and returning if a change occurred makes no difference. Even getting rid of the serializedObject.Update() call at the start and making it so ApplyModifiedProperties is called *only* when text updates still doesn't show a performance boost.

The extra script I wrote gets around this for sure, but I'm trying to figure out what I can actually apply from that workaround to the actual issue... Maybe when the custom inspector is edited, all properties are being marked as modified somehow? Or maybe the extra script can edit this property directly without needing to apply the entire object? I *could* try switching it so that the stm object is edited directly, but I thought using the serializedProperties was supposed to be the more lightweight and safe option.


Another thing I found - even if I'm calling ApplyModifiedProperties() every single frame, if I switch the text area's code like this:

//EditorGUILayout.PropertyField(serializedObject.FindProperty("_text"));
stm.text = EditorGUILayout.TextArea(stm._text);

All of a sudden, performance goes way up. (Not as extreme as the extra script, but it's actually usable) but the values don't actually save. Doing a change check and using EditorUtility.SetDirty(stm) after causes the same slowdown but now the values


Assuming SetDirty() is slowing down because it's marking *every* field for serialization, and ApplyModifiedProperties() slows down because every field is becoming modified... Maybe all my calls to FindProperty() are setting these properties as modified somehow even though they're being read not written...? I went ahead and tried changing every FindProperty() call to be a SerializedProperty field and setting the values during OnEnable() instead, (this took quite some time...) but this still gave a laggy result so I don't think this makes a difference somehow.


Maybe the reason this happens with prefabs in newer versions is that some type of modification flag is being set on all instances of the prefab now and the difference between *all* changed flags with the original?


I did find the existence of this: https://docs.unity3d.com/6000.0/Documentation/ScriptReference/PrefabUtility.Reco...

...But the documentation says that if you're using serializedObject and serialziedProperty right, there's no need for it...?



So I'm really not sure how to actually make it run smooth by itself (and work correctly) right now with all these different things that have been tried. It seems as if every property is being marked as modified (possibly due to the prefab setup - that thread I linked before was from 2020 and seemed very specific to this scenario) or ApplyModifiedProperties() considers a prefab to always be modified anyway. The workaround script I wrote gets around the issue, but if there's a genuine solution to improve editor performance, I'd like to do it!! Like I always knew the Unity editor introduced some overhead for my asset, but wow does it run *smooth* with that extra component, even increasing performance outside of a prefab. I want to make the default inspector work as good as that does!

I admittedly have little experience with serializedObject - I've always used Odin's SerializedScriptableObject and saved them to assets for things like this (and never had any performance issues, even with huge amounts of data/changes).  My hunch is that trying to do all of these updates in OnInspectorGUI is causing the issue, due to Unity's poorly optimized editor code (I have run into similar performance issues with editor text in the past, though not to this degree).

Your new workaround component would work for editing the actual text, but changing other text properties would still lock up Unity, right?  What if you made the actual text box its own separate editor that sits on top of the existing STM editor?  That way you still have everything in one place but the main STM editor isn't bogged down by the actual text.

Developer

Hm, I *could* probably make it be like a pop-out inspector just for editing the text property (like the popout text data editor) but from a UX perspective, that's really just about the same as the extra component I wrote anyway...? Both would solve the performance issue in the inspector by having a different text box to type into, while hiding the original. Now, I *could* add a toggle for hiding the text box on the base inspector for this, like the different foldouts for sections on the STM inspector! So if you have a large amount of text, you can just collapse that part of the inspector? I can test later if that has a performance boost!


So I'd really like to fix this properly, but ultimately is seems to be a Unity bottleneck issue, I've got a fix already which could potentially lead to a more permanent fix down the line, and the issue is editor-only in a very specific scenario... so I *think* this workaround is acceptable for now? 


I'm curious about your actual in-game use for this, by the way! Because I figure... once the prefab is set up, wouldn't new text be sent to it via a script in-game anyway? I'm very used to all text in games being stored in a dialogue manager rather than on any prefab instances, so I'm wondering if besides the fact I *want* to fix it... if it's an issue Unity has had since 2020... is there any *need* to if there's a working solution and Unity's own issues can't be pierced?

The problem with your current workaround is that, while it does make editing the actual text fine, changing any of the text properties still causes a lockup.  I'm actually finding that leaving the main STM editor visible while typing into the STM Text Send hardly makes any difference.

Something to try would be to cache and remove all text in the main text box before modifying any properties and then restore the text afterwards.  In fact, if this happens quickly enough, it could be seamless enough that the user wouldn't even notice.

As for my use case, I just want to be able to type rich text and be able to immediately see how it will look in-game for:

  1. Tutorials and in-game wiki pages: this is where the really long texts are
  2. Tooltips and card descriptions: these can be a up to a paragraph or two.

It's somewhat usable for tooltips and cards (though far from a great user experience); and pretty much unusable for tutorials and wikis.

Franky speaking, the reason I bought STM was because I determined it would take too long for me to fix the bugs in my own rich text system; but if I have to deal with super slow performance and/or incomplete workarounds I'd rather just take the time to get my own system working properly.

So I guess it depends on how much time you're willing to spend fixing this (I'm quite surprised I'm the first person to report it, by the way - I would think you'll get a lot more users running into this as people upgrade to Unity 6).  If you think it's a niche use case and not what the asset was designed for and you don't want to take the time to fix it, I understand - I'll just refund it and look for other options.  If you are willing to fix it, though that would be great, because it does seem like a really complete text solution; but the fix will need to be more comprehensive than the workarounds you've provided thus far.

Developer

Tried hiding the text box like I suggested but yes, the rest of the inspector still runs slow when edited. So it's unfortunately got nothing to do with the visibility of properties, but ApplyModifiedProperties() itself.


"Removing all text in the main box before modifying properties and then restore text afterwards" just does not work, unfortunately. There are two ways to display the text box in the inspector:

EditorGUILayout.PropertyField(serializedObject.FindProperty("_text")); 
stm.text = EditorGUILayout.TextArea(stm._text);

The way these work is basically... the TextArea() function is both what displays the text in the inspector, and returns the string as modified by the player. It is impossible to display editable text to the player without this. I tried variants on this approach too, and it is unavoidable, if the text is edited directly and then marked as dirty so the value actually saves, the slowdown happens.


This unfortunately seems to be an issue with Unity's prefab system (text outside of an edited prefab is just fine to edit), and while I will keep thinking on this issue, I cannot think of any perfect workaround. If there is a solution, it will come to me later.  This really really feels like a brick wall situation to me, and I can't figure out a way through at the moment, but plenty of ways around.


There are other comprehensive approaches which may be better-suited for your use-case:

1. A dialogue manager.

Instead of keeping text on the text mesh objects, they are stored elsewhere - a .txt file, a dialogue manager script, etc. Then, instead of showing specific overridden prefabs, load text to the prefab/object as needed in-game.

2. Presets over prefabs.

This is just a text renderer, so it's easy to configure one object to look exactly like another, so why use prefabs in the first place? I have a w.i.p. script that can remember settings for a given STM object (text size, color, material, etc) and easily share that between other STM objects that also have this prefab. I'm just using it internally right now, but if you wanted I could polish that up and send it your way. (The UX needs improvement, it otherwise works fine) It works by having multiple STM objects share a preset scriptableObject, and those settings on the preset can be updated later on. I was thinking of including it with the asset sometime.


I'm going to keep thinking on this issue, but it really seems like a Unity problem... It has a traceable date that it became an issue for people, and I see people talking about the issue generically on forums for the last 5 years with the generally-accepted solution just being "unpack your prefabs". I also personally cannot recommend storing your in-game wikis, tutorials, and tooltips directly on prefabs for anything outside of a jam game. (One mistake with prefabs and a large amount of data can be lost from prefab instance overrides) I *developed* STM for users like you, so I would really truly like to solve this, but I just can't see a direct solution at the moment and can only offer my own experience with Unity. So of course I am willing to fix this, I just can't think of any possible solution at the moment short of getting in contact with Unity to see what's going wrong. If anything comes up, I will of course implement it asap.

(1 edit)

I do have a UI Manager that handles standardized text (no special formatting and standard headers, icons, etc).  The reason I want to have long rich text for other things is that the formatting is not standardized.  Size, location, and number of headers... inline icons and special formatting... things like that where just having a set of standard prefabs for each template with fixed header locations and etc and then injecting text into them doesn't really make sense.

Now, I suppose as a workaround in my case, since tutorials and wikis are one-offs I could just store them right in the scene instead of using prefabs.  The drawback there is that if I want to change the general appearance of my text containers I'd have to do it one-by-one instead of just changing a base prefab.

So I guess I would end up with a system where I just mock up each long text in the scene, then have a script that extracts and stores that text.  Then at runtime, instantiate the prefab and inject the text.  I'd also have to build an editor interface for displaying and loading each text into the mock up container (for later editing). Not the workflow I was hoping for, but once set up it should require minimal maintenance - I'll give it a try this week.

Have you considered reporting this regression to Unity?  I know it's often a waste of time, but in my experience, they've actually been pretty quick about actioning bugs and regressions in Unity 6.

Developer

Ok I see, that makes sense as a use-case... The "changing the general appearance of text containers" bit sounds a lot like my presets script I wrote though - will try to clean that up and send it over soon since I think that could fix stuff when it comes to formatting.


I'll try writing a report soon - looks like there's enough evidence with the forum threads I found to make it worth a report - with any luck someone will just know what the hell I'm doing wrong and point it out, but maybe it is some caveat of UGUI... Will try that soon. 

Developer

OK, I managed to clean up my preset scripts with a custom inspector!

STMPresetController https://pastebin.com/pZymy31R

STMPreset https://pastebin.com/9mXe2emT


Add STMPresetController to whatever gameObject has STM on it and you want to control with a preset. There's a "NEW" button that will create a new preset based on the settings of the STM object.

Once a preset is assigned, "Copy Super Text Mesh to Preset" will re-apply settings to the preset as if it was newly created, "Paste Preset to Super Text Mesh" will take the settings on the preset and send that to the attached STM object, and "Paste Preset to ALL" will do the same but to every STM object in the scene. I was going to make this automatic, but it's just an editor tool so it would be impossible to run on presets not open until they're open... So I *could* have it run during runtime OnEnable(), but for now it's just there to apply multiple settings at once.

So... if you had two Preset Controllers in a scene, changed the settings on one and pressed "Paste Preset to ALL", the changed settings will apply to all STM objects with the same STMPreset assigned to them.

The settings are limited to Font, Size, Quality, Filter Mode, Line Spacing, Material, and an option for Base Offset at the moment since those are what I think is most relevant to this, but it could be expanded later.

I'd forgotten how integrated my tutorial system is with prefabs (it relies on assets for initialization of a lot of things).  So I decided that rather than redesign the whole system, it would be easier just to have an unpacked tutorial prefab in the scene that I use to mock up the text, then copy and paste that text into each prefab.  It's a bit higher maintenance since I have to replace that unpacked prefab any time there's a change to the parent (also changes to the parent are still super slow), but overall it should take a lot less time that rebuilding the system to not use prefabs.

Your preset script is cool, but having things in prefabs allows me to change ALL aspects of an object including its UI elements, not just the text itself.  I appreciate all of your effort on this, and if I can get the rich text tags to work as needed I will stick with STM, with the hope that these performance issues (both with prefabs and long text in general) will be fixed in the future.

Regarding rich text tags, I was under the impression that you can create your own custom tags; but after taking a closer look at the documentation I only see instructions on how to edit existing ones or add colors.  How would I go about implementing my own tags?  For example:

  1.  <h1> to increase relative font size and make the text bold?
  2. <ol> / <ul> / <li> Ordered and unordered (bullet) lists / list items?

It's OK if I have to define my own logic for generating the final text (or if you're using TMP under the hood, that's even better, since I already have logic for converting these tags to TMP tags).  If you could just point me to the relevant code/assets that would be great.

Developer

Ok cool, glad you have a working solution! Once again, sorry for the performance issues, but I still have not been able to come up with any other workarounds - will keep my eyes open though.

Good point, the custom text tags in STM refer to the tags like <w=MyCustomWave>, so maybe I should redo the language on this... I've got two solutions already though:


1. Use the voices tag (<v=myVoice>) which just inserts a pre-made string configured in the text data editor, which can contain other tags. So... "<v=h1>" could become "<s=1.2><b>" if set up this way.

2. If you look at the "Links" example scene, I have a more thorough example of a truly custom  tag. It uses STM's preparse event to inject a custom tag with regex. It takes a string like "<link=Label>" and turns it into <e2=link,label> which is then further sent to the custom event system. So, turning this into a string replacement script for your purpose would be easy! "<h1>" can turn into "<s=1.2><b>".

That said, lists will be a bit more work. STM's formatting may look like HTML, but it is not HTML. There isn't an internal numbering system for lists or anything like that, it's just a renderer. I'd personally just write stuff by hand, but you could  write a custom tag in this way that would do the following:

*Find the start and end tags' position ("<ol>" and either "</ol>" or the end of the string)

*Run replacement code for all text between these tags, so after every linebreak, insert a string for the numbering system. (eg 1. 2. 3.) There should be a special situation to also insert on the first index if the tag is not followed by a linebreak, and to NOT insert on the final linebreak if the tag immediately follows it.

*Remove original tags. also make sure to update the indices as the sting updates.

I am not running TMP under the hood, this is a different asset that began development before TMP was purchased by Unity. I hope this info helps!

(2 edits)

Thanks.  Instead of using that event I decided to just modify the main ParseText function to call my own preparse function, since I want these tags to be applied globally.  It works great - I implemented my custom tags as well as my list parsing functionality.

The only issue I'm running into is indentation and vertical spacing.  I need to add indent to each list item based on its nested depth (including line wraps) and I need to add a bit of vertical space (a fraction of a newline) after each heading.

Are there any tags for accomplishing these things that respect the actual text size (font size as well as any size modifiers)?  If not I suppose I'll have to move my tag parser call deeper into ParseText so that I can pass in the calculated text size.  I notice you're using some manual string indexing though which is why I'm a little hesitant to go messing around deeper in that function.

Developer

Right, that's another valid way to implement tags.


There's the <indent=x> tag, but it just uses a non-relative value like the <size=x> tag. I could add an <indentRelative=x> tag (probably with a shorter name) for that, or if you're already adding custom tags, you can modify the code to multiply by size.

Another option would be making an empty quad (with a full transparency texture), which would scale up and down with text naturally, and let you control the indent size from the width of the quad. So... that's an existing tag that would let you do this!


Does this information help?

I actually just now got everything working.  I used the indent tag multiplied by font size as you suggested, and for heading space I used y offset.  Everything appears to be working now.  Thanks for all the help and for looking into the performance issues - hopefully Unity gets back to you with something helpful.  From my perspective, the performance issues are the only thing holding this asset back from being a complete and very versatile TMP replacement.

Developer

Thank you for your patience with me, will send Unity something soon - because yeah it is quite odd that other text renderers aren't having this issue, while it's been a reported issue for other custom inspectors for at least 5 years... Not sure if it's an internal code thing or something I'm just not understanding. So thank you very much for the kind words!