Version specific packet implementation pattern#78
Conversation
added IPacketVersionSubType interface for version specific packet sub classes implemented LoginStartPacket using new method for version specific packets
|
As I was implementing the new version specific packet pattern for Since Minecraft 1.16.3 this packet changed multiple times but only slightly. Possible solutions:
My thoughts on the solutions:
What do you think? Code for public sealed partial record RespawnPacketV_1_19_4(
Identifier DimensionType,
Identifier DimensionName,
long HashedSeed,
GameMode Gamemode,
GameMode? PreviousGamemode,
bool IsDebug,
bool IsFlat,
DataKeptFlags DataKept,
bool HasDeathLocation,
Identifier? DeathDimensionName,
Position? DeathLocation
) : RespawnPacket
{
/// <inheritdoc />
public override void Write(PacketBuffer buffer, MinecraftData data)
{
buffer.WriteIdentifier(DimensionType);
buffer.WriteIdentifier(DimensionName);
buffer.WriteLong(HashedSeed);
buffer.WriteByte((byte)Gamemode);
buffer.WriteSByte(PreviousGamemode.HasValue ? (sbyte)PreviousGamemode : (sbyte)-1);
buffer.WriteBool(IsDebug);
buffer.WriteBool(IsFlat);
buffer.WriteByte((byte)DataKept);
buffer.WriteBool(HasDeathLocation);
if (HasDeathLocation)
{
buffer.WriteIdentifier(DeathDimensionName!);
buffer.WritePosition(DeathLocation!.Value);
}
}
/// <inheritdoc />
public static new RespawnPacketV_1_19_4 Read(PacketBuffer buffer, MinecraftData data)
{
var dimensionType = buffer.ReadIdentifier();
var dimensionName = buffer.ReadIdentifier();
var hashedSeed = buffer.ReadLong();
var gamemode = (GameMode)buffer.ReadByte();
var previousGamemodeValue = buffer.ReadSByte();
var previousGamemode = previousGamemodeValue == -1 ? null : (GameMode?)previousGamemodeValue;
var isDebug = buffer.ReadBool();
var isFlat = buffer.ReadBool();
var dataKept = (DataKeptFlags)buffer.ReadByte();
var hasDeathLocation = buffer.ReadBool();
Identifier? deathDimensionName = null;
Position? deathLocation = null;
if (hasDeathLocation)
{
deathDimensionName = buffer.ReadIdentifier();
deathLocation = buffer.ReadPosition();
}
return new(dimensionType, dimensionName, hashedSeed, gamemode, previousGamemode, isDebug, isFlat, dataKept, hasDeathLocation, deathDimensionName, deathLocation);
}
}
|
|
Hi, I'd also go with option 2. But maybe we can put the shared fields right into the super class, instead of putting them into another |
The drawback is that with this approach we are now back to our orignal problem for which we started the sub class for every version refactoring. The base class would get fields that the actual packet (sub class) does not have. |
|
Okay I guess there is not really a way around it (without code duplication). But the |
Yes. Fields should only be nullable if the packet for the matching protocol version contains nullable (wiki.vg language: Optional) fields.
Yes that is correct. And was the idea. We then can build packets like this (only example names): This way we could make sub packets for multiple versions without much code duplication and copying/processing this data is easier between minecraft versions. What do you think? |
|
Okay, lets go with the composition approach. One more idea: We could pass the properties of shared records through to the packet class. internal PlayerData PlayerData { get; private set; }
public Uuid Uuid
{
get => PlayerData.Uuid;
set => PlayerData.Uuid = value;
}This way we can hide the (probably messy) data records from the outside and keep the Api concise. But it would add a lot of boiler plate code again... |
I though of this too. (see below)
Yes that is possible. We could do this. But I would not hide the shared data records (instead add these properties in addition to the shared data records). Because these records bundle the fields that most use cases of these packets will need. But you would still need to switch (pattern matching) all the versioned packet classes that provide this shared data record. |
This PR is built on top of #77
This PR adds the pattern for minecraft version specific packet implementation that was discussed in #68.
The newly added
PacketSourceGeneratorproject runs when building theMineSharp.Protocolproject and generates C# files that add (viapartialkeyword) methods/fields/properties to the packet types.To debug the source generator:
Select Debug build and create the file:
Components/MineSharp.PacketSourceGenerator/debugSourceGenerator.txt.userthen do a rebuild of the
MineSharp.Protocolproject. This will then run the source generator.The source generator will look for the file mentioned above and if it exists will call
Debugger.Launch().Then you can attach with your debugger.
TODO:
There are still some things that could be improved:
IPacketClientboundandIPacketServerboundto add type constraints forOn<Packet>andSendPacket