Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make server icon modifiable by users #30

Closed
lubocode opened this issue Sep 21, 2020 · 10 comments
Closed

Make server icon modifiable by users #30

lubocode opened this issue Sep 21, 2020 · 10 comments
Assignees
Labels
enhancement New feature or request

Comments

@lubocode
Copy link
Contributor

Since one can usually set their own MC server icon by naming a 64x64 pixel png to "server-icon.png" and putting it in the main server folder, how about having the current static image as a kind of default image and trying to detect, once on script startup, whether there is a user image and then using that?

@gekigek99
Copy link
Member

Yep it is a good idea!
In a week or so I can start looking for a solution ;)

I already thought this as a possibility but the conversion from png to base 64 is not very straight forward because minecraft uses a different encoder I think.

@gekigek99
Copy link
Member

we have to try to send a raw image base64 encoded with:

base64.b64encode()

even thought the same image results in a different set of bytes if sent via original server or with b64encode() method (I think that the minecraft server sends an image with the transparent pixels compressed in some way, that are not removed when encoded through the b64encode() method)

still it's a nice experiment to see if the clients can just accept a different set of bytes and result in the same image...

@gekigek99 gekigek99 self-assigned this Oct 2, 2020
@gekigek99 gekigek99 changed the title Server Icon static Make server icon modifiable by users Oct 3, 2020
@gekigek99 gekigek99 added the enhancement New feature or request label Oct 3, 2020
@Br31zh
Copy link

Br31zh commented Oct 15, 2020

I think it’s related, so what about adding configuration for custom hibernation and startup messages? I modified the Python version for that until now but since it’s deprecated…

Sorry if it was already present or proposed.

@lubocode
Copy link
Contributor Author

I think it’s related, so what about adding configuration for custom hibernation and startup messages? I modified the Python version for that until now but since it’s deprecated…

Yes, we deprecated the Python Version simply because of too much overhead for maintenance.
We both use the Go version and as such, decided to deprecate the Python one.
However, this does not mean, that the Python version is now unusable. You can continue to use the last release and unless you run into bugs, we have not found yet, it should work fine.

As for the go version; we plan to add instructions on how to build it by yourself, but basically it is a simple matter of installing go and running the command go build minecraft-server-hibernation.go in the script folder to create yourself an executable file from the code. Modifying the code should also not be too complicated, since you successfully did so in the Python version.

@gekigek99
Copy link
Member

I'm working on adding this cool feature... but I'm having problems in finding the right encoding process to obtain the correct base64 encoded image.

Now i managed to reverse engineer the server.jar file and i found this function (the only one containing "server-icon.png" ;) )

private void a(un ) {
    File file = c("server-icon.png");
    if (!file.exists())
      file = this.d.f(); 
    if (file.isFile()) {
      ByteBuf byteBuf = Unpooled.buffer();
      try {
        BufferedImage bufferedImage = ImageIO.read(file);
        Validate.validState((bufferedImage.getWidth() == 64), "Must be 64 pixels wide", new Object[0]);
        Validate.validState((bufferedImage.getHeight() == 64), "Must be 64 pixels high", new Object[0]);
        ImageIO.write(bufferedImage, "PNG", (OutputStream)new ByteBufOutputStream(byteBuf));
        ByteBuffer byteBuffer = Base64.getEncoder().encode(byteBuf.nioBuffer());
        .a("data:image/png;base64," + StandardCharsets.UTF_8.decode(byteBuffer));
      } catch (Exception exception) {
        j.error("Couldn't load server icon", exception);
      } finally {
        byteBuf.release();
      } 
    } 
  }

I'm not much of an expert in java but i think this might be the key to solve the puzzle... if someone is able to explain/translate to golang what is happening it would be really appreciated...

@lubocode
Copy link
Contributor Author

lubocode commented Oct 24, 2020

While I don't have much experience with java, I do think that the actual conversion is happening in these lines:

ByteBuf byteBuf = Unpooled.buffer();
BufferedImage bufferedImage = ImageIO.read(file);
...
ImageIO.write(bufferedImage, "PNG", (OutputStream)new ByteBufOutputStream(byteBuf));
ByteBuffer byteBuffer = Base64.getEncoder().encode(byteBuf.nioBuffer());
.a("data:image/png;base64," + StandardCharsets.UTF_8.decode(byteBuffer));

The de-compilation of the server.jar might have caused some weirdness, especially with the last line.

From what I can see though, first the image file is loaded, then written to a new output stream with the ImageIO.write function, after which the output stream gets encoded into base64, before finally a string is created for transmission with a UTF8 decoder.

Of course, the specifics of each en-/decoding have to be looked up individually.

@gekigek99
Copy link
Member

Ok I sort of understood it in this way...

Right now I wanted to do an example script in Java, to study and understand it better.

@gekigek99
Copy link
Member

This is the working java script to get the image base64 encoded:

package net.codejava;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.io.OutputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.buffer.ByteBuf;

public class base64_encode {

	public static void main(String[] args) {
			File file = new File("C:\\path\\to\\server-icon.png");
		    
		    ByteBuf byteBuf = Unpooled.buffer();
		    BufferedImage bufferedImage = null;
			try {
				bufferedImage = ImageIO.read(file);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    try {
				ImageIO.write(bufferedImage, "PNG", (OutputStream)new ByteBufOutputStream(byteBuf));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		    ByteBuffer byteBuffer = Base64.getEncoder().encode(byteBuf.nioBuffer());
		    String out = "data:image/png;base64," + StandardCharsets.UTF_8.decode(byteBuffer);
		    System.out.print(out);
	}

}

I just downloaded and imported netty-all-4.1.53.Final.jar from here

@gekigek99
Copy link
Member

ok... apparently the base 64 encoding is not the issue but the so called "constant" (== 11264) which is not really constant since it increases with by 128 every step, depending on the length of the info message.

I found the function to calculate this constant but I really cannot explain why at mojang they would implement something so strange (I guess they are doing something at the bit level)

I still need to try some edge cases: there are some info lenghts that cannot be correctly interpreted no matter the constant...
I will try to discover how the server builds a message these particular lenghts...

@gekigek99
Copy link
Member

gekigek99 commented Nov 2, 2020

At the end i manged to completely remove the constant that was everything but constant ;)... I even found a much nicer way to calculate the header!

I added this functionality in commit 9c680be

I also updated the wiki regarding the header calculation to communicate with the server

You can find the script in the dev branch: after checking if everything works as it should, i'll open a pull request to master

Please let me know if you find some bugs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants