mirror of https://git.sr.ht/~kikoodx/kble
Two ways level loading/saving works perfectly! Very nice :D
This commit is contained in:
parent
572c94f78f
commit
f24b6340a2
|
@ -1 +1,2 @@
|
|||
zig-cache/
|
||||
sample_*.kble
|
||||
|
|
|
@ -7,6 +7,6 @@ Encoding:
|
|||
* first byte indicates how big is a chunk of data (in bytes)
|
||||
* second and third bytes indicates level width
|
||||
* fourth and fifth bytes indicates level height
|
||||
* 7th => (7 + data_size * width * height) contains level data
|
||||
* 6th => (6 + data_size * width * height) contains level data
|
||||
|
||||
If the encoding is incorrect, return an error or crash the program.
|
||||
|
|
|
@ -18,6 +18,7 @@ const SelectionUpdate = @import("movement.zig").SelectionUpdate;
|
|||
const Self = @This();
|
||||
|
||||
pub const cell_type = u16;
|
||||
const expected_bytes_per_cell = @sizeOf(cell_type);
|
||||
|
||||
width: u16,
|
||||
height: u16,
|
||||
|
@ -49,13 +50,17 @@ pub fn init(allocator: *std.mem.Allocator, width: u16, height: u16) !Self {
|
|||
return self;
|
||||
}
|
||||
|
||||
/// Load level content from given absolute path. Expect the KBLE file format (see
|
||||
/// `kbleformat.md` for more details.
|
||||
/// Free the level content.
|
||||
pub fn deinit(self: *Self, allocator: *std.mem.Allocator) void {
|
||||
allocator.free(self.selection);
|
||||
allocator.free(self.content);
|
||||
}
|
||||
|
||||
/// Load level content from given absolute or relative path.
|
||||
/// Expect the KBLE file format (see `kbleformat.md` for more details).
|
||||
pub fn init_load(allocator: *std.mem.Allocator, kble_file_path: []const u8) !Self {
|
||||
var self: Self = undefined;
|
||||
|
||||
const expected_bytes_per_cell = @sizeOf(cell_type);
|
||||
|
||||
// Open directory.
|
||||
var dir: std.fs.Dir = std.fs.cwd();
|
||||
// Open file in read mode.
|
||||
|
@ -114,14 +119,50 @@ pub fn init_load(allocator: *std.mem.Allocator, kble_file_path: []const u8) !Sel
|
|||
return self;
|
||||
}
|
||||
|
||||
/// Free the level content.
|
||||
pub fn deinit(self: *Self, allocator: *std.mem.Allocator) void {
|
||||
allocator.free(self.selection);
|
||||
allocator.free(self.content);
|
||||
/// Write header and level content to given absolute or relative path.
|
||||
/// Uses the KBLE file format (see `kbleformat.md` for more details).
|
||||
pub fn write(self: Self, kble_file_path: []const u8) !void {
|
||||
// Open directory.
|
||||
var dir: std.fs.Dir = std.fs.cwd();
|
||||
// Open file in write mode.
|
||||
const file: std.fs.File = try dir.createFile(kble_file_path, std.fs.File.CreateFlags{});
|
||||
defer file.close();
|
||||
// Get writer.
|
||||
var writer: std.fs.File.Writer = file.writer();
|
||||
|
||||
// Write first byte, indicates cell size in bytes.
|
||||
try writer.writeByte(expected_bytes_per_cell);
|
||||
|
||||
// Write level height and level width.
|
||||
{
|
||||
const width_byte1: u8 = @intCast(u8, self.width / 256);
|
||||
const width_byte2: u8 = @intCast(u8, self.width % 256);
|
||||
const height_byte1: u8 = @intCast(u8, self.height / 256);
|
||||
const height_byte2: u8 = @intCast(u8, self.height % 256);
|
||||
|
||||
std.log.info("{}·{} ; {}·{}", .{width_byte1, width_byte2, height_byte1, height_byte2});
|
||||
|
||||
try writer.writeByte(width_byte1);
|
||||
try writer.writeByte(width_byte2);
|
||||
try writer.writeByte(height_byte1);
|
||||
try writer.writeByte(height_byte2);
|
||||
}
|
||||
|
||||
// Write level content.
|
||||
{
|
||||
var i: u32 = 0;
|
||||
while (i < self.width * self.height) : (i += 1) {
|
||||
const cell: u16 = self.content[i];
|
||||
const byte1: u8 = @intCast(u8, cell / 256);
|
||||
const byte2: u8 = @intCast(u8, cell % 256);
|
||||
try writer.writeByte(byte1);
|
||||
try writer.writeByte(byte2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw level tiles from `offset` to fill the window.
|
||||
pub fn draw(self: *Self, scale: u16, offset: Vec2) void {
|
||||
pub fn draw(self: Self, scale: u16, offset: Vec2) void {
|
||||
// Pixel position (were we draw).
|
||||
var x: Vec2.int_type = 0;
|
||||
var y: Vec2.int_type = 0;
|
||||
|
@ -147,7 +188,7 @@ pub fn draw(self: *Self, scale: u16, offset: Vec2) void {
|
|||
}
|
||||
|
||||
/// Draw selection from `offset` to fill the window.
|
||||
pub fn draw_selection(self: *Self, scale: u16, offset: Vec2) void {
|
||||
pub fn draw_selection(self: Self, scale: u16, offset: Vec2) void {
|
||||
// Pixel position (were we draw).
|
||||
var x: Vec2.int_type = 0;
|
||||
var y: Vec2.int_type = 0;
|
||||
|
@ -261,11 +302,30 @@ test "select rectangle area" {
|
|||
expect(!level.selection[245]);
|
||||
}
|
||||
|
||||
test "load level from existing file" {
|
||||
test "load level from sample file and save it" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var level: Self = try Self.init_load(allocator, "sample.kble");
|
||||
defer level.deinit(allocator);
|
||||
|
||||
try level.write("sample_out.kble");
|
||||
}
|
||||
|
||||
test "write large level to file and load it back" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = &arena.allocator;
|
||||
|
||||
var level: Self = try Self.init(allocator, 300, 1);
|
||||
|
||||
try level.write("sample_large.kble");
|
||||
|
||||
level.deinit(allocator);
|
||||
level = try Self.init_load(allocator, "sample_large.kble");
|
||||
defer level.deinit(allocator);
|
||||
|
||||
expect(level.width == 300);
|
||||
expect(level.height == 1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue