summaryrefslogtreecommitdiff
path: root/bstates.ha
blob: bf329f27fa7b3ea760d45a356cbe5f433388582e (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
97
98
99
100
101
102
103
104
105
106
107
use types;
use strings;

type BstateId = u32;
type BlockPropId = u32;

type BlockBstates = struct {
	state0: BstateId,
	nstates: u32,
	props: [](str, []str),
	prop_moduli: []u32,
};

type BstateInfo = struct {
	block: BlockId,
};

let BLOCKS_BSTATES: []BlockBstates = [];
let BSTATES_INFO: []BstateInfo = [];

fn bstates_handle_blocks_onregister(blk: BlockId) void = {
	append(BLOCKS_BSTATES, BlockBstates { ... });
};

fn block_addprop(blk: BlockId, name: str, values: []str) BlockPropId = {
	assert(len(values) != 0, "Block property must have at least 1 value");
	const bstates = &BLOCKS_BSTATES[blk];
	assert(len(bstates.props) < types::U32_MAX - 1,
		"Too many block properties");
	append(bstates.props, (strings::dup(name), strings::dupall(values)));
	return len(bstates.props): u32 - 1;
};

fn init_bstates() void = {
	for (let blk: BlockId = 0; blk < blocks_count(); blk += 1) {
		const bstates = &BLOCKS_BSTATES[blk];

		bstates.prop_moduli = alloc([], len(bstates.props));
		let mod = 1u32;
		for (let j = 0z; j < len(bstates.props); j += 1) {
			// TODO: overflow...
			mod *= len(bstates.props[j].1): u32;
			static append(bstates.prop_moduli, mod);
		};
		bstates.state0 = len(BSTATES_INFO): u32;
		bstates.nstates = mod;

		assert(bstates.state0 + bstates.nstates > bstates.state0,
			"Too many blockstates");

		for (let j = 0u32; j < mod; j += 1) {
			append(BSTATES_INFO, BstateInfo {
				block = blk,
			});
		};
	};
};

fn destroy_bstates() void = {
	for (let blk: BlockId = 0; blk < blocks_count(); blk += 1) {
		const bstates = &BLOCKS_BSTATES[blk];
		for (let i = 0z; i < len(bstates.props); i += 1) {
			free(bstates.props[i].0);
			strings::freeall(bstates.props[i].1);
		};
		free(bstates.prop_moduli);
	};
	free(BLOCKS_BSTATES);
	free(BSTATES_INFO);
};

fn block_propcount(blk: BlockId) u32 =
	len(BLOCKS_BSTATES[blk].props): u32;

fn block_propname(blk: BlockId, prop: BlockPropId) str =
	BLOCKS_BSTATES[blk].props[prop].0;

fn block_findprop(blk: BlockId, name: str) (BlockPropId | void) = {
	for (let prop: BlockPropId = 0;
			prop < block_propcount(blk); prop += 1) {
		if (block_propname(blk, prop) == name)
			return prop;
	};
};

fn block_propvalcount(blk: BlockId, prop: BlockPropId) u32 =
	len(BLOCKS_BSTATES[blk].props[prop].1): u32;

fn block_propvalname(blk: BlockId, prop: BlockPropId, val: u32) str =
	BLOCKS_BSTATES[blk].props[prop].1[val];

fn block_findpropval(blk: BlockId, prop: BlockPropId, name: str)
		(u32 | void) = {
	for (let val = 0u32; val < block_propvalcount(blk, prop); val += 1) {
		if (block_propvalname(blk, prop, val) == name)
			return val;
	};
};

fn bstate_getblock(bstate: BstateId) BlockId =
	BSTATES_INFO[bstate].block;

fn bstate_getprop(bstate: BstateId, blk: BlockId, prop: BlockPropId) u32 = {
	const bstates = &BLOCKS_BSTATES[blk];
	return (bstate - bstates.state0) % bstates.prop_moduli[prop]
		/ (if (prop == 0) 1u32 else bstates.prop_moduli[prop - 1]);
};