pyCraft icon indicating copy to clipboard operation
pyCraft copied to clipboard

Client Settings

Open Lucky4Luuk opened this issue 6 years ago • 7 comments

How do I write the client settings? I tried creating a packet, then assigning all the values and sending it, but the render distance is obviously not being applied. Any examples?

Lucky4Luuk avatar Sep 18 '19 19:09 Lucky4Luuk

Hello. Here's a quick mock up of some code which sends out a client settings packet when the client joins the game with some pseudo values. Note that the reason your render distance isn't being applied may be because of a server limit. Some servers limit the number of chunks it sends in a radius around the player. This value is usually in the server properties file. view-distance or something along these lines.

    @connection.listener(clientbound.play.JoinGamePacket)
    def on_join_game_packet(self, join_game_packet):
        packet = serverbound.play.ClientSettingsPacket()
        packet.locale = 'en_US'
        packet.view_distance = 10
        packet.chat_mode = packet.ChatMode.FULL
        packet.chat_colors = False
        packet.displayed_skin_parts = packet.SkinParts.ALL
        packet.main_hand = packet.Hand.RIGHT
        connection.write_packet(packet)

zacholade avatar Sep 19 '19 09:09 zacholade

This is what I'm doing already. I'll share my code below:

#Client settings
self.client_settings = serverbound.play.ClientSettingsPacket()
self.client_settings.locale = "en_US"
self.client_settings.view_distance = 2
self.client_settings.chat_mode = self.client_settings.ChatMode.FULL
self.client_settings.chat_colors = False
self.client_settings.displayed_skin_parts = self.client_settings.SkinParts.ALL
self.client_settings.main_hand = self.client_settings.Hand.RIGHT
def on_join_game(self, join_game_packet) :
    print("Connected to a server")
    self.is_connected = True
    self.entity_id = join_game_packet.entity_id
    self.connection.write_packet(self.client_settings)

It's using self here because this is part of my Player class. I can't see any problems here, but it simply doesn't work. I still receive all the chunks within the server's render distance, and I can't possibly process them all at the same time. I even used Rust to write my Chunk class, to speed it up, and I still can't manage to process them all before my player times out.

Also, the server I'm trying to join is just a completely vanilla 1.14 server. I have made no modifications to the server whatsoever.

Lucky4Luuk avatar Sep 19 '19 16:09 Lucky4Luuk

Do you think it would be possible to just write a KeepAlive packet for every chunk that I process, so that I at least don't time out?

EDIT: I need a keep_alive_id so I guess not.

Lucky4Luuk avatar Sep 19 '19 16:09 Lucky4Luuk

Interesting.

First of all, sending a serverbound keep alive packet after every processed chunk would not be possible as it is sent upon receiving a clientbound keep alive packet. As referenced from https://wiki.vg/Protocol#Keep_Alive_.28clientbound.29 The server will frequently send out a keep-alive, each containing a random ID. The client must respond with the same packet. If the client does not respond to them for over 30 seconds, the server kicks the client. Vice versa, if the server does not send any keep-alives for 20 seconds, the client will disconnect and yields a "Timed out" exception.

One solution would be to potentially move the reading of the chunk data packet into another thread which doesn't block the NetworkingThread. However this could cause other unwanted race conditions to arise... Such as receiving a (multi) block change packet for a chunk which your other thread hasn't read data for yet. It's not perfect, but it's a potential solution. It would be interesting to know how the vanilla client handles this.

Where's the code you're using to read the chunk data packet? Could the issue be that your packet reading code is stuck in some sort of infinite loop?

Also in regards to the render distance problem...I'm not 100% sure of the behaviour here and haven't tested myself, so it is just a guess from me here. But according to https://wiki.vg/Protocol#Client_Settings it says that the View Distance field is defined as: View Distance | Byte | Client-side render distance, in chunks

It could be that the notchian server still sends clients chunk data around the player according to the view-distance value in server.properties. This is highly likely in order to fix an issue of the world not being loaded in the client's memory as the player travels quickly into neighbouring chunks. Instead, this render_distance value in the client settings packet could be a threshhold value of what is actually being rendered using OpenGL.. but it has the data in memory. This could answer your question about why chunks are being sent to the client even though they're out of your render_distance value's radius, however I may be wrong here.

zacholade avatar Sep 19 '19 17:09 zacholade

Very interesting. I will go work on this for a bit and I'll let you know if I get something to work!

Lucky4Luuk avatar Sep 19 '19 17:09 Lucky4Luuk

Okay, I think I may have figured out a way to solve this. I can create a queu of chunks that have not been processed, and then everytime I receive a chunk packet, I will decode it and put the information into the queu. Then, every tick, I process the first chunk in the queu and pop it from the list. This way, I at least don't block the whole process until all chunks have been processed. I will do some more testing but it seems to work! I'll close the issue once it works haha.

On a sidenote, it would be nice to have something like a Discord Server to ask questions. I feel like the issue section on Github is meant for actual problems with the library, and not for people like me who just can't figure out a "personal" issue.

Lucky4Luuk avatar Sep 19 '19 17:09 Lucky4Luuk

Yes that sounds reasonable. Potentially look into also adding packets such as UnloadChunkPacket, MultiBlockChangePacket and BlockChangePacket to this queue as they all need write access to your world data storage. There may be other packets but I'm not 100% sure.

And yes I completely agree a Discord server would be completely beneficial. However, this would probably be up to ammaraskar or another maintainer to do! :) Feel free to contact me however if you want any help..Ghostal#0001

I feel this project has been put a bit on the back burner for them with other interests and life getting in the way.. Which is completely understandable for a relatively old project. So no hard feelings there.

zacholade avatar Sep 19 '19 17:09 zacholade