Tags
Creators
Details
4.6.0
Compatibility
Changes
● CobbleOptimizer 4.6.0 — Changelog
New: CobBreeding compatibility patch
Added a @Pseudo mixin targeting ludichat.cobbreeding.utils.SemVerKt::toSemVer to address two distinct issues in CobBreeding (Ludichat/Cobbreeding) versions ≤ 2.2.1.
Performance fix (always active, zero risk)
CobBreeding's toSemVer constructed a new kotlin.text.Regex on every invocation, triggering Pattern.compile (1–10 µs per call). On servers with many eggs, spark profiler flagged this as a measurable hotspot during egg deserialization.
The mixin uses @Redirect on the new kotlin/text/Regex(String) instruction inside toSemVer to return one of two process-wide cached Regex singletons. Pattern compilation now happens twice total at class load instead of once per call.
Correctness fix (toggleable, off by default)
The original regex ^\d(.\d(.\d([.-_].+)?)?)?$ has two bugs:
- Single \d per component. Multi-digit version components (e.g. 1.21.1, 2.2.10) fail to match, so toSemVer returns SemVer(emptyList()) with major=minor=patch=0. Downstream, PokemonEgg.verifyComponentsAfterLoad() misidentifies the egg as pre-2.0.0 and runs the wrong migration, crashing the server with NumberFormatException when an egg is moved/cloned from a pasture block.
- [.-_] as a character class. This is a regex range from . (0x2E) to _ (0x5F) instead of three literal characters. It accidentally matches digits, uppercase letters, and various punctuation.
When the toggle is enabled, the cached regex is the corrected version: ^\d+(.\d+(.\d+([._-].+)?)?)?$.
New config option
[patches] fix_cobbreeding_semver = false # default off, opt-in
Also reachable via the existing /cobbleoptimizer config patches.fix_cobbreeding_semver <true|false> command. The mixin re-reads the config on every call to toSemVer, so the toggle takes effect immediately without a server restart.
When the toggle is false, the cache still returns a singleton with the original (buggy) regex — semantics are bit-identical to vanilla CobBreeding, but the per-call Pattern.compile cost is eliminated. When the toggle is true, the cache returns the corrected regex.
Safety properties
- No compile-time dependency on CobBreeding. The mixin uses @Pseudo + string target, so CobbleOptimizer builds and runs identically whether CobBreeding is installed or not.
- Silent no-op when CobBreeding is absent. Registered in cobbleoptimizer-patches.mixins.json with defaultRequire: 0, so missing target classes don't propagate as errors.
- Forward compatibility. If a future CobBreeding release changes the bytecode shape of toSemVer (e.g. caches the regex upstream, renames the method), the @Redirect no longer matches and the mixin becomes a silent no-op.
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:qPJLoYyi:g1IZK0LM"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:qPJLoYyi:g1IZK0LM"
}

