#Registries Overhaul

1 messages · Page 2 of 1

ripe storm
#

Holders in any sense for datapack stuff make no sense until worldgen registries exist

hearty urchin
#

You shouldn’t even need to have to store a reference of biomes. In fact you really shouldn’t. Otherwise the Holder would have to be rebound and it becomes complicated. If someone needs an instance of a biome for whatever reason you grab it with its resource key from a registry access.

Reference the key of the object, not the object itself

hoary umbra
#

Yeah, in that instance it is fine that DH does not work for datapack regs

#

those should be retrieved from the reg once available

#

(if you even ever need those for anything)

hearty urchin
#

Vanilla does it often. Look at how rabbits determine their variant on spawn based on biome

#

or foxes

gloomy sinew
#

DR objects use holders to autowire themselves to each other

hoary umbra
#

well the rabbit doesn't need a Holder<Biome>, it could just use Biome

gloomy sinew
#

perhaps

hearty urchin
#

tell you the truth, that example was pretty terrible

#

because rabbits only need to know what biome it is (aka the ID of it). They don’t need to know anything about the biome

#

Perhaps rain was a better example

#

Rain doesn’t happen in hotter biomes

hoary umbra
#

I mean I guess rabbits need the holder

#

because is(TagKey) is a holder method

hearty urchin
#

or snow in colder

#

POINT IS. Datapack objects you just need a resource key. No more, no less

quaint pagoda
#

no that doesn't make any sense to do given this is purely for builtin registries and worldgen registries have their own non-infinite lifetime

gloomy sinew
#

placedfeatures need the configuredfeature itself

#

and yeah worldgen registries never get to the root reg

#

even if they did, like

#

let's say you make a static deferredholder for a biome that somehow gets the biome value when the worldgen registries are created

hearty urchin
gloomy sinew
#

if you're playing in singleplayer, does it hold the client biome or the server biome

#

