Skip to content

Instantly share code, notes, and snippets.

@MajsterTynek
Created March 31, 2022 21:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MajsterTynek/388cf80835746d6156e69b5498fff9c6 to your computer and use it in GitHub Desktop.
Save MajsterTynek/388cf80835746d6156e69b5498fff9c6 to your computer and use it in GitHub Desktop.
Unofficial specification of Baritone Cache Region file format. (*.bcr) Check 'BcrFileFormatSpec.txt' as it explains the layout and meaning of values. Included example programs in C++20 that unpack ('bcr-gun') and parse ('bcr-parse') data contained within a single 'bcr' file. I had to port some things to mimic Java and Baritone behaviours. Those …
/* Here are stored functions that
* mimic Baritone and Java internals
* just to simplify the converter*/
// baritone.utils.pathing.PathingBlockType
enum PathingBlockType {AIR, WATER, AVOID, SOLID};
// Base values used you need to know:
#define CACHED_REGION_MAGIC 0x1B2E5B7E // 456022910 BE!
#define CHUNK_NOT_PRESENT 0
#define CHUNK_PRESENT 1
// Bitset size for cache used by single chunk
#define BITS_PER_CHUNK 131072
#define BYTES_PER_CHUNK 16384
#define WORDS_PER_CHUNK 2048
/// Returns the raw bitset index of the specified position
inline int getPosIdx(int x, int y, int z){
return (x << 1) | (z << 5) | (y << 9);
}
/// Metadata of 0 for liquids means source
inline bool possiblyFlowing(char source){
return source != 0;
}
/// Check if slab occupies lower block half
inline bool isBottomSlab(char slab){
return !(slab & 8);
}
/* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns. */
#define ADDRESS_BITS_PER_WORD 6
#define BITS_PER_WORD (1 << ADDRESS_BITS_PER_WORD)
#define BIT_INDEX_MASK (BITS_PER_WORD - 1)
// Used to shift left or right for a partial word mask */
#define WORD_MASK 0xffffffffffffffffL
/// Returns index of long integer that stores our bit
inline int wordIndex(int bitIndex){
return bitIndex >> ADDRESS_BITS_PER_WORD;
}
/// Returns memory chunk that can store specified number of bits
inline long long *newBitset(int nbits){
return new long long[wordIndex(nbits - 1) + 1]();
}
/// Sets a bit in a BitSet mimicking Java way
inline void set(long long *bitset, int bitIndex){
bitset[wordIndex(bitIndex)] |= 1L << (077 & bitIndex);
}
/// Clears a bit in a BitSet mimicking Java way
inline void clear(long long *bitset, int bitIndex){
bitset[wordIndex(bitIndex)] &= ~(1L << (077 & bitIndex));
}
/// Flips bit value at specified bit position
inline void flip(long long *bitset, int bitIndex, bool v){
bitset[wordIndex(bitIndex)] ^= (1L << (077 & bitIndex));
}
/// Sets new bit value at specified bit position
inline void change(long long *bitset, int bitIndex, bool v){
v ? set(bitset, bitIndex) : clear(bitset, bitIndex);
}
/// Just in case we need to know a bot value
inline bool get(long long *bitset, int bitIndex){
return bitset[wordIndex(bitIndex)] & (1L << (077 & bitIndex));
}
/// Interprets block type from a bitset at specified position
PathingBlockType readCache(long long *bitset, int x, int y, int z){
int idx = getPosIdx(x, y, z);
bool b1 = get(bitset, idx);
bool b2 = get(bitset, idx + 1);
using enum PathingBlockType;
return b1 ? b2 ? SOLID : AVOID : b2 ? WATER : AIR;
}
/// Writes block type to bitset cache
void writeCache(
long long *bitset,
int x, int y, int z,
PathingBlockType type)
{
int idx = getPosIdx(x, y, z);
change(bitset, idx, type & 1);
change(bitset, idx + 1, type & 2);
}
#include "endianness.hpp"
/// x86 works on little endian thus
/// we have to change it to big endian
void byteswap(long long *bitset, size_t n){
for (size_t i = 0; i < n; i++)
bitset[i] = bswap64(bitset[i]);
}
// g++ bcr-gun.cpp -o bcr-gun.exe ^
// -O2 -Wall -march=native -std=c++20 -ldeflate
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
#include <libdeflate.h>
const char* code[] =
{
"LIBDEFLATE_SUCCESS",
"LIBDEFLATE_BAD_DATA",
"LIBDEFLATE_SHORT_OUTPUT",
"LIBDEFLATE_INSUFFICIENT_SPACE"
};
int main(int argc, char *argv[])
{
if (argc != 2) return 1;
fs::path path(argv[1]);
size_t arsize= fs::file_size(path);
char* archive = new char[arsize];
std::ifstream file(path, std::ios::binary);
file.read(archive, arsize);
size_t bcr_size = *(int*)(archive + arsize - 4);
char* bcr = new char[bcr_size];
std::clog << path << ": " << "GZ" << ' '
<< arsize << ' ' << bcr_size << std::endl;
size_t consumed = 0, outputted = 0;
libdeflate_decompressor *deco = libdeflate_alloc_decompressor();
libdeflate_result r = libdeflate_gzip_decompress_ex(
deco, archive, arsize,
bcr, bcr_size, &consumed, &outputted );
libdeflate_free_decompressor(deco);
std::clog << code[r]
<< ": readen " << consumed
<< ", written " << outputted;
if (r) return 2;
std::ofstream bcr_file(
path.stem().string() + ".bcr_unpack",
std::ios::binary | std::ios::trunc );
bcr_file.write(bcr, outputted);
delete[] archive;
delete[] bcr;
return 0;
}
// g++ bcr-parse.cpp -o bcr-parse.exe ^
// -O2 -Wall -march=native -std=c++20 -ldeflate
#include <ctime>
#include <limits>
#include <cstdlib>
#include <regex>
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
#include <libdeflate.h>
#include "endianness.hpp"
#include "BLOCKS.cxx"
#include "BARITONE.cxx"
const char* code[] =
{
"LIBDEFLATE_SUCCESS",
"LIBDEFLATE_BAD_DATA",
"LIBDEFLATE_SHORT_OUTPUT",
"LIBDEFLATE_INSUFFICIENT_SPACE"
};
// making stream from buffer in memory, huh?
struct membuf: std::streambuf {
membuf(char* base, std::ptrdiff_t n) {
this->setg(base, base, base + n);
}
char * curr() {
return this->gptr(); // protected
}
};
// byte swap template magic
template<typename T>
inline T bswap(T var){
switch(sizeof(var)){
case 2: return bswap16(var);
case 4: return bswap32(var);
case 8: return bswap64(var);
default: return var;
}
}
// float specialisation
template<>
inline float bswap(float var){
return bswap_f(var);
}
// double specialisation
template<>
inline double bswap(double var){
return bswap_d(var);
}
// simple macros for stream io
#define READ(var) read((char*)&(var),sizeof(var))
#define WRITE(var) write((char*)&(var),sizeof(var))
#define BSWAP(var) (var = bswap(var))
#define LOCATION ' ' << '@' << std::hex \
<< (sbuf.curr() - bcr) << std::dec << std::endl
std::string_view readUTF(std::istream& stream){
unsigned short s;
stream.READ(s);
BSWAP(s);
using v = std::string_view;
auto p = ((membuf*)(stream.rdbuf()))->curr();
stream.ignore(s);
return v(p, s);
}
union shortpos{
unsigned short packed;
struct{ unsigned short y:8, x:4, z:4; };
};
/*union longpos{
long long packed;
struct{ int x, z; };
};*/
struct longpos{ int x, z; };
// MAIN
int main(int argc, char *argv[]) try
{
if (argc != 2) return 1;
fs::path path(argv[1]);
longpos region;
std::smatch match;
std::string format = "r.{x}.{z}.bcr";
std::regex re{R"(r\.(-?\d+)\.(-?\d+)\.bcr)"};
std::string filename = path.filename().string();
if ( std::regex_match(filename, match, re) )
{
region.x = std::stoi(match[1]) * 512;
region.z = std::stoi(match[2]) * 512;
}
else
{
std::cerr << "File needs to follow format: "
<< format << std::endl << "Got: "
<< filename << ' ' << "instead!";
return 3;
}
size_t arsize = fs::file_size(path);
char* archive = new char[arsize];
std::ifstream file(path, std::ios::binary);
file.read((char*)archive, arsize);
size_t bcr_size = *(int*)(archive + arsize - 4);
char* bcr = new char[bcr_size];
std::cout << "Loading [x:" << region.x
<< ",z:" << region.z << "]" << std::endl;
std::cout << path << ": " << "GZ" << ' '
<< arsize << ' ' << bcr_size << std::endl;
size_t consumed = 0, outputted = 0;
libdeflate_decompressor *deco = libdeflate_alloc_decompressor();
libdeflate_result r = libdeflate_gzip_decompress_ex(
deco, archive, arsize,
bcr, bcr_size, &consumed, &outputted );
libdeflate_free_decompressor(deco);
std::cout << code[r];
if (consumed != arsize || outputted != bcr_size){
std::cout << ": readen " << consumed
<< ", written " << outputted;
}
std::cout << std::endl;
if (r) return 2;
std::ofstream bcr_file(
path.stem().string() + ".bcr_unpack",
std::ios::binary | std::ios::trunc );
bcr_file.write(bcr, outputted);
membuf sbuf(bcr, outputted);
std::istream cache(&sbuf);
unsigned int MAGIC; // CACHED_REGION_MAGIC
cache.READ(MAGIC);
BSWAP(MAGIC);
std::cout << "MAGIC " << (MAGIC == 456022910 ? "OK" : "NOK");
std::cout << std::endl << std::endl;
std::cout << "Cached chunks" << LOCATION;
int chunks = 0;
long long type[4]{0};
longpos chunkpos[32 * 32]{0};
for (int x = 0; x < 32; x++){
for (int z = 0; z < 32; z++){
if (cache.get()){
chunkpos[chunks++] = {
region.x + x * 16,
region.z + z * 16
};
//auto& [a, b] = chunkpos[chunks - 1];
//std::cout << "CHUNK\t" << a << '\t' << b << std::endl;
long long* ptr = (long long*) sbuf.curr();
cache.ignore(BYTES_PER_CHUNK);
for (int by = 0; by < 256; by++){
for (int bz = 0; bz < 16; bz++){
for (int bx = 0; bx < 16; bx++){
PathingBlockType T = readCache(ptr, bx, by, bz);
type[T]++; // just count them for all present chunks
}
}
}
}
}
}
std::cout << "AIR\t" << type[PathingBlockType::AIR] << std::endl;
std::cout << "WATER\t" << type[PathingBlockType::WATER] << std::endl;
std::cout << "AVOID\t" << type[PathingBlockType::AVOID] << std::endl;
std::cout << "SOLID\t" << type[PathingBlockType::SOLID] << std::endl;
std::cout << "Live chunks: " << chunks << '\n' << std::endl;
std::cout << "Surface overview" << LOCATION;
using v = std::string_view;
long surface[BLOCKS_LAST]{};
for (int i = 0; i < chunks; i++){
for (int j = 0; j < 256; j++){
unsigned short s;
cache.READ(s);
BSWAP(s);
//std::cout << s << '|';
v name(sbuf.curr(), s);
cache.ignore(s);
//std::cout << name << '|';
int id = BLOCKID.at(name);
//std::cout << id << std::endl;
surface[id]++;
}
}
// printing out surface block counts
/*for (int i = 0; i < BLOCKS_LAST; i++){
if (surface[i] != 0){
std::cout << i << '\t' << surface[i]
<< '\t' << BLOCKS.at(i) << std::endl;
}
}*/
int len = 0;
for (int i = 0; i < BLOCKS_LAST; i++){
if (surface[i] != 0){
v b = BLOCKS.at(i);
std::cout << b << ", ";
len += 2 + b.size();
if (len > 72)
{
std::cout << '\n';
len = 0;
}
}
}
std::cout << std::endl << std::endl;
std::cout << "Tracked blocks" << LOCATION;
for (int i = 0; i < chunks; i++)
{
auto& [x,z] = chunkpos[i];
unsigned short unique;
cache.READ(unique);
BSWAP(unique);
for (int u = 0; u < unique; u++)
{
auto block = readUTF(cache);
//std::cout << block << std::endl;
unsigned short tracks;
cache.READ(tracks);
BSWAP(tracks);
for (int t = 0; t < tracks; t++)
{
shortpos pos;
cache.READ(pos.packed);
BSWAP(pos.packed);
std::cout << x + pos.x << '\t'
<< z + pos.z << '\t'
<< pos.y << '\t'
<< block << std::endl;
// here I could make absolute coord
// and store it into a set
}
}
}
std::cout << '\n' << "Timestamps" << LOCATION;
time_t stamp, min, max; // millis since epoch
min = std::numeric_limits<time_t>::max();
max = std::numeric_limits<time_t>::min();
for (int i = 0; i < chunks; i++)
{
cache.READ(stamp);
BSWAP(stamp);
if (stamp < min) min = stamp;
if (stamp > max) max = stamp;
}
min /= 1000; // ms to s
max /= 1000; // ms to s
std::cout << "min\t" << std::asctime((std::localtime(&min)));
std::cout << "max\t" << std::asctime((std::localtime(&max)));
delete[] archive;
delete[] bcr;
return 0;
} catch (const std::exception& e) { std::cerr << e.what(); }
// **Chunk caching**
Baritone simplifies chunks to a compacted internal 2-bit representation
(AIR, SOLID, WATER, AVOID) and stores them in RAM for better very-long-distance
pathing. There is also an option to save these cached chunks to disk.
// uncompressed cache takes lots of space thus it uses single GZIP stream
// you may unpack it with 7zip or other if you change extension to *.gz
// files need be named "r.{x}.{z}.bcr" to be valid, as name is used to locate it
// btw coordinate order = most significant = inner most loop
// for ex. XZY! order = for Y: { for Z: { for X: { block } } }
// minus sign indicates iteration with decrementing value
// base values used you need to know:
CACHED_REGION_MAGIC = 456022910; // BE int:0x1B2E5B7E
CHUNK_NOT_PRESENT = 0, // byte
CHUNK_PRESENT = 1; // byte
// baritone.utils.pathing.PathingBlockType:
AIR = 0b00, // 0
WATER = 0b01, // 1
AVOID = 0b10, // 2
SOLID = 0b11; // 3
// UTF-8 string:
- BE short: size (in bytes?) (2 bytes)
- array of characters of specified size (not a CString?)
// "baritone cache region" streamed fields:
- magic number
// Magic value to detect invalid cache files, or incompatible
// cache files saved in an old version of Baritone
- array of 1024 chunks {boolean exists, optional<BitSet> chunkData} // ZX! order
// if no chunk is present, it is just 1024 NUL bytes
// after each CHUNK_PRESENT, you skip BitSet to reach next boolean
- for each existing chunkData, array of 256 UTF-8 block name strings // XZ! order
// for surface overview; compute their pos using heigtmap made with BitSet
- for each existing chunkData, array of arrays of specil bloks!
// BE short number of unique block types, then
// UTF-8 block name string + BE short number of know relative postions
// following array of positions, 1st byte: Z << 4 | X; 2nd byte: just Y
- for each existing chunkData, 64 bit timestamp (miliseconds since epoch)
// EOF
// BitSet size is constant. Chunks are 16x16x256, each block requires 2 bits.
public static final int SIZE = 2 * 16 * 16 * 256; // 131072 = 0x20000 (bits)
// The size of the chunk data in bytes. Equals to 16 KiB.
public static final int SIZE_IN_BYTES = SIZE / 8; // 16384 = 0x4000 (bytes)
// The list of special blocks that are remembered in cache
public static final ImmutableSet<Block> BLOCKS_TO_KEEP_TRACK_OF;
// = ImmutableSet.of(Blocks...)
DIAMOND_BLOCK, COAL_BLOCK, IRON_BLOCK, GOLD_BLOCK, EMERALD_ORE, EMERALD_BLOCK,
ENDER_CHEST, FURNACE, CHEST, TRAPPED_CHEST, END_PORTAL, END_PORTAL_FRAME,
MOB_SPAWNER, BARRIER, OBSERVER, WHITE_SHULKER_BOX, ORANGE_SHULKER_BOX,
MAGENTA_SHULKER_BOX, LIGHT_BLUE_SHULKER_BOX, YELLOW_SHULKER_BOX,
LIME_SHULKER_BOX, PINK_SHULKER_BOX, GRAY_SHULKER_BOX, SILVER_SHULKER_BOX,
CYAN_SHULKER_BOX, PURPLE_SHULKER_BOX, BLUE_SHULKER_BOX, BROWN_SHULKER_BOX,
GREEN_SHULKER_BOX, RED_SHULKER_BOX, BLACK_SHULKER_BOX, PORTAL, HOPPER,
BEACON, BREWING_STAND, SKULL, ENCHANTING_TABLE, ANVIL,LIT_FURNACE,
BED, DRAGON_EGG, JUKEBOX, END_GATEWAY, WEB, NETHER_WART, LADDER, VINE
// Returns the raw bit index of the specified position
public static int getPositionIndex(int x, int y, int z) {
return (x << 1) | (z << 5) | (y << 9);
}
// CachedChunk pack(Chunk chunk) // creation of it
BitSet bitSet = new BitSet(CachedChunk.SIZE); // 0x4000
Map<String, List<BlockPos>> specialBlocks = new HashMap<>();
// the mapping of BlockStateContainer.getIndex
// from xyz to index is: y << 8 | z << 4 | x; // XZY! order
// for better cache locality, iterate in that order
for (int y0 = 0; y0 < 16; y0++) { // chunkInternalStorageArray[y0]; // null?
int yReal = y0 << 4;
for (int y1 = 0; y1 < 16; y1++) {
int y = y1 | yReal;
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
boolean[] bits = getPathingBlockType...
bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]);
// if "special" then add to specialBlocks
// The block names of each surface level block for generating an overview
IBlockState[] overview = new IBlockState[256]; // surface blocks or "air"
overview[z << 4 | x] = Blocks.AIR.getDefaultState(); // -YXZ!, first non AIR
// computed data is used to make cached chunk and then returned
new CachedChunk(chunk.x, chunk.z, bitSet, overview, specialBlocks, timestamp);
#include <array>
#include <string_view>
#include <unordered_map>
/// Given a map from keys to values, creates a new map from values to keys
template<typename K, typename V>
static auto reverse_map(const std::unordered_map<K, V>& m) {
std::unordered_map<V, K> r;
for (const auto& kv : m)
r[kv.second] = kv.first;
return r;
}
#define BLOCKS_LAST 255
/// map of block entries, id -> name
std::unordered_map<int,std::string_view> const BLOCKS {
{ 0, "air"}, // AIR
{ 1, "stone"},
{ 2, "grass"},
{ 3, "dirt"},
{ 4, "cobblestone"},
{ 5, "planks"},
{ 6, "sapling"},
{ 7, "bedrock"},
{ 8, "flowing_water"}, // META
{ 9, "water"}, // META
{ 10, "flowing_lava"}, // AVOID
{ 11, "lava"}, // AVOID
{ 12, "sand"},
{ 13, "gravel"},
{ 14, "gold_ore"},
{ 15, "iron_ore"},
{ 16, "coal_ore"},
{ 17, "log"},
{ 18, "leaves"},
{ 19, "sponge"},
{ 20, "glass"},
{ 21, "lapis_ore"},
{ 22, "lapis_block"},
{ 23, "dispenser"},
{ 24, "sandstone"},
{ 25, "noteblock"},
{ 26, "bed"},
{ 27, "golden_rail"},
{ 28, "detector_rail"},
{ 29, "sticky_piston"},
{ 30, "web"}, // AVOID
{ 31, "tallgrass"}, // AIR
{ 32, "deadbush"}, // AIR
{ 33, "piston"},
{ 34, "piston_head"},
{ 35, "wool"},
{ 36, "piston_extension"},
{ 37, "yellow_flower"}, // AIR
{ 38, "red_flower"}, // AIR
{ 39, "brown_mushroom"},
{ 40, "red_mushroom"},
{ 41, "gold_block"},
{ 42, "iron_block"},
{ 43, "double_stone_slab"},
{ 44, "stone_slab"}, // META
{ 45, "brick_block"},
{ 46, "tnt"},
{ 47, "bookshelf"},
{ 48, "mossy_cobblestone"},
{ 49, "obsidian"},
{ 50, "torch"},
{ 51, "fire"}, // AVOID
{ 52, "mob_spawner"},
{ 53, "oak_stairs"},
{ 54, "chest"},
{ 55, "redstone_wire"},
{ 56, "diamond_ore"},
{ 57, "diamond_block"},
{ 58, "crafting_table"},
{ 59, "wheat"},
{ 60, "farmland"},
{ 61, "furnace"},
{ 62, "lit_furnace"},
{ 63, "standing_sign"},
{ 64, "wooden_door"},
{ 65, "ladder"},
{ 66, "rail"},
{ 67, "stone_stairs"},
{ 68, "wall_sign"},
{ 69, "lever"},
{ 70, "stone_pressure_plate"},
{ 71, "iron_door"},
{ 72, "wooden_pressure_plate"},
{ 73, "redstone_ore"},
{ 74, "lit_redstone_ore"},
{ 75, "unlit_redstone_torch"},
{ 76, "redstone_torch"},
{ 77, "stone_button"},
{ 78, "snow_layer"},
{ 79, "ice"},
{ 80, "snow"},
{ 81, "cactus"}, // AVOID
{ 82, "clay"},
{ 83, "reeds"},
{ 84, "jukebox"},
{ 85, "fence"},
{ 86, "pumpkin"},
{ 87, "netherrack"},
{ 88, "soul_sand"},
{ 89, "glowstone"},
{ 90, "portal"},
{ 91, "lit_pumpkin"},
{ 92, "cake"},
{ 93, "unpowered_repeater"},
{ 94, "powered_repeater"},
{ 95, "stained_glass"},
{ 96, "trapdoor"},
{ 97, "monster_egg"},
{ 98, "stonebrick"},
{ 99, "brown_mushroom_block"},
{ 100, "red_mushroom_block"},
{ 101, "iron_bars"},
{ 102, "glass_pane"},
{ 103, "melon_block"},
{ 104, "pumpkin_stem"},
{ 105, "melon_stem"},
{ 106, "vine"},
{ 107, "fence_gate"},
{ 108, "brick_stairs"},
{ 109, "stone_brick_stairs"},
{ 110, "mycelium"},
{ 111, "waterlily"},
{ 112, "nether_brick"},
{ 113, "nether_brick_fence"},
{ 114, "nether_brick_stairs"},
{ 115, "nether_wart"},
{ 116, "enchanting_table"},
{ 117, "brewing_stand"},
{ 118, "cauldron"},
{ 119, "end_portal"}, // AVOID
{ 120, "end_portal_frame"},
{ 121, "end_stone"},
{ 122, "dragon_egg"},
{ 123, "redstone_lamp"},
{ 124, "lit_redstone_lamp"},
{ 125, "double_wooden_slab"},
{ 126, "wooden_slab"}, // META
{ 127, "cocoa"},
{ 128, "sandstone_stairs"},
{ 129, "emerald_ore"},
{ 130, "ender_chest"},
{ 131, "tripwire_hook"},
{ 132, "tripwire"},
{ 133, "emerald_block"},
{ 134, "spruce_stairs"},
{ 135, "birch_stairs"},
{ 136, "jungle_stairs"},
{ 137, "command_block"},
{ 138, "beacon"},
{ 139, "cobblestone_wall"},
{ 140, "flower_pot"},
{ 141, "carrots"},
{ 142, "potatoes"},
{ 143, "wooden_button"},
{ 144, "skull"},
{ 145, "anvil"},
{ 146, "trapped_chest"},
{ 147, "light_weighted_pressure_plate"},
{ 148, "heavy_weighted_pressure_plate"},
{ 149, "unpowered_comparator"},
{ 150, "powered_comparator"},
{ 151, "daylight_detector"},
{ 152, "redstone_block"},
{ 153, "quartz_ore"},
{ 154, "hopper"},
{ 155, "quartz_block"},
{ 156, "quartz_stairs"},
{ 157, "activator_rail"},
{ 158, "dropper"},
{ 159, "stained_hardened_clay"},
{ 160, "stained_glass_pane"},
{ 161, "leaves2"},
{ 162, "log2"},
{ 163, "acacia_stairs"},
{ 164, "dark_oak_stairs"},
{ 165, "slime"},
{ 166, "barrier"},
{ 167, "iron_trapdoor"},
{ 168, "prismarine"},
{ 169, "sea_lantern"},
{ 170, "hay_block"},
{ 171, "carpet"},
{ 172, "hardened_clay"},
{ 173, "coal_block"},
{ 174, "packed_ice"},
{ 175, "double_plant"}, // AIR
{ 176, "standing_banner"},
{ 177, "wall_banner"},
{ 178, "daylight_detector_inverted"},
{ 179, "red_sandstone"},
{ 180, "red_sandstone_stairs"},
{ 181, "double_stone_slab2"},
{ 182, "stone_slab2"}, // META
{ 183, "spruce_fence_gate"},
{ 184, "birch_fence_gate"},
{ 185, "jungle_fence_gate"},
{ 186, "dark_oak_fence_gate"},
{ 187, "acacia_fence_gate"},
{ 188, "spruce_fence"},
{ 189, "birch_fence"},
{ 190, "jungle_fence"},
{ 191, "dark_oak_fence"},
{ 192, "acacia_fence"},
{ 193, "spruce_door"},
{ 194, "birch_door"},
{ 195, "jungle_door"},
{ 196, "acacia_door"},
{ 197, "dark_oak_door"},
{ 198, "end_rod"},
{ 199, "chorus_plant"},
{ 200, "chorus_flower"},
{ 201, "purpur_block"},
{ 202, "purpur_pillar"},
{ 203, "purpur_stairs"},
{ 204, "purpur_double_slab"},
{ 205, "purpur_slab"}, // META
{ 206, "end_bricks"},
{ 207, "beetroots"},
{ 208, "grass_path"},
{ 209, "end_gateway"},
{ 210, "repeating_command_block"},
{ 211, "chain_command_block"},
{ 212, "frosted_ice"},
{ 213, "magma"}, // AVOID
{ 214, "nether_wart_block"},
{ 215, "red_nether_brick"},
{ 216, "bone_block"},
{ 217, "structure_void"},
{ 218, "observer"},
{ 219, "white_shulker_box"},
{ 220, "orange_shulker_box"},
{ 221, "magenta_shulker_box"},
{ 222, "light_blue_shulker_box"},
{ 223, "yellow_shulker_box"},
{ 224, "lime_shulker_box"},
{ 225, "pink_shulker_box"},
{ 226, "gray_shulker_box"},
{ 227, "silver_shulker_box"},
{ 228, "cyan_shulker_box"},
{ 229, "purple_shulker_box"},
{ 230, "blue_shulker_box"},
{ 231, "brown_shulker_box"},
{ 232, "green_shulker_box"},
{ 233, "red_shulker_box"},
{ 234, "black_shulker_box"},
{ 235, "white_glazed_terracotta"},
{ 236, "orange_glazed_terracotta"},
{ 237, "magenta_glazed_terracotta"},
{ 238, "light_blue_glazed_terracotta"},
{ 239, "yellow_glazed_terracotta"},
{ 240, "lime_glazed_terracotta"},
{ 241, "pink_glazed_terracotta"},
{ 242, "gray_glazed_terracotta"},
{ 243, "silver_glazed_terracotta"},
{ 244, "cyan_glazed_terracotta"},
{ 245, "purple_glazed_terracotta"},
{ 246, "blue_glazed_terracotta"},
{ 247, "brown_glazed_terracotta"},
{ 248, "green_glazed_terracotta"},
{ 249, "red_glazed_terracotta"},
{ 250, "black_glazed_terracotta"},
{ 251, "concrete"},
{ 252, "concrete_powder"},
{ 255, "structure_block"}
};
/// map of block entries, name -> id
auto const BLOCKID = reverse_map(BLOCKS);
/// preset array to ease determining block path type
std::array<bool, BLOCKS_LAST> TRACKED{};
std::array<bool, BLOCKS_LAST> SOLIDS{};
int BLOCKS_TO_KEEP_TRACK_OF[] = {
26, // BED,
30, // WEB,
41, // GOLD_BLOCK,
42, // IRON_BLOCK,
52, // MOB_SPAWNER,
54, // CHEST,
57, // DIAMOND_BLOCK,
61, // FURNACE,
62, // LIT_FURNACE,
65, // LADDER,
84, // JUKEBOX,
90, // PORTAL,
106, // VINE
115, // NETHER_WART,
116, // ENCHANTING_TABLE,
117, // BREWING_STAND,
119, // END_PORTAL,
120, // END_PORTAL_FRAME,
122, // DRAGON_EGG,
129, // EMERALD_ORE,
130, // ENDER_CHEST,
133, // EMERALD_BLOCK,
138, // BEACON,
144, // SKULL,
145, // ANVIL,
146, // TRAPPED_CHEST,
154, // HOPPER,
166, // BARRIER,
173, // COAL_BLOCK,
209, // END_GATEWAY,
218, // OBSERVER,
// SHULKER BOXES !
219, // WHITE_SHULKER_BOX,
220, // ORANGE_SHULKER_BOX,
221, // MAGENTA_SHULKER_BOX,
222, // LIGHT_BLUE_SHULKER_BOX,
223, // YELLOW_SHULKER_BOX,
224, // LIME_SHULKER_BOX,
225, // INK_SHULKER_BOX,
226, // GRAY_SHULKER_BOX,
227, // SILVER_SHULKER_BOX,
228, // CYAN_SHULKER_BOX,
229, // PURPLE_SHULKER_BOX,
230, // BLUE_SHULKER_BOX,
231, // BROWN_SHULKER_BOX,
232, // GREEN_SHULKER_BOX,
233, // RED_SHULKER_BOX,
234 // BLACK_SHULKER_BOX,
};
void initBlocks(){
// intialise block array that have SOLID property
for (bool &property : SOLIDS) property = true;
// set block ids that are tracked by Baritone itself
for (int i : BLOCKS_TO_KEEP_TRACK_OF) TRACKED[i] = true;
// those may have different property than SOLID
for (int i : {0, 8, 9, 10, 11, 30, 31, 32, 37, 38, 44,
51, 81, 119, 126, 175, 182, 205, 213})
SOLIDS[i] = false; // those need additional checks
}
inline bool isTracked(int id){
return TRACKED[id];
}
local dump = require 'ForgeRegistryDump'
local registry, registry_name = dump()
local header = 'std::unordered_map<int,std::string> const %s {\n'
local entry, footer, flush = ' { %d, "%s"}', '\n};\n', ',\n'
if not registry then return end
-- build sorted table
local ordered = {}
for k, v in pairs(registry) do table.insert(ordered, {id = k, name = v}) end
table.sort(ordered, function(a,b) return a.id < b.id end)
-- source code builder
local text, last = header:format(registry_name), #ordered
for current, res in ipairs(ordered) do
if current ~= last then
text = text .. entry:format(res.id, res.name) .. flush
else text = text .. entry:format(res.id, res.name) .. footer end
end
last = "#define "..registry_name.."_LAST "..ordered[last].id..'\n'
io.open(registry_name..".cxx", "w+"):write(last):write(text):close()
log("&6Dumped \""..registry_name.."\" registry to source file!")
#ifndef ENDIANNESS_HPP
#define ENDIANNESS_HPP
#ifdef __GNUC__
#define __BSWAP__
#include <x86intrin.h>
#define bswap16 __builtin_bswap16
#define bswap32 __builtin_bswap32
#define bswap64 __builtin_bswap64
#endif // __GNUC__
#ifdef _MSC_VER
#define __BSWAP__
#include <intrin.h>
#define bswap16 _byteswap_ushort
#define bswap32 _byteswap_ulong
#define bswap64 _byteswap_uint64
#endif // _MSC_VER
#ifdef __BSWAP__
static inline float bswap_f(float val)
{
union{ float fp; long long bytes; };
fp = val, bytes = bswap32( bytes );
return fp;
}
static inline double bswap_d(double val)
{
union{ double fp; long long bytes; };
fp = val, bytes = bswap64( bytes );
return fp;
}
#endif // __BSWAP__
#if not defined NETWORK_BYTE_ORDER and not defined __BSWAP__
#error BYTESWAPS ARE NOT IMPLEMENTED! No code written for your compiler!
#elif defined NETWORK_BYTE_ORDER
#define bswap16(x) (x)
#define bswap32(x) (x)
#define bswap64(x) (x)
#define bswap_f(x) (x)
#define bswap_d(x) (x)
#endif
#endif // ENDIANNESS_HPP
Loading [x:0,z:0]
"r.0.0.bcr": GZ 74227 4660101
LIBDEFLATE_SUCCESS
MAGIC OK
Cached chunks @4
AIR 12579406
WATER 897160
AVOID 14236
SOLID 3286414
Live chunks: 256
Surface overview @400404
stone, grass, dirt, cobblestone, planks, water, sand, gravel, log, leaves,
sandstone, bed, deadbush, brown_mushroom, red_mushroom, mossy_cobblestone,
wheat, stone_stairs, reeds, spruce_stairs, carrots, potatoes, spruce_fence,
grass_path,
Tracked blocks @47113c
1 1 65 bed
2 1 65 bed
1 2 65 bed
2 2 65 bed
121 51 44 chest
124 51 44 mob_spawner
170 145 21 chest
169 147 21 chest
171 147 21 mob_spawner
Timestamps @471385
min Sun Mar 13 14:27:26 2022
max Sun Mar 13 14:28:13 2022
-- a helper function to turn registry into table
local dumper = function(REGISTRY,includes_domain)
local Forge = luajava.bindClass'net.minecraftforge.fml.common.registry.ForgeRegistries'
local REGISTRY = REGISTRY or prompt(
"Choose registry to dump:", "choice",
table.unpack( luajava.getDeclaredFields( Forge ) )
)
if not REGISTRY then return false end
local RegistryName = REGISTRY
REGISTRY = Forge[REGISTRY]
local entries = {}
local adapter = function(entry)
local K, V = entry:getKey()
if includes_domain then
V = K:toString()
else -- getResourcePath
V = K:func_110623_a()
end
--V = REGISTRY:getValue(K)
K = REGISTRY:getIDRaw(K)
entries[K] = V -- without "minecraft:"
end
local Consumer = "java.util.function.Consumer"
local adapt = luajava.createProxy( Consumer, { accept = adapter })
REGISTRY:getEntries():forEach(adapt)
return entries, RegistryName
end
return dumper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment