Skip to content

Conversation

@Wuzzy2
Copy link
Contributor

@Wuzzy2 Wuzzy2 commented Dec 11, 2025

This a large documentation PR about integers. It took me almost a whole day to write.

It updates the lua_api.md documentation significantly by adding a distinction between "number" and "integer" in the documentation, and documenting value ranges.

Rationale

Many Luanti functions and data structures expect integers and the C++ code can only accept a limited value range. The Lua API documentation rarely mentions these restrictions which has led to some confusion in the past.

Worse, Lua programmers passing floating-point or out-of-range values to functions or data structures that expect integers can potentially lead to bugs without the programmer realizing, because it was never documented.

Real example: In one game, I have found a stack_max of 99999, which is not a supported value but the programmer can't be blamed because the upper bound was not specified there.

The goal of this PR is to make Lua code more robust longterm by mentioning our number restrictions upfront.

Overview

This PR is structured in multiple parts:

  1. Section "Numbers and integers" was added where terminology and writing conventions are introduced. The internal representation of the Lua number as C++ double is mentioned here (see LUA_NUMBER in lib/lua/src/luaconf.h)
  2. Add the word "integer" everywhere in the documentation
  3. Attempt to "standardize" the syntax of integer ranges as [min, max]
  4. Add permissible ranges where there were missing
  5. Add a "safe integer range" of [-2^53, 2^53] in the Numbers and Integers section for the few cases where no range was mentioned. This safe integer range is the range that Luanti will now officially guarantee that all integers in this range can be represented in Lua numbers without "holes". This information is relevant for builtin functions
  6. A few minor typos were fixed if they happened to be close to my other edits

The information about the integer types and value ranges is derived from the C++ code.

Noteworthy details for review

