Hmmmm right, nothing looks particularly out-of-place here... Would it be possible to see the hierarchy and inspectors for the hexes so I can better replicate this on my end?
KaiClavier
Creator of
Recent community posts
This feels pretty bespoke, I might have to look at a sample scene to solve this... So quads disappear if there are 80 hexes, regardless of position relevant to eachother...? Hm, I wonder if it could be related to masking depth... but in that situation STM *should* print a warning to the console. iirc Unity can only handle a mask depth of 7.
It could be related to generated materials, but it could also be how STM grabs it's parent canvas for rendering - maybe something is getting mixed up there I can look into on monday. Not totally sure about that since it should be using the same info for text and quads, here.
Does this still happen if you add "STMMaskableGraphic" to the gameObject? If it's already there, does it still happen if you remove it?
Is this happening with The Universal or Ultra shader? Is there a difference between the two?
Also, please try toggling "ZWrite" off if you're using the Ultra shader!
So is this not happening with, for example, a default Image component in place of your map hexes? Are you doing anything with the zBuffer or rendering order with your map hexes...? Or are they *only* composed of masks and polygon collider 2Ds...? If it's just happening with that object, it's got to be some conflicting interaction between them...
Ok, I think I know what this is... I had to change the behaviour of the <d> tag to insert a zero-width space afterwards since using <d><e=myEvent><d> just compounded on the last character. So the character spacing being set to -0.1 is basically causing double character spacing by moving those zero-width spaces.
Looks like I was accounting for that in a few places, but forgot some... should be fixed, will publish this asap!
EDIT: Update should be out, look out for v1.14.11!
Hm, I wonder if it could be...
Please try opening SuperTextMesh.cs, and replace every instance of "t.gameObject.activeInHierarchy" with "isActiveAndEnabled". It could be an inconsistency between active and enabled states, where I really should be requiring both at all times. There's a check for this related to the materials system too, but I'm not sure if it's the cause immediately.
And OK that's great to confirm it's the materials system. When the font or material is different, it's fine... Hm I did do some changes a few months back to code there that determines if two materials can be shared, I wonder if there's a value that's not being considered yet that could be causing the old material to be overridden by the new one, breaking the old text. Do you have a material that's being used on both UI and non-UI text? (This technically should be fine, but I could have messed up some values related to stencils, here:)
Try uncommenting this code that's around line 7475:
//does masking value match
//if(MaterialExists_material.uiStencilDepth != Submesh_stencilDepth)
//{
// continue;
//}
I removed this check for stencil depth since stencil ID *should* be enough to determine the materials are different, but perhaps I over-optimized and it's actually required.
If it's neither of these, I'll keep poking around. I feel it's got to be code *like* the commented code above, some value I should be checking that I'm not.
Right, a few updates ago I remember changing the behaviour for enabling STM while a parent gameobject is inactive...
Are you enabling the STM component, or the entire GameObject it's on in this scenario? Or does it not make a difference between the two? Confirming this will help narrow down the issue greatly - I see some points in the code where I'm only checking for one of these. This and the fact it's happening to all STM objects makes me think it's some type of desync with the internal materials system.
Do all the effected meshes have the same font and material? Or do they have different settings? If it's only happening to a specific font, that would mean it's related the materials system for sure, which automatically makes text meshes with the same settings share internal materials.
The materials system is basically... Upon rebuilding, STM objects will create and use a cache of materials to render, not the actual material assigned in the inspector. I think toying with these created materials could also cause problems, but I'm not sure how they'd be getting edited externally here. Could there be code in your project that's somehow effecting created materials...?
For the animation event you're talking about, does this refer to a Unity animation event, or STM's drawAnims and event tags? Another guess is... if it's not forceAnimation not being enabled, it could be another variable that's being set automatically. Are you only enabling/disabling the STM object? What is being called in the animation event exactly? With autoRead disabled, I believe it would still call Rebuild() and if the mesh has a readDelay above 0, it would idle on frame 1. (I still don't think it's this but more detail is good!)
Also, what version of Unity are you using? I just remembered that Unity 2019 specifically had some issues with rendering multiple materials on a canvas which I was forced to eventually give up on after seeing it worked fine in 2018 and 2020.
Thank you so much for your patience by the way, I understand how it is to have an issue you can't really show off, so I hope this is at least making a bit of progress!
Hello!
Yeah, that shouldn't be happening... Hm a few things that come to mind from this scenario are...
1. Re-enabling the canvas might not be properly telling child STM objects to re-appear/re-make their meshes. Is this behaviour any different when the GameObject the canvas is on is turned on/off instead? Not sure if I already is, but need to check since this can narrow it down! (If this is the case, will look into why STM isn't updating in this scenario, but that's a quick working fix for you) I have a few ideas on how to fix this if it's the problem.
2. Inside of an animation, please enable the "forceAnimation" variable on the text, at least for the frames where it will appear/disappear. This was intended as an optimization feature for animating text, but if a parent object is being set active/inactive, I can see the text or certain animations refusing to play. You can also try disabling "autoRead" or enabling "rememberReadPosition"... Those variables are true by default so if I had to guess, it's probably trying to read but refusing to automatically animate during the animation triggering it.
So, please give those a shot! setting the canvas's gameobject active/inactive, and enabling "force animation" on STM.
Does using a unity Grid Layout and multiple STM object complicate positioning too much? That would be fine for text that's spaced evenly, but I think I've seen a modified grid layout component somewhere that can use the size of what's inside for each row/column. (Together with contentsizefitter & STM that might be a solution)
Anyway, simpler second idea I have: indents and carriage returns!
A string like this will work:
"Damage:<indent=5><u=000D>A</indent>
Defense:<indent=5><u=000D>B</indent>
Complexity:<indent=5><u=000D>Moderate</indent>"

...with "5" being the width between columns (will need to be bigger for bigger text, etc), and <u=000D> being equivalent to "/r", the carriage return, which goes back to the start of a line without dropping down. (and setting the indent changes where the start of the line is)
I hope this helps!
Hm, STM has its own system to combine materials, but on the Ultra shader, at least for now, proper batching is disabled due to how it breaks vert indices for outline and dropshadow effects. (Will experiment with replacing this with index data stored on a UV channel at some point, I think there might be one UV channel free *maybe* so that would possibly allow batching if changed) If you're not using the super smooth outlines, you could try the default Universal shader instead? It's more lightweight compared to the Ultra one too, especially since I wasn't able to complete the optimization pass on the Ultra shader I tried earlier this year. (More on how to still get the outline effect with this soon...)
The material combiner system reduces draw calls if two meshes share the same basic text settings. So same font, same material, etc. Effects like basic color tags do not matter, as those are applied with vertex colour, but the"texture" color tag will make a new material. From your last screenshot, this seems to be the case already, though... So I'm not entirely sure why each component is causing a new draw call. A culling script is a great idea though regardless! (You can also try disabling the STM component but leaving the meshrenderer & meshfilter on, that could potentially give a performance boost, but I have not tested this)
STMMaskableGraphic may help, all it does is let STM behave as a "MaskableGraphic" component properly, so that could be the cause of the Z issue here, potentially. I'm not sure what would have made it not work a month ago, so it's worth another shot! That should hopefully enforce some rendering order features. Additionally!!With STMMaskableGraphic, you can use a basic shader like the default Universal one, and then use Unity's "outline" component to render an outline that way. I also did work with LeTai's assets to get their asset "True Shadow" working together with STM, which can produce a batched, smooth outline if configured properly. https://assetstore.unity.com/packages/tools/gui/true-shadow-ui-soft-shadow-and-g...
Another small thing to try is, is anything different if you nudge the text forwards a bit? There could just be an issue with the Z buffer somewhere, so if the text and background are on the same layer, I could imagine it getting scrambled together with VR rendering, somehow. (The text is *supposed* to push itself forward a bit with effects like this, but I can see VR as being an edge-case I didn't account for. There's a manual "ZDepth" value in the Ultra shader that might give a better result if adjusted, I can send shader variants soon but I think the Universal shader should be tried first)
If you can let STM do most of the work, see if that works for you! The AutoWrap feature sounds like what you're after, with VerticalLimit being its vertical counterpart. (On UI text, these values are controlled by the size of the recttransform, by the way!!! Unless"ui wrap" and "ui limit" are disabled.)
The STMMatchRect code in my sample scenes really sounds like what you're looking for - it just takes an existing rectTransform which you can change the appearance of, and resizes it based on text size. (With options for which bounds it's copying.) So please check out the sample scene for that.
What is your monitor's refresh rate? If it's higher than 60, that means the issue shouldn't be something delta-related, so that helps narrow it down at least. (Thinking it's happening on a per-frame basis, rather than a per-time basis)
Got your zip, will check it out shortly!
Layout issues like that can even stump experts, so it's a bit tough to debug this all without doing it myself... sorry for that!
For the MatchRect script, to be a bit more clear about how it works... Place it on the object you want to resize to match the text's bounds (so in your case, the background) and then in the inspector, you need to drag in the gameObject that has SuperTextMesh on it from the hierarchy into the "stm" field. (Ideally the objects are siblings in this case).
But it sounds like Adventure creator may be trying to resize the box itself, so this might be the wrong approach... (Sorry it's been a very long time since I've had AC's code in front of me, so I need to guess... If AC is trying to set the box size itself, you need to remove the ContentSizeFitter from STM, and set the anchor presets on its recttransform to stretch. (So it'll match whatever AC is actually resizing) So in this instance, instead of the text controlling the box size, the text is fitting in the box size. Not entirely sure this is the case here though.
I'm actually not too sure what to make of that maybe useful info immediately... does it *only* happen when recording? Could the STM object have anything else on it causing an issue in this instance?
For the script I sent, forget about it for now because it was incomplete and I wanted to expand on it, I don't think it would have changed much in its current state. I also think the MatchRect script might be a more direct fix for this issue. But yes, it has public fields, one for an STM component, and one for a LayoutElement... it's meant to send values generated by STM straight to the LayoutElement, which could be a parent object in your case. It's C# code, by the way!
If I'm not able to solve it like this, I might ask you to sent over a scene for me to edit, I feel like it might just be one thing out of place, and the fastest way to know is by just pushing all the buttons, haha. I'd really like to isolate the issue because it's still not completely clear if it's an issue with STM, AC, or Unity Layouts!
Yeah, I think the problem may be that it's two content size fitters immediately inside of one another (but I'd expect this to effect size, not position... so might be the wrong path to look down?) ...without a layout group or layoutelement to help decide what controls what.
The way the code I sent works is... you reference an STM component, then you reference a LayoutElement component, and the height value from STM is sent directly to the layoutElement's "preferredHeight" field. (Make sure preferred height is enabled on the layoutelement or this does nothing) The LayoutElement is intended to be the parent object of the one STM is on, in this example. I'm catching this before bed, could add the other fields besides height for you tomorrow.
Hm, you said before that TextBoxContainer also has a vertical layout group already, but it *might* work here with using a layoutelement and setting values directly from the child STM object. I'm still not completely convinced this is the error though since it's *always* just returning to the same point before being corrected what I can assume is a layout refresh... so even if we fix the layout refresh, something could still be responsible for the move.
It might also be worth seeing if reducing nesting would help - could txtSubtitles be made a sibling of Panel_TextBG instead of a child? If you go into STM's sample scenes, there's a "MatchRect" script that will let one rectTransform fit to STM with various settings, regardless of parenting. I forgot to mention this before, this is probably a more direct and thorough fix than piggybacking off LayoutElement... probably!
So please give that last one a shot! That might be better since you're trying to size a box based on text size, anyway!
Here's the code, it's quite basic and only copies over one value to the LayoutElement, but could be modified to nab other values, too: https://pastebin.com/XbvqHeCC (I don't want to do it myself because it's the long weekend - maybe tuesday!)
Can the TMP object be moved elsewhere? Curious if it's controlling position at all.
Will think more on this over the weekend, but I'd really just like to figure out... what is trying to make this move back to the origin anyway? Could it be a setting for subtitle location in AC or something...?
Hi! I saw your post with John, let's see what's changed in the last 9 years... (A lot has changed with how Unity UI handles layouts as well)
Immediately seeing, the fading animation starts and then continues as the position corrects itself...
Assuming this is Unity UI...
1) Try replacing "supertext.Text" with "supertext._text", this is something that I think might have changed in the last 9 years, but I'm not completely sure if it's the issue here. ("Text" I believe used to update text WITHOUT calling Rebuild(), while "text" would, but now "_text" has this function, so the issue could be that Rebuild() is being called twice here and some layout code is getting confused)
2) Try replacing "supertext.RegularRead()" with "supertext.Rebuild(true)", which I think should have the same effect, guaranteeing STM will both rebuild and read at the same time.
3) Try adding supertext.rt.ForceUpdateRectTransforms() after the "RegularRead()" line is called. (Assuming this is on Unity UI) That might force the layout to rebuild if it's a layout issue. You can also try "LayoutRebuilder.ForceRebuildLayoutImmediate()".
4) I'm also guessing at this but... does your STM object have a ContentSizeFitter on it? I've been running into some problems with nested layouts and contentsizefitter in just the last few days actually and wrote myself a rudimentary script to make sure the effects of ContentSizeFitter happen frame 1 with STM, rather than waiting for the layout update. (It just forwards information to a LayoutElement component) So I could try sending over a cleaned up version of the script with this, but with any luck it's one of the first 3 issues.
These are my initial guesses! There's nothing in that code that should be effecting text position besides those 3 things there, so there's a chance it's how AC works now... I can take some guesses at how *that* might work, but I don't use it myself! (I could ask the dev, but I'll try guessing first...)
5) What is the parent object of your STM object? Is it also moving when the text moves? What is making it move? (Thinking maybe AC is trying to use the position of the hidden text object to decide where STM should go, but not sure how it would play initially then decide to move after a few frames...)
Let me know if any of these help!
Ok those screenshots and description help a lot! Here's some things to try:
In the inspector try disabling ZWrite. This is basically there just to make it so Ultra shader outlines don't go over the previous letter, but if your outlines are thin enough you may as well disable it, it can *sometimes* cause something like this to happen if text is is a 3D space like this, rather than being on a UI. I feel like this shouldn't be happening with ZWrite on though, so if this solves it I'll look into how to prevent it from being a problem in the first place.
I'd also check out the rendering order of those objects in the background, is their render queue above 3000? You can try changing the render queue value on STM's material settings to something higher!
Do you get a result similar to what you want when using the Universal shader (plain version with out outline) then adding an outline through STMMaskableGraphic? That's also an option for rendering outline effects now, too!
Ah got it, so yes for the Universal shader there, that is just what it does and why I made the Ultra shader. (But apparently it works fine in builds?)
Do you have any screenshots of the weird artifacts in the Ultra shader? It sounds like... hm, the material/font is changing, but the UVs don't update to match immediately which they really should. Saving *should* usually correct that, but that's odd... if an error showed up that got cleared (an error I would like to fix btw), STM might have entered a stalled state. If you select the object in the hierarchy and press ctrl+d to duplicate it, does anything change on the new object created?
Hey!
Are you sure this is the Ultra shader? Normally the UI on the inspector there should change when it's been applied, and in your screenshot it's showing the configuration for the Universal shaders. (Additionally, the rendering going on here is what I would expect the Universal shader to do in this circumstance, where it's only rendering the final pass of the outline and ignoring the text pass) So please try clicking the "Ultra" button next to the shadier field on the inspector to apply that shader to your material. Please let me know if that makes a difference.
If nothing changes when pressing that button and you don't get any errors in the console, try saving your scene as that will force STM to rebuild the material settings.
Unclosed tags will not lead to any issues with how STM currently works, and if I were to add this tag stacking change I would also not require tag closing! As it stands, when text parses, it just goes forwards, not backwards.
(There's some benefits to the current system by the way... color tags of a different type can stack (color, gradient, texture) but now that I've got the combo color tag (<c=myColor,MyGradient,myTexture) and customizable color-mixing rules for color data, adding an alternate tag parsing system could be interesting...)
Well, with the current way it works, the closing tag means that *any* closing tag (not just fonts) will return to the default setting for that tag, which has its own uses! (But there is the <clear> tag already for clearing everything to default I suppose...) I guess I think of them more like programming the text as it's read out, rather than formatting existing text? I think I wrote a bit about this system int he docs, but I could make it a bit clearer. Anyway, should all still be workable!
Hey!
This is the current intended behaviour, a new tag will always override the state of an old one, so you'd want "<f=baseFont>1<f=newFont>2<f=baseFont>3" for this. I could add this as alternate behaviour in a future update maybe? I feel there was some reason I was avoiding it (I suppose it was because I didn't like the idea of needing closing tags, but I could still make that optional...? Or that this system technically runs faster since I never need to check which tag is closing, just override it with a null value), but with recent backend updates, it might not be that bad to add in now.
Hm, right I think I might see the behaviour that's happening... if I have the rectTransform set to something *taller* than the text, then when it's on one of those best bit modes, it will try to fit the height, not just the width. You could try setting the text's rectTransform to exactly the height you need (either manually or with a contentSizeFitter) and then using another transform to parent that, but I should probably add a setting sometime to control which axes are being considered for best fit. Or I could just... add a maxSize field for this already, augh. Don't know why I didn't just add one before (I think vertical space was not considered for best fit in the past), but I'll add it to the list of things to do! I hope the workaround is an OK immediate fix, though!
Hello!
1. This isn't TMP, so I've got my own approach to text size... The best fit system (Apart from Multiline - more on that later) was meant for text with manual linebreaks only, like small UI elements. So the other options on the "best fit" enum control how the text acts - Always will resize text to always fit in the area, SquishAlways does the same but only on the X axis. OverLimit will only make text smaller if it goes over the bounds of the box, and SquishOverLimit does the same but only on the X axis. I believe this look for limits both horizontally *and* vertically, but it's mostly made for fitting in a horizontal area.
So for these, minSize just makes it so text can't shrink down forever, and "size" effectively works as your maximum size, since that is the goal size for the text. I'm not sure how you'd be getting a random huge font size with this, though...? (Could be related to multiline...) Aside from that, I'm not sure what the problem is with my approach to text sizing?
2. This is probably because of the "multilineBETA" best fit mode you have assigned. If your option there has just one line - please use another best fit mode! I left the "BETA" tag on there because I wasn't satisfied with it - there are alignment issues with different anchor settings, and it just wasn't the result I wanted for automatically resizing text that still had automatic linebreaks. You *might* get a better automatic alignment with it if you set it to top left anchor/alignment and parent that inside another object, but if you're only doing one line of text like in the above screenshots - don't use this best fit option! You'll have much better control over how big you actually want text to appear on-screen.
Oh sorry I had a bit of a misunderstanding here, I thought you were talking about switching materials mid-string specifically.
The intended way to change materials at runtime is... set superTextMesh.textMaterial like that, and then call Rebuild() or update .text. (At runtime, STM makes internal copies of materials so multiple meshes can share, which is why updating the field in the inspector doesn't seem to work then until something forces Rebuild()) But good point, I could just make ApplyMaterials be public for this use-case where *only* material is changing and not text. I don't think there's a harm in changing that...?
Honestly I could probably implement an <outlineColor> tag that does exactly the code you just showed me since STM creates copies at runtime. I haven't done this yet because the material would have to have a compatible shader from the get-go (Ultra or Universal Outline variant) and the material caching system right now just checks if the entire material matches... so if two different meshes had runtime materials with red outlines but otherwise the same properties, they wouldn't be counted as the same material at the moment, and they might get confused with the base material too. That said, I might try to add this and worry about optimization later, it sounds useful to have! But at this moment, the suggested way is to make different materials with different outline colours before the fact. So I think creating it on Start like that is fine for now!
So... I think what you're doing there is completely fine to do! If you're not also updating text together with changing the textMaterial, I'll expose ApplyMaterials() in the next update, and also start looking into outlineColor tags so code wouldn't have to be written for this. (I've also thought of making it so the outlineColor and other properties are linked to STM rather than the applied material, but it introduces a few more downsides than upsides, so I just left it as-is.)
So to sum it up... using tags to switch pre-made materials or just assigning a pre-made material and making text rebuild will only be more efficient than creating and assigning a new material at runtime if more than 1 mesh is displaying your modified material, by saving draw calls.
Hello,
At the moment, changing materials is the correct way to set outline color with code, and that was working the last time I checked... but maybe it's possible I missed something with serialization on an update.
Does your text look anything like "<m=blackOutline>Hello, <m=redOutline>world!"? The tags should be case-sensitive.
One thing that might be happening is... if you are creating the material tags through Unity's project window instead of STM's Text Data Editor, you'll have to click "Refresh Database" at the bottom of the Text Data Editor for STM to become properly aware that the material exists. (I should probably put a note on the inspector about this or change how this works to not be required at this point...)
Ok, glad to hear! Also I'm curious, was the render order set to 3000 by default? It should be, but I could swear once or twice it got set to 2000 without me doing anything. Most likely some other script I was editing at the time, but let me know if that has happened to you! (3000 is the default order for transparent objects, 2000 is the default order for opaque)
Just in case, will link this page on default renderqueue values!
Here are some thoughts:
1. Can you change the render queue for STM and your glass shader for this situation?
2. Is a rendertexture acceptable for this? e.g. point a camera at an STM object, output rendertexture to surface?
Besides that, I do wonder if I could modify the output to go directly to a texture... it would be a pretty big rework though and not technically a mesh anymore, but I do like the potential of this, even if it's just skipping the rendertexture step. Not sure if I could get it running any more eddicient than that does anyhow off the top of my head! (on the fly texture creation vs. extra camera in scene)
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!
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?
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!
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.
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.
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.
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?
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!














