Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(core): add the ability display outputs with multiple lines to console#1370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
kagikn wants to merge2 commits intomain
base:main
Choose a base branch
Loading
fromconsole-multiline-output-fix

Conversation

@kagikn
Copy link
Member

@kagiknkagikn commentedDec 21, 2023
edited
Loading

Resolves#1301

Summary

This commit adds the ability to display output strings with multiple lines to the console, making output strings will not always get overlapped even if there is no room for displaying in single line.

Uses binary search to avoid taking too long time to calculate where to split strings.

Do note that the initial commit does not make it possible to display long strings that needs to be pushed with more than 4 substrings where the length is up to 99 excluding the null bytes. This is probably becauseEND_TEXT_COMMAND_DISPLAY_TEXT cannot display strings with more than 4 variable substrings (more than 397 bytes if all the characters in the string are ASCII ones). Maybe ScriptTextLinesFourSubstringsThreeNumbers in gameconfig.xml is relevant a bit? I'll try to find a way to draw long strings where more than 4 variable substrings has to be pushed in later commits.

This commit does not make a window for the current input since it isn't as important as the output window IMHO, the console still displays in a silly way if the input is too long to fit in a single line. Would be fixed when we start to use ImGui for the console though.

Showcase

271590_20231221215020_1
Type the lines below for each to test:

return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. aaaaagg"return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. rrrrrrr"return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla ZZZZZZZap"return "いやああここまでコンソールの出力で苦労するとは思いませんでした。でも397バイト以上のテキストを出力するにはまだまだ道は長いですね。あああああああもうやだああああああ!!!! まあImGui使うようになるまで努力しますけど。"

The last one need to set the game language to Japanese or use a font file for the font file for the language you use (the efigs one for most people who see this page?) where the Chalet 1960 London font has all the japanese glyphs of strings, before you can see the text.

I believe I could make the new code more clean, especially the pieces of it where how many spaces the console should keep for a output string and how to set text style variables...

niziul, nomakewan, and Michael21107 reacted with heart emoji
…nsoleResolves#1301This commit adds the ability to display output strings with multiplelines to the console, making output strings will not always getoverlapped even if there is no room for displaying in single line.Uses binary search to avoid taking too long time to calculate where tosplit strings.Do note that this commit itself does not make it possible to displaylong strings that needs to be pushed with more than 4 substrings wherethe length is up to 99 excluding the null bytes. This is probablybecause END_TEXT_COMMAND_DISPLAY_TEXT cannot display strings with morethan 4 variable substrings. Maybe ScriptTextLinesFourSubstringsThreeNumbersin gameconfig.xml is relevant a bit?
@kagikn
Copy link
MemberAuthor

kagikn commentedJan 9, 2024
edited
Loading

Gosh, the display text script command, well I meanGFxParagraphFormatter::Format, tries to find line break opportunities (such as space characters) without providing ways to disable to find line break opportunities but just rely on the pure text width like how common terminals such as cmd.exe and Windows Terminal wraps the input string and output strings 🤡
I guess we have to split text outputs in an disgusting way to emulate the common way to display outouts in common terminals...

END_TEXT_COMMAND_GET_NUMBER_OF_LINES_FOR_STRING may return the same value as substring without the trailing whitespaces if the string ends with whitespace characters, so I think we have to useEND_TEXT_COMMAND_GET_SCREEN_WIDTH_OF_DISPLAY_TEXT so the console can emulate how common terminals wraps the input string and output strings without doing the smart word wrap. Needs to be careful with color tokens and special character tokens such as wanted level star and Rockstar Games images though.

@kagikn
Copy link
MemberAuthor

In script display text natives/commands,CTextFormat::GetStringWidth parses as a html document if there's some styling tokens, wanted star tokens, new line tokens, color tokens, and blip tokens starting fromBLIP_ (case-sensitive), and otherwise parses as plain text document. So just manually inserting\n or<br> doesn't makeGetStringWidth parse as a html document. This bothers me a lot if I would consider HTML tags, but I think we could ignore HTML<br> tags in output strings this time as we would replace the console with one made with ImGui in the future...

For those who wants to parse HTML<br> tags for script display text natives/commands, the info in the comment block below may be useful:

// When you see '<', make sure the following character is not '!' or '/' before parsing as a start element.// When you skip HTML comments, unlike html documents in the Web, keep in mind that hyphens do not have to be placed other than before an ending greater than character// (e.g. `<!br-->` will be skipped as comments but `<!--br->` will be parsed as an HTML br tag).// See `GFxSGMLParser<Char>::SkipComment` in `GFxSGMLParser.h` in that secret code to verify how the game would skip html comments.// When you parse an starting HTML element, you may have to skip space characters and the set below contains all the characters that the scaleform treats as space characters!// This set contains all the values where `G_iswspace` in `Gstd.h` would return non-zero values and the game would treat as space characters!HashSet<char>SpaceCharactersForScaleform=new(){'\u0009','\u000a','\u000b','\u000c','\u000d','\u0020','\u00a0','\u1680','\u2000','\u2001','\u2002','\u2003','\u2004','\u2005','\u2006','\u2007','\u2008','\u2009','\u200a','\u200b','\u2028','\u2029','\u202f','\u3000'};

@kagikn
Copy link
MemberAuthor

kagikn commentedJan 15, 2024
edited
Loading

as a memo, some stuff to parse tokens output strings to avoid tearing tokens apart:

publicenumTokenStateOfParseToken{/// <summary>/// standard text (not found a token yet)/// </summary>StandardArea,/// <summary>/// inside a token, gathering all the token text/// </summary>InsideTokenArea,/// <summary>/// fully completed, ready to go back to standard text again/// </summary>Completed,}constcharTokenEscape='\\';constcharTokenDelimiter='~';publicstaticList<string>SplitStringByNewLineTokens(stringstr){// same max length as `MAX_TOKEN_LEN` macro in `TextFormat.h` but without the null terminatorconstintMaxTokenLen=63;StringBuildertokenNameBuffer=newStringBuilder(MaxTokenLen);TokenStateOfParseTokentokenState=TokenStateOfParseToken.StandardArea;charprevChar='\0';inti=0;intstartPosOfSubstring=0;intendPosOfSubstring=0;List<string>substrings=newList<string>();while(i<str.Length){charnewCharacter=str[i];if(newCharacter==TokenEscape&&(i+1)<str.Length){// Get the next character. If valid (not null), check if it is the delimiter.// If it is the delimiter, skip this escape character. The code below// will handle treating the delimiter as a normal character.// NOTE: the next token delimiter will be added as a part of the token name if the token state is// inside token area, but this behavior is exactly the same as how the game parses.charpeek=str[i+1];if(peek==TokenDelimiter){prevChar=newCharacter;i++;continue;}}if(newCharacter==TokenDelimiter&&(i==0||prevChar!=TokenEscape)){if(tokenState==TokenStateOfParseToken.StandardArea){tokenState=TokenStateOfParseToken.InsideTokenArea;prevChar=newCharacter;endPosOfSubstring=i;i++;continue;}elseif(tokenState==TokenStateOfParseToken.InsideTokenArea){stringtokenName=tokenNameBuffer.ToString();tokenNameBuffer.Clear();tokenState=TokenStateOfParseToken.StandardArea;prevChar=newCharacter;// The new line token IS case-sensitive in the game unlike how the bold and italic style// tokens, wanted star token, Rockstar logo token, and non-renderable token (~nrt~) are parsed.if(tokenName=="n"){substrings.Add(str.Substring(startPosOfSubstring,endPosOfSubstring-startPosOfSubstring));i++;startPosOfSubstring=i;endPosOfSubstring=i;}else{i++;endPosOfSubstring=i;}}}elseif(tokenState==TokenStateOfParseToken.InsideTokenArea){// Emulate how the game appends the token name to the token name buffer 😛if(tokenNameBuffer.Length<MaxTokenLen){tokenNameBuffer.Append(newCharacter);}prevChar=newCharacter;i++;}elseif(tokenState==TokenStateOfParseToken.StandardArea){prevChar=newCharacter;i++;endPosOfSubstring=i;}}endPosOfSubstring=i;if(endPosOfSubstring-startPosOfSubstring>0){substrings.Add(str.Substring(startPosOfSubstring,endPosOfSubstring-startPosOfSubstring));}returnsubstrings;}publicstaticList<RangeCompact>FindAllTokenRanges(stringstr){TokenStateOfParseTokentokenState=TokenStateOfParseToken.StandardArea;charprevChar='\0';inti=0;intstartPosOfToken=0;intendPosOfToken=0;List<RangeCompact>ranges=newList<RangeCompact>();while(i<str.Length){charnewCharacter=str[i];if(newCharacter==TokenEscape&&(i+1)<str.Length){// Get the next character. If valid (not null), check if it is the delimiter.// If it is the delimiter, skip this escape character. The code below// will handle treating the delimiter as a normal character.charpeek=str[i+1];if(peek==TokenDelimiter){prevChar=newCharacter;i++;// endPosOfToken will be set to i + 1 latercontinue;}}if(newCharacter==TokenDelimiter&&(i==0||prevChar!=TokenEscape)){if(tokenState==TokenStateOfParseToken.StandardArea){tokenState=TokenStateOfParseToken.InsideTokenArea;prevChar=newCharacter;startPosOfToken=i;endPosOfToken=i+1;i++;continue;}elseif(tokenState==TokenStateOfParseToken.InsideTokenArea){tokenState=TokenStateOfParseToken.StandardArea;prevChar=newCharacter;ranges.Add(newRangeCompact(startPosOfToken,endPosOfToken+1));i++;startPosOfToken=i;endPosOfToken=i;}}elseif(tokenState==TokenStateOfParseToken.InsideTokenArea){prevChar=newCharacter;i++;endPosOfToken=i;}elseif(tokenState==TokenStateOfParseToken.StandardArea){prevChar=newCharacter;i++;}}if(endPosOfToken-startPosOfToken>0){ranges.Add(newRangeCompact(startPosOfToken,endPosOfToken+1));}returnranges;}publicreadonlystructRangeCompact:IEquatable<RangeCompact>{/// <summary>Represent the inclusive start index of the Range.</summary>publicintStart{get;}/// <summary>Represent the exclusive end index of the Range.</summary>publicintEnd{get;}/// <summary>Construct a Range object using the start and end indexes.</summary>/// <param name="start">Represent the inclusive start index of the range.</param>/// <param name="end">Represent the exclusive end index of the range.</param>publicRangeCompact(intstart,intend){Start=start;End=end;}/// <summary>Indicates whether the current Range object is equal to another object of the same type.</summary>/// <param name="value">An object to compare with this object.</param>publicoverrideboolEquals(object?value)=>valueisRangeCompactr&&r.Start.Equals(Start)&&r.End.Equals(End);/// <summary>Indicates whether the current Range object is equal to another Range object.</summary>/// <param name="other">An object to compare with this object</param>publicboolEquals(RangeCompactother)=>other.Start.Equals(Start)&&other.End.Equals(End);/// <summary>Returns the hash code for this instance.</summary>publicoverrideintGetHashCode(){returnStart.GetHashCode()*39+End.GetHashCode();}}

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Add the ability to display long outputs with multiple lines

2 participants

@kagikn

[8]ページ先頭

©2009-2025 Movatter.jp