-High Level protocol optimization (should be smaller)
-Ability to set compression to ENet packets (check API) -Fixed small bug in StringDB that lead to duplicate empty strings -Added a new class, StreamPeerBuffer, useful to create your own tightly packed data
This commit is contained in:
parent
61cb8fd76c
commit
cbbcf72703
12 changed files with 515 additions and 85 deletions
|
@ -60,6 +60,10 @@ int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,M
|
|||
|
||||
strm.avail_in=p_src_size;
|
||||
int aout = deflateBound(&strm,p_src_size);;
|
||||
/*if (aout>p_src_size) {
|
||||
deflateEnd(&strm);
|
||||
return -1;
|
||||
}*/
|
||||
strm.avail_out=aout;
|
||||
strm.next_in=(Bytef*)p_src;
|
||||
strm.next_out=p_dst;
|
||||
|
@ -107,19 +111,21 @@ int Compression::get_max_compressed_buffer_size(int p_src_size,Mode p_mode){
|
|||
|
||||
|
||||
|
||||
void Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode){
|
||||
int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode){
|
||||
|
||||
switch(p_mode) {
|
||||
case MODE_FASTLZ: {
|
||||
|
||||
int ret_size=0;
|
||||
|
||||
if (p_dst_max_size<16) {
|
||||
uint8_t dst[16];
|
||||
fastlz_decompress(p_src,p_src_size,dst,16);
|
||||
ret_size = fastlz_decompress(p_src,p_src_size,dst,16);
|
||||
copymem(p_dst,dst,p_dst_max_size);
|
||||
} else {
|
||||
fastlz_decompress(p_src,p_src_size,p_dst,p_dst_max_size);
|
||||
ret_size = fastlz_decompress(p_src,p_src_size,p_dst,p_dst_max_size);
|
||||
}
|
||||
return;
|
||||
return ret_size;
|
||||
} break;
|
||||
case MODE_DEFLATE: {
|
||||
|
||||
|
@ -130,7 +136,7 @@ void Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *
|
|||
strm.avail_in= 0;
|
||||
strm.next_in=Z_NULL;
|
||||
int err = inflateInit(&strm);
|
||||
ERR_FAIL_COND(err!=Z_OK);
|
||||
ERR_FAIL_COND_V(err!=Z_OK,-1);
|
||||
|
||||
strm.avail_in=p_src_size;
|
||||
strm.avail_out=p_dst_max_size;
|
||||
|
@ -138,11 +144,12 @@ void Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *
|
|||
strm.next_out=p_dst;
|
||||
|
||||
err = inflate(&strm,Z_FINISH);
|
||||
int total = strm.total_out;
|
||||
inflateEnd(&strm);
|
||||
ERR_FAIL_COND(err!=Z_STREAM_END);
|
||||
return;
|
||||
ERR_FAIL_COND_V(err!=Z_STREAM_END,-1);
|
||||
return total;
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_FAIL();
|
||||
ERR_FAIL_V(-1);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
static int get_max_compressed_buffer_size(int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
static void decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
|
||||
|
||||
Compression();
|
||||
};
|
||||
|
|
|
@ -222,6 +222,7 @@ void StreamPeer::put_double(double p_val){
|
|||
void StreamPeer::put_utf8_string(const String& p_string) {
|
||||
|
||||
CharString cs=p_string.utf8();
|
||||
put_u32(p_string.length());
|
||||
put_data((const uint8_t*)cs.get_data(),cs.length());
|
||||
|
||||
}
|
||||
|
@ -348,8 +349,10 @@ String StreamPeer::get_string(int p_bytes){
|
|||
ERR_FAIL_COND_V(p_bytes<0,String());
|
||||
|
||||
Vector<char> buf;
|
||||
buf.resize(p_bytes+1);
|
||||
get_data((uint8_t*)&buf[0],p_bytes);
|
||||
Error err = buf.resize(p_bytes+1);
|
||||
ERR_FAIL_COND_V(err!=OK,String());
|
||||
err = get_data((uint8_t*)&buf[0],p_bytes);
|
||||
ERR_FAIL_COND_V(err!=OK,String());
|
||||
buf[p_bytes]=0;
|
||||
return buf.ptr();
|
||||
|
||||
|
@ -359,8 +362,10 @@ String StreamPeer::get_utf8_string(int p_bytes){
|
|||
ERR_FAIL_COND_V(p_bytes<0,String());
|
||||
|
||||
Vector<uint8_t> buf;
|
||||
buf.resize(p_bytes);
|
||||
get_data(buf.ptr(),p_bytes);
|
||||
Error err = buf.resize(p_bytes);
|
||||
ERR_FAIL_COND_V(err!=OK,String());
|
||||
err = get_data(buf.ptr(),p_bytes);
|
||||
ERR_FAIL_COND_V(err!=OK,String());
|
||||
|
||||
String ret;
|
||||
ret.parse_utf8((const char*)buf.ptr(),buf.size());
|
||||
|
@ -371,8 +376,10 @@ Variant StreamPeer::get_var(){
|
|||
|
||||
int len = get_32();
|
||||
Vector<uint8_t> var;
|
||||
var.resize(len);
|
||||
get_data(var.ptr(),len);
|
||||
Error err = var.resize(len);
|
||||
ERR_FAIL_COND_V(err!=OK,Variant());
|
||||
err = get_data(var.ptr(),len);
|
||||
ERR_FAIL_COND_V(err!=OK,Variant());
|
||||
|
||||
Variant ret;
|
||||
decode_variant(ret,var.ptr(),len);
|
||||
|
@ -420,3 +427,127 @@ void StreamPeer::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("get_utf8_string","bytes"),&StreamPeer::get_utf8_string);
|
||||
ObjectTypeDB::bind_method(_MD("get_var:Variant"),&StreamPeer::get_var);
|
||||
}
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
void StreamPeerBuffer::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("seek","pos"),&StreamPeerBuffer::seek);
|
||||
ObjectTypeDB::bind_method(_MD("get_size"),&StreamPeerBuffer::get_size);
|
||||
ObjectTypeDB::bind_method(_MD("get_pos"),&StreamPeerBuffer::get_pos);
|
||||
ObjectTypeDB::bind_method(_MD("resize","size"),&StreamPeerBuffer::resize);
|
||||
ObjectTypeDB::bind_method(_MD("set_data_array","data"),&StreamPeerBuffer::set_data_array);
|
||||
ObjectTypeDB::bind_method(_MD("get_data_array"),&StreamPeerBuffer::get_data_array);
|
||||
ObjectTypeDB::bind_method(_MD("clear"),&StreamPeerBuffer::clear);
|
||||
ObjectTypeDB::bind_method(_MD("duplicate:StreamPeerBuffer"),&StreamPeerBuffer::duplicate);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Error StreamPeerBuffer::put_data(const uint8_t* p_data,int p_bytes) {
|
||||
|
||||
if (p_bytes<=0)
|
||||
return OK;
|
||||
|
||||
if (pointer+p_bytes > data.size()) {
|
||||
data.resize(pointer+p_bytes);
|
||||
|
||||
}
|
||||
|
||||
DVector<uint8_t>::Write w = data.write();
|
||||
copymem(&w[pointer],p_data,p_bytes);
|
||||
|
||||
pointer+=p_bytes;
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error StreamPeerBuffer::put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent){
|
||||
|
||||
r_sent=p_bytes;
|
||||
return put_data(p_data,p_bytes);
|
||||
}
|
||||
|
||||
Error StreamPeerBuffer::get_data(uint8_t* p_buffer, int p_bytes){
|
||||
|
||||
int recv;
|
||||
get_partial_data(p_buffer,p_bytes,recv);
|
||||
if (recv!=p_bytes)
|
||||
return ERR_INVALID_PARAMETER;
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
Error StreamPeerBuffer::get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received){
|
||||
|
||||
|
||||
if (pointer+p_bytes > data.size()) {
|
||||
r_received=data.size()-pointer;
|
||||
if (r_received<=0) {
|
||||
r_received=0;
|
||||
return OK; //you got 0
|
||||
}
|
||||
} else {
|
||||
r_received=p_bytes;
|
||||
}
|
||||
|
||||
DVector<uint8_t>::Read r = data.read();
|
||||
copymem(p_buffer,r.ptr(),r_received);
|
||||
}
|
||||
|
||||
int StreamPeerBuffer::get_available_bytes() const {
|
||||
|
||||
return data.size()-pointer;
|
||||
}
|
||||
|
||||
void StreamPeerBuffer::seek(int p_pos){
|
||||
|
||||
ERR_FAIL_COND(p_pos < 0);
|
||||
ERR_FAIL_COND(p_pos > data.size());
|
||||
pointer=p_pos;
|
||||
}
|
||||
int StreamPeerBuffer::get_size() const{
|
||||
|
||||
return data.size();
|
||||
}
|
||||
|
||||
int StreamPeerBuffer::get_pos() const {
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
void StreamPeerBuffer::resize(int p_size){
|
||||
|
||||
data.resize(p_size);
|
||||
}
|
||||
|
||||
void StreamPeerBuffer::set_data_array(const DVector<uint8_t> & p_data){
|
||||
|
||||
data=p_data;
|
||||
pointer=0;
|
||||
}
|
||||
|
||||
DVector<uint8_t> StreamPeerBuffer::get_data_array() const{
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void StreamPeerBuffer::clear() {
|
||||
|
||||
data.resize(0);
|
||||
pointer=0;
|
||||
}
|
||||
|
||||
|
||||
Ref<StreamPeerBuffer> StreamPeerBuffer::duplicate() const {
|
||||
|
||||
Ref<StreamPeerBuffer> spb;
|
||||
spb.instance();
|
||||
spb->data=data;
|
||||
}
|
||||
|
||||
|
||||
StreamPeerBuffer::StreamPeerBuffer() {
|
||||
|
||||
pointer=0;
|
||||
}
|
||||
|
|
|
@ -91,4 +91,40 @@ public:
|
|||
StreamPeer() { big_endian=false; }
|
||||
};
|
||||
|
||||
|
||||
class StreamPeerBuffer : public StreamPeer {
|
||||
|
||||
OBJ_TYPE(StreamPeerBuffer,StreamPeer);
|
||||
|
||||
DVector<uint8_t> data;
|
||||
int pointer;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
Error put_data(const uint8_t* p_data,int p_bytes);
|
||||
Error put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent);
|
||||
|
||||
Error get_data(uint8_t* p_buffer, int p_bytes);
|
||||
Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received);
|
||||
|
||||
virtual int get_available_bytes() const;
|
||||
|
||||
void seek(int p_pos);
|
||||
int get_size() const;
|
||||
int get_pos() const;
|
||||
void resize(int p_size);
|
||||
|
||||
|
||||
void set_data_array(const DVector<uint8_t> & p_data);
|
||||
DVector<uint8_t> get_data_array() const;
|
||||
|
||||
void clear();
|
||||
|
||||
Ref<StreamPeerBuffer> duplicate() const;
|
||||
|
||||
StreamPeerBuffer();
|
||||
};
|
||||
|
||||
|
||||
#endif // STREAM_PEER_H
|
||||
|
|
|
@ -363,6 +363,7 @@ NodePath::NodePath(const String& p_path) {
|
|||
|
||||
from=i+1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
path=path.substr(0,subpath_pos);
|
||||
|
@ -380,6 +381,8 @@ NodePath::NodePath(const String& p_path) {
|
|||
|
||||
last_is_slash=false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (slices==0 && !absolute && !property)
|
||||
|
@ -413,6 +416,7 @@ NodePath::NodePath(const String& p_path) {
|
|||
} else {
|
||||
last_is_slash=false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ void register_core_types() {
|
|||
ObjectTypeDB::register_type<Resource>();
|
||||
ObjectTypeDB::register_type<FuncRef>();
|
||||
ObjectTypeDB::register_virtual_type<StreamPeer>();
|
||||
ObjectTypeDB::register_type<StreamPeerBuffer>();
|
||||
ObjectTypeDB::register_create_type<StreamPeerTCP>();
|
||||
ObjectTypeDB::register_create_type<TCP_Server>();
|
||||
ObjectTypeDB::register_create_type<PacketPeerUDP>();
|
||||
|
|
|
@ -183,7 +183,8 @@ StringName::StringName(const char *p_name) {
|
|||
|
||||
ERR_FAIL_COND(!configured);
|
||||
|
||||
ERR_FAIL_COND( !p_name || !p_name[0]);
|
||||
if (!p_name || p_name[0]==0)
|
||||
return; //empty, ignore
|
||||
|
||||
_global_lock();
|
||||
|
||||
|
@ -288,6 +289,9 @@ StringName::StringName(const String& p_name) {
|
|||
|
||||
ERR_FAIL_COND(!configured);
|
||||
|
||||
if (p_name==String())
|
||||
return;
|
||||
|
||||
_global_lock();
|
||||
|
||||
uint32_t hash = p_name.hash();
|
||||
|
|
|
@ -38,6 +38,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
|
|||
|
||||
ERR_FAIL_COND_V(!host,ERR_CANT_CREATE);
|
||||
|
||||
_setup_compressor();
|
||||
active=true;
|
||||
server=true;
|
||||
refuse_connections=false;
|
||||
|
@ -58,6 +59,8 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port
|
|||
ERR_FAIL_COND_V(!host,ERR_CANT_CREATE);
|
||||
|
||||
|
||||
_setup_compressor();
|
||||
|
||||
ENetAddress address;
|
||||
address.host=p_ip.host;
|
||||
address.port=p_port;
|
||||
|
@ -494,13 +497,124 @@ bool NetworkedMultiplayerENet::is_refusing_new_connections() const {
|
|||
return refuse_connections;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_compression_mode(CompressionMode p_mode) {
|
||||
|
||||
compression_mode=p_mode;
|
||||
}
|
||||
|
||||
NetworkedMultiplayerENet::CompressionMode NetworkedMultiplayerENet::get_compression_mode() const{
|
||||
|
||||
return compression_mode;
|
||||
}
|
||||
|
||||
size_t NetworkedMultiplayerENet::enet_compress(void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) {
|
||||
|
||||
NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet*)(context);
|
||||
|
||||
if (size_t(enet->src_compressor_mem.size())<inLimit) {
|
||||
enet->src_compressor_mem.resize( inLimit );
|
||||
}
|
||||
|
||||
int total = inLimit;
|
||||
int ofs=0;
|
||||
while(total) {
|
||||
for(size_t i=0;i<inBufferCount;i++) {
|
||||
int to_copy = MIN(total,int(inBuffers[i].dataLength));
|
||||
copymem(&enet->src_compressor_mem[ofs],inBuffers[i].data,to_copy);
|
||||
ofs+=to_copy;
|
||||
total-=to_copy;
|
||||
}
|
||||
}
|
||||
|
||||
Compression::Mode mode;
|
||||
|
||||
switch(enet->compression_mode) {
|
||||
case COMPRESS_FASTLZ: {
|
||||
mode=Compression::MODE_FASTLZ;
|
||||
} break;
|
||||
case COMPRESS_ZLIB: {
|
||||
mode=Compression::MODE_DEFLATE;
|
||||
} break;
|
||||
default: { ERR_FAIL_V(0); }
|
||||
}
|
||||
|
||||
int req_size = Compression::get_max_compressed_buffer_size(ofs,mode);
|
||||
if (enet->dst_compressor_mem.size()<req_size) {
|
||||
enet->dst_compressor_mem.resize(req_size);
|
||||
}
|
||||
int ret=Compression::compress(enet->dst_compressor_mem.ptr(),enet->src_compressor_mem.ptr(),ofs,mode);
|
||||
|
||||
if (ret<0)
|
||||
return 0;
|
||||
|
||||
|
||||
if (ret>int(outLimit))
|
||||
return 0; //do not bother
|
||||
|
||||
copymem(outData,enet->dst_compressor_mem.ptr(),ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t NetworkedMultiplayerENet::enet_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit){
|
||||
|
||||
NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet*)(context);
|
||||
int ret = -1;
|
||||
switch(enet->compression_mode) {
|
||||
case COMPRESS_FASTLZ: {
|
||||
|
||||
ret=Compression::decompress(outData,outLimit,inData,inLimit,Compression::MODE_FASTLZ);
|
||||
} break;
|
||||
case COMPRESS_ZLIB: {
|
||||
|
||||
ret=Compression::decompress(outData,outLimit,inData,inLimit,Compression::MODE_DEFLATE);
|
||||
} break;
|
||||
default: {}
|
||||
}
|
||||
if (ret<0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::_setup_compressor() {
|
||||
|
||||
switch(compression_mode) {
|
||||
|
||||
case COMPRESS_NONE: {
|
||||
|
||||
enet_host_compress(host,NULL);
|
||||
} break;
|
||||
case COMPRESS_RANGE_CODER: {
|
||||
enet_host_compress_with_range_coder(host);
|
||||
} break;
|
||||
case COMPRESS_FASTLZ:
|
||||
case COMPRESS_ZLIB: {
|
||||
|
||||
enet_host_compress(host,&enet_compressor);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::enet_compressor_destroy(void * context){
|
||||
|
||||
//do none
|
||||
}
|
||||
|
||||
|
||||
void NetworkedMultiplayerENet::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("create_server","port","max_clients","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_server,DEFVAL(32),DEFVAL(0),DEFVAL(0));
|
||||
ObjectTypeDB::bind_method(_MD("create_client","ip","port","in_bandwidth","out_bandwidth"),&NetworkedMultiplayerENet::create_client,DEFVAL(0),DEFVAL(0));
|
||||
ObjectTypeDB::bind_method(_MD("close_connection"),&NetworkedMultiplayerENet::close_connection);
|
||||
ObjectTypeDB::bind_method(_MD("set_compression_mode","mode"),&NetworkedMultiplayerENet::set_compression_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_compression_mode"),&NetworkedMultiplayerENet::get_compression_mode);
|
||||
|
||||
BIND_CONSTANT( COMPRESS_NONE );
|
||||
BIND_CONSTANT( COMPRESS_RANGE_CODER );
|
||||
BIND_CONSTANT( COMPRESS_FASTLZ );
|
||||
BIND_CONSTANT( COMPRESS_ZLIB );
|
||||
|
||||
}
|
||||
|
||||
|
@ -515,6 +629,12 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet(){
|
|||
current_packet.packet=NULL;
|
||||
transfer_mode=TRANSFER_MODE_RELIABLE;
|
||||
connection_status=CONNECTION_DISCONNECTED;
|
||||
compression_mode=COMPRESS_NONE;
|
||||
enet_compressor.context=this;
|
||||
enet_compressor.compress=enet_compress;
|
||||
enet_compressor.decompress=enet_decompress;
|
||||
enet_compressor.destroy=enet_compressor_destroy;
|
||||
|
||||
}
|
||||
|
||||
NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){
|
||||
|
|
|
@ -3,10 +3,20 @@
|
|||
|
||||
#include "io/networked_multiplayer_peer.h"
|
||||
#include "enet/enet.h"
|
||||
#include "io/compression.h"
|
||||
|
||||
class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer {
|
||||
|
||||
OBJ_TYPE(NetworkedMultiplayerENet,NetworkedMultiplayerPeer)
|
||||
public:
|
||||
enum CompressionMode {
|
||||
COMPRESS_NONE,
|
||||
COMPRESS_RANGE_CODER,
|
||||
COMPRESS_FASTLZ,
|
||||
COMPRESS_ZLIB
|
||||
};
|
||||
private:
|
||||
|
||||
|
||||
enum {
|
||||
SYSMSG_ADD_PEER,
|
||||
|
@ -37,6 +47,8 @@ class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer {
|
|||
int from;
|
||||
};
|
||||
|
||||
CompressionMode compression_mode;
|
||||
|
||||
mutable List<Packet> incoming_packets;
|
||||
|
||||
mutable Packet current_packet;
|
||||
|
@ -44,6 +56,15 @@ class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer {
|
|||
uint32_t _gen_unique_id() const;
|
||||
void _pop_current_packet() const;
|
||||
|
||||
Vector<uint8_t> src_compressor_mem;
|
||||
Vector<uint8_t> dst_compressor_mem;
|
||||
|
||||
ENetCompressor enet_compressor;
|
||||
static size_t enet_compress(void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit);
|
||||
static size_t enet_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit);
|
||||
static void enet_compressor_destroy(void * context);
|
||||
void _setup_compressor();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
@ -77,9 +98,14 @@ public:
|
|||
|
||||
virtual int get_unique_id() const;
|
||||
|
||||
void set_compression_mode(CompressionMode p_mode);
|
||||
CompressionMode get_compression_mode() const;
|
||||
|
||||
NetworkedMultiplayerENet();
|
||||
~NetworkedMultiplayerENet();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(NetworkedMultiplayerENet::CompressionMode);
|
||||
|
||||
|
||||
#endif // NETWORKED_MULTIPLAYER_ENET_H
|
||||
|
|
|
@ -1692,7 +1692,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
|
|||
& host -> buffers [1], host -> bufferCount - 1,
|
||||
originalSize,
|
||||
host -> packetData [1],
|
||||
originalSize);
|
||||
originalSize);
|
||||
if (compressedSize > 0 && compressedSize < originalSize)
|
||||
{
|
||||
host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED;
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include "scene/resources/packed_scene.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/mesh.h"
|
||||
|
||||
#include "io/marshalls.h"
|
||||
|
||||
void SceneTreeTimer::_bind_methods() {
|
||||
|
||||
|
@ -1760,6 +1760,11 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
ERR_FAIL();
|
||||
}
|
||||
|
||||
if (p_argcount>255) {
|
||||
ERR_EXPLAIN("Too many arguments >255.");
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
if (p_to!=0 && !connected_peers.has(ABS(p_to))) {
|
||||
if (p_to==get_network_unique_id()) {
|
||||
ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: "+itos(get_network_unique_id()));
|
||||
|
@ -1774,25 +1779,7 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
NodePath from_path = p_from->get_path();
|
||||
ERR_FAIL_COND(from_path.is_empty());
|
||||
|
||||
//create base packet
|
||||
Array message;
|
||||
|
||||
message.resize(3+p_argcount); //alloc size for args
|
||||
|
||||
//set message type
|
||||
if (p_set) {
|
||||
message[0]=NETWORK_COMMAND_REMOTE_SET;
|
||||
} else {
|
||||
message[0]=NETWORK_COMMAND_REMOTE_CALL;
|
||||
}
|
||||
|
||||
//set message name
|
||||
message[2]=p_name;
|
||||
|
||||
//set message args
|
||||
for(int i=0;i<p_argcount;i++) {
|
||||
message[3+i]=*p_arg[i];
|
||||
}
|
||||
|
||||
//see if the path is cached
|
||||
PathSentCache *psc = path_send_cache.getptr(from_path);
|
||||
|
@ -1804,6 +1791,53 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
|
||||
}
|
||||
|
||||
|
||||
//create base packet, lots of harcode because it must be tight
|
||||
|
||||
int ofs=0;
|
||||
|
||||
#define MAKE_ROOM(m_amount) if (packet_cache.size() < m_amount) packet_cache.resize(m_amount);
|
||||
|
||||
//encode type
|
||||
MAKE_ROOM(1);
|
||||
packet_cache[0]=p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
|
||||
ofs+=1;
|
||||
|
||||
//encode ID
|
||||
MAKE_ROOM(ofs+4);
|
||||
encode_uint32(psc->id,&packet_cache[ofs]);
|
||||
ofs+=4;
|
||||
|
||||
//encode function name
|
||||
CharString name = String(p_name).utf8();
|
||||
int len = encode_cstring(name.get_data(),NULL);
|
||||
MAKE_ROOM(ofs+len);
|
||||
encode_cstring(name.get_data(),&packet_cache[ofs]);
|
||||
ofs+=len;
|
||||
|
||||
if (p_set) {
|
||||
//set argument
|
||||
Error err = encode_variant(*p_arg[0],NULL,len);
|
||||
ERR_FAIL_COND(err!=OK);
|
||||
MAKE_ROOM(ofs+len);
|
||||
encode_variant(*p_arg[0],&packet_cache[ofs],len);
|
||||
ofs+=len;
|
||||
|
||||
} else {
|
||||
//call arguments
|
||||
MAKE_ROOM(ofs+1);
|
||||
packet_cache[ofs]=p_argcount;
|
||||
ofs+=1;
|
||||
for(int i=0;i<p_argcount;i++) {
|
||||
Error err = encode_variant(*p_arg[i],NULL,len);
|
||||
ERR_FAIL_COND(err!=OK);
|
||||
MAKE_ROOM(ofs+len);
|
||||
encode_variant(*p_arg[i],&packet_cache[ofs],len);
|
||||
ofs+=len;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//see if all peers have cached path (is so, call can be fast)
|
||||
bool has_all_peers=true;
|
||||
|
||||
|
@ -1834,15 +1868,20 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
|
||||
for (List<int>::Element *E=peers_to_add.front();E;E=E->next()) {
|
||||
|
||||
Array add_path_message;
|
||||
add_path_message.resize(3);
|
||||
add_path_message[0]=NETWORK_COMMAND_SIMPLIFY_PATH;
|
||||
add_path_message[1]=from_path;
|
||||
add_path_message[2]=psc->id;
|
||||
//encode function name
|
||||
CharString pname = String(from_path).utf8();
|
||||
int len = encode_cstring(pname.get_data(),NULL);
|
||||
|
||||
Vector<uint8_t> packet;
|
||||
|
||||
packet.resize(1+4+len);
|
||||
packet[0]=NETWORK_COMMAND_SIMPLIFY_PATH;
|
||||
encode_uint32(psc->id,&packet[1]);
|
||||
encode_cstring(pname.get_data(),&packet[5]);
|
||||
|
||||
network_peer->set_target_peer(E->get()); //to all of you
|
||||
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||
network_peer->put_var(add_path_message); //a message with love
|
||||
network_peer->put_packet(packet.ptr(),packet.size());
|
||||
|
||||
psc->confirmed_peers.insert(E->get(),false); //insert into confirmed, but as false since it was not confirmed
|
||||
}
|
||||
|
@ -1853,12 +1892,18 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
if (has_all_peers) {
|
||||
|
||||
//they all have verified paths, so send fast
|
||||
message[1]=psc->id;
|
||||
|
||||
network_peer->set_target_peer(p_to); //to all of you
|
||||
network_peer->put_var(message); //a message with love
|
||||
network_peer->put_packet(packet_cache.ptr(),ofs); //a message with love
|
||||
} else {
|
||||
//not all verified path, so send one by one
|
||||
|
||||
//apend path at the end, since we will need it for some packets
|
||||
CharString pname = String(from_path).utf8();
|
||||
int path_len = encode_cstring(pname.get_data(),NULL);
|
||||
MAKE_ROOM(ofs+path_len);
|
||||
encode_cstring(pname.get_data(),&packet_cache[ofs]);
|
||||
|
||||
|
||||
for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) {
|
||||
|
||||
if (p_to<0 && E->get()==-p_to)
|
||||
|
@ -1874,41 +1919,52 @@ void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const St
|
|||
|
||||
if (F->get()==true) {
|
||||
//this one confirmed path, so use id
|
||||
message[1]=psc->id;
|
||||
encode_uint32(psc->id,&packet_cache[1]);
|
||||
network_peer->put_packet(packet_cache.ptr(),ofs);
|
||||
} else {
|
||||
//this one did not confirm path yet, so use entire path (sorry!)
|
||||
message[1]=from_path;
|
||||
encode_uint32(0x80000000|ofs,&packet_cache[1]); //offset to path and flag
|
||||
network_peer->put_packet(packet_cache.ptr(),ofs+path_len);
|
||||
}
|
||||
|
||||
network_peer->put_var(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::_network_process_packet(int p_from, const Array& p_packet) {
|
||||
void SceneTree::_network_process_packet(int p_from, const uint8_t* p_packet, int p_packet_len) {
|
||||
|
||||
ERR_FAIL_COND(p_packet.empty());
|
||||
ERR_FAIL_COND(p_packet_len<5);
|
||||
|
||||
int packet_type = p_packet[0];
|
||||
uint8_t packet_type = p_packet[0];
|
||||
|
||||
switch(packet_type) {
|
||||
|
||||
case NETWORK_COMMAND_REMOTE_CALL:
|
||||
case NETWORK_COMMAND_REMOTE_SET: {
|
||||
|
||||
ERR_FAIL_COND(p_packet.size()<3);
|
||||
Variant target = p_packet[1];
|
||||
Node* node=NULL;
|
||||
ERR_FAIL_COND(p_packet_len<5);
|
||||
uint32_t target = decode_uint32(&p_packet[1]);
|
||||
|
||||
|
||||
Node *node=NULL;
|
||||
|
||||
if (target&0x80000000) {
|
||||
|
||||
int ofs = target&0x7FFFFFFF;
|
||||
ERR_FAIL_COND(ofs>=p_packet_len);
|
||||
|
||||
String paths;
|
||||
paths.parse_utf8((const char*)&p_packet[ofs],p_packet_len-ofs);
|
||||
|
||||
NodePath np = paths;
|
||||
|
||||
if (target.get_type()==Variant::NODE_PATH) {
|
||||
NodePath np = target;
|
||||
node = get_root()->get_node(np);
|
||||
if (node==NULL) {
|
||||
ERR_EXPLAIN("Failed to get path from RPC: "+String(np));
|
||||
ERR_FAIL_COND(node==NULL);
|
||||
}
|
||||
} else if (target.get_type()==Variant::INT) {
|
||||
} else {
|
||||
|
||||
int id = target;
|
||||
|
||||
|
@ -1928,26 +1984,51 @@ void SceneTree::_network_process_packet(int p_from, const Array& p_packet) {
|
|||
}
|
||||
|
||||
|
||||
} else {
|
||||
ERR_FAIL();
|
||||
}
|
||||
|
||||
StringName name = p_packet[2];
|
||||
ERR_FAIL_COND(p_packet_len<6);
|
||||
|
||||
//detect cstring end
|
||||
int len_end=5;
|
||||
for(;len_end<p_packet_len;len_end++) {
|
||||
if (p_packet[len_end]==0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(len_end>=p_packet_len);
|
||||
|
||||
StringName name = String::utf8((const char*)&p_packet[5]);
|
||||
|
||||
|
||||
|
||||
|
||||
if (packet_type==NETWORK_COMMAND_REMOTE_CALL) {
|
||||
|
||||
if (!node->can_call_rpc(name))
|
||||
return;
|
||||
|
||||
int argc = p_packet.size()-3;
|
||||
int ofs = len_end+1;
|
||||
|
||||
ERR_FAIL_COND(ofs>=p_packet_len);
|
||||
|
||||
int argc = p_packet[ofs];
|
||||
Vector<Variant> args;
|
||||
Vector<const Variant*> argp;
|
||||
args.resize(argc);
|
||||
argp.resize(argc);
|
||||
|
||||
ofs++;
|
||||
|
||||
for(int i=0;i<argc;i++) {
|
||||
args[i]=p_packet[3+i];
|
||||
|
||||
ERR_FAIL_COND(ofs>=p_packet_len);
|
||||
int vlen;
|
||||
Error err = decode_variant(args[i],&p_packet[ofs],p_packet_len-ofs,&vlen);
|
||||
ERR_FAIL_COND(err!=OK);
|
||||
//args[i]=p_packet[3+i];
|
||||
argp[i]=&args[i];
|
||||
ofs+=vlen;
|
||||
}
|
||||
|
||||
Variant::CallError ce;
|
||||
|
@ -1964,9 +2045,13 @@ void SceneTree::_network_process_packet(int p_from, const Array& p_packet) {
|
|||
if (!node->can_call_rset(name))
|
||||
return;
|
||||
|
||||
int ofs = len_end+1;
|
||||
|
||||
ERR_FAIL_COND(ofs>=p_packet_len);
|
||||
|
||||
Variant value;
|
||||
decode_variant(value,&p_packet[ofs],p_packet_len-ofs);
|
||||
|
||||
ERR_FAIL_COND(p_packet.size()!=4);
|
||||
Variant value = p_packet[3];
|
||||
bool valid;
|
||||
|
||||
node->set(name,value,&valid);
|
||||
|
@ -1979,9 +2064,13 @@ void SceneTree::_network_process_packet(int p_from, const Array& p_packet) {
|
|||
} break;
|
||||
case NETWORK_COMMAND_SIMPLIFY_PATH: {
|
||||
|
||||
ERR_FAIL_COND(p_packet.size()!=3);
|
||||
NodePath path = p_packet[1];
|
||||
int id = p_packet[2];
|
||||
ERR_FAIL_COND(p_packet_len<5);
|
||||
int id = decode_uint32(&p_packet[1]);
|
||||
|
||||
String paths;
|
||||
paths.parse_utf8((const char*)&p_packet[5],p_packet_len-5);
|
||||
|
||||
NodePath path = paths;
|
||||
|
||||
if (!path_get_cache.has(p_from)) {
|
||||
path_get_cache[p_from]=PathGetCache();
|
||||
|
@ -1993,19 +2082,31 @@ void SceneTree::_network_process_packet(int p_from, const Array& p_packet) {
|
|||
|
||||
path_get_cache[p_from].nodes[id]=ni;
|
||||
|
||||
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||
network_peer->set_target_peer(p_from);
|
||||
|
||||
Array message;
|
||||
message.resize(2);
|
||||
message[0]=NETWORK_COMMAND_CONFIRM_PATH;
|
||||
message[1]=path;
|
||||
network_peer->put_var(message);
|
||||
{
|
||||
//send ack
|
||||
|
||||
//encode path
|
||||
CharString pname = String(path).utf8();
|
||||
int len = encode_cstring(pname.get_data(),NULL);
|
||||
|
||||
Vector<uint8_t> packet;
|
||||
|
||||
packet.resize(1+len);
|
||||
packet[0]=NETWORK_COMMAND_CONFIRM_PATH;
|
||||
encode_cstring(pname.get_data(),&packet[1]);
|
||||
|
||||
network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
|
||||
network_peer->set_target_peer(p_from);
|
||||
network_peer->put_packet(packet.ptr(),packet.size());
|
||||
}
|
||||
} break;
|
||||
case NETWORK_COMMAND_CONFIRM_PATH: {
|
||||
|
||||
ERR_FAIL_COND(p_packet.size()!=2);
|
||||
NodePath path = p_packet[1];
|
||||
String paths;
|
||||
paths.parse_utf8((const char*)&p_packet[1],p_packet_len-1);
|
||||
|
||||
NodePath path = paths;
|
||||
|
||||
PathSentCache *psc = path_send_cache.getptr(path);
|
||||
ERR_FAIL_COND(!psc);
|
||||
|
@ -2031,17 +2132,15 @@ void SceneTree::_network_poll() {
|
|||
while(network_peer->get_available_packet_count()) {
|
||||
|
||||
int sender = network_peer->get_packet_peer();
|
||||
Variant packet;
|
||||
Error err = network_peer->get_var(packet);
|
||||
const uint8_t *packet;
|
||||
int len;
|
||||
|
||||
Error err = network_peer->get_packet(&packet,len);
|
||||
if (err!=OK) {
|
||||
ERR_PRINT("Error getting packet!");
|
||||
}
|
||||
if (packet.get_type()!=Variant::ARRAY) {
|
||||
|
||||
ERR_PRINT("Error getting packet! (not an array)");
|
||||
}
|
||||
|
||||
_network_process_packet(sender,packet);
|
||||
_network_process_packet(sender,packet,len);
|
||||
|
||||
if (!network_peer.is_valid()) {
|
||||
break; //it's also possible that a packet or RPC caused a disconnection, so also check here
|
||||
|
|
|
@ -217,7 +217,9 @@ private:
|
|||
|
||||
Map<int,PathGetCache> path_get_cache;
|
||||
|
||||
void _network_process_packet(int p_from, const Array& p_packet);
|
||||
Vector<uint8_t> packet_cache;
|
||||
|
||||
void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
|
||||
void _network_poll();
|
||||
|
||||
static SceneTree *singleton;
|
||||
|
|
Loading…
Reference in a new issue