aboutsummaryrefslogtreecommitdiff
path: root/server/save_load.ha
blob: db5a18a2a3df328a65fdce0afde041627c38d782 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use bytes;
use errors;
use fmt;
use fs;
use io;
use os;
use strings;

use drawing;
use drawing::{pos,CHUNKSIZE};

// caller should free return value
fn filename_from_world_pos(pos: pos) str =
	fmt::asprintf("./c.{}.{}.ppm",pos.0,pos.1);

fn save_world(state: *server_state) (void | fs::error) = {
	for (const pic &.. state.pictures) {
		const filename = filename_from_world_pos(pic.world_pos);
		fmt::printfln("\t-> {}",filename)!;
		defer free(filename);

		const mode = fs::mode::USER_RW | fs::mode::GROUP_RW;
		const file = os::create(filename, mode)?;
		defer io::close(file): void;

		fmt::fprintf(file, "P6\n{} {}\n{}\n", pic.w, pic.h, 255)?;

		let buf: []u8 = alloc([0...],3*pic.w*pic.h);
		defer free(buf);
		for (let i = 0z; i < pic.w * pic.h; i += 1) {
			const px = pic.d[i];
			buf[3*i  ] = ((px>>16)&0xff): u8;
			buf[3*i+1] = ((px>>8) &0xff): u8;
			buf[3*i+2] = ((px)    &0xff): u8;
		};
		io::writeall(file, buf)?;

	};
		
};

fn new_picture(world_pos: pos) drawing::picture = {
	let picture_buf: []u32 = alloc([0xffffff...], CHUNKSIZE*CHUNKSIZE);
	return drawing::picture {
		w = CHUNKSIZE,
		h = CHUNKSIZE,
		d = picture_buf: *[*]u32,
		world_pos = world_pos,
	};
};

type bad_header = !void;

// loads the chunk at the given position from the filesystem,
// or, if no file is found, creates a fresh new chunk
fn load_picture_from_file(world_pos: pos) (drawing::picture | fs::error | bad_header) = {
	const filename = filename_from_world_pos(world_pos);
	defer free(filename);
	const file = match (os::open(filename)) {
		case let f: io::file => yield f;
		case errors::noentry => return new_picture(world_pos);
		case let e: fs::error => return e;
	};
	fmt::printfln("reading from {}",filename)!;
	defer {
		fmt::printfln("closing {}",filename)!;
		match (io::close(file)) {
			case let err: io::error => fmt::println("error",io::strerror(err))!;
			case => yield;
		};
	};

	const header = fmt::asprintf("P6\n{} {}\n{}\n",CHUNKSIZE,CHUNKSIZE,255);
	defer free(header);
	const header_bytes = strings::toutf8(header);
	let header_buf: []u8 = alloc([0...],len(header_bytes));
	defer free(header_buf);
	io::readall(file, header_buf)?;
	if (!bytes::equal(header_buf, header_bytes)) return bad_header;

	let file_buf: []u8 = alloc([0...], 3*CHUNKSIZE*CHUNKSIZE);
	defer free(file_buf);
	io::readall(file, file_buf)?;
	let picture_buf: []u32 = alloc([0...], CHUNKSIZE*CHUNKSIZE);
	for (let i = 0z; i < len(picture_buf); i += 1) {
		picture_buf[i] = (file_buf[3*i]:u32<<16)
						|(file_buf[3*i+1]:u32<<8)
						|(file_buf[3*i+2]:u32);
	};
	return drawing::picture {
		w = CHUNKSIZE,
		h = CHUNKSIZE,
		d = picture_buf: *[*]u32,
		world_pos = world_pos,
	};
};