(they're not the same biome)

hoary umbra
#

uh

ripe storm
#

I do have to ask though, what is the process for making a new registry going to look like and how are we going to make it more similar to the vanilla system?

hoary umbra
#

are all dpregs synced?

gloomy sinew
#

they are

hoary umbra
#

then probably the server

gloomy sinew
#

err

#

no they are not all synced

#

just two of them

hoary umbra
gloomy sinew
#

biomes and dimensiontypes

#

(and custom dprs if marked as syncable)

ripe storm
# hoary umbra then probably the server

I mean, but then you compare it to the biome or whatever on the client and suddenly they're not equivalent when they ought to be. Gets dicey fast. I'd just say no deferred holders for datapack registries

gloomy sinew
#

also the biomes on the client don't even have the same data as the biomes on the server

hoary umbra
#

DH == "core" regs only

gloomy sinew
#

so, registryobjects but holders

hoary umbra
#

I guess BuiltIn is the name mojang has selected

#

pretty much

ripe storm
#

So, anything owned by the root registry

hearty urchin
#

especially since /reload can be invoked and the new datapack data could delete entries and then weird stuff happens with DH

hoary umbra
ripe storm
hoary umbra
#

that part makes me screm

hearty urchin
#

i mean the entries

#

the objects registered

ripe storm
hoary umbra
#

the fact that DPR doesn't /reload and no mechanism exist to makes them do so is a bit spaghetti

glossy vault
#

That's only half true. The order only matters for new worlds if forge feels like it

#

For existing worlds, order is based on order mods originally were in with new ones appended

hearty urchin
ripe storm
#

Other datapack stuff does but not registries

hoary umbra
#

You may have for mods that use reload listeners for datapack data

#

but not for things that are "proper" datapack regs

hearty urchin
#

perhaps. Alright thanks for clearing that one up

glossy vault
#

If forge switched to a compound datapacks for all mods like they do for resource packs, it could always matter and save a lot of pack maker headache though

ripe storm
#

Still a bit curious about this though. Can we somehow make new registry creation use Holders? #1131130393144336385 message

#

Or otherwise be more vanilla like?

glossy vault
#

The only downside is you cannot reorder mod datapacks with commands, which no one wants to do anyways

ripe storm
#

Not quite sure how vanilla does it actually

glossy vault
#

I should make a difference thread about that probably

hoary umbra
#

new registry creation is just new MappedRegistry for vanilla

#

I would implore keeping it that way

ripe storm
#

Yeah. I agree

#

Let's not make this complicated

hoary umbra
#

and then registration to the root reg™️

#

NewRegistryEvent can stay as an early "register your new regs"

#

but ideally™️ reg creation is

public static final Registry<Spaghetti> MY_REGISTRY = new MappedRegistry<>(...);
#

syncing and saving (both forge features) will need to either be done via extension methods which raise flags (and become locked at registration time) or via ctor params (annoying for updating vanilla)

ripe storm
hoary umbra
#

DefReg iirc already has that capacity (to make the registry for the underlying type)

#

but the return type of that method isn't Registry

ripe storm
#

Hmm. But I mean, if you're using def reg you're not really using the vanilla system anymore?

#

But yeah, I guess that makes sense

hoary umbra
#

I mean in general I would never advise using a pure vanilla system unless you have absolute classloading control (i.e. you declare the registry and all entries in clinit for a particular type)

quaint pagoda
hoary umbra
#

I mean that's fine

public static final Registry<T> REG = Registry.builder().blah().saved().build();
quaint pagoda
#

It's easy

hoary umbra
#

it doesn't need to error if its only accessible via the builder, lol

ripe storm
#

Like, we should still allow creation of registries unlinked to the root registry. Heck, vanilla uses that for world gen. I'd say it would error when someone tries to register to it

quaint pagoda
#

new RegistryBuilder<>(KEY), check if KEY is registered to root registry later

ripe storm
#

I figured even that might not be necessary as we could just watch for people trying to register stuff to registries that don't exist (not registered )during the registry events

quaint pagoda
#

better safe than sorry

ripe storm
#

But yeah, using the builder is clean

hoary umbra
#

you don't need that many sanity checks, DH will just explode if the registry isn't registered

ripe storm
#

Especially if you expect most people to use that

hoary umbra
#

and it will say that explicitly "no registry exists"

ripe storm
#

(is this all package private in vanilla normally?)

hoary umbra
#

I don't think many things in vanilla are package private

ripe storm
#

What is the access modifier on making a new registry in vanilla?

hoary umbra
#

well, the helpers are private, but you can just copy them

ripe storm
#

But the actual constructor is public then?

hoary umbra
#

so in literal terms, public™️

ripe storm
#

Then yeah, we don't need any special checks in the builder, if DH would error anyways and if they can always just use the constructor straight away

hoary umbra
#

In general I always disliked the excessive amount of defensive programming

ripe storm
#

Yeah, I'm with you there

#

Doesn't ever protect as much as it claims to, and makes it way harder for the one guy who actually has a reason to dig under it

hoary umbra
#

Unless its in netcode

keen thicket
#

also, slight detail.. has anyone checked the thread safety of holder creation

#

which I'm going to assume isn't safe

hoary umbra
#

normal holder creation? no, not a chance, lol

gloomy sinew
#

getOrCreateHolder is a write operation on the vanilla registries and vanilla registries are not threadsafe

#

noodogthonk could frozen registries be made threadsafe?

#

I guess if all write operations are forbidden then they already would be

#

ah no, reloading tags is a write operation on... something

ripe storm
#

They're thread safe during common setup and after registry reloads though, right?

gloomy sinew
#

maybe, unless somebody's cheesing things into the registries post-registration

#

(which I suspect is something that both of us do)

#

okay, tag reloading is an atomic operation on the registry's tag map, but mutates all holders iteratively

ripe storm
gloomy sinew
ripe storm
#

Heh. Well, yeah, fair enough

#

I'm excited to hopefully get registry callbacks as a way around that rather ugly mixin I currently use

gloomy sinew
#

half the reason I originally wanted this to be an official forge feature was so people wouldn't assume the dimension registry was immutable (because immersive portals was caching it for some reason)

quaint pagoda
#

looks to me like people should always use DeferredHolder then

ripe storm
#

Within a parallelizable context I'd say yeah, it's probably safer

hoary umbra
quaint pagoda
#

I haven't looked at your implementation at all

hoary umbra
#

if we get registry callbacks we can register all DH's as callbacks and then that won't be an issue

#

technically™️ the registry step is singlethreaded so it shouldn't be an issue™️

quaint pagoda
#

even though people can statically create registries

#

those registries won't be registered immediately

#

therefore there won't always be a registry to lookup to register to

hoary umbra
#

all registries will be available after NewRegistryEvent, which DH's can listen to and bind

quaint pagoda
#

that's exactly what ModifyRegistryEvent is for

quaint pagoda
#

PoC is pain

#

I'm thinking phase 2 would be a nice idea

#

do a role reversal and have forge registry be a wrapper on registry<?>

hoary umbra
#

phase 2 good

#

lessens burden significantly™️

keen thicket
quaint pagoda
#

stupid to mention that

queen notch
#

Phase 2 will be great, just lets not repeat Thor: Dark World okey?

hoary umbra
winged iris
#

I will try to take a look at it in the next couple days, but I think you need to rebase as the jar compat check is failing (as things have been added that aren’t in your pr due to older base)

hoary umbra
#

screm

#

compat check should probably run a local rebase first

#

or, well, wait actually

#

doesn't the compat check failure on any method removal, not just api-breaking changes?

#

wondering if its picking up removal of the package-private methods or smth

keen thicket
hoary umbra
#

oh well, rebase is clean, so that took 3 seconds

#

CI at my work runs a rebase before doing any pipeline things, but I'm not sure how difficult that is for our infra to handle

winged iris
past saffron
hoary umbra
#

hm, yeah

hoary umbra
#

oh, neat, didn't realize that was a thing

quaint pagoda
#

yes :p

#

otherwise it would error on every lambda change

hoary umbra
#

I think I recall it complaining about removing a non-api method at some point

quaint pagoda
#

it should respect api status internal now I think

hoary umbra
#

bleh, I've realized I want to write something but it depends on defholder existing

winged iris
#

just write it against maven local and then wait a day or two to commit WeSmart

quaint pagoda
#

@hoary umbra why isn't there a factory method that simply takes a resource key?

hoary umbra
#

uh

#

idk™️

#

because you can't make a strong resource key on your own, its a huge pita

#

and the expectation is that your DH is strongly-typed to your object type

quaint pagoda
#

the docs probably shouldn't be using <br> but we haven't standardized that yet

#

and also I don't think there should be spaces between the doc and the method or class start

hoary umbra
#

is <br> illegal now thonk

deep lance
#

can't you use a dangling generic?

hoary umbra
#

I've tried everything I can think of, the issue is in the signature of ResourceKey.create

#

it only returns a type of the registry type

deep lance
#

registry keys are ResourceKey<Registry<T>>, not ResourceKey<? extends Registry<? super T>>

hoary umbra
#

they're ResourceKey<? extends Registry<T>>

quaint pagoda
#

yeah it's certified awful

quaint pagoda
#

that doesn't sound right

deep lance
hoary umbra
#

anyhow we can leave the javadoc formatting up to #1131782966989828156

quaint pagoda
#

I thought vanilla used ? extends Registry<T> for everything

hoary umbra
#

it does

deep lance
#

i think maybe they used to have that wildcard mess in, like, 1.18.2 when i first looked at it

hoary umbra
#

obviously the declarations aren't

quaint pagoda
quaint pagoda
#

the declarations could be if Mojang wanted

hoary umbra
#

The javadocs in there are autoformatted by my eclipse profile

#

well the decls are decompiled, so who knows

quaint pagoda
#

true I guess

deep lance
#

....oh

#

you want the holder to be typed to your type, not to e.g. Block

hoary umbra
#

I could just make the ctor public if you want a reskey one

#

but yeah, generic hell™️

deep lance
#

honestly

#

i'd be half tempted to make DeferredHolder take two types

#

the registry type and a more specific type

hoary umbra
#

yeah but that achieves nothing, lol

#

it doesn't fix the unchecked cast and it just makes all declarations longer

deep lance
#

it lets DeferredHolder<Block, MyBlock> implement Holder<Block> so it can be part of a set of Holder<Block>s

hoary umbra
#

it already can be, wew type erasure

deep lance
#

i still don't understand the unchecked cast

hoary umbra
#

I left the compiler error in the pr

deep lance
#

or why the type can't simply be ResourceKey<Registry<T>>

hoary umbra
#

It could be, but that doesn't fix it

#

? extends Registry<? super T>> is just the biggest "umbrella"

deep lance
#

how doesn't it fix it

#

voila fixed. only the ? super is problematic, even. and I don't understand why it has to be there.

hoary umbra
#

now get me a ? extends Registry<MyBlock>, lol

#

you've just moved the cast location to outside the method

deep lance
#

but Registries.BLOCK's type is ResourceKey<Registry<Block>>

hoary umbra
#

yes, so now create only makes DH<Block>

deep lance
#
    public DeferredHolder(ResourceKey<? super T> resourceKey) {
        // ...
    }

    public static <T, U extends T> DeferredHolder<U> create(ResourceKey<Registry<T>> registryKey, ResourceLocation valueName)
    {
        return new DeferredHolder<U>(ResourceKey.create(registryKey, valueName));
    }

bam

hoary umbra
#

Hm, I suppose we can bypass the type on the key like that

deep lance
#

like ultimately the type of the key is block

#

this does mean you have an unchecked cast in the value method, but that's the method that actually has the potential of returning the wrong type and will have a checkcast in its caller

#

like, ultimately the question to consider is

#

what actually happens if someone creates a deferredholder for a type that doesn't match the actual type placed in the registry

#

no matter how the unchecked casts are arranged, at the end of the day the return value of value() is caller-checked

#

though an unchecked cast is a little less ugly than a raw type at least

quaint pagoda
quaint pagoda
hoary umbra
#

top 10 illegal generic techniques

abstract scarab
#

We got a summary on the end-goal for this?

#

Like what an average user’s registry process would look like

hoary umbra
#

currently I have to do some fairly ugly reflection to make this possible, lol

abstract scarab
#

Looks exactly like it is now

#

Whats the point of the change

hoary umbra
#

pretty much

#

this change makes RO a Holder<T> so it can be used in Holder places

#

RO is currently really bulky

#

its just a huge pile of overengineered spaghetti

abstract scarab
#

Does that actually offer any tangible benefit

#

People can already call .asholder

hoary umbra
#

not really

#

only for vanilla registries with intrusive holders enabled

abstract scarab
#

I see

hoary umbra
#

this is basically the first step in "delete ForgeRegistry"

abstract scarab
#

I was expecting something actually useful from a registry overhaul in neoforge

hoary umbra
#

as it also makes all registries vanilla-backed

#

well there will be™️

#

but not yet

#

because it requires changing so many internals

surreal turret
#

one step at a time

hoary umbra
#

we are still at non-breaking-change phase

abstract scarab
#

Is there a reason it needs to be not yet?

hoary umbra
#

non-breaking-change phase™️

abstract scarab
#

Then defer the change for breaking so you can do it properly?

hoary umbra
#

I have to do this part anyway

abstract scarab
#

This seems rushed for the sake of it

hoary umbra
#

why would I defer this part until later?

abstract scarab
#

Idk I’m just coming in off the periphery

hoary umbra
#

Ultimately this is mostly an internals thing

abstract scarab
#

If this is 100% non breaking then I guess its ok from a dev perspective

hoary umbra
#

the registry system is a horrible unmaintainable mess

abstract scarab
#

If theres any amount of change required from the dev side for this its an outright disappointment from my perspective

hoary umbra
#

probably not significant differences to the typical end-user

abstract scarab
#

Not significant isnt none..

hoary umbra
#

I mean the class ForgeRegistries will vanish

abstract scarab
#

So its breaking

#

Which leads me back to why

hoary umbra
#

not right now™️

#

I mean I have no idea what your goal is with this question, lol

abstract scarab
#

So this specific pr is typically 100% binary compatible with current mods (ignoring edge cases)

#

?

hoary umbra
#

yes

abstract scarab
#

Ok cool

hoary umbra
winged iris
rocky estuary
#

Without looking at the internals what consequences will this change have for most everyday uses beside not referencing forge registries anymore?

high raptor
#

you'd be renaming RegistryObject to DeferredHolder or something to that effect

rocky estuary
#

And that's it?

gloomy sinew
high raptor
#

using registry keys more when creating deferred registers too, i think

#

since deferredregister.create or whatever has like three overloads

rocky estuary
#

So from an outsider prespecrive it's just a name change

lofty citrus
#

RegistryObject still remains, but it's deprecated and it's only a light wrapper over DeferredHolder

#

it'll get yeeted come breaking changes time yeef

rocky estuary
#

Right so it's not a breaking chsnge for first phase:TM:

deep lance
past saffron
#

What would be the point of that? The idea behind DeferredHolder is to keep the lazy init of RegistryObject while being a Holder, in part to make multiplatform stuff simpler

deep lance
#

for backwards compatibility, i had it in my head that if we do that then DeferredRegister.register can return an actual DeferredHolder rather than a wrapper

#

actually is there a need for there to be two classes at any time? why couldn't we just make RegistryObject implement Holder, and wait for breaking to rename

past saffron
past saffron
hoary umbra
quaint pagoda
#

I am pretty sure the answer is no

#

but you would have to ask pup how that comment came about

winged iris
#

I mean vanilla might not do registry sync

#

I have no idea

keen thicket
#

it doesn't (need to)

winged iris
#

I haven't had a chance to look through the code and realized that maybe that is something we have to worry about

quaint pagoda
#

why do you think vanilla does? In my eyes we would have already removed the forge feature if vanilla did this

keen thicket
#

why would vanilla do it in the first place thinkies

quaint pagoda
#

to be nice :>

keen thicket
#

vanilla? nice? funny joke

gloomy sinew
#

yeah I'd be very surprised if vanilla does any registry syncing in the static registries

keen thicket
#

it doesn't make sense for vanilla to sync registries when they're static init'd smh. useless packets

gloomy sinew
#

even the numeric ids should be consistent in vanilla

keen thicket
#

numeric ids are the thing you need to sync/persist

quaint pagoda
gloomy sinew
#

right but I mean in vanilla they're probably consistent on both sides without needing a sync

keen thicket
#

yes

hoary umbra
#

All DH's support optional registries

#

just don't call .get()

#

because, obviously, the item is not present since the registry is not present

winged iris
#

and my comment was just asking to make sure whether or not the binding would cause issues

#

I thought it wouldn't but wanted to check

hoary umbra
#

no bc the event doesn't fire for registries that don't exist

winged iris
#

given the fact that the registry event shouldn't fire if the registry doesn't exist

#

I know

#

I just wanted confirmation is why I asked

hoary umbra
#

I mean technically it could, I guess

#

there's no sanity checks in the signature to make sure the registry is present thonk

#

the ctor should check at least one of the regs is present

#

and the names used are based on this weird patched-in MappedRegistry.getKnownRegistries()

winged iris
#

that's so that it is in a consistent order and one that follows vanilla's init order

quaint pagoda
#

how are you supposed to ensure your entries registered even if you don't want to query them

hoary umbra
#

why...?

gloomy sinew
#

well

hoary umbra
#

isPresent thonk

quaint pagoda
#

like by default I think we should error if an entry isn't registered when the user expected it to be registered

#

which is already what happens

gloomy sinew
#

if they're my own entries, for vanilla's registries or my own registries, I can reasonably assume they're registered without checking isPresent

#

if my own entries didn't register then something went horribly wrong and it should crash very fast

quaint pagoda
#

it's not always going to crash fast though

winged iris
gloomy sinew
#

those're datapack registries now though thinkies

quaint pagoda
#

I'm curious if the deferred register not being registered throws an error if the registry object doesn't detect itself as registered (right now without this PR)

quaint pagoda
#

e.g. command argument providers

winged iris
quaint pagoda
#

I'm never gonna need to query that entry but it still has to be registered

gloomy sinew
#

also the way vanilla holders work is that if a holder was created for a registry but the value was never registered/bound, the registry throws on freeze

winged iris
#

and those were the two most common ones when we wrote that bit so that it fires in that order

hoary umbra
#

if the registry exists then the element will be registered, unless you don't register your DR, in which case it just fails anyway

quaint pagoda
#

the point of the createOptional things was by default things explicitly error if they don't get registered

hoary umbra
#

all createOptional did was error check if the registry exists, you can do that yourself

quaint pagoda
#

rip yeah I guess that's all it did

#

nvm it's just static wrapper methods that are never actually used

#

this is a lot easier than declaring an optional dependency on repurposed structures to ensure their mod constructor runs first so that you can do a ModList check from your constructor to optionally register the Deferred Register

#

actually I guess you don't have to sort your mod constructor to know if a mod is loaded

#

so meh it's only like a one liner difference to change the DR registration, theoretically

#

it's a pretty niche case anyways because the custom registry has to not use custom mod class types for it to be useful at all anyways without requiring a ModList#isLoaded check before loading the class and getting massive classloading errors

#

anyways all that to say I guess it makes sense to get rid of as it's not doing much at all

hoary umbra
#

Yeah if it was doing something else that was potentially more useful I could see it being helpful

#

but its just a very obscure "does registry exist" check

#

marking that comment as resolved

quaint pagoda
#

maybe we should link back to this convo as evidence

hoary umbra
#

done™️

winged iris
#

fairly certain it is fine, not marking it as approved yet (may not until tomorrow or something idk) as I want to test it against say mek to do an extra level of testing/validation that it doesn't cause any compile or runtime breaking changes

hoary umbra
#

yeah, not 100% certain on the impact of everything having a vanilla registry

#

pretty sure it's harmless

gloomy sinew
#

"what's the worst that could happen?"

winged iris
#

well that part I don't know, especially given my custom registries 4/5 of them have vanilla registries already

quaint pagoda
#

that's just causing 2 blank lines for no reason

#

so, most of the keys in ForgeRegistries$Keys should be deprecated and disappear soon

#

I can also move these to github, probably should

#

I did that

hoary umbra
#

I think messing with the key deprecations is out of scope for now, I was going to do another one which shuffles the deprecation fields from the vanilla stuff to the forge stuff

quaint pagoda
hoary umbra
#

yeah that's fine

hoary umbra
#

Not sure why the dislike for <br> and <p> in the same thing, they have different purposes

#

I use br to split sentences to their own lines, and p to split ideas into their own paragraphs

#

though any cases of <br> with an immediate <p> following are just me being stupid

abstract scarab
#

^

#

people have a go at me for doing the same thing lol

#

br and p format differently, so I use them differently

quaint pagoda
#

I wasn't aware of that. Different how?

hoary umbra
#

<br> is just a line break

#

<p> is a line break + empty line

quaint pagoda
hoary umbra
#

most of our codebase is using whatever the writer decided was good enough, lol

quaint pagoda
#

mm fair most of the time I find p and br to be equivalent and stick to p for larger separation but that's new info to me

hoary umbra
#

i.e. this one

#

the first three are <br> but the space between time. and Example is <p>

quaint pagoda
#

difference of opinions then

#

I think adding a line break after every sentence is unnecessary

hoary umbra
#

the first three sentences are disjoint but the not disjoint enough that they warrant a new paragraph

#

it is unnecessary if the sentences form a coherent thought

keen thicket
#

let's poke @lofty citrus for a qualified opinion

quaint pagoda
#

yes that sounds good

#

he can do a formal writeup which we can all vote upon if he wants :p

keen thicket
#

or we can just trust him and shipit because a vote over br/p is stupid

#

smh

hoary umbra
#

In absolute terms I use
<br> for disjoint sentences that are part of the same thought
<p> for disjoint thoughts

quaint pagoda
#

if we "just trust" people then nothing is actually decided upon democratically smh

hoary umbra
#

just trust me bro™️
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

keen thicket
#

you mean <bro>

hoary umbra
#

we're good with this DR modid -> namespace change right? The ctor is private so nobody could be extending the class

#

mfw find-replace

#

Also, anyone else have any thoughts on providing a "super-DR" which is preloaded with helpers for the vanilla registries?
that way you don't need to make multiple DR objects, just one

winged iris
hoary umbra
#

yeah not for now

#

but it is a little bit cleaner (imo) to have one object that you call .item(() -> x) .block(() -> x) etc on instead of one per registry

ripe storm
#

Throwing my own opinion in on the whole br/p tag thing: I think it's rare to see individual sentences that are disjoint enough to warrant new lines but not a new paragraph, but br still has uses as a formatting mark when a visual break is necessary

ripe storm
#

As someone who works on a low resolution screen, single line paragraphs are hell and should be avoided like the plague

#

Because they turn into one-and-an-eigth line paragraphs instead

#

So if the sentences aren't disjoint enough for a paragraph break, I'd string em together

#

That way you don't get lots of little short fragments that don't wrap right as you're trying to read on a small screen (or heck, read javadocs on mobile!)

hoary umbra
#

I don't think that box gets any smaller (I'm pretty sure it's fixed-width by default)

ripe storm
#

Keep in mind that people read javadocs in lots of different ways

#

They're just HTML when it comes down to it

#

If it would be a bad idea on a webpage, it's probably a bad idea in javadocs (to a reasonable degree, of course)

#

(at least in IntelliJ it scales to your screen width to a degree, if your screen is small. Or maybe that's a setting I turned on. So it's definitely not "fixed width" and should not be treated as such)

hoary umbra
#

eclipses is fixed width for sure, bc its this little tiny box no matter how I resize the window

ripe storm
#

Yeah, but eclipse is not what everyone uses

hoary umbra
#

I mean yeah, but neither is IDEA, so what's the point of this convo lol
as long as the doc is readable this is just nitpicking

ripe storm
#

Such as IntelliJ, or on the web

quaint pagoda
ripe storm
#

Or, heck, for anyone who doesn't have a screen wide enough to show that whole line at once

hoary umbra
#

No i mean for bincompat with the rename

#

if the class was (currently) extensible I couldn't rename the field

hoary umbra
#

alright, things updated again

#

someone should fix the compat check to auto-rebase before checking screm

quaint pagoda
#

meh

#

It should automatically work

#

it tries to find the fork point to bin compat check with

lofty citrus
#

re: javadoc
<br>/hard line breaks should be avoided when possible. <p> for paragraph separation (none of this <br><br> nonsense). don't be afraid to have paragraphs with multiple sentences; they're normal. the first paragraph of a javadoc is special anyway, because (a) it's the first thing the reader readers in logical order, and (b) the first sentence of the first paragraph is taken as its summary (except when overriden by {@summary}, but that rarely if ever happens)

high raptor
#

out of curiosity is there any reason javadoc can't use something like markdown, outside of the {@things}?

quaint pagoda
#

cuz this isn't kotlin?

deep lance
#

because javadoc was invented in 1996

high raptor
#

I mean, it's just the tool displaying it that needs to support it, right?

quaint pagoda
#

yes and that includes all IDEs

#

it's not really feasible for us to go to markdown at all

hoary umbra
#

all two ide's, lol

#

but idk how complicated ide plugins are to write

quaint pagoda
#

I'm just gonna say now we are not gonna write custom IDE plugins that we have to maintain just to use markdown...

#

and that would install all users wanting to read our jdocs to use those plugins

hoary umbra
#

Yeah there's not been any more noise on the jdk issue for now

heavy zephyr
#

markdown isn't particularly nice for things like @link

#

I largely prefer javadoc to whatever python does... you can't really @param with markdown

warped forge
#

thinkies someoen should create a "markdoc" that's like markdown but with additional syntax for tagging params, return types and such

#

I mean as a tool you can run on a source folder and it outputs documentation

#
/*#
@Summary
  Wheee `code`

@Param arg1
  The first argument. See @[](dev.wheee.TheClass) for details.

@Return
  Returns `nothing`.
#*/
``` ![hyperthonk](https://cdn.discordapp.com/emojis/572303917275152395.webp?size=128 "hyperthonk")
quaint pagoda
#

@hoary umbra this was caused by u from upstream merges I think

---
Index: src/main/resources/forge.exc
===================================================================
diff --git a/src/main/resources/forge.exc b/src/main/resources/forge.exc
--- a/src/main/resources/forge.exc    (revision d80f945e2b9ebfc07908e7cf573000e514ad795c)
+++ b/src/main/resources/forge.exc    (revision 1f323abe4a129bba3640345b9a7690b727834584)
@@ -87,6 +87,8 @@
 net/minecraft/server/network/ServerStatusPacketListenerImpl.<init>(Lnet/minecraft/network/protocol/status/ServerStatus;Lnet/minecraft/network/Connection;Ljava/lang/String;)V=|p_272864_,p_273586_,statusCache
 net/minecraft/server/packs/metadata/pack/PackMetadataSection.<init>(Lnet/minecraft/network/chat/Component;ILjava/util/Map;)V=|p_10371_,p_10372_,packTypeVersions
 net/minecraft/server/packs/repository/Pack$Info.<init>(Lnet/minecraft/network/chat/Component;IILnet/minecraft/world/flag/FeatureFlagSet;Z)V=|f_244592_,dataFormat,resourceFormat,f_244041_,hidden
+net/minecraft/tags/TagFile.<init>(Ljava/util/List;ZLjava/util/List;)V=|f_215959_,f_215960_,remove
+net/minecraft/tags/TagLoader$EntryWithSource.<init>(Lnet/minecraft/tags/TagEntry;Ljava/lang/String;Z)V=|f_216042_,f_216043_,remove
 net/minecraft/world/entity/Entity.changeDimension(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraftforge/common/util/ITeleporter;)Lnet/minecraft/world/entity/Entity;=|p_20118_,teleporter
 net/minecraft/world/entity/Entity.playCombinationStepSounds(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)V=|p_277472_,p_277630_,primaryPos,secondaryPos
 net/minecraft/world/entity/Entity.playMuffledStepSound(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)V=|p_283110_,pos
#

it causes patch artifacts which I found while working on the overhaul

hoary umbra
#

scrim

quaint pagoda
#

hopefully this will be solved by the new PR check going forward? But I thought that would have already caught this

#

when did this get merged...

hoary umbra
#

had to be part of the huge upstream pr, right?

quaint pagoda
#

yes

#

anyways a status update about the overhaul (at least, my draft of it):
I got everything compiling but haven't run the game yet

#

currently all forge registries are now just Registry<xxx>

#

and Registry now extends INewForgeRegistry with extra methods that either vanilla is missing cuz bad api or like, aliases

hoary umbra
#

smh, INewForgeRegistry and not INeoForgeRegistry

quaint pagoda
#

hmmm honestly good point

hoary umbra
#

I thought we pinned XExtension earlier

quaint pagoda
#

I was probably gonna move it to just IForgeRegistry after I delete the original

hoary umbra
#

so it should just be IRegistryExtension™️

quaint pagoda
#

that can be discussed later stabolb

#

I still have to actually make syncing and serializing work

#

and also reverting to frozen when you leave a world

#

the system is a fucking mess if you couldn't tell

hoary umbra
#

hm

#

you know, thinking about it

#

why does it need to revert to frozen

#

it has to reconfigure when you load up a world

#

and it always does that, so... tonk

quaint pagoda
#

shrug it can be removed later

#

get a working product that does what the old system does is my current priority then api design and review can be done

#

not to mention if your deferredholder shit is merged soon then I have an entire other thing to worry about rebasing on top of...

#

god you did a lot of changes to that pr

#

did not notice

hoary umbra
#

I did not

#

its just rebase spaghetti

quaint pagoda
#

ah

hoary umbra
#

only the last two commits on the bottom are "new"

quaint pagoda
#

oop

quaint pagoda
#

I edited message

hoary umbra
#

Unless we feel like debating javadoc semantics anymore we're probably good :p

lofty citrus
#

you rang?

hoary umbra
quaint pagoda
#

The namespace will be the one passed to the constructor.

#

imo this is still too generic and should specify the namespace is the one used when the DR was constructed

hoary umbra
#

screm

quaint pagoda
# lofty citrus you rang?

the autoformat line adjust all params to start at the same column is a bit annoying but that's probably a eclipseism

hoary umbra
#

what does constructor indicate, the other constructor?

quaint pagoda
#

in my eyes this could easily be confusing as you are registering a supplier to a constructor, i.e. factory

hoary umbra
#

I'm pretty sure anyone with half a braincell does not need that javadoc at all, lol

quaint pagoda
#

using {@linkplain #namespace the provided namespace}.
honestly this makes a lot more sense to use

hoary umbra
#

autoformatter probably did that

quaint pagoda
#

yeah turn it off screm

hoary umbra
#

see, I have a better profile I can use

#

but it has same-line braces stabolb

quaint pagoda
#

there should be a public getter

#

therefore the jdoc is always relevant

#

I am quoting from jdoc for createTagKey

#

and that format should likely be copied to #register

#

linking to the exact namespace used

hoary umbra
#

* @param path The path of the new entry. The namespace will be {@linkplain #namespace the provided namespace}.

#

that work?

#

I hate having "namespace" twice in the sentence, idk brain no like™️

quaint pagoda
#

up to you if you want to make it a getter so you can query the namespace the defreg was made with without having to subclass it

hoary umbra
#

also I just renamed name to path™️

#

Would that ever be useful thonk

quaint pagoda
#

I don't know how useful being able to query the namespace is soo

hoary umbra
#

Probably not very, tbh

#

I still want to contribute a "super defreg" which is one to many instead of one to one (in terms of defreg to registry)

quaint pagoda
#

meh

#

at that point just use registerevent

#

that would be a lot of duplication of the same registry key over and over if its once per field

hoary umbra
#

nah builtin helpers for the vanilla classes

quaint pagoda
#

eww

hoary umbra
#

I actually already wrote it™️

#

also its cursed because RO is... well RO is RO

quaint pagoda
#

I do not like the idea of hardcoding a bunch of vanilla classes

hoary umbra
#

well it has all of the vanilla helpers + public <P, T extends P> RegistryObject<T> custom(String path, ResourceKey<Registry<P>> registry, Supplier<T> factory)

quaint pagoda
#

that's just more maintenance

#

it means we have to add or remove every time vanilla does

hoary umbra
#

its not like vanilla is going to remove their registries, lol

quaint pagoda
#

I still don't like the maintenance burden and it's just method spaghet/explosion for not much reason

#

it would basically make defreg or whatever custom class less resilient across mc versions

#

defreg is so generic that it mostly is consistent

#

now we would have to consider renaming things as vanilla renames them and things not working as well across mc version boundaries

hoary umbra
#

eh it should be fine with DH being a thing now

#

this is only terrible rn due to how I have to reflect into RO

quaint pagoda
#

why do u have to

hoary umbra
#

package private spaghetti 🙃

#

there's no other way to bind an RO and I didn't want to reimplement it

quaint pagoda
#

are you making update reference public or something?

hoary umbra
#

I guess the alternative is I make this class delegate to a fuckton of DR's

#

but that's also bleh

quaint pagoda
#

btw ping me with the new commit in your pr when it is done and otherwise it's up to pup / any other team mebers

hoary umbra
#

maps on maps on maps

#

is it just the one change in register()?

quaint pagoda
hoary umbra
#

DH binds on call

#

I don't need to bind it™️

quaint pagoda
#

ah yes

hoary umbra
#

(DH is also non-final so I can just do that too)

quaint pagoda
#

hopefully that doesn't become a problem

#

cuz bind eager vs bind on call is semantically different

hoary umbra
#

its still binds eager for ones from DR

quaint pagoda
#

it also means cycles checking for bind on every access

#

but should be minor™️

quaint pagoda
hoary umbra
quaint pagoda
#

I would say you could try to limit the random whitespace changes but I don't personally care that much given I've also done the same before

lofty citrus
#

is the namespace exposed as a getter?

hoary umbra
#

I mean once bound its just a != null

quaint pagoda
#

no it's a protected field

lofty citrus
#

hmmmm

quaint pagoda
#

101 dalmations files changed

keen thicket
hoary umbra
#

thats what I said stabolb

quaint pagoda
#

it depends on if I preserved the dummying system or not

#

blocks used to get dummied into air

#

that means you would have extra entries depending on what world you are in

#

and if you dont revert to frozen or clear then they would never go away

hoary umbra
#

that thing is worthless, lol

quaint pagoda
#

I think it is gone in my thing tho

#

right now only the aliases would pollute the registries if I didn't revert to frozen

hoary umbra
#

aliases don't get ids

quaint pagoda
#

that's not what I said

#

they're polluting the registry

#

in my eyes it is the safest bet to have it be like normal when not in a world

hoary umbra
#

its a huge overhead though

quaint pagoda
#

with how I've designed it not really

#

in the old system sure

#

as reverting to frozen and loading from disk were separate

#

I'm trying to unify those codepaths

#

and it's I think maybe 2-3 patches to do?

#

it's actually 2 method calls and neither change patches cuz they are in forge classes and there's a layer of indirection

#

esp. cuz I have brain fog cuz I like let this sit for a while

hoary umbra
#

last doc change pushed

keen thicket
#

time for shrimp's never-ending nitpicks

lofty citrus
#

nitty-picky

#

nitty-gritty

keen thicket
#

nit-stabby

deep lance
#

if we're doing DeferredHolder<MyBlock>, how does that affect e.g. Holder#is(TagKey<T>)?

quaint pagoda
#

@hoary umbra update: trying to run the registry overhaul has led me to find multiple infinite stackoverflow loops

#

hooray

past saffron
quaint pagoda
#

no no

#

the generics is teh problem

#

that is a good point

#

that's a problem

keen thicket
#

screm

deep lance
#

Holder<? super T> cast()?

#

that wouldn't solve it but it might help

keen thicket
#

at that point why implement Holder

#

if for most operations you'll want to cast to the base

hoary umbra
#

the generics are always the problem screm

deep lance
#

we could do DeferredHolder<Block, MyBlock> and solve a lot of generic problems (this is an option i suggested before, but worth bringing up again with the method parameter issues), at the cost of longer declarations

hoary umbra
#

that gets tricky while trying to maintain signature compat with RO

deep lance
#

I'm pretty sure we can override get [and value] to return the more specific type

hoary umbra
#

because RO has to then be DH<T, T>

past saffron
#

This generics issue is nothing new, RO#getHolder() already blows up with exactly the same problem

deep lance
#

not new perhaps but more visible

ripe storm
deep lance
#

wait no

#

i don't know if you did, but you could do a sneaky cast for RO

hoary umbra
#

RO cannot have two generic types in the declaration

#

bc its breaking

quaint pagoda
#

generics are all fake anyways

#

you should just actually test it

#

but also I think double the generics is a horrible solution

ripe storm
deep lance
#

it's for damn sure be source breaking, unclear if it'd be binary breaking

ripe storm
#

Hmm. What else do you do besides double generics?

deep lance
#

but anywy

#

we can do one thing now and another thing in the next phase when RO is gone gone

ripe storm
hoary umbra
#

yeah that's an issue™️

#

stupid ass generics

keen thicket
#

horrible idea

hoary umbra
#

hm

#

cursed thought

#

can the override be a rawtype?

keen thicket
#

is(TagKey key)

hoary umbra
#

ah yes, that works

ripe storm
#

Oh god. Type safety would be nice

hoary umbra
#

good plan™️

#

type safety on what, its a tag key, lol

#

like resource key, the generic is entirely made up™️

past saffron
hoary umbra
#

yeah I figured

ripe storm
#

Hmm. I think long term double generics may be the only way to fix this

hoary umbra
#

if we want to avoid rawtypes, yeah

past saffron
#

Meanwhile I'm just typing my ROs to the basic type (i.e. Block)

hoary umbra
#

However, for double types

#

inference will not work right

#

i.e.

deep lance
ripe storm
#

That just tossed the ball. The type safety there is made up but still useful to avoid passing your thing intended as an item tag to a block

hoary umbra
#

BLOCKS.register("test_block", () -> new AirBlock(BlockBehaviour.Properties.of().mapColor(MapColor.STONE)));

#

this would infer AirBlock twice

deep lance
#

like, it won't crash, it'll just silently accept the argument and not work

keen thicket
#

you can yeet type safety but have runtime safety

#

tag keys contain the associated registry ID

deep lance
#

yes that's safe

#

but it doesn't stop you from passing in the wrong thing

#

safely

#

this is the string capability ids argument all over again

hoary umbra
#

its just mojang fault for not making it ? super T

ripe storm
deep lance
#

i don't blame them, generic wildcards are hell

ripe storm
#

Then you'll infer AirBlock and Block

deep lance
#

yeah, <U extends T> DeferredHolder<T, U> register(string, supplier<U>)

hoary umbra
#

@quaint pagoda what think, dual generic or rawtype overloads

keen thicket
#

we can go the BDFL route, no overlords

ripe storm
#

Given that the type info has to be somewhere you'll have to use one of the two

hoary umbra
#

though rawtype overloads are never going to work right with public Stream<TagKey<T>> tags()

deep lance
#

the rawtypes are so cursed, we might as well just have register return a Supplier that secretly implements Holder

ripe storm
#

Keep in mind that if you choose raw type overloads, you'll be unable to pass it to anywhere where vanilla expects a normal Holder<Block> unless you have a cast method or something

quaint pagoda
#

it's generic hell, we should be able to just fix vanilla's methods manually

keen thicket
#

pls no

ripe storm
keen thicket
#

no more messing with vanilla signatures

quaint pagoda
#

how would it screw multiloader

ripe storm
deep lance
#

no

#

oh wait

ripe storm
deep lance
#

ok it is a problem, but it's just a problem the raw overloads don't solve, not one that they cause.

#

that's where i was confused

quaint pagoda
#

you're not making sense to me

#

I'm just suggesting we use ? super T in place of T

hoary umbra
#

changing Holder to <? super T does not change the signature

#

its still Object

deep lance
#

use ? super T where?

quaint pagoda
#

in the .is() methods

deep lance
#

you cannot

quaint pagoda
#

??

ripe storm
#

Shrimp means in a patch on vanilla

deep lance
#

oh, not just in the DH override?

hoary umbra
#

Nonetheless public Stream<TagKey<T>> tags() is still a problem

quaint pagoda
#

not really

ripe storm
#

Which... Please can we not change signatures of vanilla methods? It always causes pain

hoary umbra
#

that one cannot be ? super T

quaint pagoda
#

tagkey<myblock> wouldn't be a mega problem

ripe storm
#

Yes it would

hoary umbra
#

yeah it would be, lol

#

its unusable

ripe storm
#

Cause you couldn't compare it to anything

hoary umbra
#

you cannot ask a Holder<Block> if it is(TagKey<MyBlock>)

gloomy sinew
#

what if we just... waited until the next breaking period to add DeferredHolder, and toss out RegistryObject when we did

keen thicket
quaint pagoda
#

you can if you patch it to use ? super T

deep lance
hoary umbra
#

MyBlock is not ? super Block, lol

ripe storm
deep lance
#

we could just tell them no

ripe storm
#

My personal preference is double generics

deep lance
#

DeferredHolder<Block> is what you get

hoary umbra
#

yeah honestly RO's signature is a non-issue, that thing is spaghetti™️

gloomy sinew
#

doubel generics should be fine

deep lance
#

cast it yourself if you want

ripe storm
#

It's easy, it's typesafe, and it works

quaint pagoda
#

it's so much more verbose for so little gain

deep lance
#

I mean, is it?

gloomy sinew
#

it's either that or make DeferredHolder not implement Holder :p

deep lance
#

Item is four letters

ripe storm
deep lance
#

Block is five

#

Entity is six

quaint pagoda
#

just add a unsafe cast method that lets people get whatever type of holder they want unsafely

ripe storm
hoary umbra
#

it is either that or not implement holder, unfortunately
I mean I can just strip the direct holder impl and add .holder() which generic downcasts to whatever

#

no good solutions, java generic just bad™️

keen thicket
#

probably a better idea imo. but it also wouldn't really fix .is(TagKey)

quaint pagoda
#

the java generics aren't bad mojang just didn't design their system right

ripe storm
hoary umbra
#

well then DH gets a native is<TagKey<? super T>> and holder() for other things

keen thicket
#

you'd do MY_THING.<Block>holder().is(BlockTags.STONE)

#

which is ugly

#

and not intuitive

quaint pagoda
#

a cursed suggestion would be adding isForge methods thru an interface extension and isForge(TagKey<?>) etc.

ripe storm
ripe storm
winged iris
#

Question if you add an intermediary class that then rawtypes the generics on the stream and the is tagkey does Java let you then make deferredholder extend that and use whatever generics you please?

ripe storm
#

So you'd be fine

keen thicket
#

it wouldn't, inferrence is serial

deep lance
#

so still super

hoary umbra
#

its also very annoying that public <R super T> Holder<R> holder() { is illegal, because it does mean that you have to downcast

#

maybe we just make .get() downcast, idk

ripe storm
hoary umbra
#

but then supplier's signature isn't correct

#

The only thing that makes everything work™️ is dual generic

ripe storm
#

Personally, dual generics aren't a huge issue. It's, like, one find and replace or whatever to add them

#

I'd say go for it, since it is the least intrusive solution that still has all the various features we'd like

deep lance
hoary umbra
#

what happens if I implement rawtype Holder thinkies

ripe storm
#

If you've made your tag keys also raw types you're not doing well

quaint pagoda
#

then tags() becomes Stream

#

and you dont even get a tagkey

ripe storm
#

Okay, so, besides the slight extra verbosity, what are the actual issues with double generics?

hoary umbra
#

what thonk
it would be stream<TagKey>

winged iris
#

Alternatively can we just add extra methods with slightly different names in DH that act as bouncers for the proper type? And if someone is using a DH they use those as needed but if they pass their DH as a holder still (maybe?)

quaint pagoda
#

no it wouldnt

winged iris
#

No shadows

quaint pagoda
#

if you rawtype a class all generics is stripped

#

all

winged iris
#

When you kill class level rawtypes it nukes everything

ripe storm
quaint pagoda
hoary umbra
#

why tf does it do that

ripe storm
hoary umbra
#

screm to generics

quaint pagoda
keen thicket
ripe storm
#

But seriously:

Okay, so, besides the slight extra verbosity, what are the actual issues with double generics?

hoary umbra
#

There are none its just the verbosity, its probably the right call

winged iris
#

Idk I am fine with double generics, some of my registry object wrappers have between two and five generics

ripe storm
#

I really wish Java let you have var fields with initializers right about now

hoary umbra
#

if only we had c++ template magic

#

it could just work™️

quaint pagoda
#

I think they mean IntermediaryClass<T> extends Holder with no T

gloomy sinew
#

what if you had DeferredHolder deprecate is and add an isTag

hoary umbra
#

just fyi this also fixes the issue with ResourceKey

#

(this being dual types)

deep lance
quaint pagoda
winged iris
deep lance
#

well, DH would put back whatever generics we want

#

alas, no

#

you cannot override a raw method with a method with a proper generic param, period, regardless of what happened higher up

ripe storm
past saffron
#

Turning the question the other way round, what's the problem with making people type their DHs to the registry base type (i.e. Block, Item, etc.)?

gloomy sinew
#

carpal tunnel

hoary umbra
#

I frequently have methods on my classes that I don't want to call via ((MyClass) DH.get()).blah()

gloomy sinew
#

oh you mean like

ripe storm
deep lance
#

hmm

winged iris
#

Technically we could add a getTyped but that would be an unchecked cast

quaint pagoda
deep lance
#

what if we made it opt-in

hoary umbra
#

its already an unchecked cast

gloomy sinew
#

DeferredHolder<Block> block = register("block", () -> new ReallySpecificBlockClass())

hoary umbra
#

no sugarcoating it, its always an unchecked cast, even now

gloomy sinew
#

that's no good because you need the actual type of the block a lot

past saffron
#

Yes

ripe storm
#

Could just have a <B extends T> B getAndCast() method

deep lance
#

DeferredHolder has a single type argument, but it implements an interface with two type arguments

keen thicket
#

<Z extends T> Z getUnchecked() { return (Z) get(); }

deep lance
#

and has a method that casts to this interface

winged iris
#

Tbh double generic is likely the way to go (even though then the supplier bit might not be the generic type the person wants but kaishrug )

ripe storm
hoary umbra
#

getUnchecked is going to have inference problems

ripe storm
#

Unless we do double generic

hoary umbra
#

I can't just call getUnchecked().myMethod()

ripe storm
#

Eh, store it on a local variable

gloomy sinew
#

double generic is fine, you'll only ever have to type the whole type in your static init fields

ripe storm
#

Or just do double generics

hoary umbra
#

dual generic is the best option here

#

its trivial to implement as well

ripe storm
#

Definitely

deep lance
#

also honestly

past saffron
deep lance
#

Item, <- 6 chars

quaint pagoda
#

imo if you go dual generics route then you should not deprecate registryobject for removal and just remove the holder stuff from it

hoary umbra
#

screms return (T) this.holder.get(); (it did this anyway, but now I have to look at it)

deep lance
#

and if your supplier returns the wrong type you can cast there to avoid having to write type params on register

quaint pagoda
#

people who want deferredholder -> DeferredRegister#registerHolder, have to hold 2 generics
people who dont need holder -> DeferredRegister#register, just like normal, everything is the same

ripe storm
past saffron
hoary umbra
#

RO has to extend DH, there is no "remove the holder stuff from it"

hoary umbra
#

bincompat™️

ripe storm
#

I say we just merge this with breaking changes and drop RO entirely

gloomy sinew
#

why do registryobjects and deferredholders both need to exist at the same time

quaint pagoda
#

^^^^

hoary umbra
#

bincompat™️

quaint pagoda
#

they dont need to

#

is the answer

gloomy sinew
#

we can wait for a breaking change and add deferredholders and remove robs

deep lance
#

ok but why do we need bincompat

ripe storm
#

Like, if this waits till the breaking change window we can just drop RO

deep lance
#

why do we need phase 1

quaint pagoda
#

oh commoble had a different ide afrom me

#

my idea is that they can be separate solutions for different people and coexist

hoary umbra
#

because DR can't make both of them at once

deep lance
#

it's a fun party trick but sweeping changes like this are what breaking windows are meant for

gloomy sinew
#

and then I had a mental image of sweeping all the robjects out the door

winged iris
#

DR2 xdab

#

Pls no

hoary umbra
#

DeferredRegistwo

deep lance
#

if deferred registers are so great why isn't there deferred register 2

ripe storm
keen thicket
#

RO is the dumber older sibling of DH, we should just remove RO. if you want one generic, use a supplier

ripe storm
#

Hey, that's an idea

deep lance
#

if you don't need DH and don't like the double generics

ripe storm
#

Why not add a method to DH to get a supplier

deep lance
#

you can declare your statics as Supplier

gloomy sinew
#

why not make DH implement Supplier

deep lance
#

DH DOES IMPLEMENT SUPPLIER

hoary umbra
#

Holder implements Supplier

#

thus DH does

ripe storm
#

Oh so there's no issue

#

Wait nevermind that's worse

keen thicket
#

not if you make DH extends the base class in Holder

#

also the holder-implements-supplier is patched by forge

deep lance
#

can we make it implement Supplier<MyBlock>?

hoary umbra
#

public class DeferredHolder<R, T extends R> implements Holder<R>, Supplier<T>

deep lance
#

like, the method override is allowed but is the implements decl allowed

ripe storm
#

That way if you want to type less, your field is just a supplier

winged iris
#

Given holder is an interface would any of this be easier if we made DH extend RO implements Holder instead of RO extends DH

hoary umbra
#

no

winged iris
#

Okay

ripe storm
hoary umbra
#

it means i have to keep all the logic in RO or make RO an interface (can't do that bc of the factories)

#

basically makes it way more work for later to keep RO as the base class

deep lance
#

goddamnit it can't

hoary umbra
#

with the deprecation we have everything ready to go do just press delete when bc arrives

ripe storm
#

But yeah, I think making DH implement Supplier<MyBlock>` is a good solution, and maybe removing the forge patch that shoves Supplier on holders to allow that? Not entirely sure

hoary umbra
#

don't need to remove the patch

deep lance
#

wait

hoary umbra
#

you can implement supplier again with a stronger type

ripe storm
deep lance
#

it can, it just can't inherit the default impl of get

gloomy sinew
deep lance
#

wait no

#

the error went away and came back

ripe storm
deep lance
hoary umbra
#

maybe it can't, hm

#

let me see™️

gloomy sinew
#

still doesn't work

ripe storm
quaint pagoda
#

you can override get() with the resolved type cuz covariant but you wouldn't be able to automatically keep it around as a Supplier<R>

gloomy sinew
#

yeah if we remove the supplier patch from holder we could add it to deferredholder

deep lance
#

goddammit you could do this in C#

quaint pagoda
ripe storm
#

We could also just have a getSupplier() method on DH that gets a supplier of the stricter type

past saffron
gloomy sinew
#
public interface Holder<T> extends java.util.function.Supplier<T>, net.minecraftforge.registries.tags.IReverseTag<T> {
keen thicket
#

if you want a Supplier from a Holder just ::value

deep lance
#

what would be the patch surface of porting minecraft to C#

gloomy sinew
ripe storm
#

Like, why don't we give DH a method to get a specific supplier, and have it extend holder which is the generic supplier?

keen thicket
#

it'd be bedrock but more MS

hoary umbra
ripe storm
#

Which is easy

#

So yeah, this works great

#

People who want to type less get a supplier, otherwise you just specify both

gloomy sinew
#

thinkies oh, yeah, that does work

keen thicket
#

yeah but it wouldn't be a Supplier<T>

#

so you still need to ::get

gloomy sinew
#

oh right

ripe storm
#

Yeah, but that's easy

hoary umbra
#

yeah but that's fine imo

#

who really needs a strongly-typed supplier

gloomy sinew
#

okay, let's just take the supplier patch off holder and put it on deferredholder

hoary umbra
#

for their thingy

gloomy sinew
#

is anyone actually using holders as suppliers

ripe storm
quaint pagoda
ripe storm
#

Cause if get returns MyBlock, ::get will get you a Supplier<MyBlock> even if the DH is a Supplier<Block>

hoary umbra
#

clearly we should just patch those all to Holder stabolb

#

(this is a bad idea)™️

deep lance
#

is it though

hoary umbra
#

yeah, if you need to pass vanilla

ripe storm
#

I mean, they're forge added suppliers

hoary umbra
#

vanilla doesn't keep holder fields

deep lance
#

vanilla has holders

#

builtinIntrusiveHolder

ripe storm
keen thicket
#

just wrapAsHolder()

hoary umbra
#

well yes but I can () -> STONE pretty easily

ripe storm
#

Ah, fair enough

hoary umbra
#

also most things with supplier have a T constructor and a Supplier<T>

#

because the supplier one is for deferred /modded st uff

#

now this, this is an issue

ripe storm
#

Personally, I am in favor of keeping holders as suppliers, and making get on DH return MyBlock so that the DH will be a Supplier<Block> but that using ::get on it will provide a Supplier<MyBlock>

ripe storm
keen thicket
ripe storm
#

Or that, keep bin compat and break source compat

#

Generics don't exist at runtime anyways really

hoary umbra
#

I have a potential solution, one second™️

#

cursed™️

deep lance
#

really we get two short ways to declare statics, as a bonus

DeferredHolder<Block, MyBlock> = register()
Holder<Block> = register()
Supplier<MyBlock> = register()::get```
#

ItemLike x = register()::get

hoary umbra
#

actually it has to be even more cursed and I have to shadow R to let it infer RO<T>

#

screm

#

public <R, T extends R, D extends DeferredHolder<R, T>> D register(String path, Supplier<T> sup)

#

however

#

even this huge pile of generic garbage has an issue

#

if someone is, for whatever reason, manually typing register, it does not have source compat

#

granted idk why it does that

#

it just works if removed

gloomy sinew
#

or I might be thinking of Builder.<>of

past saffron
#

The builder has to be typed in a lot of cases, not the RO

hoary umbra
#

yeah that's the builder

#

I can't think of an instance where the RO has to be typed since the inference is very loose

gloomy sinew
hoary umbra
#

but it's still technically source breaking

gloomy sinew
#

eclipse org says it breaks bincompat

#

err wait

hoary umbra
#

I think due to erasure this is bin breaking as well

gloomy sinew
#

yeah register does already have a type param

hoary umbra
#

since the signature becomes (...)DeferredHolder instead of (...)RegistryObject

#

could just hold off on the dual generic

gloomy sinew
#

could just hold off on adding deferredholders until we yeet robjects :p

hoary umbra
keen thicket
#

screm shadows that MH is slower than reflection...

hoary umbra
#

ultimately a gradual transition will be smoother even if it involves a little refactoring here and there™️

#

for now people get to swap to DH, and then later they can implement the second generic on the DH

ripe storm
hoary umbra
#

the generic hack is bin breaking anyway so its irrelevant

ripe storm
#

Ah, yeah

hoary umbra
#

personally I think that source compat example in particular is silly (nobody should be doing that)

#

but yeah, D is breaking since it erases to DH not RO

#

I hate that I can't do this as a temp workaround

#

public <X super T> Holder<X> weakHolder()

#

I can just do <X> but typesafety peepoHands

keen thicket
#

public <X super T> Holder<X> weakHolder(Class<X>) just to make it nicer for chaining

winged iris
#

X super T is illegal Maty, that’s the problem

keen thicket
#

shhh

#

just rewrite java

hoary umbra
#

honestly idk why its illegal

keen thicket
#

I was fixing his idea stabolb

hoary umbra
#

bit of a weird restriction

winged iris
#

Makes it hard to know how to handle something like
T, V super T, Z extends V

#

Would be my guess