'XML nhị phân' cho dữ liệu trò chơi?


17

Tôi đang làm việc trên một công cụ chỉnh sửa mức lưu dữ liệu của nó dưới dạng XML.

Điều này là lý tưởng trong quá trình phát triển, vì không khó để thực hiện các thay đổi nhỏ đối với định dạng dữ liệu và nó hoạt động độc đáo với dữ liệu giống như cây.

Tuy nhiên, nhược điểm là các tệp XML khá cồng kềnh, chủ yếu là do trùng lặp tên thẻ và thuộc tính. Cũng do dữ liệu số chiếm nhiều không gian hơn so với sử dụng kiểu dữ liệu gốc. Một mức nhỏ có thể dễ dàng kết thúc là 1Mb +. Tôi muốn giảm các kích thước này xuống đáng kể, đặc biệt nếu hệ thống này được sử dụng cho một trò chơi trên iPhone hoặc các thiết bị khác có bộ nhớ tương đối hạn chế.

Giải pháp tối ưu, cho bộ nhớ và hiệu năng, sẽ là chuyển đổi XML sang định dạng mức nhị phân. Nhưng tôi không muốn làm điều này. Tôi muốn giữ định dạng khá linh hoạt. XML giúp dễ dàng thêm các thuộc tính mới vào các đối tượng và cung cấp cho chúng một giá trị mặc định nếu một phiên bản cũ của dữ liệu được tải. Vì vậy, tôi muốn giữ theo thứ bậc của các nút, với các thuộc tính là cặp giá trị tên.

Nhưng tôi cần lưu trữ cái này ở định dạng nhỏ gọn hơn - để loại bỏ sự trùng lặp lớn của tên thẻ / thuộc tính. Cũng có thể để cung cấp cho các thuộc tính kiểu gốc, vì vậy, ví dụ dữ liệu dấu phẩy động được lưu trữ dưới dạng 4 byte cho mỗi float, không phải dưới dạng chuỗi văn bản.

Google / Wikipedia tiết lộ rằng 'XML nhị phân' hầu như không phải là vấn đề mới - nó đã được giải quyết một số lần. Có ai ở đây có kinh nghiệm với bất kỳ hệ thống / tiêu chuẩn hiện có nào không? - có bất kỳ lý tưởng nào cho việc sử dụng trò chơi - với thư viện trình tải / trình phân tích cú pháp / trình tải đa nền tảng miễn phí, nhẹ và có sẵn (C / C ++) không?

Hay tôi nên tự sáng tạo lại cái bánh xe này?

Hoặc tốt hơn hết là tôi quên đi lý tưởng và chỉ nén dữ liệu .xml thô của mình (nó sẽ đóng gói tốt với nén giống như zip) và chỉ cần tải bộ nhớ / hiệu năng khi tải?


1
XML có thể được nén bằng gzip et al rất tốt.
ThiefMaster

Câu trả lời:


18

Chúng tôi đã sử dụng XML nhị phân rất nhiều cho Superman Returns: The Videogame . Chúng tôi đang nói chuyện hàng ngàn và hàng ngàn tập tin. Nó hoạt động tốt, nhưng thực sự có vẻ không đáng nỗ lực. Nó đã ăn một phần đáng chú ý trong thời gian tải của chúng tôi và "tính linh hoạt" của XML không tăng lên. Sau một thời gian, các tệp dữ liệu của chúng tôi có quá nhiều định danh kỳ lạ, các tham chiếu bên ngoài cần được giữ đồng bộ và các yêu cầu lạ khác để chúng thực sự được chỉnh sửa một cách khả thi.

Ngoài ra, XML thực sự là một định dạng đánh dấu và không phải là định dạng dữ liệu. Nó được tối ưu hóa cho nhiều văn bản với các thẻ thỉnh thoảng. Nó không tuyệt vời cho dữ liệu có cấu trúc đầy đủ. Đó không phải là cuộc gọi của tôi, nhưng nếu nó đã được và tôi biết thì bây giờ tôi biết gì, có lẽ tôi đã thực hiện JSON hoặc YAML. Cả hai đều đủ để không yêu cầu nén và được tối ưu hóa để thể hiện dữ liệu , không phải văn bản .


