
Cobblemon:Crzbrain
CRZbrain is a Kotlin-based Fabric mod for Minecraft/Cobblemon that gives Pokemon an AI-powered brain featuring reinforcement learning, sentiment analysis, cross-trainer knowledge sharing, and adaptive response generation to make Pokemon interaction
Tags
Creators
Details
2.1.0
Compatibility
Changes
● v3.2 Fixes - AI Quality + Performance + Persistence (~55 fixes across 17 files)
Critical: RL + Persistence (7 fixes)
- RL: Fixed REINFORCE score function - Was advantage * (1-probability), now (advantage / probability).coerceIn(-3, 3) - same fix in experience replay
- RL: EMA baseline - Was cumulative average (stale after thousands of episodes), now 0.99avg + 0.01reward
- RL: O(n) chooseBestAction - Was O(n²) recomputing totalWeight per action inside maxByOrNull
- RL: Thread-safe stats - totalUpdates/totalRewardsPositive/totalRewardsNegative changed to AtomicInteger; reset() now also clears replayBuffers
- AdaptiveLearning: Full persistence - Was completely lost on restart! Now saves/loads 6 JSON files in config/CRZbrain/adaptive/
- AdaptiveLearning: Fixed importStrategy - Floor was 0.225 (below failure threshold), now maxOf(rate * 0.3, 0.4). Also fixed equals vs contains for context matching, capped trainerPatterns at 200
- CRZbrainMod: Shutdown saves 4 missing systems - Added ExternalAILearning, EmotionalMomentum, LearningContextIntegration, AdaptiveLearning to shutdown. Added LearningSystem.forceSave() to periodic async saves
High: Bug Fixes (14 fixes)
- SRG: Atomic read-and-remove for feedback attribution - Was race condition where another thread could read null between get() and remove()
- SRG: English keywords added to all scoring/filtering - Was Italian-only, English-speaking players got random responses instead of contextual ones
- SRG: Fixed part.first() crash - Changed to firstOrNull()?.isUpperCase() == true. Added probability gates to shiny/seasonal/first-Pokemon responses
- SRG: Cross-Pokemon RL transfer - Filter was using contains (impossible match on context strings), fixed to startsWith
- ExternalAILearning: English keywords - Added EN keywords to detectTopic (10 categories) and detectEmotion (6 categories)
- ExternalAILearning: Atomic writes + multiple fixes - All 11 files now use temp+rename atomic writes. Fixed diversityScore Gson deserialization. Fixed extractOpener while-loop. Added read-time quality decay
- DeepUnderstanding: Fixed 4 broken Regex - Escaped :) :( >:) special characters. Elongation pattern now requires 2+ repeated chars
- DeepUnderstanding: Fixed detectEmotion double-call - Was computing emotion twice per message. Added caps: 500 words/Pokemon in learnedMeanings, 200 players in communicationPatterns
- IntelligenceEvolution: Fixed totalKnowledge - Wasn't decremented after knowledge eviction. Fixed learningSpeed cap at 3.0 using maxOf instead of overwrite
- IntelligenceEvolution: Word-boundary Regex - "male" and "no" were matching inside other Italian words. Skip English context keys in enrichment. Minimum 2-word overlap for deductive inference
- LCI: Thread-safe inner maps - Changed mutableMapOf() to ConcurrentHashMap() inside getOrPut calls. Fixed quality score normalization (divide by totalWeightUsed)
- LCI: Feedback detection - Now requires keyword AND sentiment agreement. Was false-positive on common Italian words like "sono", "pokemon"
- APM: Fixed substring matching - Sentiment markers used substring contains (false positives). Now split into single-word Set checks + explicit multi-word contains
- EmbeddedAIProvider: Moods actually work - EXCITED was a no-op, ANGRY destroyed ellipses, TIRED never triggered. All 4 maps changed to ConcurrentHashMap
Medium: Performance (14 fixes)
- APM: Eliminated ~200 allocations per call - All per-call maps, lists, sets, regex moved to object-level vals
- APM: Sentiment cache String key - Was using hashCode (collisions). Added caps: 100 topics, 200 actions. synchronizedList for inner lists. Atomic file writes
- LearningSystem: Removed sync I/O from markDirty - Was calling checkAutoSave() which could block main thread. Pre-compiled 17 regex
- SmartConversation: Pre-compiled 20+ regex - normalizeMessage was creating new Regex objects per call. Hoisted SPECIES_QUIRKS map to object level
- MoveAnimationSystem: Cached getNearbyPlayers - Was doing 16 entity searches per attack, now does 2 (query once, pass list to all sub-functions)
- PokemonDefenseSystem: Cached entity search - One search per player shared across all Pokemon. Replaced sortedWith().first() with minWithOrNull()
- MemorySystem: Bulk eviction - removeAt(0) in while loop replaced with subList(0, excess).clear() (single array shift)
- LanguageGrowth: Word-boundary replacement - upgradeVocabulary now uses Regex word boundaries to avoid replacing inside other words
- EmotionalMomentum: Fixed stale lastUpdate - Added timestamp update in applyEmotionalTransfer and applyBuildup (was never refreshed, states appeared inactive)
- IntelligenceEvolution: Sliding window learning rate - Was using lifetime cumulative average (never changed after early episodes). Now uses window of last 50 results
- AdaptiveLearning: Normalized activityPattern - Was accumulating 0.1 per call (grew unbounded). Now stores raw counts, normalizes at read-time. feedbackHistory changed to ArrayDeque for O(1) removeFirst
- CRZbrainMod: Fixed sender duplicate - allNearbyPlayers included the sender themselves. Added cleanup of lastChatLearnTime on player disconnect
- ExternalAILearning: Removed double loadData() - init block was calling loadData() which was also called at server start
- LCI: Debounced saveContextWeights - Added dirty flag, only saves when explicitly called instead of on every weight update
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:JbNzzoj3:Nz1H7Ksp"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:JbNzzoj3:Nz1H7Ksp"
}
