using Network.Codecs;
namespace Network.Packets
{
public interface Packet {
public void Read(DataSerializer data);
public void Write(DataSerializer data);
}
}
using System.Collections.Generic;
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Channels;
using Network.Packets;
using Network.Protocols;
namespace Network.Codecs
{
public class PacketCodec<Packet> : ByteToMessageCodec<Packet>
{
public static DataSerializer CreateDataSerializer(IByteBuffer buf) => new DataSerializer(buf);
private Client client;
public PacketCodec(Client client)
{
this.client = client;
}
protected override void Encode(IChannelHandlerContext context, Packet packet, IByteBuffer output){
int? id = ProtocolRegistry.GetPacketID(this.client.connection.GetProtocol().GetState(), packet.GetType(), false);
if (id == null || id < 0){
throw new System.IO.IOException("Unknown packet (" packet.GetType().Name ")");
}
else
{
DataSerializer serializer = CreateDataSerializer(output);
serializer.WriteVarInt(id.Value); <<< Getting error here
packet.Write(serializer);
}
}
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output){
}
}
}
I am getting this error even though there is a Write method in the 'Packet' interface class.
Error: error CS1061: 'Packet' does not contain a definition for 'Write' and no accessible extension method 'Write' accepting a first argument of type 'Packet' could be found (are you missing a using directive or an assembly reference?)
CodePudding user response:
Packet
in your PacketCodec
class is totally unrelated to your Packet
type. It is generic - that's why we typically use T
to avoid confusion.
If you want it to really be class Packet, you should write
public interface IPacket
{
public void Read(DataContractSerializer data);
public void Write(DataContractSerializer data);
}
public class ByteToMessageCodec<T> {}
public class PacketCodec<T> : ByteToMessageCodec<T> where T : IPacket
{
private readonly DataContractSerializer _data;
private T _packet;
public PacketCodec(DataContractSerializer data, T packet)
{
_data = data;
_packet = packet;
}
public void Input()
{
_packet.Read(_data);
}
public void Output()
{
_packet.Write(_data);
}
}
CodePudding user response:
According to the .NET naming conventions interface names must be prepended with an upper case I
. Also interface members are public by default.
public interface IPacket
{
void Read(DataContractSerializer data);
void Write(DataContractSerializer data);
}
Since PacketCodec
will always handle packets of type IPacket
, it does not need to be generic.
// Note: only ByteToMessageCodec has a generic type parameter.
public class PacketCodec : ByteToMessageCodec<IPacket>
{
public static DataSerializer CreateDataSerializer(IByteBuffer buf) =>
new DataSerializer(buf);
private Client client;
public PacketCodec(Client client)
{
this.client = client;
}
// >>> Here the packet parameter is typed IPacket.
protected override void Encode(IChannelHandlerContext context, IPacket packet,
IByteBuffer output)
{
int? id = ProtocolRegistry.GetPacketID(
this.client.connection.GetProtocol().GetState(), packet.GetType(), false);
if (id == null || id < 0){
throw new System.IO.IOException("Unknown packet (" packet.GetType().Name ")");
}
else
{
DataSerializer serializer = CreateDataSerializer(output);
serializer.WriteVarInt(id.Value);
packet.Write(serializer); // <<< Error was here.
}
}
protected override void Decode(IChannelHandlerContext context, IByteBuffer input,
List<object> output)
{
}
}