Logging text inputs

I’ve been programming for 10 months now.

I started making my own system to set key bindings during runtime and it somehow snowballed into a whole terminal messaging system so I could also control a character by parsing string inputs.

Many chat box tutorials just slapped stuff into a list, removed index 0 to set a limit. If I recall, that will cause the list to rewrite itself to shift its internal array down.

I attempted to come up with a more efficient solution just using arrays. I’ll have pages worth of data in memory but only 1 paragraph of it will be visible in any chat box. I’m just keeping track of iterators to build a paragraph worth of text to display in 1 text mesh pro text box.

The array of strings I’m logging just turns over back to zero when it reaches max.

Everytime I log a text, I have to create 1 new string from 10 congruent strings stored in my array. 9 of those strings would technically exist in my paragraph before I looped through the last 10 messages and remake it. I’m feeling like my solution is still a little heavy and wasteful.

maybe what I can do is grab my paragraph from my 1 UI text box and take all the text after my first new line character and add the last logged string to it. I can get rid of the for loop, provided my array has more than 10 new line escapes to start with.

My question is, am I going about my chat box all wrong? Is there, like a bunch of stuff people smarter than I built into the text mesh pro that do everything better?

Hard to say without code.

You gotta ask yourself: how much of an issue is deleting index 0 from a list for a text chat system? None. Players just don’t type new stuff every frame. Perhaps if this were the backend chat system of an MMO world, in that case I’d understand getting rid of any possible GC allocs but they cannot be avoided in a chat system anyway.

Personally, I’d probably have a chat window that’s a list of UI Textboxes in a vertical layout and you can scroll them around to some extend. Textboxes at the top are simply removed every time a new chat text comes in and the line limit is reached. Multiline text goes into the same textbox of course, you’d have to make sure to adjust its height or set it up for auto height.

Why that way? Because it makes adding, selecting and removing a single chat entry that much easier - they could be anything from “ok” to the max (I’d use 1024 unicode chars as the upper limit). Oldest chat entry just goes away with the textbox (which you can pool and re-use if you’re worried about GC).

1 Like

This sounds like it could be a good use case for a linked list. It’s short, so the slow iteration speed isn’t a big deal, and it needs to be re-ordered nearly as often as it needs to be iterated, so the super cheap insertion / removal is neat. When at the max number of messages I’d just change the contents of the least recent item and re-link it to the front of the list.

In C# strings are immutable. Every time you concatenate strings (add them together) it creates a new string object. The StringBuilder class makes this more efficient if you need to do it a lot, but I don’t remember where the break-even point is between that and standard concatenation.

It’s entirely possible that adding to / removing from 1 big string is more efficient than adding 10 strings together, but it’s still going to re-allocate for at least one operation.

But, I think this whole thing is likely premature optimisation. I very much doubt that the performance bottlenecks of a chat system come from how the text is stored, unless it’s written very poorly in the first place. Yeah, there’s a bunch of string objects which we need to do stuff with and, yeah, messing with strings in C# is notoriously wasteful. But you can’t really get around that part. Moving some stuff around in a List or array is just shifting references, which isn’t really a big deal unless there’s a lot of them. That’s probably all small fry stuff compared to updating the GameObjects, components, etc. which are involved in getting all of that stuff to show up on the UI. But even that only has to happen when new messages actually arrive.

If you do in fact need to optimise a text chat system, my gut feel is that effort needs to go more into how it’s rendered than into how the text is stored.

1 Like

Thank you both for some feed back, I was so busy with homework yesterday forgot to check on my post.

I hope to show my code, but its still proof-of-concept code with bad names that don’t make great sense because I had no idea what I was doing. Right now, I didn’t want things I know are wrong to be the highlight of people’s responses. Eventually, when everything is working, I plan to demo it all on a asp.net site I’m working on. Because it would be cool to do so. Basically, I would like to refactor my code before I show it.

I don’t have a specific project in mind, I was just trying to understand design patterns better. I could just use the new Input system that was released, but I don’t think that will teach programming concepts. I targeted the command pattern to solve my input problem.

Though I don’t have a specific project, but I am working with extremes in mind, which I guess would be logging vast amounts of data, possibly over a network.

Let’s assume it’s a MMO. I think sending strings over a network connection is a bad idea. The Input system uses the command pattern. If an MMO, I could send just a few integers over a connection, those integers could recreate strings from the command pattern. Player to player dialogue would need a unique command who’s value is a unique player defined input, among other unforeseen challenges.

