Quantcast

Jump to content

» «
Photo

How to draw long multibyte strings

2 replies to this topic
kagikn
  • kagikn

    Ghillie

  • Members
  • Joined: 05 Jun 2014
  • Japan

#1

Posted 11 August 2017 - 01:58 PM Edited by kagikn, 25 August 2017 - 02:29 PM.

There are workarounds to add long single-byte characters to the stack in GTA, but as for long multibyte strings, there aren't any workarounds.
I thought I needed to find how to draw long multibyte strings when I was making Insane Stunt Bonus V (I'll upload to GTA5-Mods.com when I release it) and trying to draw long Japanese texts.
Anyway, this is how to get sliced multibyte strings whose byte lengths are properly limited to 99 or less.

// in C#
public static string[] ToSlicedStrings(string input, int maxByteLengthPerString = 99)
{
    if (maxByteLengthPerString < 0)
    {
        throw new ArgumentOutOfRangeException("maxLengthPerString");
    }
    if (string.IsNullOrEmpty(input) || maxByteLengthPerString == 0)
    {
        return new string[0];
    }

    var utf8ByteCount = Encoding.UTF8.GetByteCount(input);
    if (utf8ByteCount <= maxByteLengthPerString )
    {
        return new string[] { input };
    }

    var initListCapacity = utf8ByteCount / maxByteLengthPerString;
    if (utf8ByteCount % maxByteLengthPerString > 0)
    {
        initListCapacity += 1;
    }

    var stringList = new List<string>(initListCapacity);
    var startIndex = 0;

    for (int i = 0; i < input.Length; i++)
    {
        var length = i - startIndex;
        if (Encoding.UTF8.GetByteCount(input.Substring(startIndex, length)) > maxByteLengthPerString)
        {
            stringList.Add(input.Substring(startIndex, length - 1));
            i -= 1;
            startIndex = (startIndex + length - 1);
        }
    }
    stringList.Add(input.Substring(startIndex, input.Length - startIndex));

    return stringList.ToArray();
}
// I'll change the method name if I find a better name or somebody tells me.
// Probably I could do with StringBuilder but I need to test it before I post it here.

When you use some natives like ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME or _BEGIN_TEXT_COMMAND_WIDTH, you can use these strings by calling _SET_TEXT_COMPONENT_FORMAT with CELL_EMAIL_BCON and then calling those natives repeatedly with individual strings.

Yeah, I will post a workaround for C++, but I need to make one first.

 

EDIT: Fixed not slicing at a correct position.

  • ikt likes this

uNiverselEgacy
  • uNiverselEgacy

    Player Hater

  • Members
  • Joined: 15 Jul 2015
  • United-States

#2

Posted 24 August 2017 - 02:14 PM

This looks quite inefficient. Just write a custom UTF8 decoder. It only takes several lines of code.

kagikn
  • kagikn

    Ghillie

  • Members
  • Joined: 05 Jun 2014
  • Japan

#3

Posted 25 August 2017 - 01:33 PM Edited by kagikn, 25 August 2017 - 03:05 PM.

Could you show me an example? I can't come up with anything better in performance. I tried a similar method using StringBuilder, but it was worse in performance.
This methods costs about 1600 ticks for 100-200 byte string, and this doesn't cost much FPS (at least calling Enum.GetValues with Control enum costs way more time)
If you slice strings by using Math.Min when you slice ASCII characters, you can save many (timer) ticks, though.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users