#include #include #include #include #include #include "globals.h" #include "tools.h" #include "registries.h" uint32_t getHash (const void *data, size_t len) { const uint8_t *bytes = data; uint32_t hash = 2166136261u; for (size_t i = 0; i < len; i ++) { hash ^= bytes[i]; hash *= 16777619u; } return hash; } int sapling (short x, short y, short z) { uint8_t buf[10]; memcpy(buf, &x, 2); memcpy(buf + 2, &y, 2); memcpy(buf + 4, &z, 2); memcpy(buf + 6, &world_seed, 4); if (getHash(buf, sizeof(buf)) % 20 == 0) return B_oak_sapling; return B_air; } uint32_t getChunkHash (short x, short z) { uint8_t buf[8]; memcpy(buf, &x, 2); memcpy(buf + 2, &z, 2); memcpy(buf + 4, &world_seed, 4); return getHash(buf, sizeof(buf)); } int getCornerHeight (uint32_t hash) { int height = 60 + hash % 8 + (hash >> 8) % 5; if (height < 64) height -= (hash >> 16) % 5; return height; } #define chunk_size 8 int interpolate (int a, int b, int c, int d, int x, int z) { int top = a * (chunk_size - x) + b * x; int bottom = c * (chunk_size - x) + d * x; return (top * (chunk_size - z) + bottom * z) / (chunk_size * chunk_size); } int getHeightAt (int x, int z, uint32_t chunk_hash) { int _x = x / chunk_size; int _z = z / chunk_size; int rx = x % chunk_size; int rz = z % chunk_size; if (rx < 0) { rx += chunk_size; _x -= 1; } if (rz < 0) { rz += chunk_size; _z -= 1; } if (rx == 0 && rz == 0) { int height = getCornerHeight(chunk_hash); if (height > 67) return height - 1; } else { return interpolate( getCornerHeight(chunk_hash), getCornerHeight(getChunkHash(_x + 1, _z)), getCornerHeight(getChunkHash(_x, _z + 1)), getCornerHeight(getChunkHash(_x + 1, _z + 1)), rx, rz ); } } uint8_t getBlockAt (int x, int y, int z) { uint8_t block_change = getBlockChange(x, y, z); if (block_change != 0xFF) return block_change; if (y > 80) return B_air; int _x = x / chunk_size; int _z = z / chunk_size; int rx = x % chunk_size; int rz = z % chunk_size; int height; // make remainders positive and move the cell index when negative if (rx < 0) { rx += chunk_size; _x -= 1; } if (rz < 0) { rz += chunk_size; _z -= 1; } uint32_t chunk_hash = getChunkHash(_x, _z); if (rx == 0 && rz == 0) { height = getCornerHeight(chunk_hash); if (height > 67) height -= 1; } else { height = interpolate( getCornerHeight(chunk_hash), getCornerHeight(getChunkHash(_x + 1, _z)), getCornerHeight(getChunkHash(_x, _z + 1)), getCornerHeight(getChunkHash(_x + 1, _z + 1)), rx, rz ); } if (y >= 64 && y > height) { uint8_t tree_position = chunk_hash % (chunk_size * chunk_size); short tree_x = tree_position % chunk_size; if (tree_x < 3 || tree_x > chunk_size - 3) goto skip_tree; tree_x += _x * chunk_size; short tree_z = tree_position / chunk_size; if (tree_z < 3 || tree_z > chunk_size - 3) goto skip_tree; tree_z += _z * chunk_size; uint8_t tree_y = getHeightAt(tree_x, tree_z, chunk_hash) + 1; if (tree_y < 64) goto skip_tree; if (x == tree_x && z == tree_z && y >= tree_y && y < tree_y + 6) return B_oak_log; uint8_t dx = x > tree_x ? x - tree_x : tree_x - x; uint8_t dz = z > tree_z ? z - tree_z : tree_z - z; if (dx < 3 && dz < 3 && y > tree_y + 2 && y < tree_y + 5) { if (y == tree_y + 4 && dx == 2 && dz == 2 && (chunk_hash >> (x + z + y)) & 1) return B_air; return B_oak_leaves; } if (dx < 2 && dz < 2 && y >= tree_y + 5 && y <= tree_y + 6) { if (y == tree_y + 6 && dx == 1 && dz == 1 && (chunk_hash >> (x + z + y)) & 1) return B_air; return B_oak_leaves; } } skip_tree: if (y >= 63 && y == height) return B_grass_block; if (y < height - 3) return B_stone; if (y <= height) return B_dirt; if (y < 64) return B_water; return B_air; }