Tags
Creators
Details
All versions
0.10.11
Release
0.10.11last week 46
Compatibility
Minecraft: Java Edition
1.7.10
Platform
Forge
Supported environments
Client and server
Required content
Any compatible version
Changes
CatFrame - 0.10.11
What is changed?
Change version number from previous to 0.10.11
➕Add:
- Implement blockstate uvlock. Parse path already existed (BlockstateJson.Variant.uvlock); now threaded through the bake pipeline. JsonModelBake.applyUvLock re-derives each rotated quad's UV from its world position per the final facing (mirrors vanilla FaceBakery.lockVertexUv), so geometry turns but the texture stays world-locked. UnbakedModel gains a default bake(...,uvlock) overload; ModelJsonUnbakedAdapter applies the lock only when a non-zero rotation is present. uvlock is plumbed through ModelBaker/BakingCore and encoded into the BakedModelCache key via a trailing '!' marker (lazy-baked; async pre-bake keeps plain keys). Consumers (ResidentStateModel, RenderDispatcher, StateProviderBlockModel) pass variant.uvlock.
- Add chunk-boundary render refresh on chunk load (IWorldAccess notification bypass). Vanilla 1.7.10 only re-marks neighbour sections on chunk UNLOAD (WorldClient.doPreChunk false branch); both client chunk handlers (NetHandlerPlayClient.handleChunkData S21 / handleMapChunkBulk S26) mark only the received chunk's own range after fillChunk, so connection geometry across chunk seams stays stale until an unrelated block update. New client-only MixinNetHandlerPlayClient injects at the handler TAILs (block data already filled, deferred rebuild reads it next render pass) and emits four one-block-wide World.markBlockRangeForRenderUpdate strips hugging the loaded column; the +/-1 section dilation is vanilla's own RenderGlobal.markBlocksForUpdate behaviour, and the unload path is skipped. Registered under Mixins.RENDERING.
- Add unit tests for the joinCode staticization work: stateIndexOf injectivity/domain/-1 bypass and static-property participation, MultipartWhen precomputed split with fallback equivalence, BakedModelCache generation bump, ResidentStateModel memo identity/exclusion/rebuild; set compileTestJava UTF-8 encoding
- Memoize merged blockstate parts by full cartesian-product state index (joinCode): add BlockStateDefinition.stateIndexOf with -1 bypass, ResidentStateModel per-target part memo with weighted-array exclusion, and BakedModelCache generation counter to invalidate memos on reload
- WorldTranslucentPasses (new): marks blocks whose BLOCK_WORLD part contains force-translucent quads, maintains a per-thread chunk-tessellation scope, sequence-pairs getRenderBlockPass -> canRenderInPass -> render to carry the current tessellation pass (0 solid / 1 alpha), and coalesces first-time discoveries into a deferred loadRenderers rebuild on client tick end. clear() drops marks on model re-registration so a hijack never outlives its model.
- MixinBlock (new): base-only, narrow-gate injections. getRenderBlockPass returns 1 for marked blocks (so the pass loop compiles an alpha mesh); canRenderInPass(opts the solid pass 0 back in for the paired block). Blocks overriding these themselves (native glass, GTNH-style multi-pass) dispatch to their subclass body first and stay untouched. canRenderInPass is a Forge-patched method (no SRG name in prod), so it is targeted with remap=false rather than an extraMappings srg entry.
- JsonModelBake: add per-quad BakedQuad.forceTranslucent; new bakeElement overload taking a force-variable set; an element is force-translucent as a whole when any face references a flagged variable (element granularity per spec). deepCopyQuad copies the flag.
- BlockStateModelPart: add translucentSplit() (solid vs force-translucent sub-parts, zero-allocation when homogeneous), mirroring atlasSplit.
- Add canonicalKey(): bare paths default to the minecraft namespace, builtin/ passes through.
🔧Fix:
- Fix StateProviderBlockModel.collectPartsWithProps ignoring blockstate rotation. Both the variants and multipart paths now resolve via BakedModelCache.buildKey(model, x, y, z, uvlock) instead of ModelBaker.bake(model), so variant.x/y/z and uvlock take effect and results are cached (previously re-baked identity model every call). Removed the now-unused ModelBaker import.
- Add compile-window neighbor probe reuse (B1 scratch, never a store). ChunkProbeCache is a ThreadLocal-gated IBlockAccess decorator over a hand-rolled open-addressing long[]/Block[]/byte[] table (no fastutil in the baseline): getBlock and getBlockMetadata dedupe per cell inside one WorldRenderer.updateRenderer pass, where client chunk compilation sees an immutable world. Meta lines fill lazily so block-only probes cost a single delegate read. begin/end ride the existing MixinWorldRenderer HEAD/TAIL next to BlockModelLighter (no new mixin class, no new injection point); ResidentStateModel wraps the world only when a dynamic resolver is present, so GUI/held/particle paths get the untouched reference and zero overhead. Adds ChunkProbeCacheTest (4 cases: wrap no-op outside windows, mutual pane probe dedup, cached identity, no cross-window residue).
- Switch the static-layer memo to canonical interned BlockState keys. DynamicPropertyResolver gains a default resolveState that folds its string output back onto the definition via getPropertyByName + getValueByName + O(1) setValue neighbor jumps, returning null (legacy string-code lane) on any out-of-domain name/value. ResidentStateModel tries this typed identity-memo first (hit builds no props map), keeping partMemo/stateIndexOf untouched as fallback. BlockStateDefinition exposes getPropertyByName from a name index built in create(). Six built-in resolvers unchanged; lambda SAM compatibility preserved. Adds ResidentStateModelTypedMemoTest (5 cases: shared snapshot on hit, cross-meta convergence, value/name downgrades, generation clear).
- Fix two runClient-reported rendering bugs. Stairs: computeShape used parity ((a & 1) != (b & 1)) to test perpendicular facings, but STAIR_FACINGS order {east,west,south,north} groups axes by the high bit, so east-south corners were missed and east-west pairs produced false corners (visible as broken 3x3 stair rings); now compares (a >> 1) != (b >> 1), matching vanilla 1.7.10 func_150145_f/func_150144_g neighbor sets. Torch/redstone torch: Property.getNames() returned value.toString() (uppercase enum names) instead of the StringRepresentable serialized form, so BlockstateKeyValidator rejected every facing=* variant key of torch blockstates and fell back to builtin/missing; getNames now goes through getName(value), also reviving all EnumMetaProperty<Direction> blocks (lever/ladder/hopper/dispenser/furnace/comparator facings). Adds StairsCornerShapeTest (8 cases over a fake IBlockAccess with a standalone BlockStairs instance) and PropertyNamesSerializedTest (3 cases).
- Wire force_translucent end-to-end: ModelResolver, baking and render stages.
- ModelResolver.merge/deepCopy: propagate the per-texture-variable textureForceTranslucent map (child overrides parent, same policy as textures).
- ModelResolver.resolveTextureVariables: expand force_translucent along the #reference chain, so a variable that (transitively) references a force_translucent leaf is itself marked translucent; adds a null-value guard for object-form entries without a sprite.
- ModelJson: support extended texture-variable object form under 'textures'. Each texture variable may now be declared either as a plain string (direct form) or as a JSON object with "sprite" and optional "force_translucent" (default false). The deserializer stores the sprite into the existing Map<String,String> textures (keeping the ModelResolver/TextureSlots pipeline untouched) and records explicit force_translucent=true into a new side map textureForceTranslucent keyed by variable name (null when no variable opts in; absence means default false). Added JavaDoc documenting both forms, #ref resolution and child-overrides-parent semantics.
- Fix sandstone inner/outer stairs face textures.
- Add element-level light_emission (int 0-15) to JSON models, aligned with 26.1.2 CuboidModelElement: parse and range-validate in ModelJson (reject non-number/out-of-range), propagate via ModelResolver.deepCopyElement and JsonModelBake (bakeElement/emitFaceFromCorners/deepCopyQuad) into BakedQuad.lightEmission; AOShadeExtension floors sky/block light components on the AO or uniform brightness channel via LightCoordsUtil.lightCoordsWithEmission without touching AO dispatch or directional shade; add ModelJsonParseTest cases for default/range/rejection/truncation
- ModelResolver: drop the redundant depth limit, thread the cycle chain explicitly, canonicalize model keys
- ModelResolver.java
- Both stack.clear() calls in resolve() are gone, so a nested resolve() can no longer clobber an
- unreachable via resolve() but kept for direct loader invocation, noted at each site.
- ModelResolverCanonicalKeyTest.java (new)
❗❗❗Deprecated:
- Revert chunk-boundary render refresh (ba0f8bd9). Misread of the intended bypass: the goal is hash-table-lookup rendering for the dynamic connection types, not an extra World.markBlockRangeForRenderUpdate notification on chunk load. Removes MixinNetHandlerPlayClient and its Mixins.RENDERING entry.
- UniformRenderPipeline.renderBlockQuads: on BLOCK_WORLD, split the part by translucentSplit() according to the paired tessellation pass (pass0 -> non-forced quads, pass1 -> forced quads, unpaired -> whole part, never drop faces). Rewrote the stale limitation comment.
- UniformRenderPipeline.renderItemQuads: route the force-translucent sub-part to a blend-enabled render group on the item/GUI/hand/dropped batched path; skip splitting when the phase already blends (zero regression). World block path documents why per-quad translucency cannot apply (vanilla chunk pass owns blend).
- Remove MAX_DEPTH (16) and the depth parameter. ModelJson.parent is a single value, so resolution
Notes
Full Changelog: https://github.com/song682/CatFrame/commits/v0.10.11
Supplementary resources
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:lSH4nVom:zJ07Wm6V"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:lSH4nVom:zJ07Wm6V"
}

