1 /// Provides the Packet class. 2 3 module gfm.enet.packet; 4 5 import std.traits : isArray, isScalarType; 6 import derelict.enet.enet; 7 import gfm.enet.enet; 8 9 10 /// Encompasses an ENetPacket with an object-oriented wrapper. Once a packet has 11 /// been sent, the data cannot be modified. 12 final class Packet 13 { 14 private size_t _largestPacketSize; 15 16 package 17 { 18 ENet _enet; 19 ENetPacket *_handle; 20 bool _dirty; // Disallows changing after being sent 21 bool _destroyed; // When ENet internally destroys packet 22 } 23 24 /** 25 * Creates an ENetPacket internally. 26 * Throws: ENetException when enet_packet_create fails 27 * Params: 28 * enet = Library object 29 * data = Initial contents of the packet's data 30 * dataLength = Size of the data allocated for this packet 31 * flags = Flags for this packet 32 */ 33 this(ENet enet, const(void) *data, size_t dataLength, uint flags=0) 34 { 35 _enet = enet; 36 _handle = enet_packet_create(data, dataLength, flags); 37 if(_handle is null) 38 throw new ENetException("enet_packet_create failed"); 39 _largestPacketSize = dataLength; 40 _dirty = false; 41 _destroyed = false; 42 } 43 44 /// A convenience constructor for an already existing ENetPacket. 45 this(ENet enet, ENetPacket *packet) 46 { 47 _enet = enet; 48 _handle = packet; 49 if(_handle != null) 50 _largestPacketSize = _handle.dataLength; 51 _dirty = false; // Not guaranteed, but trust thy user. 52 _destroyed = false; 53 } 54 55 /// A convenience constructor for array data. 56 this(T)(ENet enet, T data, uint flags=0) if(isArray!T) 57 { 58 this(enet, &data[0], data.length, flags); 59 } 60 61 /// A convenience constructor for scalar data. 62 this(T)(ENet enet, T data, uint flags=0) if(isScalarType!T) 63 { 64 this(enet, &data, 1, flags); 65 } 66 67 /// Cleans up the internal ENetPacket. 68 ~this() 69 { 70 if(_handle !is null && !_destroyed) 71 { 72 debug ensureNotInGC("Packet"); 73 enet_packet_destroy(_handle); 74 _handle = null; 75 } 76 } 77 78 /** 79 * Resizes the ENetPacket. 80 * Throws: ENetException if the packet cannot be resized 81 * Throws: ENetException if the packet is dirty (has been sent) 82 */ 83 void resize(size_t dataLength) 84 { 85 if(!_dirty) 86 { 87 if(dataLength != _handle.dataLength) 88 { 89 if(dataLength > _largestPacketSize) 90 _enet._logger.warning("Packet size is larger than underlying data"); 91 92 auto errCode = enet_packet_resize(_handle, dataLength); 93 if(errCode < 0) 94 throw new ENetException("enet_packet_resize failed"); 95 } 96 } 97 else 98 { 99 throw new ENetException("Resizing sent packets is not allowed"); 100 } 101 } 102 103 /// Gets the ENetPacket's data. 104 ubyte[] data() 105 { 106 return _handle.data[0.._handle.dataLength]; 107 } 108 109 /** 110 * Sets the ENetPacket's data. 111 * Throws: ENetException if the packet is dirty (has been sent) 112 * See_Also: resize 113 */ 114 void setData(ubyte[] data) 115 { 116 if(!_dirty) 117 { 118 if(data.length > _largestPacketSize) 119 _largestPacketSize = data.length; 120 resize(data.length); 121 _handle.data = &data[0]; 122 } 123 else 124 { 125 throw new ENetException("Changing sent packets is not allowed"); 126 } 127 } 128 129 /// Gets the size of the ENetPacket in bytes. 130 size_t size() pure const nothrow 131 { 132 return _handle.dataLength; 133 } 134 135 /// Gets application private data. 136 void* userData() 137 { 138 return _handle.userData; 139 } 140 141 /// Sets application private data. 142 void setUserData(void *newData) 143 { 144 _handle.userData = newData; 145 } 146 }