#Fluid Unit Hell
3412 messages · Page 4 of 4 (latest)
if you dont need the api thats fine, the rest of us think its useful and it doesnt harm you in any way, so let us implement it
I do not
No, I don't interact with any arbitrary fluid unless a pack maker also defines it via datapack (which also requires a melting temperature, specific heat capacity, etc.) So the fact a common tag exists doesn't help.
alright, so for your case at most a tag that is "molten iron at the 100mb standard" would be useful
I think thats probably the simpliest way to handle these standards, have prefixes that mean "100mb", "90mb" and "250mb" for the common standards (and 144mb if people insist on reviving the bad legacy standard). Then you just use the appropitate prefix for what you do
We could do that alongside the tooltip, and people wishing to do conversions between standards just use multiple tags
Only awkward part here is coming up with names for each standard. I've been calling 90mb "metals", which is a bit weird if you apply it to redstone for instance but not the worst thing
I tossed in a section about unit standard tags to the fluid tooltip proposal, a fluid constant PR could reference those tag prefixes for relevant constants (e.g. INGOT would mention "tag fluids using this unit under c:metals/<fluid name>")
The fluid unit API does solve it though -- not for buckets, but for the case of ingots and all other units
It means that you don't need to worry about an ingot "standard" size that's divisible by whatever people want -- you can just have each person set that themselves
And in the long run -- looking at versions further down the road -- it could solve the millibucket issue too
yeah, its really just a question of how we want to solve this
everything the fluid unit API proposes apart from tooltip formatting could be done via other methods (tag conventions and mod added datamaps), however it is a lot more streamlined and potentially eaiser for pack devs to work with
I personally am not too partial to either approach, as long as we make no changes to the bucket divisions before we get some unit display in Neo
With either approach we can change the bucket divisions with minimal impact on players
Idk, I don’t think the “document every standard” approach is helpful. I mean it’s nice, but if you’re using anything other than the base standard it’s more helpful to use fluid units than doing special casing for each standard we write here
that is true, its easier to not have to special case each standard
it all comes down to how much do we expect conflicting standards to occur?
if its just 1 or 2 standards for a thing, its not a huge deal
if its regularly 2-4 standads, that becomes a pretty big maintenance burden on the modders side
The standard tags are arguably useful whether the unit API is added or not, since they grant a quick and easy way to detect fluids of a particular standard, though I'd call them non-essential with the unit API
without the unit API they are also arguably non-essential, though given we have some conflicting standards already its probably better to have them than not
I think so far we have 3 reasonable standards, 90 mb, 100 mb, and 144 mb
we don't have to have a completely separate set of tags for the standards
like, we could have recipes that are based on the intersection of c:molten_iron and c:ingot_is_90 [if we don't have intersection holdersets, or holderset-based ingredients, we should]
I'd argue 144mb is not reasonable 😛
250mb is the third reasonable standard
its mainly used for non-metals
thats a fair point, had not considered that
Neo should have intersection fluid ingredients if it does not already
it does as of a few weeks ago
perfect, that solves that
Tag standard proposal:
c:metals/<name>orc:gems/<name>would be the standard place for metals and gems alike. What qualfies as either is the same semantics as using the item tagsc:ingots/andc:gems/respectively- Not sure what to do with weird fluids like redstone or clay that are neither, probably just tag under root
c:redstoneorc:clay, though a genericc:molten/<name>might be an option - For units, we use
c:units/<number>where<number>is the size of the most standard. e.g. the Tinkers ingot standard would usec:units/90, and the gem standard is underc:units/100 - May be worth retroactively applying this standard to existing Neo fluid tags, e.g.
c:honeyandc:potionwould typically usec:units/250but you could if you wish use another standard.
This solves the problem of conflicting units by just telling people to publically expose which standard they are using in a way other mods can query
Not sure if the c:units/ proposal should be mutually exclusive with the unit API proposal. I think its probably still beneficial if that API exists as you may have a context where tags are way easier than querying the unit API
is c:units/90 just assumed nugget, thing, and block being 10, 90, 810?
there is an assumption here the standard is named after the ingot, not the nugget
and since nugget/ingot/block is 1/9/81, you just multiply/divide the fluid unit as needed
non-9 ingots will break as much here as they will in item tags
plus, if you are using non-9, you probably don't need the 90mb standard, 4 is way better in the 250mb standard
maybe it should be
c:unit/ninth-ninth 10 : 90 : 810
c:unit/ninth-quarter 25 : 100 : 900
c:unit/quarter 250 : 1000
c:unit/third 333 : 1000 ? this one might just be unsupported for now
Yeah, I think the fluid unit API does it better though, cause it doesn't force different fluids to have the same sizes for a given unit -- whereas tags, whatever end up requiring mods to do that
I feel like it'd almost be better to make an ingredient type that could work with the fluid unit system instead of a bunch of wacky tags like this
...though honestly I don't think people should be designing recipes that way to begin with. Like, your recipe shouldn't care that a fluid has 90-ingots
You should only care that that fluid has, say, an ingot unit and a nugget unit (and the one is 9 times the other)
it would be better yes
In what scenario do you actually need to know that it's a 90-ingot-fluid?
And how can we design an ingredient type that lets you represent that actual condition (fluid with ingot and nugget units) instead?
Could we have the c:ingot unit somehow define an implicit c:unit/has_ingot tag on the fluid or something?
And then "fluids with ingots and nuggets" is just a tag intersection
I'd have to think about hte practical end of that a bit more
oh, well no, recipes still need to take in a specific liquid in order to get an outcome generally speaking
very rare that you need a recipe that takes all ingots
the recipe could take in a tag and then filter out all the fluids in the tag that dont have the particular unit
Sure, guess I'm saying I don't really see the advantage of a ingot_90 tag. I'd argue we should be encouraging people not to rely on how "big" a given unit is for a given fluid, or hardcode stuff to only work on a certain unit size. People should instead only care which units something has (and that the ratios work as the mod expects I suppose)
Yeah, this makes sense
I want molten copper, but only if its molten copper with an ingot unit
etc
i think the idea would be to use an intersection tag for that. All fluids that are both molten_iron and ingot_90, which the current fluid ingredient system supports
Right but that's the issue. People shouldn't be relying on it having an ingot unit with value 90, they should only care that it has an ingot unit
If you're filtering only fluids where a unit is equal to a certain value, and you have the fluid unit API available, you're doing something wrong imo
agreed. honestly the tag stuff does seem very annoying and i dont really plan on using it for anywhere other than just writing the 1 json it takes to tell mods its in that tag
fluid units are more ergonomic in basically every way but people are convinced that we dont need them, not really sure what else to say on that front :/
I don't know that people are convinced on that
Some people sure but I've also seen a lot of interest for it in this thread
Heck, I wasn't fully in favor to begin with but I think I've come around since. Just seems like the cleanest long-term solution
yeah, i guess the question is if this PR got created what would the maintainers do with it. cuz tech is still convinced we dont need it. but shadows seems to be good with it. I think the only real concern is that the existence of this system would disincentivize people from using the tag standards
Someone should make the PR as a draft at least just so there's something solid to work with
I mean yeah, I think it ought to. I think the idea of an ingot_90 tag is terrible just by its nature
Cause then you encourage people to filter things based on a units value... which you really want people not to do
That said, c:units/ingot tag -- for fluids with an c:ingot unit definition (of any value) -- isn't a bad idea
The question is, is it possible to make such a tag automagically contain any fluids that have the c:ingot unit?
there is merit to having both imo. if you only want to work with things in 1 specific standard the tag is nice. the unit system currently doesnt really allow that. actually i guess you could do something like fluid.getUnit("ingot") == 90
My point is nobody should only ever want to work with things in 1 specific standard. Like, what's a case where you'd actually want that, when what you want isn't instead something about having a specific set of units and ratios between them? Saying "I want only fluids with with 90 units per ingot" is really an XY problem -- nobody ever wants that really, they want fluids where they can do certain unit conversions and have them work out, or grab fluid in certain unit sizes, or have certain guarantees about ratios of unit sizes or whatever.
Like, why would you want an ingot_90? Maybe it's that you want:
- ingot unit exists
- nugget unit exists
- 9 nuggets to an ingot
- bucket to be divisible by nugget
And you should be checking that set of conditions instead, not just saying "I want things where ingot is 90"
Because you don't really want things where ingot is 90, you want those other conditions because something you're doing relies on those assumptions. A fluid where ingot was 180 would still work just as well in your system in that scenario, for instance.
So the question is: how do we design a fluid unit API that makes checking those conditions -- ideally from an ingredient or holderset thingy -- easy? Because that's the sort of stuff people actually need, not ingot_90 fluids
Custom holderset type maybe?
(currently looking up what the hell a holderset type is)
forge has custom holder sets?
Basically: vanilla has tags. Neo lets you register custom things like intersections/unions of holdersets (tags in vanilla)
I think you could extend such a system with some sort of "fluid unit holder set" for filtering, say, all fluids with a given unit defined or something? Haven't poked the system enough, could be wrong
no idea, i also need to take a look at this
i have not been in the "neo exclusive" game for very long lol. i have never really taken a hard look at neo's apis until like a month or 2 ago
Regardless, I think that sort of solution is the proper approach here if its possible -- having tags for different standards or whatever just, like, bakes in those standards -- when in the long run I think we should be getting rid of a lot of those standards, and in the long run hoping to make even the size of the bucket unit fluid-specific
This solution solves all the problems those standards are needed to solve, without the sort of limitations that they drag with them
the reason why you need ot know the standard is one of two reasons
either a: you want to know for divisibility sake or b: you want to know how much fluid is needed for a recipe
both are handled by a unit API of course
so I think based on this discussion, I'll conclude the tag standards are only needed if we don't do a unit API
and tbh, maybe they are what we need to convince people a unit API is good, because otherwise they will have to do that nonsense 🙂
if we're gonna have units tags, they should probably say ingot, gem, bottle [though again that raises the question of what a unit of redstone is]
also, is a tag that's just a number legal?
i think there's been discussion about automagically populated tags in the past and the answer has been no
anyway, if we have a unit quantity based ingredient it can simply not match fluids that don't have the unit, if we want to check it in code we could add a .hasUnit helper method to Fluid and/or FluidStack
or fluid resouce hehehehe
I wouldn't do it as unit tags honestly -- I'd try and make a new holderset type that grabs fluids with certain units
Then there's no magical tag generation
But yeah, regardless -- I'd just avoid the tags for units
Either they're redundant and a source of error (if the tag is just the same as checking if the fluid has the unit) or they include numbers which we should avoid, as you shouldn't be reasoning/filtering based off of a unit number (and a unit API would mean you don't need to)
there is maybe something to be said for something like "is it divisible by 4, recipe quantity is 3/4 unit" but that's niche enough that it can probably be left to whoever needs it
Sure -- and even then, that's a lot different than "exactly 90" or the like
[i have been tempted to suggest a floating point unit quantity, but i don't actually think it's a good idea, and honestly it should really be rational, that's just ugly to try to implement in json]
floating point has terrible percision at the points we are trying to get by changing bucket standards
thta is, 3, 9, 81, etc.
they only wnat powers of 2 for precise values
floating point precision has a much bigger issue than rounding: digits of precision.
float has 6-7 digits. that means you can't have a tank with 100 million buckets because if you extract one bucket at a time you would either lose additional fluid (if it rounds up) or duplicate fluid (if it rounds down)
i meant for ingredient notation ("i want 1.5 ingots"), not actual storage, but fair enough
https://factorio.com/blog/post/fff-416
Friday Facts #416 - Fluids 2.0
Hello,
Grab your best lube, because it's time to talk about fluids!
During one of the fluids discussions, Rseding proposed an algorithm very close to one he had played with several times, an algorithm from the Minecraft mod Thermal Expansion by team CoFH:
how topical 
obvious issue when gamers have different opinions how realistic a game should be^^... and minecraft is as far away as you can get while some mods try to relive the real world industrialisation 
that's fun lol
oh god I missed this sidebar somehow
how many other terrible ideas are brewing that I'm unaware of
5, if I'm counting correctly 
The main idea brewing here is a fluid unit API
Either purely for rendering fluid units in tooltips (similar to what tinkers does ) or extending the idea to work with logical fluid units
Logical fluid units means you could for instance make an item that holds 1 ingot, but 1 ingot may have different mb on different fluids
Or make an ingredient that matches 1 gem and not care whether a gem is 100mb or 90mb for that fluid
I think it's not worth changing the bucket capacity without at minimum having a fluid unit display API, so I've been in pushing for that being done before we further bikeshed the bucket divisions
There is more info in the pins if you want
hello fluid folks
just an FYI that I've made a comment on https://github.com/neoforged/NeoForge/pull/1138 (Define standard FluidConstants) proposing that PR to go forward if this discussion leads to nowhere concrete -- an issue or PR, as I've somewhat alluded to in my pinned message
just so we have something in place to discuss concretely
alright. well honestly i dont really know where we stand on this issue
i understand there was still some aprehension from tech, and orion insists on a PR being written before he can decide. idk where everyone else is on this
i'm not sure i understand what the blocker is - is it just that there's not a PR, or are there still serious objections to the proposal
a PR might be needed to actually arrive at some definite conclusion, it looks like.
i'm tired of looking at or thinking about openblocks for a while, i might put together a PR
the phrase "out of the frying pan and into the fire" comes into mind /jk
aiui a PR is being requested for further discussion
But even if no PR arises, I don't think that #1138 should be merged, it will introduce more problems than it fixes.
ok i think i might have some code ready to PR, though I didn't do any ingredient stuff [i don't think we have fluid ingredient stuff at all yet do we?]
i do not have a good way to test this though, there's nothing in vanilla or neoforge itself that actually uses fluid stacks
the fluid ingredient PR was merged a while ago
ah... maybe i should have pulled before starting work on this
ok how do i make a codec that does this "maybe a list or object, maybe just an integer" stuff
should be an either codec?
how does that work
what i want is a codec for a single type with two json representations, not a codec that can represent two types of object
maybe i should just make a straightforward codec and let it be ugly, [[{"unit": "mb", "amount", 10}]] isn't that bad.
aiui what you want is a codec that allows both
10
```and
```json
{
"amount": 10,
"unit": "mb"
}
```Is that correct?
technically i want all of 10, {"amount": 10, "unit": "mb"}, [{"amount": 10, "unit": "mb"}], and [[{"amount": 10, "unit": "mb"}]]
why double list?
yeah, what are the lists doing there?
the inner lists are sums, the outer list is alternatives
so e.g. you can have "2 ingots and 1 nugget, or 2 gems"
please for the love of god, make that "fluid_any_of" and "fluid_all_of" (or similar naming)
as separate ingredient types
(I'm assuming this is about fluid unit ingredients)
ok it still at least needs the sum list for like "1 ingot and 3 nuggets", that's a single quantity
okay, a codec that is either a single element or a list thereof is pretty simple, hold on
Codec.either(Thing.CODEC, Thing.CODEC.listOf())
and wrap that in another either if you want the single int too
how do i map that to "the single thing becomes a list of a single element at runtime" though?
.xmap(either -> either.map(List::of, Function.identity()), Either::right)
do i just have to do it by hand with xmap
there's Codec.withAlternative(), which is just a wrapper over xmap
but otherwise, yeah what Platin suggested
yeah ok, that would make it a bit nicer, since it would just be Codec.withAlternative(Thing.CODEC.listOf(), Thing.CODEC, List::of)
yeah
I also find that a bit nicer to read: "expect Thing.CODEC.listOf(), if it's just a Thing.CODEC then that's fine too, we'll just wrap that in List.of() and be done with it"
it does turn everything into list on encode, but I doubt that matters here
yeah I figure that doesn't matter
is there any better alternative to .filter(Optional::isPresent).map(Optional::get)?
hmm technically the inner lists should be maps or sets
probably maps, they'll look nicer as json maps too
is there an open map codec that returns an ordered map? the ordering would be nice to keep for the toString, but isn't critical
.flatMap(Optional::stream)
thanks
ok i think i've got the ingredient type otherwise implemented, i need to go now but i'll tackle the codec later
...where's the open map codec at again?
checked Codec, ExtraCodecs, NeoForgeExtraCodecs?
i still don't know how to test literally any of this though
??
you should be using the name of the unit as the key here
this is just really hard to read
it should be an either of an integer or an unbound map of string to number
yeah i got there, i was stuck on that format because the actual datamap data, which looks similar, has more fields
i made it so the integer can only substitute for the whole list though, not the entries inside it
hmm did i? let me check again
oh, it accepts an integer but doesn't write it back out as an integer, but it does write single-element lists out as single values
ask somebody (maybe multiple people) who would be a consumer of this system to make a branch using that PR build
i dont have ad astra on 1.21 yet otherwise id offer
oh wait no, i do have a mod using fluid ingredients i could use
this would be really useful to me rn for liquid experience. id love to have that unit be in terms of exp points
hmm
OpenBlocks also had an XP fluid iirc, that one could be used as well
i've been going back and forth on whether to have separate abbreviated and long translations for units, the issue is that most units don't have sensible abbreviations
maybe keep that as a lang thing? idk
yeah but it doesn't do much else with fluids. I do have plans for this once the system gets in, but it's not a very thorough test
I think for now I'm going to have just singular and plural, and have mb as "mb" but everything else longhand including "experience points"
I think using mb is fine, everything else should use "long" names (i.e., ingots, gems, nuggets, blocks, shards)
maybe the lang would be like 1 ingot(s)?
i already have plurals working
yeah, experience_points is fine because there is no user-facing xp anymore, and removing the _points makes it unclear
well, theoretically working as i have not tested anything
er i was using xp for the key but "Experience Points" to display to end users
nah, I'm assuming count == 1 ? singularComponent : pluralComponent
[the translated names are capitalized because it's easier for a mod that wants to display in lowercase to lowercase it than to titlecase]
I'd rather that be experience_points internally tbh
or at the very least, xp_points
because otherwise it could be interpreted as xp_levels
the game calls it totalExperience and experienceLevel, so it should be full "experience"
is there a resourcelocation codec that can use a different default namespace?
ah, yeah make it singular, that's fine
seems beyond scope, the way it works rn is fine imo
fair enough
so, experience_point
also, i set it up so you can put "bucket" or "mb" in the list for display purposes, but they're required to have the correct values
1 bucket is still a constant 1000 mb?
[i needed them in the map internally for the recipe stuff]
yeah, changing that is beyond scope
yeah that's fine then
maybe just make them properties of the datamap thing? cuz you'll have more data than just the list in the datamap no?
not sure what you mean
[why the hell doesn't applyAllFormatting actually fix any of the issues it complains about? isn't that the purpose of having check and apply separate?]
nvm, i just typed out what i was thinking and it was dumb
i guess it only applies whitespace
what other values are we putting in the individual entries for the datamap values
display_in_tooltip flag
"#tconstruct:fluid_units/metal": [
{ "name": "c:block", "value": 810 },
{ "name": "c:ingot", "value": 90 },
{ "name": "c:nugget", "value": 10 },
{ "name": "tconstruct:copper_can", "value": 90, "show_in_tooltips": false }
],
"#tconstruct:fluid_units/metal": {
"c:block": 810,
"c:ingot": 90,
"c:nugget": 10,
"tconstruct:coppper_can": {
"amount": 90,
"show_in_tooltips": false
}
}
should be possible and how id prefer it to be written
i think this would just change the value codec to be an either
... can you do that?
oh
i can just make the entry codec not include the name
and use that as a value in the unboundedmapcodec
yeah, itd be an unbound map of string to either an int or "configuredint" or something
wait no how would i get the name into the entry when reconstructing the
do map codecs guarantee order?
actually, i don't need them ordered, nevermind
it doesnt really matter the order
its ordered by the value anyways
but in my experience yes, the order does usually stay the same
yeah, type should generally be int here
i just realized i don't actually need a class that includes both the key and the value
gah i'm getting an exception on this codec and i don't know why
public static final Codec<FluidUnitSpec> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.unboundedMap(FluidUnit.CODEC, UnitInfo.CODEC).fieldOf("units").forGetter(s -> s.map),
FluidUnit.CODEC.optionalFieldOf("default_unit", FluidUnit.BUCKET).forGetter(FluidUnitSpec::defaultUnit),
Codec.INT.optionalFieldOf("smallest_decimals").forGetter(s -> s.smallestUnitDecimals)).apply(instance, FluidUnitSpec::new));```
[on actually statically initializing the codec, as far as i can tell]
...oh
it was caused by me putting the static public constants in the FluidUnit class above the map that holds them [toolaction style]
i guess that's why tool actions have a separate class for holding the constants, i guess i could do that
one last push, gonna leave it up overnight for people to look at before doing the PR
lol i just realized all my discussion from the last hour was in #neoforge-github
theres also Codec.lazy
it wasn't a codec issue at all, i screwed up the static initializers in the FluidUnit class so it crashed on classload
ah
I posted the PR
enabled PR publishing
@fluid mortar @pure lynx
could you link the PR here so I can pin it
This implements the system described at https://gist.github.com/KnightMiner/ec4f21d56d466e32ac5d14a1b1124923, with a handful of extra features [a default display unit can be specified for contexts ...
why optional of an int instead of just returning 0?
0 means round, empty means it's calculated based on the size of the unit being displayed fractionally
er, i assume you mean in the decimal places parameter, optional is a couple other places but it's used with map/orelse, you can't really do that with an int with a magic sentinel value
if we really don't like Optional<Integer> all uses of it can be replaced in principle but it's more and less elegant code
We could also use -1 if we need a third state there
Though that gets awkward
I'll take a look when I have some free time and give my thoughts
Isn't there also an OptionalInt you could xmap with?
I tried OptionalInt first, it doesn't have the map methods
It's also not just about the code in the ingredient handler - getValue is arguably a user-facing API too, and returning 0 or -1 there is just asking for trouble, people will call it not expecting it and end up actually using that value
though looking again, i'm actually returning null there instead of an optional
the optional for decimals is mostly internal and fine to change i guess
i actually should probably do a pass through the codecs adding validations to prevent zero and negative values where inappropriate in general
i think i was stuck on the codec needing an optional, i'll go ahead and change the decimals field since it's internal
ok yeah most of my concern was actually for getAmount [which i misrembered as using an optional for, i think i had one at one time and then switched it to a nullable], not the decimals field
incidentally, i was half tempted to implement a system for allowing fractions to be printed as fractions too, but that seems out of scope.
hmm
should i put some of this codec stuff in NeoForgeExtraCodecs?
lol oops i completely forgot to make a stream codec
is there a built-in stream codec for maps?
found it - i do not understand why it cannot infer these types though ```
ByteBufCodecs.<RegistryFriendlyByteBuf, FluidUnit, Integer, Map<FluidUnit, Integer>>map(HashMap::new, FluidUnit.STREAM_CODEC, ByteBufCodecs.INT).apply(ByteBufCodecs.list()),
ok i've got a bunch of the codec stuff fixed, and that Optional removed, gonna push as soon as i can verify it still compiles and runs datagen
are there really languages where the way its currently setup wouldnt work? I know mandarin doesnt really make a distinction between plural and singular but that could just be solved by using the same text twice. Maybe the plural ibm thing would be helpful, i havent ever used it tho so idk how thatd work
gonna also add simple tests of the ingredient
the plural thing is something i was concerned about, but gave up since, well, i have no understanding of how PluralFormat is actually available using the Component system. I had actually assumed it wasn't available, and that adding support to it would be a different PR entirely.
@chrome dirge ???
After I spent an hour looking into the Java side, I was a bit fed up with the topic and didn't look into the Minecraft side of things. However, at its base, what's behind the formatter is a lookup which of 6 translation forms to use. So even fi the formatter itself is useless, that lookup still should be in there and we may need to go traditional with 6 seperate lang keys instead of the modern 1-key-with-inlines format
ok but the function may be called on the server, and the user's locale is unavailable there
i think pluralization for languages that don't use a simple singular-plural form is outside of scope if there's no actual way to do it
it's worth looking into in general though
i wrote some gametests for the ingredient types, and my matching is failing for some reason
oh, yes. there it is: com.ibm.icu.text.PluralRules
Yes -- consider, say, the pluralising of "0 buckets" in different languages. You can find some iffy ones with that pretty easily
um, getTooltipComponents() called on the server? seems odd
Getting components on the server is common
dont commands do that?
The basic formatting function could be called to format a command output. I also think AE2 and the like might build tooltips on the server for search purposes
You often grab them there, then sync them to the client for whatever reason
https://www.unicode.org/cldr/charts/45/supplemental/language_plural_rules.html here are some examples...
Does MC deal with this anywhere?
ah shit i forgot to run apply formatting before pushing
MC mostly just does always plural or (s)
Why don't we follow that then?
because it's ugly
(s) i think is fine?
1 bucket(s) looks fine to me
and it's mostly in command outputs, which is less user-facing
"1 block(s), 4 ingot(s), 4.5 nugget(s)"?
There's no good way to handle plural vs singular via translation components as they currently work
Then do always plural. 1 blocks, 4 ingots, 4.5 nuggets. Yes, it'll be technically wrong sometimes, but, eh
lets just make everyone learn mandarin or something, no distinction between singular and plural 😄
the optimal solution™️
how about this: people translating for languages that the english rules don't work for can put their equivalent of bucket(s) in both keys if they want, but we'll keep the plural system for those that do
[it'll work for french too, these never get printed with zero, at least not by the helper function]
what?
How does 0 print then?
Empty
im also personally iffy on the keys being singular. for ingredients it doesnt look correct
{ buckets: 1 } > { bucket: 1 }
Ah, okay
The keys should be singular because it's the name of the unit itself
And in the data map for setting those, the plural versoin would look weird
well either way its going to look weird somewhere. the datamap one is more for the mod dev while the usage in recipes is more used for consumers and users, i say make the key plural :P
you write a data map once, you could end up writing dozens of recipes, it affects one more than the other
what if i made each one have two names
have that and a special codec that omits the c: namespace, for maximum friendliness
[to be clear, having two names is not actually viable, they'd have to be registered in code instead of auto-interning like tool actions]
the no-namespace codec is viable though
No aliases. I'd rather have only-plural than that
no-namespace codec though -- that's a good idea. Stops you from accidentally using minecraft: units too
aside from the decision for this specific case, what would be the general opinion in the room on patching proper pluralisation support into the translatable component? Naturally, using it for Components sent to vanilla clients wouldn't work, but aside from that I see no compatibility issues when hijacking the % placeholder as any other character than % and s after it is a fatal error atm.
(i.e. would it be a waste of time if I were to look into doing that)
as a separate PR it might be a nice feature
im sure this is not the first or last time someone will run into this issue
i like the idea
but i wonder if inline formatting might not be the best solution
actually nevermind, fuck messing with the component codecs
my idea if to hijack the % and use e.g. "%(standard ICU plural format)" for this
[yeah inline formatting is fine]
yeah, i had a vague idea of using some sort of custom json format, then i just realized what a nightmare that would be to implement
i think there are some places in FML that use some kind of %{} thing, so it's not without precedent, though i think they only work for logging not for the game itself
what exactly is the ICU plural format? like, is %() part of it, or is that your own invention? all i can find just uses {}
and named variables instead of numbered ones
i guess as long as it works it doesn't matter what the particulars of the format are
so in the json it'd be "key": "I see %s %(one{dog} other{dogs}) here!",
%1$(...) surely
[not passing the argument twice means we can in principle fix vanilla's (s)s with a resource pack]
%s is the only allowed placeholder in vanilla, and while it would be great for localisation to provide positional ones, I'm not sure if that should be mixed in with pluralisation
oh, that
i'm pretty sure vanilla does support %1$s
it's been a while since i looked at it though
yes, I think "key": "I see %(one{%s dog} other{%s dogs}) here!", could work
But I'll have a look ath what the ICU classes provide first before I spin my own thing here
pluralization support is... complicated
I don't see it in net.minecraft.network.chat.contents.TranslatableContents.decomposeTemplate(), but there may be other places that split up that string?
its simple for english
it could, but not being able to reference the argument twice means you're limited in cases where a different variable needs to be printed in between the number and the pluralized form
but some languages go up to... 6? different forms based on plurality
Shadows, see above, I posted a reference link
yup, we're aware - i only used simple pluralization because fixing the component system to do more is outside the scope of this particular PR, but that doesn't mean it's not worth doing
(incidentally, it's not like complexity is foreign to english - our plurals are simple, but we have the same problem with ordinals)
some of the rules on that page for plurals actually remind me a lot of english ordinals, with the 1 vs 11 vs 101 thing
yes, funnily enough, given how many different variants of languages there are, they all are a mix of very few building blocks
[i don't know for sure if there are places in vanilla or mods that do "1th" ordinals, but i don't particularly doubt it either]
I'm pretty sure vanilla only uses number inserts in their strings very, very, rarely
yeah vanilla doesn't do it very much
mostly in the options menu or debug
where they don't need to display X things, but rather Value: X
"translation.test.complex": "Prefix, %s%2$s again %s and %1$s lastly %s and also %1$s again!", ok, there is a complex pattern. I just need to find the code that handles that
we could always print singular
eh scratch that
for some reason i had it in my head that vanilla does "1 [singular item name]" in tooltips, but the count isn't in the tooltip
um, duh. found it. the code checks the second part before the fist part. I stopped reading before I got to that 🤦
anyway, we should probably split off another thread for this
It looks like we can also just add new ComponentContents
So if we need a different "plural-sensitive-contents" that's a thing we can do, I guess
finally found one in the vanilla lang file: "Chat message was too long (%s > maximum %s characters)", and chat.queue": "[+%s pending lines]",, "clear.failed.multiple": "No items were found on %s players",, "commands.banip.info": "This ban affects %s player(s): %s", "commands.banlist.list": "There are %s ban(s):", and a couple more command result messages
huh, how hard is that? i'm not convinced it's a good solution on its own, but in combination with something someone else was showing off [a port of some fabric thing called owo-lib that lets translation strings be components themselves] a while back it could be nice
iirc there were some vanilla compat concerns but I guess they got that worked out
grrr, not a single line of javadoc. how will anyone know how to use that? (re 1134)
I don't think you are intended to interact with the contents object
i tried to document most of my public methods, i might have missed a few though
eh
i mean, javadoc isn't a totally non-viable venue for documentation of a json format
my ingredient type has json info in the javadocs on its codec fields [copied from sizedfluidingredient which also does it]
I have taken to describing json syntax with markdown using js highlighting: https://github.com/Shadows-of-Fire/Placebo/blob/1.20/schema/ItemStack.md
grrr, even after spending ten minutes reading that PR's diff, I still have no idea how I would use that thing other than copy&pasting the test that comes with it and trying out what works .-(
there's a formal doc here https://docs.wispforest.io/owo/rich-translations/
"When owo is installed, " Alt-F4.
;) ;)
just a quick&dirty proof-of-concept hack. that patch is 5 lines plus a tool method to safely convert the parameter to double
A problem you will run into as well is existing resource packs
especially if you extend it to vanilla plurals
should be no issue, unless someone uses "%(" somewhere...and I just noticed that that was an ignored, not an illegal combination. I may need to change it to e.g. "%n(", an actually illegal combination.
have you tried 0 yet
you mean as a value? sure, that has been the test case for my last "does it still work" tests...
very convenient one, already there and comes up when starting the server ;)
ugh i forgot to check notifications - i'll go through the PR review comments in the next few days
Its probably worth having a method on FluidStack to get the full tooltip including display name to standardize the order and color between that and the amount string. Plus would call appendHoverText
I thought about this and actually almost started writing one, but then it occurred to me that about half of the vanilla itemstack components that affect tooltips [e.g. name, lore, rarity, etc - maybe potion effects] could be applied to fluidstacks as well and figured it's something that deserves some discussion on its own.
is there a tool i can run to find public methods that don't have javadocs? i think i got all of them but it'd be nice to be sure
ugh i thought i did run datagen, apparently it failed
I partly wonder if such things shouldn't be left up to future work
we could start with a bare bones "getHoverText" then expand it in the future
alternatively, we could do that PR first and do the units PR after
only concern with that idea is the unit display would have to be fixed to millibuckets which makes it more difficult for mods with their own unit display in the meantime
