Update Connections to use UID, ensure package readiness on sending

This commit is contained in:
Sofia 2020-08-05 20:39:52 +03:00
parent 0c35bf8d50
commit d26ed426cf
8 changed files with 133 additions and 209 deletions

View File

@ -34,10 +34,12 @@ namespace NeonTea.Quakeball.Net {
Net.Singleton.Stop(); Net.Singleton.Stop();
}); });
Send.onClick.AddListener(() => { Send.onClick.AddListener(() => {
if (Net.Singleton.Peer != null && Net.Singleton.Connections.Count > 0) { if (Net.Singleton.Peer != null) {
HelloPckt pckt = new HelloPckt(); foreach (ulong uid in Net.Singleton.Connections) {
pckt.Text = MessageField.text; HelloPckt pckt = new HelloPckt();
Net.Singleton.Peer.SendReliable(Net.Singleton.Connections[0], pckt); pckt.Text = MessageField.text;
Net.Singleton.Peer.SendReliable(uid, pckt);
}
} }
}); });
} }

View File

@ -9,7 +9,7 @@ namespace NeonTea.Quakeball.Net {
private static byte[] FP = new byte[] { 0xFF, 0xF7 }; private static byte[] FP = new byte[] { 0xFF, 0xF7 };
public Peer Peer; public Peer Peer;
public List<Connection> Connections = new List<Connection>(); public List<ulong> Connections = new List<ulong>();
public bool IsServer = false; public bool IsServer = false;

View File

@ -10,7 +10,7 @@ namespace NeonTea.Quakeball.Net {
public class TestProtocol : Protocol { public class TestProtocol : Protocol {
public override byte Identifier => 0x7A; public override byte Identifier => 0x7A;
public override string Version => "0.0.2"; public override string Version => "0.0.1";
public TestProtocol() { public TestProtocol() {
RegisterPacket(typeof(HelloPckt)); RegisterPacket(typeof(HelloPckt));
@ -18,11 +18,14 @@ namespace NeonTea.Quakeball.Net {
public override void ConnectionStatusChanged(ConnectionStatus oldStatus, ConnectionStatus newStatus, Connection conn) { public override void ConnectionStatusChanged(ConnectionStatus oldStatus, ConnectionStatus newStatus, Connection conn) {
Peer.MessageListener.Message($"Connection Status Changed into {newStatus.ToString()} for {conn.Endpoint}"); Peer.MessageListener.Message($"Connection Status Changed into {newStatus.ToString()} for {conn.Endpoint}");
if (newStatus == ConnectionStatus.Ready && !Net.Singleton.Connections.Contains(conn)) { if (conn.IsReady() && !Net.Singleton.Connections.Contains(conn.uid)) {
Net.Singleton.Connections.Add(conn); Net.Singleton.Connections.Add(conn.uid);
} else if (newStatus == ConnectionStatus.Closed) { } else if (newStatus == ConnectionStatus.Closed) {
Net.Singleton.Peer.MessageListener.Message($"Conncection closed: {conn.ClosingReason}"); Net.Singleton.Peer.MessageListener.Message($"Conncection closed: {conn.ClosingReason}");
} }
if (conn.IsDisconnected()) {
Net.Singleton.Connections.Remove(conn.uid);
}
} }
public override void Receive(Connection conn, Packet packet) { public override void Receive(Connection conn, Packet packet) {

View File

@ -20,8 +20,8 @@ namespace NeonTea.Quakeball.TeaNet.Packets {
public abstract void Timeout(Connection conn); public abstract void Timeout(Connection conn);
public void SendPacket(Packet p, Connection conn) { public void SendPacket(Packet p, Connection conn) {
Peer.ConnectionManager.AddPacketToQueue(conn, p); Peer.ConnectionManager.AddPacketToQueue(conn.uid, p);
Peer.ConnectionManager.SendPacketQueue(conn); Peer.ConnectionManager.SendPacketQueue(conn.uid);
} }
public int RegisterPacket(Type t) { public int RegisterPacket(Type t) {
@ -50,7 +50,7 @@ namespace NeonTea.Quakeball.TeaNet.Packets {
buffer.Write((byte)connection.ClosingReason); buffer.Write((byte)connection.ClosingReason);
} else if (connection.Status == ConnectionStatus.Ready) { } else if (connection.Status == ConnectionStatus.Ready) {
buffer.Write((byte)PacketStage.Ready); buffer.Write((byte)PacketStage.Ready);
buffer.WriteInt(connection.LatestInwardReliable); buffer.WriteInt(connection.Internal.LatestInwardReliable);
} }
return buffer; return buffer;
} }

View File

@ -9,24 +9,44 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
public class Connection { public class Connection {
public IPEndPoint Endpoint; public IPEndPoint Endpoint;
public ulong uid;
public ConnectionStatus Status; public ConnectionStatus Status;
public byte AssignedProtocol;
public ClosingReason ClosingReason; public ClosingReason ClosingReason;
public long LastMessage; public ConnectionInternalData Internal = new ConnectionInternalData();
public int LatestOutwardReliable = -1; // Last reliable Packet ID the connection has told us they have
public int LatestOutwardUnreliable = -1; // Last unreliablePacket ID the connection has told us they have
public int LatestInwardReliable = -1; // Last reliable Packet ID we've received from the connection
public int LatestInwardUnreliable = -1; // Last unreliable Packet ID we've received from the connection
public int ReliablePacketIDCounter; // Reliable Packet ID counter for packets we're sending them
public int UnreliablePacketIDCounter; // Unreliable Packet ID counter for packets we're sending them
public Connection(IPEndPoint endpoint, ConnectionStatus status = ConnectionStatus.Establishing) { public Connection(IPEndPoint endpoint, ConnectionStatus status = ConnectionStatus.Establishing) {
Endpoint = endpoint; Endpoint = endpoint;
Status = status; Status = status;
LastMessage = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
Internal.LastMessage = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
Internal.LatestInwardReliable = -1;
Internal.LatestInwardUnreliable = -1;
Internal.LatestOutwardReliable = -1;
Internal.LatestOutwardUnreliable = -1;
} }
public bool IsReady() {
return Status == ConnectionStatus.Ready;
}
public bool IsDisconnected() {
return !(Status == ConnectionStatus.Ready
|| Status == ConnectionStatus.Awaiting
|| Status == ConnectionStatus.Establishing);
}
}
public struct ConnectionInternalData {
public byte AssignedProtocol;
public long LastMessage;
public int LatestOutwardReliable; // Last reliable Packet ID the connection has told us they have
public int LatestOutwardUnreliable; // Last unreliablePacket ID the connection has told us they have
public int LatestInwardReliable; // Last reliable Packet ID we've received from the connection
public int LatestInwardUnreliable; // Last unreliable Packet ID we've received from the connection
public int ReliablePacketIDCounter; // Reliable Packet ID counter for packets we're sending them
public int UnreliablePacketIDCounter; // Unreliable Packet ID counter for packets we're sending them
} }
public enum ConnectionStatus { public enum ConnectionStatus {

View File

@ -7,8 +7,10 @@ using NeonTea.Quakeball.TeaNet.Packets;
namespace NeonTea.Quakeball.TeaNet.Peers { namespace NeonTea.Quakeball.TeaNet.Peers {
public class ConnectionManager { public class ConnectionManager {
private Dictionary<IPEndPoint, Connection> Connections = new Dictionary<IPEndPoint, Connection>(); private ulong ConnectionCounter;
private Dictionary<Connection, List<Packet>> PacketQueue = new Dictionary<Connection, List<Packet>>(); private Dictionary<ulong, Connection> Connections = new Dictionary<ulong, Connection>();
private Dictionary<IPEndPoint, ulong> IPtoID = new Dictionary<IPEndPoint, ulong>();
private Dictionary<ulong, List<Packet>> PacketQueue = new Dictionary<ulong, List<Packet>>();
private Peer Peer; private Peer Peer;
private Thread UpdateThread; private Thread UpdateThread;
@ -27,36 +29,47 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
} }
public Connection Find(IPEndPoint endpoint) { public Connection Find(IPEndPoint endpoint) {
if (Connections.ContainsKey(endpoint)) { if (IPtoID.ContainsKey(endpoint)) {
return Connections[endpoint]; return Connections[IPtoID[endpoint]];
} }
Connection conn = new Connection(endpoint, ConnectionStatus.Awaiting); Connection conn = new Connection(endpoint, ConnectionStatus.Awaiting);
Connections.Add(endpoint, conn); AddConnection(conn);
PacketQueue.Add(conn, new List<Packet>());
return conn; return conn;
} }
public bool StartConnection(IPEndPoint endpoint, byte protocolIdent) { public bool StartConnection(IPEndPoint endpoint, byte protocolIdent) {
if (Connections.ContainsKey(endpoint)) { if (IPtoID.ContainsKey(endpoint)) {
return false; return false;
} }
Connection conn = new Connection(endpoint); Connection conn = new Connection(endpoint);
conn.AssignedProtocol = protocolIdent; conn.Internal.AssignedProtocol = protocolIdent;
Connections.Add(endpoint, conn); AddConnection(conn);
PacketQueue.Add(conn, new List<Packet>());
return true; return true;
} }
public void AddPacketToQueue(Connection conn, Packet p) { public Connection GetConnection(ulong uid) {
p.Id = conn.ReliablePacketIDCounter++; Connection conn;
PacketQueue[conn].Add(p); Connections.TryGetValue(uid, out conn);
return conn;
} }
public void SendPacketQueue(Connection conn) { public void AddPacketToQueue(ulong uid, Packet p) {
Protocol protocol = Peer.GetProtocol(conn.AssignedProtocol); if (!Connections.ContainsKey(uid)) {
if (protocol != null) { return;
}
p.Id = Connections[uid].Internal.ReliablePacketIDCounter++;
PacketQueue[uid].Add(p);
}
public void SendPacketQueue(ulong uid) {
if (!Connections.ContainsKey(uid)) {
return;
}
Connection conn = Connections[uid];
Protocol protocol = Peer.GetProtocol(conn.Internal.AssignedProtocol);
if (protocol != null && conn.IsReady()) {
ByteBuffer buffer = protocol.BuildMessage(conn); ByteBuffer buffer = protocol.BuildMessage(conn);
List<Packet> list = PacketQueue[conn]; List<Packet> list = PacketQueue[uid];
buffer.WriteInt(list.Count); buffer.WriteInt(list.Count);
foreach (Packet p in list) { foreach (Packet p in list) {
buffer.WritePacket(protocol, p); buffer.WritePacket(protocol, p);
@ -65,11 +78,15 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
} }
} }
public void SendSingleUnreliable(Connection conn, Packet p) { public void SendSingleUnreliable(ulong uid, Packet p) {
p.Id = conn.UnreliablePacketIDCounter++; if (!Connections.ContainsKey(uid)) {
return;
}
Connection conn = Connections[uid];
p.Id = conn.Internal.UnreliablePacketIDCounter++;
p.Reliable = false; p.Reliable = false;
Protocol protocol = Peer.GetProtocol(conn.AssignedProtocol); Protocol protocol = Peer.GetProtocol(conn.Internal.AssignedProtocol);
if (protocol != null) { if (protocol != null && conn.IsReady()) {
ByteBuffer buffer = protocol.BuildMessage(conn); ByteBuffer buffer = protocol.BuildMessage(conn);
buffer.WriteInt(1); buffer.WriteInt(1);
buffer.WritePacket(protocol, p); buffer.WritePacket(protocol, p);
@ -77,8 +94,21 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
} }
} }
private void AddConnection(Connection conn) {
conn.uid = ConnectionCounter++;
Connections.Add(conn.uid, conn);
IPtoID.Add(conn.Endpoint, conn.uid);
PacketQueue.Add(conn.uid, new List<Packet>());
}
private void RemoveConnection(Connection conn) {
Connections.Remove(conn.uid);
IPtoID.Remove(conn.Endpoint);
PacketQueue.Remove(conn.uid);
}
private void SendPlain(Connection conn) { private void SendPlain(Connection conn) {
Protocol protocol = Peer.GetProtocol(conn.AssignedProtocol); Protocol protocol = Peer.GetProtocol(conn.Internal.AssignedProtocol);
if (protocol != null) { if (protocol != null) {
ByteBuffer buffer = protocol.BuildMessage(conn); ByteBuffer buffer = protocol.BuildMessage(conn);
Send(conn, buffer); Send(conn, buffer);
@ -96,7 +126,7 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
public void Handle(IPEndPoint endpoint, ByteBuffer buffer) { public void Handle(IPEndPoint endpoint, ByteBuffer buffer) {
Connection conn = Find(endpoint); Connection conn = Find(endpoint);
conn.LastMessage = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); conn.Internal.LastMessage = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
ConnectionStatus oldStatus = conn.Status; ConnectionStatus oldStatus = conn.Status;
byte protocolId = buffer.Read(); byte protocolId = buffer.Read();
Protocol protocol = Peer.GetProtocol(protocolId); Protocol protocol = Peer.GetProtocol(protocolId);
@ -104,7 +134,7 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
switch (stage) { switch (stage) {
case PacketStage.Establishing: case PacketStage.Establishing:
if (conn.Status == ConnectionStatus.Awaiting) { if (conn.Status == ConnectionStatus.Awaiting) {
conn.AssignedProtocol = protocolId; conn.Internal.AssignedProtocol = protocolId;
string version = buffer.ReadString(); string version = buffer.ReadString();
if (protocol == null || !version.Equals(protocol.Version)) { if (protocol == null || !version.Equals(protocol.Version)) {
conn.Status = ConnectionStatus.Rejected; conn.Status = ConnectionStatus.Rejected;
@ -134,29 +164,29 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
} }
break; break;
case PacketStage.Ready: case PacketStage.Ready:
if (conn.AssignedProtocol != protocolId || protocol == null) { if (conn.Internal.AssignedProtocol != protocolId || protocol == null) {
break; break;
} }
if (oldStatus == ConnectionStatus.Establishing) { // Update connection status if (oldStatus == ConnectionStatus.Establishing) { // Update connection status
conn.Status = ConnectionStatus.Ready; conn.Status = ConnectionStatus.Ready;
protocol.ConnectionStatusChanged(oldStatus, conn.Status, conn); protocol.ConnectionStatusChanged(oldStatus, conn.Status, conn);
} }
conn.LatestOutwardReliable = buffer.ReadInt(); conn.Internal.LatestOutwardReliable = buffer.ReadInt();
List<Packet> list = PacketQueue[conn]; List<Packet> list = PacketQueue[conn.uid];
list.RemoveAll(p => p.Id <= conn.LatestOutwardReliable); list.RemoveAll(p => p.Id <= conn.Internal.LatestOutwardReliable);
PacketQueue[conn] = list; PacketQueue[conn.uid] = list;
int PacketAmount = buffer.ReadInt(); int PacketAmount = buffer.ReadInt();
for (int i = 0; i < PacketAmount; i++) { for (int i = 0; i < PacketAmount; i++) {
Packet p = buffer.ReadPacket(protocol); Packet p = buffer.ReadPacket(protocol);
if (p.Reliable) { if (p.Reliable) {
if (p.Id > conn.LatestInwardReliable) { if (p.Id > conn.Internal.LatestInwardReliable) {
conn.LatestInwardReliable = p.Id; conn.Internal.LatestInwardReliable = p.Id;
protocol.Receive(conn, p); protocol.Receive(conn, p);
} }
} else if (p.Id > conn.LatestInwardUnreliable) { } else if (p.Id > conn.Internal.LatestInwardUnreliable) {
conn.LatestInwardUnreliable = p.Id; conn.Internal.LatestInwardUnreliable = p.Id;
protocol.Receive(conn, p); protocol.Receive(conn, p);
} }
} }
@ -168,30 +198,30 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
try { try {
while (Thread.CurrentThread.IsAlive) { while (Thread.CurrentThread.IsAlive) {
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
List<KeyValuePair<IPEndPoint, Connection>> timedOut = new List<KeyValuePair<IPEndPoint, Connection>>(); List<ulong> timedOut = new List<ulong>();
foreach (KeyValuePair<IPEndPoint, Connection> pair in Connections) { foreach (ulong uid in Connections.Keys) {
Connection conn = pair.Value; Connection conn = Connections[uid];
if ((now - conn.LastMessage) > Timeout || conn.Status == ConnectionStatus.Lost) { if ((now - conn.Internal.LastMessage) > Timeout || conn.Status == ConnectionStatus.Lost) {
timedOut.Add(pair); timedOut.Add(uid);
} }
if (conn.Status != ConnectionStatus.Awaiting || conn.Status != ConnectionStatus.Stopped) { if (conn.Status != ConnectionStatus.Awaiting || conn.Status != ConnectionStatus.Stopped) {
if (conn.Status == ConnectionStatus.Ready) { if (conn.Status == ConnectionStatus.Ready) {
SendPacketQueue(conn); SendPacketQueue(uid);
} else { } else {
SendPlain(conn); SendPlain(conn);
} }
} }
} }
foreach (KeyValuePair<IPEndPoint, Connection> pair in timedOut) { foreach (ulong uid in timedOut) {
Connections.Remove(pair.Key); Connection conn = Connections[uid];
PacketQueue.Remove(pair.Value); RemoveConnection(conn);
if (pair.Value.Status == ConnectionStatus.Ready if (conn.Status == ConnectionStatus.Ready
|| pair.Value.Status == ConnectionStatus.Establishing || conn.Status == ConnectionStatus.Establishing
|| pair.Value.Status == ConnectionStatus.Awaiting || conn.Status == ConnectionStatus.Awaiting
|| pair.Value.Status == ConnectionStatus.Lost) { || conn.Status == ConnectionStatus.Lost) {
Protocol protocol = Peer.GetProtocol(pair.Value.AssignedProtocol); Protocol protocol = Peer.GetProtocol(conn.Internal.AssignedProtocol);
if (protocol != null) { if (protocol != null) {
protocol.Timeout(pair.Value); protocol.Timeout(conn);
} }
} }
} }

View File

@ -58,13 +58,17 @@ namespace NeonTea.Quakeball.TeaNet.Peers {
MessageListener.Message($"Connecting to {endpoint}"); MessageListener.Message($"Connecting to {endpoint}");
} }
public void SendReliable(Connection conn, Packet packet) { public void SendReliable(ulong uid, Packet packet) {
ConnectionManager.AddPacketToQueue(conn, packet); ConnectionManager.AddPacketToQueue(uid, packet);
ConnectionManager.SendPacketQueue(conn); ConnectionManager.SendPacketQueue(uid);
} }
public void SendUnreliable(Connection conn, Packet packet) { public void SendUnreliable(ulong uid, Packet packet) {
ConnectionManager.SendSingleUnreliable(conn, packet); ConnectionManager.SendSingleUnreliable(uid, packet);
}
public Connection GetConnection(ulong uid) {
return ConnectionManager.GetConnection(uid);
} }
public byte RegisterProtocol(Protocol protocol) { public byte RegisterProtocol(Protocol protocol) {

View File

@ -18,11 +18,6 @@
"key": "log.path", "key": "log.path",
"value": "{\"m_Value\":\"ProBuilderLog.txt\"}" "value": "{\"m_Value\":\"ProBuilderLog.txt\"}"
}, },
{
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "VertexColorPalette.previousColorPalette",
"value": "{\"m_Value\":\"Assets/ProBuilder Data/Default Color Palette.asset\"}"
},
{ {
"type": "UnityEngine.ProBuilder.SemVer, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "type": "UnityEngine.ProBuilder.SemVer, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "about.identifier", "key": "about.identifier",
@ -37,136 +32,6 @@
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "lightmapping.autoUnwrapLightmapUV", "key": "lightmapping.autoUnwrapLightmapUV",
"value": "{\"m_Value\":true}" "value": "{\"m_Value\":true}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "mesh.newShapesSnapToGrid",
"value": "{\"m_Value\":true}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "editor.autoRecalculateCollisions",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "mesh.meshColliderIsConvex",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "UnityEngine.ProBuilder.ProBuilderEditor-isUtilityWindow",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "editor.backFaceSelectEnabled",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "editor.toolbarIconGUI",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "editor.showSceneInfo",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "editor.showEditorNotifications",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "GrowSelection.useAngle",
"value": "{\"m_Value\":true}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "GrowSelection.iterativeGrow",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "smoothing.showPreview",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "smoothing.showNormals",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "smoothing.showSettings",
"value": "{\"m_Value\":false}"
},
{
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "smoothing.showHelp",
"value": "{\"m_Value\":false}"
},
{
"type": "UnityEngine.ProBuilder.PivotLocation, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "mesh.newShapePivotLocation",
"value": "{\"m_Value\":1}"
},
{
"type": "UnityEngine.Rendering.ShadowCastingMode, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "mesh.shadowCastingMode",
"value": "{\"m_Value\":1}"
},
{
"type": "UnityEngine.Material, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "mesh.userMaterial",
"value": "{\"m_Value\":{\"instanceID\":0}}"
},
{
"type": "UnityEditor.StaticEditorFlags, UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "mesh.defaultStaticEditorFlags",
"value": "{\"m_Value\":0}"
},
{
"type": "UnityEngine.ProBuilder.ColliderType, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "mesh.newShapeColliderType",
"value": "{\"m_Value\":2}"
},
{
"type": "UnityEngine.ProBuilder.UnwrapParameters, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "lightmapping.defaultLightmapUnwrapParameters",
"value": "{\"m_Value\":{\"m_HardAngle\":88.0,\"m_PackMargin\":20.0,\"m_AngleError\":8.0,\"m_AreaError\":15.0}}"
},
{
"type": "UnityEngine.ProBuilder.SelectionModifierBehavior, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "editor.rectSelectModifier",
"value": "{\"m_Value\":2}"
},
{
"type": "UnityEngine.ProBuilder.RectSelectMode, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "editor.dragSelectRectMode",
"value": "{\"m_Value\":0}"
},
{
"type": "UnityEngine.ProBuilder.SelectMode, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "editor.selectMode",
"value": "{\"m_Value\":1}"
},
{
"type": "UnityEngine.ProBuilder.ExtrudeMethod, Unity.ProBuilder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "editor.extrudeMethod",
"value": "{\"m_Value\":2}"
},
{
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "ExtrudeFaces.distance",
"value": "{\"m_Value\":0.5}"
},
{
"type": "System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "GrowSelection.angleValue",
"value": "{\"m_Value\":15.0}"
} }
] ]
} }