Switched the Generic MLAPI message layer to BitWriter & BitReader
This commit is contained in:
parent
85ecca2af9
commit
4d28f3420e
@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
|||||||
using MLAPI.NetworkingManagerComponents.Cryptography;
|
using MLAPI.NetworkingManagerComponents.Cryptography;
|
||||||
using MLAPI.NetworkingManagerComponents.Core;
|
using MLAPI.NetworkingManagerComponents.Core;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
using MLAPI.NetworkingManagerComponents.Binary;
|
||||||
|
|
||||||
namespace MLAPI.MonoBehaviours.Core
|
namespace MLAPI.MonoBehaviours.Core
|
||||||
{
|
{
|
||||||
@ -821,28 +822,26 @@ namespace MLAPI.MonoBehaviours.Core
|
|||||||
|
|
||||||
private void HandleIncomingData(uint clientId, byte[] data, int channelId)
|
private void HandleIncomingData(uint clientId, byte[] data, int channelId)
|
||||||
{
|
{
|
||||||
using(MemoryStream readStream = new MemoryStream(data))
|
BitReader reader = new BitReader(data);
|
||||||
{
|
|
||||||
using (BinaryReader reader = new BinaryReader(readStream))
|
ushort messageType = reader.ReadUShort();
|
||||||
{
|
bool targeted = reader.ReadBool();
|
||||||
ushort messageType = reader.ReadUInt16();
|
|
||||||
bool targeted = reader.ReadBoolean();
|
|
||||||
uint targetNetworkId = 0;
|
uint targetNetworkId = 0;
|
||||||
ushort networkOrderId = 0;
|
ushort networkOrderId = 0;
|
||||||
if(targeted)
|
if (targeted)
|
||||||
{
|
{
|
||||||
targetNetworkId = reader.ReadUInt32();
|
targetNetworkId = reader.ReadUInt();
|
||||||
networkOrderId = reader.ReadUInt16();
|
networkOrderId = reader.ReadUShort();
|
||||||
}
|
}
|
||||||
bool isPassthrough = reader.ReadBoolean();
|
bool isPassthrough = reader.ReadBool();
|
||||||
|
|
||||||
uint passthroughOrigin = 0;
|
uint passthroughOrigin = 0;
|
||||||
uint passthroughTarget = 0;
|
uint passthroughTarget = 0;
|
||||||
|
|
||||||
if (isPassthrough && isServer)
|
if (isPassthrough && isServer)
|
||||||
passthroughTarget = reader.ReadUInt32();
|
passthroughTarget = reader.ReadUInt();
|
||||||
else if (isPassthrough && !isServer)
|
else if (isPassthrough && !isServer)
|
||||||
passthroughOrigin = reader.ReadUInt32();
|
passthroughOrigin = reader.ReadUInt();
|
||||||
|
|
||||||
|
|
||||||
//Client tried to send a network message that was not the connection request before he was accepted.
|
//Client tried to send a network message that was not the connection request before he was accepted.
|
||||||
@ -853,9 +852,11 @@ namespace MLAPI.MonoBehaviours.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ushort bytesToRead = reader.ReadUInt16();
|
//ushort bytesToRead = reader.ReadUShort();
|
||||||
byte[] incommingData = reader.ReadBytes(bytesToRead);
|
reader.SkipPadded();
|
||||||
if(NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId]))
|
|
||||||
|
byte[] incommingData = reader.ReadByteArray();
|
||||||
|
if (NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId]))
|
||||||
{
|
{
|
||||||
//Encrypted message
|
//Encrypted message
|
||||||
if (isServer)
|
if (isServer)
|
||||||
@ -869,12 +870,12 @@ namespace MLAPI.MonoBehaviours.Core
|
|||||||
Debug.LogWarning("MLAPI: Client " + clientId + " tried to send a passthrough message for a messageType not registered as passthrough");
|
Debug.LogWarning("MLAPI: Client " + clientId + " tried to send a passthrough message for a messageType not registered as passthrough");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(isClient && isPassthrough && !NetworkConfig.PassthroughMessageHashSet.Contains(messageType))
|
else if (isClient && isPassthrough && !NetworkConfig.PassthroughMessageHashSet.Contains(messageType))
|
||||||
{
|
{
|
||||||
Debug.LogWarning("MLAPI: Server tried to send a passthrough message for a messageType not registered as passthrough");
|
Debug.LogWarning("MLAPI: Server tried to send a passthrough message for a messageType not registered as passthrough");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(isServer && isPassthrough)
|
else if (isServer && isPassthrough)
|
||||||
{
|
{
|
||||||
if (!connectedClients.ContainsKey(passthroughTarget))
|
if (!connectedClients.ContainsKey(passthroughTarget))
|
||||||
{
|
{
|
||||||
@ -896,7 +897,7 @@ namespace MLAPI.MonoBehaviours.Core
|
|||||||
{
|
{
|
||||||
#region CUSTOM MESSAGE
|
#region CUSTOM MESSAGE
|
||||||
//Custom message, invoke all message handlers
|
//Custom message, invoke all message handlers
|
||||||
if(targeted)
|
if (targeted)
|
||||||
{
|
{
|
||||||
if (!SpawnManager.spawnedObjects.ContainsKey(targetNetworkId))
|
if (!SpawnManager.spawnedObjects.ContainsKey(targetNetworkId))
|
||||||
{
|
{
|
||||||
@ -1015,8 +1016,6 @@ namespace MLAPI.MonoBehaviours.Core
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void DisconnectClient(uint clientId)
|
internal void DisconnectClient(uint clientId)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
using MLAPI.Data;
|
using MLAPI.Data;
|
||||||
using MLAPI.MonoBehaviours.Core;
|
using MLAPI.NetworkingManagerComponents.Binary;
|
||||||
using MLAPI.NetworkingManagerComponents.Cryptography;
|
using MLAPI.NetworkingManagerComponents.Cryptography;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
@ -20,41 +20,29 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizeOfStream = 10;
|
using (BitWriter writer = new BitWriter())
|
||||||
if (networkId != null)
|
{
|
||||||
sizeOfStream += 4;
|
writer.WriteUShort(messageType);
|
||||||
if (orderId != null)
|
writer.WriteBool(networkId != null);
|
||||||
sizeOfStream += 2;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write(messageType);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(true);
|
|
||||||
writer.Write(sourceId);
|
writer.WriteBool(true);
|
||||||
|
writer.WriteUInt(sourceId);
|
||||||
|
|
||||||
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId]))
|
if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId]))
|
||||||
{
|
writer.WriteByteArray(CryptographyHelper.Encrypt(data, netManager.connectedClients[targetId].AesKey));
|
||||||
//Encrypted message
|
|
||||||
byte[] encrypted = CryptographyHelper.Encrypt(data, netManager.connectedClients[targetId].AesKey);
|
|
||||||
writer.Write((ushort)encrypted.Length);
|
|
||||||
writer.Write(encrypted);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
writer.WriteByteArray(data);
|
||||||
writer.Write((ushort)data.Length);
|
|
||||||
writer.Write(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
byte error;
|
byte error;
|
||||||
NetworkTransport.QueueMessageForSending(targetNetId.HostId, targetNetId.ConnectionId, channelId, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(targetNetId.HostId, targetNetId.ConnectionId, channelId, writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,28 +68,23 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizeOfStream = 6;
|
using (BitWriter writer = new BitWriter())
|
||||||
if (networkId != null)
|
{
|
||||||
sizeOfStream += 4;
|
writer.WriteUShort(MessageManager.messageTypes[messageType]);
|
||||||
if (orderId != null)
|
writer.WriteBool(networkId != null);
|
||||||
sizeOfStream += 2;
|
|
||||||
if (isPassthrough)
|
|
||||||
sizeOfStream += 4;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write(MessageManager.messageTypes[messageType]);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(isPassthrough);
|
|
||||||
|
writer.WriteBool(isPassthrough);
|
||||||
|
|
||||||
if (isPassthrough)
|
if (isPassthrough)
|
||||||
writer.Write(clientId);
|
writer.WriteUInt(clientId);
|
||||||
|
|
||||||
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName))
|
if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName))
|
||||||
{
|
{
|
||||||
@ -112,23 +95,18 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
else
|
else
|
||||||
encrypted = CryptographyHelper.Encrypt(data, netManager.clientAesKey);
|
encrypted = CryptographyHelper.Encrypt(data, netManager.clientAesKey);
|
||||||
|
|
||||||
writer.Write((ushort)encrypted.Length);
|
writer.WriteByteArray(encrypted);
|
||||||
writer.Write(encrypted);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
writer.WriteByteArray(data);
|
||||||
//Send in plaintext.
|
|
||||||
writer.Write((ushort)data.Length);
|
|
||||||
writer.Write(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte error;
|
byte error;
|
||||||
if (isPassthrough)
|
if (isPassthrough)
|
||||||
netId = NetId.ServerNetId;
|
netId = NetId.ServerNetId;
|
||||||
if (skipQueue)
|
if (skipQueue)
|
||||||
NetworkTransport.Send(netId.HostId, netId.ConnectionId, MessageManager.channels[channelName], stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.Send(netId.HostId, netId.ConnectionId, MessageManager.channels[channelName], writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
else
|
else
|
||||||
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, MessageManager.channels[channelName], stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, MessageManager.channels[channelName], writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,27 +118,23 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizeOfStream = 6;
|
using (BitWriter writer = new BitWriter())
|
||||||
if (networkId != null)
|
{
|
||||||
sizeOfStream += 4;
|
writer.WriteUShort(MessageManager.messageTypes[messageType]);
|
||||||
if (orderId != null)
|
writer.WriteBool(networkId != null);
|
||||||
sizeOfStream += 2;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write(MessageManager.messageTypes[messageType]);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(false);
|
|
||||||
writer.Write((ushort)data.Length);
|
writer.WriteBool(false);
|
||||||
writer.Write(data);
|
|
||||||
}
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
|
writer.WriteByteArray(data);
|
||||||
|
|
||||||
int channel = MessageManager.channels[channelName];
|
int channel = MessageManager.channels[channelName];
|
||||||
for (int i = 0; i < clientIds.Length; i++)
|
for (int i = 0; i < clientIds.Length; i++)
|
||||||
{
|
{
|
||||||
@ -176,7 +150,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
netId = NetId.ServerNetId;
|
netId = NetId.ServerNetId;
|
||||||
}
|
}
|
||||||
byte error;
|
byte error;
|
||||||
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,28 +163,23 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
using (BitWriter writer = new BitWriter())
|
||||||
int sizeOfStream = 6;
|
{
|
||||||
if (networkId != null)
|
writer.WriteUShort(MessageManager.messageTypes[messageType]);
|
||||||
sizeOfStream += 4;
|
writer.WriteBool(networkId != null);
|
||||||
if (orderId != null)
|
|
||||||
sizeOfStream += 2;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write(MessageManager.messageTypes[messageType]);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(false);
|
|
||||||
writer.Write((ushort)data.Length);
|
writer.WriteBool(false);
|
||||||
writer.Write(data);
|
|
||||||
}
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
|
writer.WriteByteArray(data);
|
||||||
|
|
||||||
int channel = MessageManager.channels[channelName];
|
int channel = MessageManager.channels[channelName];
|
||||||
for (int i = 0; i < clientIds.Count; i++)
|
for (int i = 0; i < clientIds.Count; i++)
|
||||||
{
|
{
|
||||||
@ -226,7 +195,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
netId = NetId.ServerNetId;
|
netId = NetId.ServerNetId;
|
||||||
}
|
}
|
||||||
byte error;
|
byte error;
|
||||||
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,29 +209,23 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
using (BitWriter writer = new BitWriter())
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
|
||||||
int sizeOfStream = 6;
|
|
||||||
if (networkId != null)
|
|
||||||
sizeOfStream += 4;
|
|
||||||
if (orderId != null)
|
|
||||||
sizeOfStream += 2;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
{
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
writer.WriteUShort(MessageManager.messageTypes[messageType]);
|
||||||
{
|
writer.WriteBool(networkId != null);
|
||||||
writer.Write(MessageManager.messageTypes[messageType]);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(false);
|
|
||||||
writer.Write((ushort)data.Length);
|
writer.WriteBool(false);
|
||||||
writer.Write(data);
|
|
||||||
}
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
|
writer.WriteByteArray(data);
|
||||||
|
|
||||||
int channel = MessageManager.channels[channelName];
|
int channel = MessageManager.channels[channelName];
|
||||||
foreach (KeyValuePair<uint, NetworkedClient> pair in netManager.connectedClients)
|
foreach (KeyValuePair<uint, NetworkedClient> pair in netManager.connectedClients)
|
||||||
{
|
{
|
||||||
@ -278,7 +241,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
netId = NetId.ServerNetId;
|
netId = NetId.ServerNetId;
|
||||||
}
|
}
|
||||||
byte error;
|
byte error;
|
||||||
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,28 +254,23 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
using (BitWriter writer = new BitWriter())
|
||||||
int sizeOfStream = 5;
|
{
|
||||||
if (networkId != null)
|
writer.WriteUShort(MessageManager.messageTypes[messageType]);
|
||||||
sizeOfStream += 4;
|
writer.WriteBool(networkId != null);
|
||||||
if (orderId != null)
|
|
||||||
sizeOfStream += 2;
|
|
||||||
sizeOfStream += data.Length;
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream(sizeOfStream))
|
|
||||||
{
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write(MessageManager.messageTypes[messageType]);
|
|
||||||
writer.Write(networkId != null);
|
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
writer.Write(networkId.Value);
|
writer.WriteUInt(networkId.Value);
|
||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
writer.Write(orderId.Value);
|
writer.WriteUShort(orderId.Value);
|
||||||
writer.Write(false);
|
|
||||||
writer.Write((ushort)data.Length);
|
writer.WriteBool(false);
|
||||||
writer.Write(data);
|
|
||||||
}
|
writer.WriteAlignBits();
|
||||||
|
|
||||||
|
writer.WriteByteArray(data);
|
||||||
|
|
||||||
int channel = MessageManager.channels[channelName];
|
int channel = MessageManager.channels[channelName];
|
||||||
foreach (KeyValuePair<uint, NetworkedClient> pair in netManager.connectedClients)
|
foreach (KeyValuePair<uint, NetworkedClient> pair in netManager.connectedClients)
|
||||||
{
|
{
|
||||||
@ -331,7 +289,7 @@ namespace MLAPI.NetworkingManagerComponents.Core
|
|||||||
netId = NetId.ServerNetId;
|
netId = NetId.ServerNetId;
|
||||||
}
|
}
|
||||||
byte error;
|
byte error;
|
||||||
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(netId.HostId, netId.ConnectionId, channel, writer.Finalize(), (int)writer.GetFinalizeSize(), out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user