Compare commits

...

6 Commits

3 changed files with 87 additions and 65 deletions

View File

@@ -6,9 +6,7 @@ A from-scratch rewrite of [mcaselector](https://github.com/Querz/mcaselector) in
[![licence](https://img.shields.io/github/license/thepigeongenerator/mcaselector-lite.svg)](https://github.com/thepigeongenerator/mcaselector-lite/blob/main/LICENSE) [![licence](https://img.shields.io/github/license/thepigeongenerator/mcaselector-lite.svg)](https://github.com/thepigeongenerator/mcaselector-lite/blob/main/LICENSE)
[![issues](https://img.shields.io/github/issues/thepigeongenerator/mcaselector-lite.svg)](https://github.com/thepigeongenerator/mcaselector-lite/issues/) [![issues](https://img.shields.io/github/issues/thepigeongenerator/mcaselector-lite.svg)](https://github.com/thepigeongenerator/mcaselector-lite/issues/)
[![CI](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/ci.yaml/badge.svg)](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/ci.yaml) [![CI](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/ci.yaml/badge.svg)](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/ci.yaml)
[![release](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/release.yaml/badge.svg)](https://github.com/thepigeongenerator/mcaselector-lite/actions/workflows/release.yaml)
## what does it do ## what does it do
MCA selector lite is a tool used to edit [region files](https://minecraft.wiki/w/Region_file_format) of your [Minecraft java](https://minecraft.wiki/w/Java_Edition) worlds. MCA selector lite is a tool used to edit [region files](https://minecraft.wiki/w/Region_file_format) of your [Minecraft java](https://minecraft.wiki/w/Java_Edition) worlds.
@@ -20,3 +18,7 @@ MCA selector is a tool written in Java. Where it depends upon JRE21 and JavaFX.
The goal of this project is to create a version of the original MCA selector, but written in C, leveraging the improved performance due to native execution and more low-level control. The goal of this project is to create a version of the original MCA selector, but written in C, leveraging the improved performance due to native execution and more low-level control.
I have picked C as the language for the core portions of the application, where I prefer fine-grained control with little abstractions. I have picked C as the language for the core portions of the application, where I prefer fine-grained control with little abstractions.
This version is not intended to serve to entirely replace MCA selector, just to offer an alternative. Both tools will have their strengths and weaknesses. This version is not intended to serve to entirely replace MCA selector, just to offer an alternative. Both tools will have their strengths and weaknesses.
# planned features
- [ ] CLI-only version
- [ ] filtering chunks based on time spent in them

View File

@@ -7,10 +7,76 @@
#include "../util/compat/endian.h" #include "../util/compat/endian.h"
#include "../util/types.h" #include "../util/types.h"
int nbt_primsize(u8 tag) {
switch (tag) {
case NBT_I8: return 1;
case NBT_I16: return 2;
case NBT_I32: // fall through
case NBT_F32: return 4;
case NBT_I64: // fall through
case NBT_F64: return 8;
default: return -1;
}
}
const u8 *nbt_nextcompound(const u8 *restrict cdat) {
return NULL;
}
const u8 *nbt_nextlist(const u8 *restrict ldat) {
const u8 *ptr = ldat + 5;
i32 len = be32toh(*(u32 *)(ldat + 1));
switch (*ldat) {
case NBT_I8:
case NBT_I16:
case NBT_I32:
case NBT_I64:
case NBT_F32:
case NBT_F64:
return ptr + nbt_primsize(*ldat) * len;
// loop for each compound, whilst `ptr` isn't `NULL`
case NBT_COMPOUND: {
for (u32 i = 0; i < (u32)len && ptr; i++) {
ptr = nbt_nextcompound(ptr);
}
return ptr;
}
// TODO: implement list/array/string handling
case NBT_STR:
case NBT_ARR_I8:
case NBT_ARR_I32:
case NBT_ARR_I64:
case NBT_LIST:
default:
return NULL;
}
}
const u8 *nbt_nexttag(const u8 *restrict buf, u16 naml) { const u8 *nbt_nexttag(const u8 *restrict buf, u16 naml) {
size_t len = nbt_tagdatlen(buf); const u8 *ptr = buf + naml + 3;
if (!len) return NULL; // TODO: compound tags should be handled here size_t mems = 0;
return buf + naml + len + 3;
switch (*buf) {
case NBT_I8:
case NBT_I16:
case NBT_I32:
case NBT_F32:
case NBT_I64:
case NBT_F64:
return ptr + nbt_primsize(*buf);
case NBT_ARR_I64: mems += sizeof(i64) - sizeof(i32); __attribute__((fallthrough));
case NBT_ARR_I32: mems += sizeof(i32) - sizeof(i8); __attribute__((fallthrough));
case NBT_ARR_I8: return ptr + ++mems * (i32)be32toh(*(u32 *)(ptr)) + 4;
case NBT_STR: return ptr + be16toh(*(u16 *)(ptr)) + 2;
case NBT_LIST: return nbt_nextlist(ptr);
default: return NULL;
}
} }
// TODO: not actually doing anything // TODO: not actually doing anything
@@ -95,56 +161,3 @@ int nbt_proc(struct nbt_path const *restrict pats, uint npats, const u8 *restric
// TODO: finish function // TODO: finish function
return !dpt; return !dpt;
} }
int nbt_primsize(u8 tag) {
switch (tag) {
case NBT_I8: return 1;
case NBT_I16: return 2;
case NBT_I32: // fall through
case NBT_F32: return 4;
case NBT_I64: // fall through
case NBT_F64: return 8;
default: return -1;
}
}
size_t nbt_tagdatlen(const u8 *restrict buf) {
size_t mems = 0;
switch (*buf) {
case NBT_I8:
case NBT_I16:
case NBT_I32:
case NBT_F32:
case NBT_I64:
case NBT_F64:
mems = nbt_primsize(*buf);
return -(mems >= 0) & mems;
case NBT_ARR_I64: mems += sizeof(i64) - sizeof(i32); __attribute__((fallthrough));
case NBT_ARR_I32: mems += sizeof(i32) - sizeof(i8); __attribute__((fallthrough));
case NBT_ARR_I8: return +mems * (i32)be32toh(*(u32 *)(buf)) + 4;
case NBT_STR: return be16toh(*(u16 *)buf) + 2;
case NBT_LIST:
mems = nbt_primsize(*buf);
if (mems > 0) return mems * (i32)be32toh(*(u32 *)(buf + 1)) + 5;
return 0;
default: return 0;
}
}
int nbt_isprim(u8 tag) {
switch (tag) {
case NBT_I8:
case NBT_I16:
case NBT_I32:
case NBT_F32:
case NBT_I64:
case NBT_F64:
return 1;
default:
return 0;
}
}

View File

@@ -41,6 +41,20 @@ struct nbt_path {
i16 len; // specifies the length of the NBT elements i16 len; // specifies the length of the NBT elements
}; };
/* searches for the end of a compound tag without processing data, the final pointer is returned.
* `NULL` is returned upon failure, the otherwise returned pointer is not guaranteed to be valid.
* `cdat` is assumed to be the start of the **compound tag's data**. */
PURE NONNULL((1)) const u8 *nbt_nextcompound(const u8 *restrict cdat);
/* searches for the end of a list tag without processing data, the final pointer is returned.
* `NULL` is returned upon failure, the otherwise returned pointer is not guaranteed to be valid.
* `ldat` is assumed to be the start of the **list tag's data.** */
PURE NONNULL((1)) const u8 *nbt_nextlist(const u8 *restrict ldat);
/* searches for the end of a named tag without processing data, the final pointer is returned.
* `NULL` is returned upon failure, the otherwise returned pointer is not guaranteed to be valid. */
PURE NONNULL((1)) const u8 *nbt_nexttag(const u8 *restrict buf, u16 naml);
/* returns the name length of a specific tag. `buf` is the pointer to start of the tag */ /* returns the name length of a specific tag. `buf` is the pointer to start of the tag */
atrb_pure atrb_nonnull(1) static inline u16 nbt_namelen(const u8 *restrict buf) { atrb_pure atrb_nonnull(1) static inline u16 nbt_namelen(const u8 *restrict buf) {
assert(*buf != NBT_END); assert(*buf != NBT_END);
@@ -51,13 +65,6 @@ atrb_pure atrb_nonnull(1) static inline u16 nbt_namelen(const u8 *restrict buf)
* `NULL` is returned if anything went wrong. */ * `NULL` is returned if anything went wrong. */
atrb_pure atrb_nonnull(1) const u8 *nbt_nexttag(const u8 *restrict buf, u16 naml); atrb_pure atrb_nonnull(1) const u8 *nbt_nexttag(const u8 *restrict buf, u16 naml);
/* checks whether the tag is a primitive data tag. (not recommended for filtering tags, use a `switch`)
* returns a boolean value. */
atrb_const int nbt_isprim(u8 tag);
/* gets the byte size of an NBT tag's data (excluding id and name), returns `0` upon error. */
atrb_pure size_t nbt_tagdatlen(const u8 *buf);
/* gets the tag size of primitive types, returns `>0` on success, `<0` on failure */ /* gets the tag size of primitive types, returns `>0` on success, `<0` on failure */
atrb_const int nbt_primsize(u8 tag); atrb_const int nbt_primsize(u8 tag);