-
Notifications
You must be signed in to change notification settings - Fork 13
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
Version specific packet implementation pattern #78
base: main
Are you sure you want to change the base?
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
PacketSourceGenerator
project runs when building theMineSharp.Protocol
project and generates C# files that add (viapartial
keyword) methods/fields/properties to the packet types.To debug the source generator:
Select Debug build and create the file:
Components/MineSharp.PacketSourceGenerator/debugSourceGenerator.txt.user
then do a rebuild of the
MineSharp.Protocol
project. 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:
IPacketClientbound
andIPacketServerbound
to add type constraints forOn<Packet>
andSendPacket