To the reviewers I want to bring special attention to these points:

  1. I was rather paranoid with value ranges and sometimes picked the most "pessimistic" ranges (read: smallest allowed range)
    1. I picked a "pessimistic" range of [-2^37, 2^37] for the safe integer range. This one is derived from the lowest guaranteed value of DBL_MANT_DIG in <float.c>. (raised to [-2^53, 2^53])
    2. I mentioned that if IEEE-754 floating-point numbers are supported, the safe integer range is [-2^53, 2^53]. Why 53? Because 53 is the 52-bit mantissa of double-precision IEEE-754 floats plus 1 extra bit because the specification implies there is an extra 1 bit at the beginning of the mantissa that is not actually stored. (no longer relevant)
    3. (I don't know if Luanti ALWAYS has IEEE-754 floats (thus making this distinction moot) or if it is possible to compile Luanti with lower float ranges) (the answer is, for all practical intents and purposes, yes)
    4. For set_int of metadata storage, I made the value range explicitly 32-bit, rather than this just being a suggestion
    5. For inventory list sizes, I picked a much lower range than the C++ code indicates because in my tests, Luanti becomes very angry and laggy if I use extremely large sizes. So this range is picked exclusesively as a precaution
  2. Oddly, a C++ comment for the implementation of core.set_node_level claims the allowed range is only [0, 63] although other parts of the documentation indicate that it can go up to 127 and in my tests the high values work as well. Should I fix the C++ comment?
  3. star_seed in player:set_stars is internally a 64-bit unsigned integer, which I guess is larger than Lua 5.1 can represent safely in integers. I intentionally did not mention a range here so that the safe integer range kicks in (star_seed range now specified as [ulua])
  4. For the reast, just review the changes. 😝

Things to test

Although I have proofread my changes myself by using the C++ code as a reference, it is possible that still errors have snuck in. Please compare the documentation updates against the C++ code as well.

Status

This PR is ready for review.

Off-topic: Things to keep in mind for later

  1. IMO the C++ type of the internal stored value after you call meta:set_int should be switched from int to long because of the de-facto usage of 32-bit integers and the fact the documentation already suggests 32-bit integers. Technically, int only guarantees 16-bit values in the C++ spec (This point is moot, Luanti refuses to compile on systems wheere int is 16-bit.)
  2. It may make sense to define math.mininteger and math.maxinteger to define the safe integer range, so that programmers know exactly which numbers are "safe" to use as integer and at which point integers are "skipped" due to floating-point arithmetic. The names math.mininteger and math.maxinteger are stolen from Lua 5.3. 😉

@appgurueu
Copy link
Contributor

Thanks for documenting this! I will try to take a comprehensive look soon.

Some thoughts:

For all practical purposes, we can assume IEEE-754. But the more limiting factor is usually going to be a cast to some 32-bit (or even smaller) integer type on the C++ side. This is what I wrote on the matter in the other repo: https://docs.luanti.org/for-creators/lua-conventions/#integers

[set_int:] Technically, this is wrong because it is internally stored as an int which guarantees only 16-bit.

Then let's make it use s32, no? (That said, int is basically always 32 bit in practice.)
Spec should certainly guarantee at least 32 bits.

@sfan5 sfan5 added the @ Documentation Improvements or additions to documentation label Dec 12, 2025
@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 12, 2025

It has been brought to my attention that Luanti essentially "forces" int to be 32-bit by outright refusing to compile on systems where int has a lower value range. This defuses my worries about the meta:set_int range; the documentation of meta:set_int() is now simpler because of this.

Good point about IEEE 754. Yeah, I'm probably being overly paranoid here. I can't recall any relevant system where a double is somehow not IEEE-754-based (but correct me if I'm wrong). I consider extending the "safe integer range" to [-2^53, 2^53] in the docs and drop any mention of the more paranoid [-2^37, 2^37] range.

Please note that I sometimes took the liberty to document only a 16-bit range when theoretically a 32-bit range is possible. This was the case where my tests indicate Luanti behaves poorly with large values (i.e. very poor performance, lag spikes), or a value beyond 16-bit does not make even theoretical sense in that case. Please complain about all 16-bit ranges in the documentation where you think I was too restrictive.

But more importantly, we must be extra sure that no range in the documentation is larger than is actually supported because that will be a BugFactory.

Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

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

looks solid, some small things i found while reading through it

Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

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

Another thought: Could you make explicit that VoxelAreas expect integer positions (in bounds)? It seems to be a frequent mistake that people pass non-integer positions and end up surprised by nodes at wrong places.

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 13, 2025

OK, I addressed all comments.

I have added shorthands for common integer ranges like [int16], [int32] etc. to make it hopefully more readable.

I am not touching the [crack documentation any further because that modifier appears to be broken right now (#16746) or I have no idea how to use it correctly. I'm not sure about the intended meaning of the parameters anyway.

Good catch about [verticalframe: indexing, that was important.

Copy link

@wmikita wmikita left a comment

Choose a reason for hiding this comment

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

great job and thanks for taking on this! here are some typos and my attempts at making this sound better (though keep in mind that I am too only a second-language English speaker).

BTW, you could mention that some Lua 5.1 APIs are ambiguous on whether they take any real number or an integer and that behavior may vary there too from implementation to implementation (and to look out for that), e.g. with when floats are passed to math.random in PUC Lua 5.1 and LuaJIT 2.1. maybe (and I'm totally not doing this to substitute cat picture payments to @appgurueu) you could mention that there are tools like Runtime Strictness to catch undefined behaviors in both Lua and Luanti API? it would be a good idea to refer scripters to RTFM, but when the whole ordeal is that a part of the API is undocumented, there's really no FM to R specifically...

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 15, 2025

All direct code comments by @wmikita addressed. Thank you for looking at the small details, it is important to be precise.

BTW, you could mention that some Lua 5.1 APIs are ambiguous on whether they take any real number or an integer and that behavior may vary there too from implementation to implementation (and to look out for that), e.g. with when floats are passed to math.random in PUC Lua 5.1 and LuaJIT 2.1. maybe (and I'm totally not doing this to substitute cat picture payments to @appgurueu)

Not sure, this might be overkill for a reference. I don't think we have to also document every Lua quirk as well.

you could mention that there are tools like Runtime Strictness to catch undefined behaviors in both Lua and Luanti API?

Not sure about that, I don't know how useful this tool is. Maybe a good recommentation in docs.luanti.org tho (if it's a good tool).


Question to everyone important in Luanti:

Is it safe to assume that in Luanti, double is a IEEE-754 double-precision floating point number? Or in other words: Does Luanti care enough to support systems where double is NOT based on IEEE-754 (for some reason)?
If the answer (to the 2nd question) is "no", I will increase the "safe integer range" to [-2^53, 2^53] and simplify the documentation a little. Please note this PR would then add to the lua_api.md a promise that this larger range works (instead of the current smaller range of [-2^37, 2^37]).

Copy link
Contributor

@j-r j-r left a comment

Choose a reason for hiding this comment

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

Added some comments concerning the world seed (also named map seed in at least one place) and block positions.

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 17, 2025

New comments addressed. I also decided to rename all ranges to the more familiar Luanti C++ style s16, u32, etc. to make everything a bit more consistent.


Question to everyone important in Luanti:

Is it safe to assume that in Luanti, double is a IEEE-754 double-precision floating point number? Or in other words: Does Luanti care enough to support systems where double is NOT based on IEEE-754 (for some reason)?
If the answer (to the 2nd question) is "no", I will increase the "safe integer range" to [-2^53, 2^53] and simplify the documentation a little. Please note this PR would then add to the lua_api.md a promise that this larger range works (instead of the current smaller range of [-2^37, 2^37]).

@j-r
Copy link
Contributor

j-r commented Dec 17, 2025

Thank you for working on this, this will definitely prevent some breakage.

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 17, 2025

Added the missing documentation for texture modifier sizes and coordinates. New [imagesize] range introduced as [1, 23000], based on MAX_IMAGE_DIMENSION in src/client/imagesource.h.

Still waiting for an answer for what the "official" safe integer range should be (see above).

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 17, 2025

  • PcgRandom seed and seq range reduced to [ulua] (from [u64])
  • Clarified correct use of seed in mapgen settings
  • Increased safe integer range to [-2^53, 2^53] (from [-2^37, 2^37]); documentation now assumes that Lua numbers are IEEE-754 double precision floating point numbers because systems where that's not the case don't seem to supported by Luanti anyway (discussed in IRC)

Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

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

looked at the changes since my last review, looks good, i have some minor comments

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 19, 2025

@appgurueu comments addressed.

Copy link
Contributor

@corpserot corpserot left a comment

Choose a reason for hiding this comment

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

i managed to review all the way to the end of Flag Specifier Format section today. seems like this PR won't be easy to be thorough. i hope floats/lua numbers are considered in-scope of this PR considering your rationale.

doc/lua_api.md Outdated
Comment on lines 1763 to 1777
Copy link
Contributor

Choose a reason for hiding this comment

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

what is the expected number ranges for selection boxes? is it different between nodes and entities? can you have it documented? from quick testing without fiddling with any server/client settings and without forceloads, i got a selection box that works fine up to 96 nodes tall from an entity's origin. it's something i've never been able to figure out.

also collision boxes should describe its range with the PR's range format instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ugh, this one is tricky. I agree specifying a range for selection boxes is important but I have no idea what it is. Clearly it cannot be infinite.

I believe I saw a #define in the code somewhere but maybe I misremember things.

I also believe that entities allow much larger collision/selection boxes than nodes to, but I don't know the limits for them as well. The only thing that is certain is that node boxes use floating point coordinates.

Or maybe the limits never have been determined to begin with which would mean we would have to decide on limits from scratch.

Unless someone outright tells me the correct range, this is out of scope. This sounds like something for a new PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

(same here) that's alright. i suppose i was hoping for more considering the motivations you had.

@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 21, 2025

@corpserot comments addressed. I agree that float ranges should also be specified but sadly they are much harder to figure out. Specifying ranges that have not been specified anywhere before is out of scope for this PR. E.g. I would love to know the correct selection_box range as well.

Here's the deal:
This PR is starting to get ridiculously large and we have to finish it up at some point. From now on, I will only add documentation for missing ranges if either it is easy to figure out from the code (s32, u32, etc.) or someone tells me the correct range upfront.

@Zughy
Copy link
Contributor

Zughy commented Dec 21, 2025

@Wuzzy2 rebase needed

@Zughy Zughy added the Rebase needed The PR needs to be rebased by its author label Dec 21, 2025
@Wuzzy2 Wuzzy2 force-pushed the doc_integer_update branch from c03b608 to a16cbd5 Compare December 21, 2025 10:40
@Wuzzy2
Copy link
Contributor Author

Wuzzy2 commented Dec 21, 2025

Rebase complete. I removed the ColorInteger pseudo-type again because after recent changes (alpha value in HUD text), this definition would only be relevant in one place.


There is still an open question from the 1st post:

Oddly, a C++ comment for the implementation of core.set_node_level claims the allowed range is only [0, 63] although other parts of the documentation indicate that it can go up to 127 and in my tests the high values work as well. Should I fix the C++ comment?

Relevant code in src/script/lua_api/l_env.cpp:

// set_node_level(pos, level)
// pos = {x=num, y=num, z=num}
// level: 0..63
int ModApiEnv::l_set_node_level(lua_State *L)
{

@Zughy Zughy removed the Rebase needed The PR needs to be rebased by its author label Dec 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

@ Documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants