Client Settings
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?
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)
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.
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.
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.
Very interesting. I will go work on this for a bit and I'll let you know if I get something to work!
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.
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.