1 /**
2 Copyright: Copyright (c) 2016-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.world.blockentity.blockentitydata;
7 
8 import voxelman.math;
9 
10 enum BlockEntityType : ubyte
11 {
12 	localBlockEntity,
13 	foreignBlockEntity,
14 	//componentId
15 }
16 
17 enum ENTITY_DATA_MASK = (1UL << 46) - 1;
18 enum PAYLOAD_MASK = (1UL << 62) - 1;
19 
20 // 3 bytes from LSB side
21 enum MAIN_OFFSET_BITS = 8*3;
22 enum MAIN_OFFSET_MASK = (1 << MAIN_OFFSET_BITS) - 1;
23 // ushort for block index
24 enum MAIN_BLOCK_INDEX_MASK = ushort.max;
25 
26 /// Layout (bit fields, MSB -> LSB)
27 /// 2: type; 16 id + 46 entityData = 62 payload
28 /// data is:
29 /// localBlockEntity: entity id + data in payload
30 /// foreignBlockEntity: position of localBlockEntity (relative to current entity)
31 /// componentId: id in component system
32 struct BlockEntityData
33 {
34 	ulong storage;
35 
36 	this(ulong data) {
37 		storage = data;
38 	}
39 	this(BlockEntityType type, ushort id, ulong entityData) {
40 		storage = cast(ulong)type << 62 | cast(ulong)id << 46 |
41 			entityData & ENTITY_DATA_MASK;
42 	}
43 	this(BlockEntityType type, ushort id, ubyte[3] mainOffset, ushort blockIndex) {
44 		storage =
45 			cast(ulong)type << 62 |
46 			cast(ulong)id << 46 |
47 			(cast(ulong)blockIndex << MAIN_OFFSET_BITS) |
48 			(cast(ulong)mainOffset[0]) |
49 			(cast(ulong)mainOffset[1] << 8) |
50 			(cast(ulong)mainOffset[2] << 16);
51 	}
52 	this(BlockEntityType type, ulong payload) {
53 		storage = cast(ulong)type << 62 |
54 			payload & PAYLOAD_MASK;
55 	}
56 
57 	BlockEntityType type() { return cast(BlockEntityType)(storage >> 62); }
58 	ushort id() { return cast(ushort)(storage >> 46); }
59 	ulong entityData() { return storage & ENTITY_DATA_MASK; }
60 	ulong payload() { return storage & PAYLOAD_MASK; }
61 	MainChunkPointer mainChunkPointer() {
62 		MainChunkPointer res;
63 		res.entityId = id;
64 
65 		ulong offData = storage & MAIN_OFFSET_MASK;
66 		res.mainChunkOffset = ivec3(*cast(ubyte[3]*)&offData);
67 		res.blockIndex = (storage >> MAIN_OFFSET_BITS) & MAIN_BLOCK_INDEX_MASK;
68 
69 		return res;
70 	}
71 }
72 
73 ivec3 entityDataToSize(ulong entityData) {
74 	enum MASK_8_BIT = (1<<8) - 1;
75 	uint x = entityData & MASK_8_BIT;
76 	uint y = (entityData >> 8) & MASK_8_BIT;
77 	uint z = (entityData >> 16) & MASK_8_BIT;
78 	return ivec3(x, y, z);
79 }
80 
81 ulong sizeToEntityData(ivec3 size) {
82 	enum MASK_8_BIT = (1<<8) - 1;
83 	ulong x = cast(ulong)size.x & MASK_8_BIT;
84 	ulong y = (cast(ulong)size.y & MASK_8_BIT) << 8;
85 	ulong z = (cast(ulong)size.z & MASK_8_BIT) << 16;
86 	return x | y | z;
87 }
88 
89 // data assigned to foreign chunk of multichunk entity.
90 struct MainChunkPointer
91 {
92 	// offset in chunk coords from main chunk that contains entity data.
93 	// mainChunkOffset = otherPos - mainPos;
94 	// mainPos = otherPos - mainChunkOffset
95 	ivec3 mainChunkOffset;
96 	// block index in main chunk. Can be used as key to entity map in main chunk.
97 	ushort blockIndex;
98 	// id of the whole block entity.
99 	ushort entityId;
100 }