Maybe storing strings isn’t necessary. I can store the command, and the values associated with it. Then each chat window added only has 1 stringbuilder with 1 string to manage, based on the array of objects containing previous command data. Or as you suggested, keep a short list of text objects I can roll on and off the chat box. Its not as though the rolladex solution can’t also be applied to chat displayed in a chat box. Strings can be written to files if the user wants to save or log it.

Wouldn’t that be cool to click a chatbox text item, and pull up more details about the command its related to. But also be able to construct a new chat box containing all related messages related to certain values in that clicked dialog. If you wanted to isolate messages from a certain player or NPC, I think I could do it quite simply through the command pattern. I’m liking the idea of having separate text box for each string.

That’s all probably a nightmare I’ll look at later. I’m just going to get strings working for now.

In relation to me, all of this is totally premature optimization, especially considering I’m trying to optimize without any idea if what I do is actually improving things.

In relation to the program itself, I’m not sure I can call it premature because I’m not targeting a performance standard, but rather more interested in seeing how much I can front load the program. It’s a bit like the hobby overclocker who invests all his time and money trying to get 100 extra Mhz out of his processor. What practical use is that gain other than to flex ego on a internet forum?

I should really be documenting my development phases because the goal is to learn. Trying to do this has opened up doors to an overwhelming number of things I didn’t know exist. Like the profiler, and a whole unity pdf document detailing the 50 or so optimization techniques. I’m much more familiar and comfortable with Eventsystems, common design patterns and working with UI canvas related things than when I started doing this.

Conclusion
I think the take away from the dialogue here so far is I need more numbers before I start going nuts with different approaches.

To the point you guys made, the things I’m addressing might be trivial in the big picture. It’s true that I’m fretting over things like lists and and the GC when I don’t know if I should be. Other parts of a game will likely be more intense than these issues. But I don’t have a game. I have inputs and ui chat boxes.

I think before I move forward, I need a baseline to work from. Measure the performance and document to test my changes against. Because I have no idea what I’m doing.

Some help defining a practical testing criteria.
Lets say 10 chat boxes creating strings at a fixedDeltaTime which would be a max 250 strings created a second with default Time settings. Maybe I need more load to notice differences.

Measure the base performances at low and high yield string making with the profiler.

Then I can start optimizing, put in the stringbuilder, give each chatbox its own canvas, test against lists to see if I actually improved anything, etc. Collect real data on the different approaches. Hopefully, we can all have a better idea about when, what and why.

Do not worry about the time taken to parse text. It is trivial for your purposes. Do not use enterprise principles or code that relied on console writes as examples. Unity is component based. You should have one component that handles the text inputs, tracks the number of responses or textfields in play and adds/deletes/pools/tracks size. Your though process should be…what comprises a standalone subsystem that takes an input and does it’s very specific thing with it. That is what you should be writing as components. Personally I would create a List of messages, prune the beginning and log that to file everytime the text scrolled out of the chatbox due to a new message being added.

In the past I would create gameobject variables and drag gameobjects into the inspector window. But it sounds like your saying I should instead create scripts to add to the respective gameobject. That script would do what it needs with the gameobject, and initialize itself in scripts higher in the chain?

That would eliminate my concern game designers knowing what objects need to be dragged around. Would knowing what script components are needed be less confusing?

I got my string array rolling over when max entries are reached, and added a mouse scroll wheel event to iterate through the array that clamps at the newest and oldest entries in the array. I also got it to not update the contents when I’m not scrolled to the newest entry. So If I scrolled to any older entry, and a new entry is added, it won’t change the contents until I scroll the wheel. Because it would be annoying to have things update while you’re trying to look at something.

It still has a fence post error in how many strings it displays, if I set it to display 10 strings, it only displays the last 9. But I’m more concerned about my scroll bar. I have to manage its position in the script to be based on the stored array rather than what’s just displayed in the content window. I don’t know how to do this yet.

I feel like I’m in cool school, even though I might have just spent 12 hours of my life saving not a pennies worth of processing power. But I’m almost set up to start learning to write test methods and learn the profiler. Then I can see first hand just how trivial my concerns are.

Just a small piece of information:
Unity’s TextMeshPro UI elements have a setCharArray method. That can be the base for using it completely without those pesky immutable strings.
However that normally isn’t a very high concern.

The Inspector is your most powerful diagnostics and workflow tool. Use it.