File dữ liệu là một khái niệm thú vị; về cơ bản, chúng chỉ là một tập hợp các dữ liệu được chứa trong một “vật chứa” duy nhất, và dữ liệu đó được tổ chức thành một mảng byte một chiều. Nhiều hệ điều hành hiện đại sử dụng đuôi file để xác định loại file, và điều này, đến lượt nó, quy định các quy tắc về cách dữ liệu được tổ chức để có thể được giải thích một cách có ý nghĩa. Tuy nhiên, khi nói đến một “file” là một tập hợp dữ liệu, nó không có gì quá đặc biệt. Bạn không cần một loại file cụ thể trên bất kỳ file nào. Bạn có thể lưu một file JPG dưới dạng .zip nếu muốn, và nếu bạn ép trình chỉnh sửa ảnh của mình mở nó, rất có thể nó vẫn sẽ… mở ra. Với kiến thức đó, dữ liệu không phải là thứ bạn không thể biểu diễn dưới các dạng khác. Chúng ta đã chứng minh cách file có thể được lưu trữ bên trong các trò chơi điện tử trước đây, và giờ đây, mục tiêu tiếp theo là liệu chúng ta có thể lưu trữ file trong Minecraft không? Với một thế giới vô tận, về mặt lý thuyết, bạn có thể lưu trữ bất kỳ file nào bạn muốn bên trong trò chơi, miễn là bạn biết cách giải thích nó sau này. Đó chính xác là những gì chúng tôi đã thực hiện, và dù khá tốn công, đây cũng là một cách tuyệt vời để giải thích cách dữ liệu được lưu và tham chiếu.
Hãy cùng blogcongnghe.net đi sâu vào chi tiết của dự án độc đáo này, nơi chúng ta biến thế giới khối hộp của Minecraft thành một kho lưu trữ dữ liệu tiềm năng.
Thiết Lập Bối Cảnh
Hiểu Về Lưu Trữ Dữ Liệu
Đầu tiên và quan trọng nhất, chúng tôi muốn tìm một cách dễ dàng để biểu diễn dữ liệu trong Minecraft theo một phương pháp có thể thu thập được thông qua các cách hợp pháp và cũng có thể biểu diễn một lượng dữ liệu đáng kể trên mỗi khối. Một số ý tưởng phức tạp hơn mà chúng tôi có bao gồm việc bóc vỏ các khúc gỗ và sử dụng hướng của chúng, trong khi một ý tưởng khác sử dụng khung vật phẩm với các vật phẩm bên trong. Tuy nhiên, chúng tôi nhận ra rằng có 16 màu trong trò chơi, điều này thật hoàn hảo. Len không chỉ dễ kiếm mà việc có sẵn 16 màu cũng có nghĩa là chúng ta có thể lưu trữ bốn bit dữ liệu bên trong mỗi khối len, và điều đó cũng có nghĩa là chúng ta nhận được một toàn bộ byte cứ sau hai khối.
Cốt lõi của một file là một chuỗi byte, và khi được tách ra, chuỗi này được chia thành các phân đoạn nhỏ hơn, dễ quản lý hơn. Việc phân chia này được thực hiện sao cho mỗi phân đoạn là một tập hợp con chính xác, liền kề của chuỗi byte gốc của file. Quá trình này về bản chất là không mất mát, nghĩa là nó không làm thay đổi nội dung của các byte. Miễn là các phân đoạn này được lắp ráp lại đúng thứ tự, file gốc có thể được tái tạo hoàn hảo. Nắm vững kiến thức này, chúng tôi đã tạo ra một ánh xạ từ các chữ số hex và chuỗi bốn bit sang một màu len, mà chúng ta có thể sử dụng để đọc và ghi dữ liệu. Đối với các file nhỏ, việc tự xây dựng các cấu trúc này khá thực tế; như chúng tôi sẽ minh họa sau, một file 67 byte sử dụng 144 khối len, trong đó mười khối chỉ đơn thuần là phần đệm để đảm bảo chiều cao và chiều rộng đồng đều. Xin lưu ý rằng dự án này được phát triển cho Minecraft phiên bản Java.
Dưới đây là bảng ánh xạ mà chúng tôi đã tạo:
Chữ số Hex | Nhị phân | Màu len | ID Khối (Java) |
---|---|---|---|
0 | 0000 | Trắng | minecraft:white_wool |
1 | 0001 | Xám nhạt | minecraft:light_gray_wool |
2 | 0010 | Xám | minecraft:gray_wool |
3 | 0011 | Đen | minecraft:black_wool |
4 | 0100 | Nâu | minecraft:brown_wool |
5 | 0101 | Đỏ | minecraft:red_wool |
6 | 0110 | Cam | minecraft:orange_wool |
7 | 0111 | Vàng | minecraft:yellow_wool |
8 | 1000 | Xanh nõn chuối | minecraft:lime_wool |
9 | 1001 | Xanh lá cây | minecraft:green_wool |
A | 1010 | Xanh ngọc | minecraft:cyan_wool |
B | 1011 | Xanh da trời | minecraft:light_blue_wool |
C | 1100 | Xanh dương | minecraft:blue_wool |
D | 1101 | Tím | minecraft:purple_wool |
E | 1110 | Hồng cánh sen | minecraft:magenta_wool |
F | 1111 | Hồng | minecraft:pink_wool |
Ví dụ, nếu bạn muốn viết chuỗi 1111 0000 1010 0001, nó sẽ được mã hóa thành:
- Len Hồng
- Len Trắng
- Len Xanh ngọc
- Len Xám nhạt
May mắn thay, dù có nhiều thao tác đặt khối thủ công cho người thực hiện bằng tay, việc mã hóa dữ liệu theo cách này không quá khó tổng thể. Chúng tôi đã xây dựng một bộ mã hóa sẽ tạo ra một hình ảnh bạn có thể tham khảo để xây dựng định dạng dữ liệu của mình.
Trình chỉnh sửa hex hiển thị siêu dữ liệu tệp được đặt cho tệp ZIP đã giải mã, minh họa cấu trúc dữ liệu cơ bản.
Mã Hóa Dữ Liệu Vào Minecraft
Tạo File mcfunction Để Tự Động Hóa
Mã hóa dữ liệu khá dễ dàng và không tốn quá nhiều thời gian trong số thời gian đáng kể mà chúng tôi đã dành để lưu trữ file trong Minecraft. Một gợi ý về điều gì đã tốn quá nhiều thời gian có thể được thấy trong hình ảnh bên dưới, cụ thể là số lượng bộ giải mã mà chúng tôi đã cố gắng triển khai. Chúng ta sẽ nói đến điều đó sau. Tuy nhiên, bạn có thể thấy bộ mã hóa đã chạy trong terminal ở cuối màn hình, một hình ảnh đã được tạo và một file “mcfunction” đã được tạo ra. File “mcfunction” về cơ bản là một script có thể chạy tất cả các lệnh được nhập vào đó, vì vậy chúng ta có thể ngay lập tức đặt tất cả các khối mà không cần phải làm thủ công. Hình ảnh được tạo ra để tham khảo để bạn có thể tự đặt chúng, nếu bạn thích.
Để gọi bộ mã hóa của chúng tôi, chúng ta chạy lệnh sau, yêu cầu cài đặt module Pillow:
python3 encoder.py hello.txt --cols 12 --y -60
Lệnh này yêu cầu bộ mã hóa chỉ sử dụng 12 cột một lần (mặc định là 64) và sử dụng mức Y là -60, vì chúng tôi đang thử nghiệm điều này trong một thế giới siêu phẳng. Đây là những gì kết quả trông giống như trong trò chơi:
Giao diện terminal hiển thị quá trình chạy công cụ mã hóa file Minecraft, tạo ra ảnh tham chiếu và file mcfunction.
Mã hóa file Minecraft
Chúng tôi đã thêm các khối xung quanh rìa cho mục đích thử nghiệm khi giải mã, vì vậy, những gì bạn sẽ nhận được thực sự chỉ là ma trận các khối len. Tùy thuộc vào giá trị “cols” của bạn, nó có thể rộng hơn nhiều. Giờ đây, chúng ta đã hoàn thành việc mã hóa, đã đến lúc thử giải mã file của chúng ta.
Giải Mã File Từ Minecraft
Thử Nghiệm Với OCR và Giải Pháp Amulet
Đây là lúc chúng tôi gặp phải những vấn đề lớn, và giải pháp cuối cùng mà chúng tôi lựa chọn, đáng tiếc, không phải là điều chúng tôi mong muốn ban đầu. Chúng tôi đã lên kế hoạch sử dụng công nghệ nhận dạng hình ảnh (OCR) để xác định các khối được đặt trong ảnh chụp màn hình, và đây là lý do tại sao chúng tôi đặt các khối khác nhau quanh rìa để cố gắng xác định cạnh của ma trận len. Nó một phần hoạt động sau khi chúng tôi sử dụng sklearn, nhưng sự thay đổi phối cảnh và độ dài hơi khác nhau của các khối vì điều này, do khoảng cách của chúng đến ma trận len, có nghĩa là nó không nhất quán. Đôi khi nó giải mã được một phần, đôi khi lại không thể giải mã được gì cả. Chúng tôi đã dành quá nhiều thời gian cho nhiều cách tiếp cận khác nhau bằng cách sử dụng hình ảnh, nhưng cuối cùng, chúng tôi đã sử dụng Amulet, một thư viện Python có thể đọc trực tiếp từ file thế giới.
Giải mã thất bại từ ảnh chụp màn hình bằng công nghệ OCR trong Minecraft, cho thấy thách thức nhận diện.
Phương pháp này hoạt động hoàn hảo, mặc dù nó có một vài nhược điểm. Nó không đơn giản như việc chỉ cần chụp ảnh màn hình những gì đang hiển thị trước mặt bạn và chuyển đổi lại thành file, và nó yêu cầu nhiều công đoạn tái tạo thủ công hơn nếu bạn muốn chia sẻ một file với bạn bè qua Minecraft bằng cách sử dụng máy chủ, chẳng hạn. Về cơ bản, bạn sẽ cần chụp ảnh màn hình, xây dựng lại cục bộ trong thế giới của riêng bạn, và sau đó tái tạo nó bằng bộ giải mã. Rõ ràng, không ai thực sự thích làm điều đó, nhưng chúng tôi cũng dám chắc không ai thực sự hào hứng với việc chia sẻ file qua Minecraft, ngay cả khi có thể chụp ảnh màn hình ma trận len để lấy file. Chúng tôi chỉ muốn thực hiện điều đó “đúng cách”, theo một cách tiếp cận, và không yêu cầu truy cập vào các file thế giới thực tế.
Như bạn có thể thấy dưới đây, việc lấy dữ liệu từ file thế giới hoạt động hoàn hảo, như bạn mong đợi với tính chất xác định của việc có thể đọc từng khối riêng lẻ.
Chương trình giải mã Minecraft dựa trên thư viện Amulet đang hoạt động, hiển thị quá trình đọc dữ liệu từ file thế giới.
Có một vài hạn chế khi đọc file thế giới; bạn sẽ cần xác định tọa độ X và Y của góc trên bên trái của ma trận len, chọn xem bạn di chuyển điển hình dọc theo trục X và Z (tức là tăng X và Z khi bạn di chuyển ngang và xuống), và xác định chiều cao và chiều rộng của ma trận. Đây là một quá trình khá thủ công, nhưng nó hoạt động. Khi bạn chạy chương trình lần đầu tiên, bạn sẽ được yêu cầu cung cấp các chi tiết này:
- X góc trên bên trái
- Y góc trên bên trái
- Z góc trên bên trái
- Kích thước [overworld/nether/end] (mặc định = overworld)
- Chiều rộng (cột)
- Chiều cao (hàng)
- Bước cột dX dZ [1 0]
- Bước hàng dX dZ [0 1]
- Padding (các khối len trắng thừa để bỏ qua, 0 nếu không có)
Bạn cũng cần chạy nó bằng cách định nghĩa cờ --world
, vì vậy bạn chạy script như thế này:
python3 .decode_from_world.py --world '.New World'
Nếu nó gặp một khối không mong muốn, nó sẽ báo lỗi, hiển thị khối mà nó gặp phải để bạn có thể có ý tưởng sơ bộ về những gì bạn cần điều chỉnh. Ngoài ra, bạn sẽ cần đổi tên “decoded.bin” để khớp với định dạng file mong muốn. Như đã đề cập trước đó, loại file là một chỉ báo bên ngoài cho các ứng dụng muốn tương tác với file, và không hơn. Dữ liệu vẫn giữ nguyên bất kể loại file là gì. Đây cũng là lý do tại sao “container” (vật chứa), khi nói đến các định dạng video, lại rất quan trọng, vì chúng thực sự định nghĩa cấu trúc dữ liệu, nén, và nhiều hơn nữa.
Nội dung file decoded.bin được hiển thị trong trình chỉnh sửa hex, xác nhận quá trình giải mã dữ liệu từ Minecraft thành công.
Sau khi chạy bộ giải mã, chúng ta có thể thấy đầu ra của mình, được tính toán từ việc ánh xạ mỗi khối len sang một giá trị hex và sau đó ghi dữ liệu đó vào một file có tên decoded.bin
:
Hi there, this is a test file to show encoding a file in Minecraft!
Mặc dù chúng ta biết nó đã được giải mã thành công, chúng ta thậm chí có thể thấy các giá trị hex và so sánh chúng với bản đồ len của chúng ta. File của chúng ta bắt đầu bằng “48 69 20 74” trong hex, tương ứng với:
- Len Nâu
- Len Xanh nõn chuối
- Len Cam
- Len Xanh lá cây
- Len Xám
- Len Trắng
- Len Vàng
- Len Nâu
Điều này khớp với các khối mà chúng ta đã đặt trong trò chơi.
File Có Thể Được Biểu Diễn Bằng Bất Cứ Thứ Gì
Như chúng ta đã thấy trước đây, các file có thể được biểu diễn bằng bất kỳ thứ gì. Nếu bạn có thể định nghĩa cấu trúc riêng để đọc các file đó, bạn có thể lưu trữ bất cứ thứ gì trong bất kỳ định dạng nào. Một chuỗi đèn LED có thể biểu diễn 0 và 1 dựa trên trạng thái của chúng, hoặc một chai nước có thể biểu diễn hai bit dữ liệu dựa trên việc nó rỗng, đầy một phần tư, đầy một nửa, hay đầy hoàn toàn. Miễn là bạn biết nó có nghĩa là gì, bạn có thể nói cho người khác biết, và họ có thể giải thích dữ liệu được biểu diễn theo cách giống như bạn.
Dự án này không nhằm mục đích sử dụng dưới dạng hiện tại. Thực tế, chúng tôi sẽ đi xa đến mức nói rằng bạn không bao giờ nên sử dụng một trò chơi để gửi file cho người khác, đặc biệt là theo một cách tẻ nhạt như vậy. Thay vào đó, nó phục vụ để minh họa cách các file có thể được lưu trữ độc đáo. Nếu bạn quan tâm đến việc kiểm tra mã mà chúng tôi đã viết cho dự án này, nó có sẵn trên GitHub.
Dự án này là minh chứng rõ ràng cho sự sáng tạo trong việc hiểu và thao tác dữ liệu. Hãy tiếp tục khám phá những khả năng không giới hạn của công nghệ cùng blogcongnghe.net!
Minh họa khái niệm lưu trữ dữ liệu dưới dạng video trên YouTube, từ file nén đến định dạng MP4.
Bạn có biết?
Bạn có thể sử dụng YouTube làm bộ nhớ đám mây không giới hạn bằng cách lưu trữ file dưới dạng video. Mặc dù chúng tôi thực sự không khuyến nghị điều đó, nhưng về mặt kỹ thuật, nó hoàn toàn khả thi!