Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Approximates chatmessage's height and width valueWe so back #11947

Closed
wants to merge 3 commits into from

Conversation

Archanial
Copy link
Member

Same as #6788 but I can't reopen it

About The Pull Request

This PR removes call to MeasureText(), effectively making creating chatmessages synchronous.
This fixes a few possible runtimes and weird undefined behaviors.

CHAR_WIDTH is (width / 1000) * font_size
Where width is width as calculated by FontForge. width / 1000 is the conversion between FontForge's em-size value and 1000 em-size is just 1 em.
Check the FontForge's docs for better explanation. https://fontforge.org/docs/
APPROX_HEIGHT is font_size * 1.7
Where 1.7 is approximation, based on comparing results of the MeasureText() and used font.

The values from FontForge are saved in static list. If something isn't on the list we assume the worst and give it width of 1000.

The values from font forge were inacurate. The approx width compared to measured one differed by about 20%.
The more naive solution has been implemented - measure cache of some sort. Every client should have the same viewport so the measurements between clients should be the same. Thus, once, we calculate values for every character and keep using them.
After testing it is about ~1% inacurate (which is huge improvement over 20%).

Additionally the values are cached now per client plus every uncached character will be calculated for all the clients.

I changed my mind. I precalculated values for first 1500 characters for unicode. That should cover all the characters you would ever need. Anything that isn't included gets replaced with "?".
If you ever need a new character you can modify json with the value.

Why It's Good For The Game

Less chatmessage bugs and better performance.

Testing Photographs and Procedure

Screenshots&Videos

obraz

obraz
obraz

obraz

obraz

obraz

obraz

NEW CONTENT BELLOW
(old is still relevant though)
image
sunglasses emoji was replaced with "?"

Changelog

🆑
refactor: refactored how chatmessage width and height is calculated
/:cl:

code/datums/chatmessage.dm Outdated Show resolved Hide resolved
code/datums/chatmessage.dm Show resolved Hide resolved
code/datums/chatmessage.dm Show resolved Hide resolved
code/datums/chatmessage.dm Show resolved Hide resolved
@Archanial
Copy link
Member Author

I can't do pointers, we are not on 515 yet

@PowerfulBacon
Copy link
Member

The testing evidence is completely meaningless since it doesn't show the case that this actually affects; the case where text wraps to a new line

I also have concerns about users that dont have the small fonts font and have downloaded a replacement, since different fonts would break it again. It's not a huge case that's likely to cause a ton of issues, but I think there are much more elegant solutions overall, like giving them infinite width and manually controlling the line breaks ourselves by just adding them when we see enough characters.

@PowerfulBacon
Copy link
Member

There are also so many hard coded values that it would become extremely annoying to modify text formatting if we merge this and it wouldn't be able to be ported to codebases that have different sized for italics easier. As I said above, manually inserting the new lines when we read enough chars is a much better solution and would be a lot more generic while never having any size inaccuracies or client calls

@Archanial
Copy link
Member Author

Small fonts is included in windows.
I can add some images of text wrapping if you wish.


if(has_icon)
value += CHAT_MESSAGE_ICON_SIZE
return list(value, string)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allocating lists in the return value is a bad idea, since its on a datum you don't need a pointer because you can just modify the message as a class scoped variable.


var/i = 1
while(i <= length(string))
var/list/letters = SSrunechat.letters[string[i]]
Copy link
Member

@PowerfulBacon PowerfulBacon Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For how many times this gets called, using an assoc lookup is going to be slow. If you have a sequence of characters you can just use an int lookup with base offset

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are sure converting char to int will be faster than accessing this list I can change it

Copy link
Member

@PowerfulBacon PowerfulBacon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I would like some test cases. Show us what you have tested, the point of testmerges isn't to be the first point that something is given extensive testing. Note that there should also be some testing for sentances that have 3 lines in them, since you can never underestimate with 1 line strings. This is important, because if we overestimate a string, it really doesn't matter, but if we underestimate then we ruin our text and make things unreadable.
  2. This changes how much spacing there is between words, meaning that when this fails, it is significantly more noticable than when it fails on the server which is relatively hard to spot.

Running through some test cases, I had 1 case that showed an improvement though I need a more varied set of testing cases when it comes to word length.

image

In the case of a 3 line long string I tried, this new method underpredicts the length which results in text being culled, which is worse than the current method which has a tendancy to over-predict the amount of text. Try using the string W90 4i5ut9oap tia9pe4i tpoaiwW90 4i5ut9oap tia9pe4i tpoaiw

Failure on live server:
image

Failure when running this branch:
image

@EvilDragonfiend
Copy link
Member

EvilDragonfiend commented Nov 28, 2024

This might have been related to how font style is defined in skin.dmf maptext
also 10000 lines json scary

@PowerfulBacon
Copy link
Member

Feel free to reopen if this is actually going to be worked on

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants