Lot of bugfixes

* Adding clipper to generate the terrain's negative powder-contour offset.
* Fixing RDB issues (fracture, active trigger, performances)
* Fixing blood emission
* Fixing the freezing formula on liquids
* Fixing Steve spawning due to a missed test.
* Reaction table properly build
This commit is contained in:
Gaël committed 2026-10-21 20:46:13 +02:00
1 parent a34f42d53e
commit 00a9c1c26c
48 files changed
+5799 -435

No files matched your search

+72
View File
@@ -20,6 +20,53 @@ layout(std430, set = 0, binding = 8) readonly buffer Tables { uint tbl[]; }; /
uint flame_material(uint m, uint dflt) { const uint v = tbl[1024u + 4u * mats[mats.length() - 1u].w + 2u * m]; return v != 0u ? v - 1u : dflt; }
uint smoke_material(uint m, uint dflt) { const uint v = tbl[1024u + 4u * mats[mats.length() - 1u].w + 2u * m + 1u]; return v != 0u ? v - 1u : dflt; }
#include "biome_mods.glsl"
layout(std430, set = 0, binding = 28) readonly buffer RHead { uint rhead[]; };
layout(std430, set = 0, binding = 29) readonly buffer RRec { uint rrec[]; };
const ivec2 TD4[4] = ivec2[4](ivec2(0,-1), ivec2(-1,0), ivec2(1,0), ivec2(0,1));
uint native_material(uint m) { const uint n = mats[mats.length()-1u].w; return rhead[2u*n*(n+1u)+m]; }
uint body_neighbor(ivec2 q, Body B, int s, vec2 com, float cs, float sn, uint m, uint base) {
const ivec2 grid = q - ivec2(pc.view_x, pc.view_y);
if (grid.x < 0 || grid.y < 0 || grid.x >= pc.gw || grid.y >= pc.gh) return NONE;
const ivec2 local = ivec2(floor(rot2(cs, -sn, vec2(q) + 0.5 - B.p.xy) + com));
if (shape_solid(s, local.x, local.y) && (burn[base + uint(local.y*shi(s,0)+local.x)] & BURNT) == 0u) return m;
return cell_mat(cells[grid.y*pc.gw+grid.x]);
}
// Solid-cell 0070e060 calls the combined/fast paths when body record +0x2e
// permits them. Ice glass must keep that path after leaving the terrain grid.
int solid_conversion(ivec2 wc, Body B, int s, vec2 com, float cs, float sn, uint m, uint base, uint seed) {
if ((B.i.z & 65536) != 0) return -1; // native collapse record disables reactions
const uint r = hash3(seed, uint(pc.frame), 40u) & 32767u;
const uint R = r % 10001u;
const uint dir = hash3(seed, uint(pc.frame), 41u) & 3u;
const ivec2 q = wc + TD4[dir];
const uint nm = body_neighbor(q, B, s, com, cs, sn, m, base);
if (nm == NONE) return -1;
const bool full = (pc.frame % 11) == 0;
if (full) {
const uint bb = bm_bytes(vec2(wc));
const uint fc = (bb >> 16) & 255u, uc = bb >> 24;
const uvec2 cv = bm_conversions(m);
const bool cold = fc != 0u && (cv.x & 65535u) != 0u && (hash3(seed,uint(pc.frame),42u)&32767u) % ((cv.x>>16)+1u) < fc;
const bool warm = uc != 0u && (cv.y & 65535u) != 0u && (hash3(seed,uint(pc.frame),43u)&32767u) % ((cv.y>>16)+1u) < uc;
if (cold) return nm == 0u || (mflags(nm)&F_LIQCELL) == 0u || (mflags(nm)&F_POWDER) != 0u ? int((cv.x&65535u)-1u) : -1;
if (warm) return native_material(nm) != native_material(m) ? int((cv.y&65535u)-1u) : -1;
}
const uint n = mats[mats.length()-1u].w, table = full ? 0u : n*(n+1u);
const uint h = rhead[table + m*n+nm], count = h & 255u;
if (count == 0u || rhead[table+n*n+m] == 0u || R > rhead[table+n*n+m]) return -1;
const uint e = ((h>>8) + R%count)*5u, pw = rrec[e+1u];
const uint requiredDir = (pw>>16)&7u, actualDir = dir == 0u ? 1u : dir == 1u ? 3u : dir == 2u ? 4u : 2u;
if (R > (pw&65535u) || (requiredDir != 0u && requiredDir != actualDir)) return -1;
// Complex sprite reactions need per-pixel material storage; leave those to
// the existing fracture path rather than applying only half their outputs.
if ((rrec[e+2u]&65535u) != 65535u || (rrec[e+3u]&65535u) != 0u || (rrec[e+4u]&0x7FFFFFFFu) != 0u) return -1;
const uint target = rrec[e]&65535u, other = rrec[e]>>16;
if (target == 65535u || native_material(target) == native_material(m)) return -1;
if (other != 65535u && native_material(other) != native_material(nm)) return -1;
return int(target);
}
void main() {
int bi = int(gl_WorkGroupID.x);
if (bi >= bhdr.x) return;
@@ -29,6 +76,13 @@ void main() {
if (matp1 == 0u) return;
const uint m = matp1 - 1u;
const uint mz = mats[3u * m + 2u].z, mw = mats[3u * m + 2u].w;
// Most rigid materials have no fast reactions. Avoid visiting their pixels
// on the ten ordinary updates between combined updates.
if (((mz >> 16) & 1u) == 0u) {
if ((B.i.z & 65536) != 0) return;
const uint n = mats[mats.length()-1u].w;
if ((pc.frame % 11) != 0 && rhead[n*(n+1u)+n*n+m] == 0u) return;
}
const int s = B.i.x;
const int w = shi(s, 0), h = shi(s, 1);
if (w * h > 4096) return;
@@ -50,6 +104,24 @@ void main() {
const ivec2 wc = ivec2(floor(wp));
const uint seed = uint(bi) * 4099u + uint(px);
if ((st & BURNING) == 0u) {
const int target = solid_conversion(wc, B, s, com, cs, sn, m, base, seed);
if (target >= 0 && (mflags(uint(target)) & (F_LIQCELL | F_GAS | F_FIRE | F_AIR)) != 0u) {
const ivec2 grid = wc - ivec2(pc.view_x, pc.view_y);
if (grid.x >= 0 && grid.y >= 0 && grid.x < pc.gw && grid.y < pc.gh) {
const int index = grid.y*pc.gw+grid.x;
const int ei = atomicAdd(ctrl.burnN.x, 1);
if (ei < 256) {
if (atomicCompSwap(cells[index], 0u, uint(target)) == 0u) {
material_changed(index, 0u, uint(target));
ctrl.burnEv[ei] = ivec4(bi, px, target+1, 0);
burn[base+uint(px)] = BURNT;
continue;
}
ctrl.burnEv[ei] = ivec4(-1);
} else atomicAdd(ctrl.burnN.x, -1);
}
}
if (((mz >> 16) & 1u) == 0u) continue;
// fire sources in the pixel's cell and the four around it (cells are free under a body)
float keep = 1.0, bestFade = -1.0;
bool wet = false;