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]); };