- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 507
- Реакции
- 13
Вижу, в тредах по реверсу Раста народ до сих пор клянчит актуальные prefab id. Видимо, не все в курсе, что обновлять prefab.h руками после каждого патча — это путь для мазохистов.
Сливаю годноту, которая позволяет генерить ID прямо из имени префаба в компайл-тайме или рантайме. Метод не новый, но крайне эффективный: вместо того чтобы хранить тонны мусора, просто скармливаете строку хешеру и получаете валидный uint32_t.
Как юзать в своем проекте:
Теперь достаточно просто передать полный путь к префабу, например:
"assets/prefabs/deployable/tier 2 workbench/workbench2.deployed.prefab" — и функция вернет правильный ID.
Пользуйтесь, пока разработчики Rust не придумали что-то посложнее обычного хеширования строк.
Сливаю годноту, которая позволяет генерить ID прямо из имени префаба в компайл-тайме или рантайме. Метод не новый, но крайне эффективный: вместо того чтобы хранить тонны мусора, просто скармливаете строку хешеру и получаете валидный uint32_t.
Код:
#ifndef CONSTEXPR_MD5_H_
#define CONSTEXPR_MD5_H_
#include <array>
#include <climits>
#include <cstdint>
#include <cstring>
namespace md5 {
using Digest = std::array<unsigned char, 16>;
namespace details {
constexpr uint32_t CBLOCK = 64;
constexpr uint32_t LBLOCK = CBLOCK / 4;
constexpr size_t const_strlen(const char* str)
{
return (*str == 0) ? 0 : const_strlen(str + 1) + 1;
}
constexpr Digest make_digest(const std::array<uint32_t, 4>& input) noexcept {
Digest digest{};
for (size_t i = 0; i < input.size(); ++i) {
digest[i * 4] = static_cast<unsigned char>((input[i]) & 0xff);
digest[i * 4 + 1] = static_cast<unsigned char>((input[i] >> 8) & 0xff);
digest[i * 4 + 2] = static_cast<unsigned char>((input[i] >> 16) & 0xff);
digest[i * 4 + 3] = static_cast<unsigned char>((input[i] >> 24) & 0xff);
}
return digest;
}
using Fn = uint32_t(*)(uint32_t, uint32_t, uint32_t);
constexpr uint32_t f(uint32_t b, uint32_t c, uint32_t d) noexcept { return (b & c) | (~b & d); }
constexpr uint32_t g(uint32_t b, uint32_t c, uint32_t d) noexcept { return (b & d) | (c & ~d); }
constexpr uint32_t h(uint32_t b, uint32_t c, uint32_t d) noexcept { return b ^ c ^ d; }
constexpr uint32_t i(uint32_t b, uint32_t c, uint32_t d) noexcept { return c ^ (b | ~d); }
constexpr Fn F[4] = { f, g, h, i };
constexpr uint32_t G[CBLOCK] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
};
constexpr uint32_t K[CBLOCK] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
constexpr uint32_t S[LBLOCK] = {
7, 12, 17, 22,
5, 9, 14, 20,
4, 11, 16, 23,
6, 10, 15, 21
};
constexpr char PADDING[CBLOCK] = {
-128, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
constexpr uint32_t rotate(uint32_t x, uint32_t n) noexcept { return (x << n) | (x >> (32 - n)); }
constexpr uint32_t t(Fn f, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) noexcept {
return b + rotate(a + f(b, c, d) + x + ac, s);
}
constexpr uint32_t to_uint32(const unsigned char* data) noexcept {
return (static_cast<uint32_t>(data[3]) << 24) | (static_cast<uint32_t>(data[2]) << 16) | (static_cast<uint32_t>(data[1]) << 8) | (static_cast<uint32_t>(data[0]));
}
struct Context {
std::array<unsigned char, CBLOCK> buffer;
std::array<uint32_t, 4> state;
uint32_t nl, nh;
constexpr Context() noexcept : buffer(), state{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }, nl(0), nh(0) {}
constexpr void append(const char* data, size_t len) noexcept {
std::array<uint32_t, LBLOCK> input{};
auto k = (nl >> 3) & 0x3f;
auto length = static_cast<uint32_t>(len);
nl += length << 3;
if (nl < length << 3) nh += 1;
nh += length >> 29;
for (auto ptr = data; ptr != data + len; ++ptr) {
buffer[k++] = static_cast<unsigned char>(static_cast<int16_t>(*ptr) + UCHAR_MAX + 1);
if (k == 0x40) {
auto j = 0;
for (auto i = 0; i < LBLOCK; ++i) { input[i] = to_uint32(&buffer[j]); j += 4; }
transform(input);
k = 0;
}
}
}
constexpr void transform(const std::array<uint32_t, LBLOCK>& input) noexcept {
auto a = state[0], b = state[1], c = state[2], d = state[3];
for (uint32_t r = 0; r < 4; ++r) {
const auto g = G + r * LBLOCK;
const auto s = S + r * 4;
const auto k = K + r * LBLOCK;
for (auto i = 0; i < input.size(); ++i) {
const auto new_b = t(F[r], a, b, c, d, input[g[i]], s[i % 4], k[i]);
a = d; d = c; c = b; b = new_b;
}
}
state[0] += a; state[1] += b; state[2] += c; state[3] += d;
}
constexpr Digest final() noexcept {
std::array<uint32_t, LBLOCK> input{};
const auto k = ((nl >> 3) & 0x3f);
input[14] = nl; input[15] = nh;
append(PADDING, k < 56 ? 56 - k : 120 - k);
auto j = 0;
for (auto i = 0; i < 14; ++i) { input[i] = to_uint32(&buffer[j]); j += 4; }
transform(input);
return make_digest(state);
}
};
}
template <size_t N>
constexpr Digest compute(const char(&data)[N]) noexcept {
details::Context c;
c.append(data, N - 1);
return c.final();
}
constexpr Digest compute(const char* s) noexcept {
details::Context c;
c.append(s, details::const_strlen(s));
return c.final();
}
}
#endif
Как юзать в своем проекте:
Код:
constexpr uint32_t int_32(md5::Digest const& num)
{
return (uint32_t)((int)(num[0]) | ((int)num[1] << 8) | ((int)num[2] << 16) | ((int)num[3] << 24));
}
constexpr uint32_t prefab_id(const char* str)
{
return int_32(md5::compute(str));
}
Теперь достаточно просто передать полный путь к префабу, например:
"assets/prefabs/deployable/tier 2 workbench/workbench2.deployed.prefab" — и функция вернет правильный ID.
Пользуйтесь, пока разработчики Rust не придумали что-то посложнее обычного хеширования строк.