NeoForge icon indicating copy to clipboard operation
NeoForge copied to clipboard

Server-side Resource Pack API

Open ChiefArug opened this issue 11 months ago • 6 comments

NOTE: If you are looking into adding a server side resource pack into your mod, this is already possible, see this gist made as a result of the following discussions. https://gist.github.com/AEAEAEAE4343/575ad5aeb4cd7d9bd69148185cd8738e

Minecraft supports sending resource packs to the client on join, allowing servers to get clients to load a resource pack for their custom content. This issue was going to be a long and lengthy dissecting of the problem of NeoForge collecting, merging and hosting server side resource packs, however after some code analysis and wiki reading most of this isn't required (multiple packs can be sent, and merging can be handled by the client provided mods aren't dumb).

What is still required is the hosting of packs. The packs are sent to the client in the form of URLs to download the pack from, and the client checks if the URL protocoi is http or https (so no base64 encoded packs sent through data://, sorry).

It would be great if NeoForge could provide an API to allow these packs to point back at the server who sent them, and the server provide the packs directly. This is going to be increasingly useful as vanilla moves to data-driven resources that need both a client and server component.

This would require a few things:

  • A minimal system to reply to http packets requesting a resource pack. This could be a tiny web server (ie latvian-dev/tiny-java-server), or just a minimal custom setup using the built in java api to only respond to this one type of packet. Java also has one built in: https://docs.oracle.com/en/java/javase/17/docs/api/jdk.httpserver/module-summary.html
  • Server hosts to open another port for these packets to go through. This is the only thing Neo cannot control, and unfortunately removes a bit of the 'it just works' magic.
  • A system to allow server owners to host the packs themselves, in case they want to reduce bandwith to the main server. This requires being able to export the packs and swap the URL Neo sends for each pack.
  • A system for mods to register packs (extension to AddPackFindersEvent?) to be hosted and sent to client.
  • Sending a URL for the server requires the server knowing it's own IP address so it can direct clients back to itself. This requires some external service to tell the server it's public IP address, such as https://www.ipify.org/. A sneaky catch here is also that the server can have up to 6 ip address depending on the client connecting (one for ipv4 and ipv6 for each of localhost, local network and public), however this is easily solved by having the respond in kind to the client's IP (ipv6 public ip —> iv6 public ip, ipv4 private use ip —> ipv4 private use ip).

ChiefArug avatar Apr 03 '25 23:04 ChiefArug

Long discussion and background about why this issue was made: https://discord.com/channels/313125603924639766/313125603924639766/1357480055785263195

leetftw avatar Apr 03 '25 23:04 leetftw

Another thing that would be neat: the ability for datapacks to specify such a resource pack.

ChiefArug avatar Apr 03 '25 23:04 ChiefArug

Some additional thoughts after more discussion on the discord:

  • It would be great for a mod to be able to specify a different url for packs to be sourced from and get access for those packs so they can be uploaded. The usecase for this is a pseudolan mod like E4MC which has a relay server and only requiring the packs to be uploaded to that server once (per session at least). Another usecase is a server hosting provider getting packs to be hosted seperately so that bandwith to the actual Minecraft server isn't impacted.
  • The API should just be able to accept a PackResources which it then zips and caches. This maximizes flexibility for mod authors as they are then able to easily provide a nested resourcepack zip, a subfolder of their jar or even dynamically generate resources.

ChiefArug avatar Apr 04 '25 01:04 ChiefArug

Summary for anyone confused:

You know how servers can tell a client to download a resourcepack from the server and if declined, kicks the user? What if multiple serversided only mods want to use this system to have vanilla users download the resourcepack from the mod to extend the mod's functionality on vanilla clients?

issue is vanilla by default, only sends 1 resourcepack from server to client. To get each mod that opts-in to push their resource pack to client, some workarounds are needed to be implemented by NeoForge to make the vanilla system work

If this gets added to neo in a polished form, it could lead to more serversided mods able to work together and be easier on users without server owner needing to manually merge resourcepacks into one or forcing clients to download resourcepacks manually from modding sites. It is also likely to be more trustworthy for NeoForge to implement the system rather than a library mod if ports and stuff needs to be used. Users would trust downloading from NeoForge than some side thirdparty mod doing this

TelepathicGrunt avatar Apr 04 '25 16:04 TelepathicGrunt

There has yet again been a lot more talk in Discord. It became reasonably clear from talking with various developers on the NF team: The proposal as is will not be added to NeoForge. However, an alternative solution has been provided.

By checking the first few bytes of a request on port 25565, it can be determined whether the request is for the game itself (starting with 0x0) or for HTTP (GET ). If the request is for the game itself, it can be sent to the normal pipeline. If it is an HTTP request, it can be intercepted and forwarded onto Netty’s builtin HTTP handlers.

This way we can have both the game and HTTP for resource packs on the same port. This also solves the problem of security concerns about the custom HTTP servers that were being written for a potential PR. Orion and shartte have said this is would be nice to implement, but it has no priority.

Idk how relevant this is for the issue itself, but it was my main reason for participating in creating the issue: For the NeoForge Mod Jam, I have been asked to write a document on how to get around the fact that we have no built-in solutions. This will be given to everyone that wants to include RP’s in their submissions.

TLDR: Original solution rejected, other solution somewhat acceptable but no promises or ETA

leetftw avatar Apr 04 '25 18:04 leetftw

In my opinion, the best option here would be for neo to expose an event that provides resource packs -- as streams or whatever other form -- that are to be shared with a client, and is given, by event listeners, URLs providing that pack -- which it can then send to clients as needed. Thus, a mod that does something like e4mc and has a proxy running somewhere -- which is a very sensible way to do this; a reverse proxy eliminates the whole issue of needing a port exposed or a known IP or the like -- would listen to that event and be responsible for actually providing the URL as needed. Neo is not responsible for running an HTTP server of any kind, nor for having to figure out a server's own IP or the like (something which is by and large not possible to do in a sensible way if you want to expose things, depending on how the network is set up!).

The idea of reusing the same port for HTTP and normal MC traffic is interesting -- would definitely take a bit of poking to see if that's going to work in a sensible fashion but it may be doable. The bigger issue is that in many cases, depending once again on how a network is set up, it may be quite impossible for an MC server to determine the proper IP to connect to it with -- there's no guarantee that this is the same IP that it would see were it to try to ping the internet itself and use some public IP lookup tool!

lukebemish avatar Apr 28 '25 18:04 lukebemish