1
Có một phiên bản nhị phân của JSON được gọi là BSON .
Philipp

12

Lưu trữ và chỉnh sửa các cấp của bạn như XML thông thường, nhưng công cụ trò chơi của bạn sẽ lười biếng nướng nó thành XML nhị phân trong khi tải và lưu XML nhị phân trở lại đĩa để có thể tải lần sau (nếu XML thô không thay đổi) .

Một cái gì đó như thế này:

data loadXml(xmlFile)
{
    if (xmlFile has changed OR binFile doesn't exist)
    {
        binFile = convertToBinary(xmlFile)
        save(binFile)
    }
    return loadBinaryXml(binFile)
}

Bằng cách đó bạn có được điều tốt nhất của cả hai thế giới. Khi phát hành, bạn chỉ cần đảm bảo tất cả các tệp nhị phân đều ở đó.


5

Bộ đệm giao thức Google có vẻ như là cách để đi, nhưng tôi đã không sử dụng chúng cho mình.
http://code.google.com.vn/p/protobuf/

Bạn xác định tệp .proto mô tả định dạng tệp:

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

Điều này sau đó được biên dịch bằng một công cụ dòng lệnh tạo ra các lớp C / C ++ để ghi và phân tích các tệp dữ liệu nhị phân theo định dạng dữ liệu được xác định trước đó. Ngoài ra còn có một vài phần mở rộng cho các ngôn ngữ lập trình khác nhau.

Nhược điểm của ProtocolBuffer là chúng không phải là định dạng văn bản gốc. Bạn sẽ cần một công cụ để tạo, đọc và chỉnh sửa chúng. Nhưng điều này không phải là vấn đề nếu bạn chỉ sử dụng chúng để trao đổi dữ liệu giữa trình chỉnh sửa trò chơi và trò chơi của bạn. Tôi sẽ không sử dụng nó để xác định tập tin cấu hình;)

Nén các tệp xml thô cũng sẽ hoạt động. Bạn đang làm loại trò chơi nào? Nếu nó dựa trên cấp độ thì bạn chỉ nên tải tất cả các tài nguyên cần thiết một lần khi cấp được tải.

cập nhật: Có một số dự án cho các ngôn ngữ khác như C # hoạt động với ProtocolBuffers:
http://code.google.com.vn/p/protobuf/wiki/ThirdPartyAddOns


Không phải là một serializer thích ứng với loại vấn đề đó? Tôi đoán là không nhưng tôi không thấy một sự khác biệt rõ ràng. Nhưng với tôi câu trả lời này có vẻ thích hợp. Nhưng tar / gzip, các tệp xml sẽ giảm đáng kể kích thước của chúng (vì nó là văn bản, nhưng tôi đoán nó cũng sẽ hoạt động với xml), vì vậy đó có thể là giải pháp "dễ dàng hơn". Dù sao XML là một ngôn ngữ dễ dàng, nhưng nó rất tốn kém về mặt phân tích cú pháp / bộ nhớ bằng cách sử dụng: khi bạn sử dụng XML, bạn nên đọc / ghi càng nhiều lần càng tốt.
jokoon

Đây là một tùy chọn thú vị, nhưng trông giống như một sự thay thế hoàn toàn cho việc sử dụng XML ở bất cứ đâu trong đường ống. Thành thật mà nói, tôi không quá hào hứng với mã được tạo, mặc dù vậy - và một điều phức tạp khác là tôi đang sử dụng C # cho các công cụ (tôi rất vui khi các công cụ tiếp tục làm việc với các tệp .XML lớn ). Trình chuyển đổi XML-> PB có thể là một tùy chọn, mặc dù tôi nghĩ rằng tôi vẫn đang tìm kiếm thứ gì đó 'XML nhị phân mục đích chung' hơn là cách để nướng 'dữ liệu mức nhị phân' cụ thể (ngay cả khi đó sẽ nhiều hơn một chút hiệu quả)
bluescrn

