เมื่อพัฒนาเกมแบบผู้เล่นหลายคนด้วย PUN2 จะมีกรณีที่การส่งประเภทที่กำหนดเอง เช่น โครงสร้างหรือคลาสที่ผู้ใช้กำหนดผ่าน RPC และเหตุการณ์ ฯลฯ อย่างไรก็ตาม PUN2 ไม่อนุญาตให้ส่งประเภทที่กำหนดเองเหล่านี้ไปยังเครือข่ายโดยตรง แต่ PUN2 จัดเตรียมวิธีการลงทะเบียนประเภทแบบกำหนดเองไว้เป็นวิธีแก้ปัญหา
สำหรับการใช้วิธีการลงทะเบียนประเภทแบบกำหนดเองของ PUN2 ประเภทแบบกำหนดเองจะต้องถูกทำให้เป็นอนุกรมในอาร์เรย์ไบต์ ในหลายกรณี การทำให้เป็นอนุกรมไบต์จะดำเนินการโดยใช้ Binary Formatter อย่างไรก็ตาม Binary Formatter จะสร้างไบต์เพิ่มเติมจำนวนมาก ซึ่งจะส่งผลกระทบต่อการรับส่งข้อมูลสำหรับเกมที่ใช้เครือข่ายมาก และมอบประสบการณ์ที่ไม่ดีสำหรับผู้ใช้มือถือที่ไม่สามารถใช้การเชื่อมต่อ WiFi ฟรีได้ นอกจากนี้ Binary Formatter ไม่สามารถทำให้ Vector2, Vector3, Quaternion และอื่นๆ ของ Unity เป็นอนุกรมได้
ไฟล์เก็บถาวรนี้จัดเตรียมวิธีการลงทะเบียนประเภทแบบกำหนดเองพร้อมสคริปต์ และเปรียบเทียบความแตกต่างกับวิธีการซีเรียลไลซ์อื่น ๆ
โครงสร้างที่กำหนดจะถูกทำให้เป็นอนุกรมด้วย Binary Formatter และขนาดจะถูกวัดโดย Marshal โปรดทราบว่าจะไม่รวมออบเจ็กต์ Unity เช่น Vector3, Quaternion และอื่นๆ เนื่องจากไม่สามารถทำให้เป็นอนุกรมโดย Binary Formatter
public struct TestStruct
{
public int int_1 ;
public int int_2 ;
public string string_1 ;
public float float_1 ;
public float float_2 ;
}
TestStruct testStruct = new TestStruct
{
int_1 = 30 ,
int_2 = 71 ,
string_1 = " ABC가나다 " ,
float_1 = 0.162f ,
float_2 = 62f ,
} ;
การเรียงลำดับโครงสร้างและขนาดการวัดมีดังนี้:
public void BinaryFormatterSerialize ( TestStruct testStruct )
{
byte [ ] bytes ;
MemoryStream memoryStream = new MemoryStream ( ) ;
BinaryFormatter binaryFormatter = new BinaryFormatter ( ) ;
binaryFormatter . Serialize ( memoryStream , testStruct ) ;
memoryStream . Close ( ) ;
bytes = memoryStream . ToArray ( ) ;
Debug . Log ( string . Format ( " Bianary Formatter Serialized Size : {0} bytes " , bytes . Length ) ) ;
}
public void CheckSize ( TestStruct testStruct )
{
Debug . Log ( string . Format ( " Original Size : {0} bytes " , Marshal . SizeOf ( testStruct ) ) ) ;
Debug . Log ( JsonUtility . ToJson ( testStruct , true ) ) ;
}
ผลลัพธ์จะเป็นดังนี้:
ขนาด(ไบต์) | |
---|---|
ต้นฉบับ | 24 ไบต์ |
ฟอร์แมตไบนารี | 199 ไบต์ |
ขนาดทางทฤษฎีของโครงสร้างที่กำหนดคือ 24 ไบต์ เมื่อโครงสร้างที่กำหนดถูกทำให้เป็นอนุกรมด้วย Binary Formatter จะมีขนาด 199 ไบต์ ซึ่งใหญ่กว่าขนาดตามทฤษฎีถึง 8 เท่า ซึ่งอาจนำไปสู่ค่าใช้จ่ายในการรับส่งข้อมูลเมื่อซีเรียลไลซ์และส่งไปยังเครือข่าย
โครงสร้างที่กำหนดข้างต้นจะถูกทำให้เป็นอนุกรมด้วย JsonUtility และแปลงเป็นไบต์ การจัดลำดับโครงสร้างมีดังนี้:
public void JsonSerialize ( TestStruct testStruct )
{
byte [ ] bytes = Encoding . UTF8 . GetBytes ( JsonUtility . ToJson ( testStruct ) ) ;
Debug . Log ( string . Format ( " JsonUtility Serialized Size : {0} bytes " , bytes . Length ) ) ;
}
ผลลัพธ์จะเป็นดังนี้:
ขนาด(ไบต์) | |
---|---|
ต้นฉบับ | 24 ไบต์ |
JsonUtility และการแปลงไบต์ | 94 ไบต์ |
เมื่อโครงสร้างที่กำหนดถูกทำให้เป็นอนุกรมด้วย JsonUtility และแปลงเป็นไบต์ ขนาดจะเป็น 94 ไบต์ ซึ่งใหญ่กว่าขนาดตามทฤษฎีประมาณ 4 เท่า ขนาดนี้สามารถลดลงได้โดยการทำให้ชื่อของตัวแปรสั้นลง เช่น เมื่อเปลี่ยนชื่อตัวแปรดังภาพด้านล่าง ผลลัพธ์จะเป็นดังนี้
public struct TestStruct
{
public int a ;
public int b ;
public string c ;
public float d ;
public float e ;
}
TestStruct testStruct = new TestStruct
{
a = 30 ,
b = 71 ,
c = " ABC가나다 " ,
d = 0.162f ,
e = 62f ,
} ;
ขนาด(ไบต์) | |
---|---|
ต้นฉบับ | 24 ไบต์ |
JsonUtility และการแปลงไบต์ | 67 ไบต์ |
ขนาดของไบต์จะลดลงจาก 94 ไบต์เป็น 67 ไบต์ อย่างไรก็ตาม มันยังคงมีขนาดใหญ่กว่าขนาดทางทฤษฎีที่ 24 ไบต์
ไฟล์เก็บถาวรนี้แนะนำซีเรียลไลเซอร์แบบกำหนดเองซึ่งสามารถทำให้ซีเรียลไลซ์ประเภทที่กำหนดเองได้ เช่น โครงสร้างหรือคลาสที่ผู้ใช้กำหนด ตัวซีเรียลไลเซอร์นี้สามารถให้ขนาดที่ใกล้เคียงกับขนาดทางทฤษฎีได้ ประเภทและขนาดที่ต่อเนื่องได้มีดังนี้:
พิมพ์ | ขนาด(ไบต์) |
---|---|
ไบต์ | 1 ไบต์ |
ไบต์[] | 4 + (1 * ความยาว) ไบต์ |
บูล | 1 ไบต์ |
บูล[] | 4 + (1 * ความยาว) ไบต์ |
ภายใน | 4 ไบต์ |
อินท์[] | 4 + (4 * ความยาว) ไบต์ |
ลอย | 4 ไบต์ |
ลอย[] | 4 + (4 * ความยาว) ไบต์ |
เวกเตอร์2 | 8 ไบต์ |
เวกเตอร์2[] | 4 + (8 * ความยาว) ไบต์ |
เวกเตอร์3 | 12 ไบต์ |
เวกเตอร์3[] | 4 + (12 * ความยาว) ไบต์ |
ควอเทอร์เนียน | 16 ไบต์ |
ควอเทอร์เนียน[] | 4 + (16 * ความยาว) ไบต์ |
เชือก | 4 + α (การเข้ารหัส UTF8) ไบต์ |
สตริง[] | 4 + ((4 + α) * ความยาว) ไบต์ |
ก่อนอื่นให้ประกาศโดยใช้ MSLIMA.Serializer ด้านบน
using MSLIMA.Serializer;
จากนั้น สมมุติว่าได้รับโครงสร้างดังนี้
public struct TestStruct
{
public int int_1 ;
public int int_2 ;
public float float_1 ;
public bool bool_1 ;
public string string_1 ;
public Vector3 vector3_1 ;
public Vector3 vector3_2 ;
public Quaternion quaternion_1 ;
}
TestStruct testStruct = new TestStruct
{
int_1 = 30 ,
int_2 = 71 ,
float_1 = 0.162f ,
bool_1 = true ,
string_1 = " ABC가나다 " ,
vector3_1 = new Vector3 ( - 23f , 62f , 26f ) ,
vector3_2 = new Vector3 ( 1f , 7f , - 15f ) ,
quaternion_1 = Quaternion . Euler ( 35f , 0f , 15f )
} ;
ขั้นแรก สร้างวิธีการคงที่โดยใช้ชื่อ "Serialize" และ "Deserialize" ภายในประเภทที่กำหนดเอง วิธีการ "ซีเรียลไลซ์" มีพารามิเตอร์หนึ่งตัวพร้อมประเภทของอ็อบเจ็กต์และประเภทส่งคืนพร้อมประเภทไบต์ [] วิธีการ "ดีซีเรียลไลซ์" มีหนึ่งพารามิเตอร์ที่มีประเภทไบต์ [] และประเภทส่งคืนของวัตถุ
โปรดทราบว่าชื่อของวิธีการ พารามิเตอร์ และประเภทการส่งคืนจะต้องเหมือนกับที่อธิบายไว้ นอกจากนี้วิธีการเหล่านี้จะต้องคงที่
public static byte [ ] Serialize ( object customObject )
{
}
public static object Deserialize ( byte [ ] bytes )
{
}
ประการที่สอง แคสต์ customObject เป็นประเภทที่กำหนดเอง ประกาศอาร์เรย์ไบต์ในวิธี "ซีเรียลไลซ์"
public static byte [ ] Serialize ( object customObject )
{
TestStruct o = ( TestStruct ) customObject ;
byte [ ] bytes = new byte [ 0 ] ;
}
ตอนนี้ให้ใช้วิธีการของ Serializer เพื่อทำให้ฟิลด์ที่ต้องการเป็นอนุกรมและส่งคืนไบต์ในที่สุด โปรดทราบว่าอาร์เรย์ไบต์จะถูกส่งผ่านด้วยคีย์เวิร์ด ref
public static byte [ ] Serialize ( object customObject )
{
.. .
Serializer . Serialize ( o . int_1 , ref bytes ) ;
Serializer . Serialize ( o . int_2 , ref bytes ) ;
Serializer . Serialize ( o . float_1 , ref bytes ) ;
Serializer . Serialize ( o . bool_1 , ref bytes ) ;
Serializer . Serialize ( o . string_1 , ref bytes ) ;
Serializer . Serialize ( o . vector3_1 , ref bytes ) ;
Serializer . Serialize ( o . vector3_2 , ref bytes ) ;
Serializer . Serialize ( o . quaternion_1 , ref bytes ) ;
return bytes ;
}
ประการที่สาม สร้างประเภทที่กำหนดเองใหม่ในวิธี "ดีซีเรียลไลซ์" และประกาศตัวแปรออฟเซ็ตด้วยประเภท int และกำหนดค่าเริ่มต้นด้วย 0
public static object Deserialize ( byte [ ] bytes )
{
TestStruct o = new TestStruct ( ) ;
int offset = 0 ;
}
ตอนนี้ ใช้วิธีการดีซีเรียลไลซ์ของ Serializer เพื่อดีซีเรียลไลซ์ฟิลด์ที่มีการซีเรียลไลซ์ด้านบน ออฟเซ็ตจะถูกส่งผ่านด้วยคีย์เวิร์ดอ้างอิง และส่งคืนประเภทที่กำหนดเองที่สร้างขึ้นด้านบน
โปรดทราบว่าลำดับของการดีซีเรียลไลซ์จะต้องเหมือนกับลำดับของการซีเรียลไลซ์
public static object Deserialize ( byte [ ] bytes )
{
.. .
o . int_1 = Serializer . DeserializeInt ( bytes , ref offset ) ;
o . int_2 = Serializer . DeserializeInt ( bytes , ref offset ) ;
o . float_1 = Serializer . DeserializeInt ( bytes , ref offset ) ;
o . bool_1 = Serializer . DeserializeBool ( bytes , ref offset ) ;
o . string_1 = Serializer . DeserializeString ( bytes , ref offset ) ;
o . vector3_1 = Serializer . DeserializeVector3 ( bytes , ref offset ) ;
o . vector3_2 = Serializer . DeserializeVector3 ( bytes , ref offset ) ;
o . quaternion_1 = Serializer . DeserializeQuaternion ( bytes , ref offset ) ;
return o ;
}
สุดท้าย ควรลงทะเบียนประเภทแบบกำหนดเองกับ PUN2 เรียกวิธีที่อธิบายไว้ด้านล่างหนึ่งครั้งเพื่อลงทะเบียนประเภทแบบกำหนดเอง หากจำเป็นต้องลงทะเบียนประเภทแบบกำหนดเองหลายประเภท รหัสไบต์จะต้องแตกต่างกัน ทำได้ง่ายๆ โดยการเปลี่ยนตัวอักษรของพารามิเตอร์ในวิธีการ
Serializer . RegisterCustomType < TestStruct > ( ( byte ) 'A' ) ;
ผลลัพธ์ของการทำให้เป็นอนุกรมของโครงสร้างที่กำหนดมีดังนี้:
ขนาด(ไบต์) | |
---|---|
ต้นฉบับ | 64 ไบต์ |
ซีเรียลไลเซอร์แบบกำหนดเอง | 69 ไบต์ |
ขนาดตามทฤษฎีคือ 64 ไบต์ โดยที่ขนาดซีเรียลไลซ์จริงคือ 69 ไบต์ ความแตกต่าง 5 ไบต์เกิดจากสตริง ซึ่งอาจมีขนาดแตกต่างกันไปตามความยาว ผลลัพธ์เป็นที่ยอมรับได้
ตัวซีเรียลไลเซอร์แบบกำหนดเองจะให้ขนาดที่เล็กกว่า Binary Formatter หรือ JsonUtility การทำให้เป็นซีเรียลไลซ์ อย่างไรก็ตาม มีข้อจำกัดที่อาจไม่สะดวกที่จะมีเมธอด wirte ซีเรียลไลซ์ทั้งหมดสำหรับประเภทที่กำหนดเองทุกประเภท ซึ่งควรจะซีเรียลไลซ์และไม่รองรับประเภทที่ซ้อนกัน อย่างไรก็ตาม หากซีเรียลไลซ์ประเภทแบบกำหนดเองแบบธรรมดาด้วยประเภทดั้งเดิมและส่งไปยังเครือข่ายบ่อยครั้ง ซีเรียลไลเซอร์แบบกำหนดเองนี้จะช่วยได้
เพิ่มขอบเขตรีจิสทรีนี้
"scopedRegistries" : [
{
"name" : " MS-LIMA " ,
"url" : " https://package.openupm.com " ,
"scopes" : [
" com.ms-lima "
]
}
]