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 ~this() 68 { 69 close(); 70 } 71 72 /// Cleans up the internal ENetPacket. 73 void close() 74 { 75 if(_handle !is null && !_destroyed) 76 { 77 enet_packet_destroy(_handle); 78 _handle = null; 79 } 80 } 81 82 /** 83 * Resizes the ENetPacket. 84 * Throws: ENetException if the packet cannot be resized 85 * Throws: ENetException if the packet is dirty (has been sent) 86 */ 87 void resize(size_t dataLength) 88 { 89 if(!_dirty) 90 { 91 if(dataLength != _handle.dataLength) 92 { 93 if(dataLength > _largestPacketSize) 94 _enet._logger.warning("Packet size is larger than underlying data"); 95 96 auto errCode = enet_packet_resize(_handle, dataLength); 97 if(errCode < 0) 98 throw new ENetException("enet_packet_resize failed"); 99 } 100 } 101 else 102 { 103 throw new ENetException("Resizing sent packets is not allowed"); 104 } 105 } 106 107 /// Gets the ENetPacket's data. 108 ubyte[] data() 109 { 110 return _handle.data[0.._handle.dataLength]; 111 } 112 113 /** 114 * Sets the ENetPacket's data. 115 * Throws: ENetException if the packet is dirty (has been sent) 116 * See_Also: resize 117 */ 118 void setData(ubyte[] data) 119 { 120 if(!_dirty) 121 { 122 if(data.length > _largestPacketSize) 123 _largestPacketSize = data.length; 124 resize(data.length); 125 _handle.data = &data[0]; 126 } 127 else 128 { 129 throw new ENetException("Changing sent packets is not allowed"); 130 } 131 } 132 133 /// Gets the size of the ENetPacket in bytes. 134 size_t size() pure const nothrow 135 { 136 return _handle.dataLength; 137 } 138 139 /// Gets application private data. 140 void* userData() 141 { 142 return _handle.userData; 143 } 144 145 /// Sets application private data. 146 void setUserData(void *newData) 147 { 148 _handle.userData = newData; 149 } 150 }