"Tôi đang sử dụng C # cho các công cụ của mọi thứ" có một số dự án cho c #. cập nhật câu trả lời của tôi
Stephen

@bluescrn, tôi sẽ không quá lo lắng về mã được tạo. Google cung cấp hỗ trợ hạng 1 cho C ++, Java và Python. Họ sử dụng nó rộng rãi trong nội bộ; mã được tạo ra khá mạnh mẽ. Một lợi thế lớn với PB, là chương trình công cụ của bạn chống lại một .prototệp, gần như loại bỏ các vấn đề truyền thông. Protos dễ đọc / duy trì hơn nhiều so với lược đồ xml, nếu bạn thậm chí có kỷ luật (và thời gian) để sử dụng lược đồ xml.
deft_code

4

Còn định dạng JSON thì sao?

http://www.json.org/xml.html


Nó trông gọn hơn một chút so với XML, nhưng vẫn có vấn đề chính là các tên thuộc tính trùng lặp. Nếu tệp chứa danh sách các đối tượng trò chơi có thuộc tính 'XP vị trí', 'YP vị trí' và 'Tỷ lệ', chuỗi 'XP vị trí' / 'YP vị trí' / 'Tỷ lệ' sẽ được sao chép cho mọi đối tượng trò chơi. Đây là điều chính mà tôi đang nhắm đến 'nén' vào lúc này
bluescrn

