|
| 1 | +# AGENTS.md - NeteaseMusicDisplay |
| 2 | + |
| 3 | +A Minecraft Fabric mod that displays the current playing song from Netease Music on Windows. |
| 4 | + |
| 5 | +## Tech Stack |
| 6 | + |
| 7 | +- **Build System**: Gradle with Fabric Loom |
| 8 | +- **Primary Language**: Kotlin (2.3.0) |
| 9 | +- **Secondary Language**: Java (for Mixin classes) |
| 10 | +- **Java Version**: 21 |
| 11 | +- **Minecraft Version**: 1.21.10 |
| 12 | +- **Mod Loader**: Fabric |
| 13 | + |
| 14 | +## Build Commands |
| 15 | + |
| 16 | +```bash |
| 17 | +# Build the mod JAR |
| 18 | +./gradlew build |
| 19 | + |
| 20 | +# Run all tests |
| 21 | +./gradlew test |
| 22 | + |
| 23 | +# Run a specific test class |
| 24 | +./gradlew test --tests "com.as9929.display.netease.YourTestClass" |
| 25 | + |
| 26 | +# Run a specific test method |
| 27 | +./gradlew test --tests "com.as9929.display.netease.YourTestClass.testMethod" |
| 28 | + |
| 29 | +# Run all checks (includes tests, ABI checks) |
| 30 | +./gradlew check |
| 31 | + |
| 32 | +# Clean build directory |
| 33 | +./gradlew clean |
| 34 | + |
| 35 | +# Full clean build |
| 36 | +./gradlew clean build |
| 37 | + |
| 38 | +# Generate sources JAR |
| 39 | +./gradlew sourcesJar |
| 40 | +``` |
| 41 | + |
| 42 | +## Project Structure |
| 43 | + |
| 44 | +``` |
| 45 | +src/ |
| 46 | +├── main/ |
| 47 | +│ ├── java/com/as9929/display/netease/mixin/ # Java Mixin classes |
| 48 | +│ ├── kotlin/com/as9929/display/netease/ # Kotlin source |
| 49 | +│ └── resources/ # Mod metadata, assets |
| 50 | +│ ├── fabric.mod.json |
| 51 | +│ └── netease-music-display.mixins.json |
| 52 | +├── test/ # Test sources (if any) |
| 53 | +build.gradle # Build configuration |
| 54 | +gradle.properties # Version constants |
| 55 | +settings.gradle # Project settings |
| 56 | +``` |
| 57 | + |
| 58 | +## Code Style Guidelines |
| 59 | + |
| 60 | +### Kotlin |
| 61 | + |
| 62 | +- **Indentation**: 4 spaces (no tabs) |
| 63 | +- **Line endings**: LF |
| 64 | +- **Package**: `com.as9929.display.netease` |
| 65 | +- Use `object` for singletons (e.g., `object TextRender`) |
| 66 | +- Use `by lazy` for expensive initialization |
| 67 | +- Prefer `val` over `var` |
| 68 | +- Use nullable types (`String?`) over exceptions for optional returns |
| 69 | +- Comments: Use `// --- Description ---` for section headers |
| 70 | + |
| 71 | +Example: |
| 72 | +```kotlin |
| 73 | +package com.as9929.display.netease |
| 74 | + |
| 75 | +import net.fabricmc.api.ModInitializer |
| 76 | + |
| 77 | +object NeteaseMusicDisplay : ModInitializer { |
| 78 | + const val MOD_ID = "netease-music-display" |
| 79 | + |
| 80 | + override fun onInitialize() { |
| 81 | + // Initialization code |
| 82 | + } |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | +### Java |
| 87 | + |
| 88 | +- **Indentation**: 4 spaces |
| 89 | +- **Package**: `com.as9929.display.netease.mixin` for Mixin classes |
| 90 | +- Use Mixin pattern for Minecraft injection points |
| 91 | +- Annotations on separate lines for complex injections |
| 92 | + |
| 93 | +Example: |
| 94 | +```java |
| 95 | +package com.as9929.display.netease.mixin; |
| 96 | + |
| 97 | +import org.spongepowered.asm.mixin.Mixin; |
| 98 | + |
| 99 | +@Mixin(InGameHud.class) |
| 100 | +public class InGameHudMixin { |
| 101 | + @Inject( |
| 102 | + method = "render", |
| 103 | + at = @At(value = "INVOKE", target = "...") |
| 104 | + ) |
| 105 | + private void onRender(...) { } |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +### Naming Conventions |
| 110 | + |
| 111 | +- **Classes**: PascalCase (e.g., `CloudMusicHelper`, `TextRender`) |
| 112 | +- **Objects**: PascalCase (e.g., `TextRender.INSTANCE`) |
| 113 | +- **Methods/Functions**: camelCase (e.g., `getCloudMusicTitle()`) |
| 114 | +- **Constants**: UPPER_SNAKE_CASE (e.g., `MOD_ID`, `PROCESS_QUERY_INFORMATION`) |
| 115 | +- **Packages**: lowercase (e.g., `com.as9929.display.netease`) |
| 116 | + |
| 117 | +### Imports |
| 118 | + |
| 119 | +- Group imports by source: |
| 120 | + 1. Kotlin/Java standard library |
| 121 | + 2. Minecraft/Fabric libraries |
| 122 | + 3. Project imports |
| 123 | + 4. Third-party libraries (JNA, etc.) |
| 124 | +- Use wildcard imports sparingly |
| 125 | + |
| 126 | +### Error Handling |
| 127 | + |
| 128 | +- Use nullable return types instead of throwing exceptions for expected failures |
| 129 | +- Wrap platform-specific code (Windows API) with OS checks first |
| 130 | +- Use try-finally for resource cleanup (handles, processes) |
| 131 | +- Log errors using SLF4J: `LoggerFactory.getLogger(MOD_ID)` |
| 132 | + |
| 133 | +### Threading |
| 134 | + |
| 135 | +- Offload heavy work to background threads using `Executors` |
| 136 | +- Mark shared mutable state with `@Volatile` |
| 137 | +- Use daemon threads: `t.isDaemon = true` |
| 138 | +- Always access Minecraft client on main render thread only |
| 139 | + |
| 140 | +### Mixin Guidelines |
| 141 | + |
| 142 | +- Place all Mixin classes in `mixin` package |
| 143 | +- Use `@Inject` for adding behavior |
| 144 | +- Use proper `@At` targets (e.g., `INVOKE`, `HEAD`, `TAIL`) |
| 145 | +- Include shift when needed: `shift = At.Shift.BEFORE` |
| 146 | + |
| 147 | +## Key Dependencies |
| 148 | + |
| 149 | +- Fabric Loader: `0.18.4` |
| 150 | +- Fabric API: `0.138.4+1.21.10` |
| 151 | +- Fabric Language Kotlin: `1.13.8+kotlin.2.3.0` |
| 152 | +- JNA: For Windows API access (cloudmusic.exe integration) |
| 153 | + |
| 154 | +## Testing |
| 155 | + |
| 156 | +Currently no tests exist. When adding tests: |
| 157 | +1. Place in `src/test/kotlin/` mirroring main package structure |
| 158 | +2. Use JUnit 5 (included via Gradle) |
| 159 | +3. Run with `./gradlew test` |
| 160 | + |
| 161 | +## CI/CD |
| 162 | + |
| 163 | +GitHub Actions workflow at `.github/workflows/build.yml` |
| 164 | + |
| 165 | +## Resources |
| 166 | + |
| 167 | +- Fabric Wiki: https://fabricmc.net/wiki |
| 168 | +- Mixin Wiki: https://github.com/SpongePowered/Mixin/wiki |
0 commit comments