1
@bluescrn: Không, nó không có vấn đề đó. Đối tượng là một cấu trúc; bạn cũng có thể sử dụng mảng [mà, chỉ, nhìn, như thế này]. Điều đó có nghĩa là bạn có thể kết thúc với một cái gì đó như thế này để lưu trữ tên và thuộc tính của ô tô: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}Bạn thậm chí có thể bỏ qua định danh "ô tô" và chỉ cần đi thẳng vào một mảng nếu bạn biết trường ô tô sẽ ở đâu. Bạn thậm chí có thể bỏ qua tên "ford" và "Holden" nếu bạn không cần lưu dữ liệu đó, để lại cho bạn : [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. Liệu nó có được nhỏ gọn hơn?
doppelgreener

1
@Axidos: Nếu bạn định tạo đánh dấu không thể đọc được và không có cấu trúc, bạn cũng có thể biến nó thành nhị phân. Bên cạnh đó, đó là một khoản tiết kiệm sai, trừ khi bạn phân tích dữ liệu không nén trong thời gian chạy (trong trường hợp đó, bạn có thể bị vặn dù sao) hoặc bằng cách nào đó bị ràng buộc cho vài trăm byte bộ nhớ trong khi phân tích cú pháp (trừ khi bạn bật lò vi sóng, bạn thì không).

@Joe: bluescrn dường như đang tìm kiếm một định dạng có thể đọc được mà không có tên trùng lặp. Tôi đã minh họa khả năng của JSON để cung cấp điều đó. Tôi hoàn toàn đồng ý mặc dù tại một thời điểm nhất định, bạn cũng có thể tự hỏi tại sao bạn thậm chí bận tâm với việc đánh dấu như thế này.
doppelgreener

4

Sử dụng JSON.

(Dựa trên phản hồi của Munificent, và phần lớn là để đáp lại những lo lắng của bạn thể hiện ở nơi khác)

Bạn đã đề cập đến mối quan tâm rằng JSON có vấn đề lãng phí các yếu tố đặt tên không gian, như XML. Nó không.

JSON được xây dựng trên hai cấu trúc: cặp tên / giá trị ( đối tượng ) và danh sách các giá trị ( mảng ) theo thứ tự. XML chỉ được xây dựng trên các cặp tên / giá trị.

Nếu bạn nghĩ JSON dựa vào các đối tượng bạn đã đọc JSON được xây dựng để tự mô tả và có thể đọc được, như thế này (sử dụng các cặp chữ số bát phân để biểu thị các byte đơn):

{
    "some": ...,
    "data": ...,
    "fields": ...,
    "cars": [
        {"name":"greg","cost":8C,"speed":FA,"age":04,"driverID":384FFFFF},
        {"name":"ole rustbucket","cost":00,"speed":00,"age":2A,"driverID":04FF54A9}
    ]
}

Tuy nhiên, bạn cũng có tùy chọn viết nó như thế này, miễn là bạn biết mọi thứ sẽ ở đâu (và vì vậy có thể tìm chỉ số 4, thay vì đối tượng "xe hơi", để lấy danh sách xe của bạn):

{
    [
        ...,
        ..., 
        ...,
        [["greg",8C,FA,04,384FFFFF],["ole rustbucket",00,00,2A,04FF54A9]],
        ...,
    ]
}

Liệu nó có được ngắn gọn hơn chỉ có [, ], ,và giá trị của bạn?

Vâng, điều đó sẽ xảy ra nếu bạn sẵn sàng đến gần hơn và gần hơn với luồng nhị phân thuần túy.

"cars":{"names":["greg","ole rustbucket"],"stream":8CFA04384FFFFF00002A04FF54A9}
or
[["greg","ole rustbucket"],8CFA04384FFFFF00002A04FF54A9]

Đừng tự bắn vào chân mình bằng cách tối ưu hóa quá nhiều.


2

Tôi biết bạn đã chấp nhận câu trả lời, nhưng Google cả "Fast Infoset" (XML nhị phân) và vtd-xml.

Mặc dù (VTD) sau này có thể không giải quyết được khía cạnh nén của việc sử dụng XML của bạn, nhưng nó có thể tăng tốc độ truy cập nút trên các tệp lớn, đáng kể (nó sử dụng từ điển nhị phân 'từ điển' để nhảy đến các nút và không tạo đối tượng cho mỗi nút , thay vì làm việc trên chuỗi XML gốc). Do đó, việc tra cứu XML của nó [được cho là] nhanh hơn và nó không đòi hỏi nhiều bộ nhớ trong quá trình để truy cập / thao tác với tài liệu XML.

Cả hai điều trên đều có các ràng buộc trong các ngôn ngữ phổ biến (bao gồm C #).

Chúc mừng

Giàu có


1

Bạn có thể thử Karvonite . Nó được cho là nhanh nhẹn. Đó là một khung kiên trì sẽ thích ứng với các thay đổi trong dữ liệu của bạn khá tốt (điều này tốt so với việc tự xử lý nhị phân của bạn). Tôi thực sự không chắc chắn làm thế nào dữ liệu được cấu trúc, nhưng các tệp nhỏ hơn rất nhiều so với các tệp cồng kềnh xml. (Tôi cho rằng nó lưu dữ liệu ở định dạng nhị phân thay vì văn bản như xml)

Điều duy nhất tôi có thể nghĩ đến với điều này là nếu dữ liệu của bạn bị hỏng hoặc một số cách gây rối theo cách mà Karvonite không thích nó, bạn sẽ cảm thấy xót xa cho những người tạo ra nó trừ khi bạn tìm ra cách cấu trúc của dữ liệu hoạt động.

Cách bạn chỉ định cách lưu / tải dữ liệu của mình là bạn chỉ cần mở trình soạn thảo kiên trì của họ, nhập cụm của bạn với tất cả các đối tượng dữ liệu và chọn một số hộp kiểm để hiển thị những đối tượng bạn muốn được hỗ trợ và trường / thuộc tính nào cần lưu.

Nó đáng để thử. Vì bạn đang sử dụng C #, điều này phù hợp với ngôn ngữ của bạn vì nó hoạt động với XNA (Windows, Xbox360 và Windows Phone 7 mà tôi nghĩ bạn quan tâm từ khi bạn đề cập đến iPhone?).

Chỉnh sửa: Chỉ cần lưu ý rằng bạn chỉ sử dụng C # cho các công cụ. Điều này có lẽ sẽ không phù hợp lắm trong quy trình làm việc của bạn. Vì một số lý do, tôi đã có XNA trong đầu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.