Skip to content

Commit c8b08f1

Browse files
committed
feat: Centralize icon sizing and enhance AI documentation
- Add IconSizeConfig class for centralized icon dimension constants (ADDON_ICON_SIZE=64, INSTALLED_INDICATOR_SIZE=32) - Update all GUI components to use IconSizeConfig instead of hardcoded sizes (AddonDetailScreen, BrowseAddonsScreen, InstalledAddonsScreen, WAddonCard) - Update IconPreloadSystem to use centralized size constants for texture creation Documentation improvements: - Expand CLAUDE.md with project structure, architecture patterns, and detailed icon sizing/texture rendering documentation - Add comprehensive GEMINI.md with project context, threading model, build instructions, and code search guidelines - Add Gemini MCP server configuration (.gemini/settings.json) This refactoring makes icon sizes configurable from a single location and provides comprehensive guidance for AI assistants working on the codebase.
1 parent a40852a commit c8b08f1

9 files changed

Lines changed: 253 additions & 31 deletions

File tree

.gemini/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"mcpServers": {
3+
"gradle-mcp-server": {
4+
"command": "cmd.exe",
5+
"args": [
6+
"/c",
7+
"cd C:\\Users\\Cope\\Documents\\GitHub\\gradle-mcp-server && npm start"
8+
]
9+
},
10+
"code-search-mcp": {
11+
"command": "cmd.exe",
12+
"args": [
13+
"/c",
14+
"cd C:\\Users\\Cope\\Documents\\GitHub\\code-search-mcp && node dist/index.js"
15+
]
16+
}
17+
}
18+
}

CLAUDE.md

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,51 @@ This is a **Meteor Client addon** that provides an in-game GUI for browsing, ins
2323
./gradlew clean build
2424
```
2525

26+
## Project Structure
27+
28+
```
29+
src/main/java/com/cope/meteoraddons/
30+
├── MeteorAddonsAddon.java # Entry point, addon initialization
31+
├── config/
32+
│ └── IconSizeConfig.java # Centralized icon size constants
33+
├── systems/
34+
│ ├── AddonManager.java # Core system: addon fetching, filtering, downloads
35+
│ └── IconPreloadSystem.java # Icon download & GPU texture management
36+
├── addons/
37+
│ ├── Addon.java # Base interface for all addons
38+
│ ├── OnlineAddon.java # Addon from meteor-addon-scanner API
39+
│ └── InstalledAddon.java # Local addon from mods/ folder
40+
├── models/
41+
│ └── AddonMetadata.java # JSON model for addon metadata
42+
├── gui/
43+
│ ├── tabs/
44+
│ │ └── AddonsTab.java # Main tab in Meteor GUI
45+
│ ├── screens/
46+
│ │ ├── BrowseAddonsScreen.java # Online addons browse screen
47+
│ │ ├── InstalledAddonsScreen.java # Installed addons screen
48+
│ │ └── AddonDetailScreen.java # Detail modal for individual addon
49+
│ └── widgets/
50+
│ └── WAddonCard.java # Grid view addon card widget
51+
└── util/
52+
├── IconCache.java # Facade for instant icon lookups
53+
├── HttpClient.java # OkHttp wrapper with fallbacks
54+
├── VersionUtil.java # Minecraft version detection
55+
└── TimeUtil.java # Relative time formatting
56+
57+
src/main/resources/
58+
├── fabric.mod.json # Fabric mod metadata
59+
└── assets/meteor-addons/
60+
├── icon.png # Addon icon (shown in mod menu)
61+
└── installed-icon.png # Badge overlay for installed addons
62+
```
63+
64+
**Key Patterns:**
65+
- `config/` - Configuration constants (sizes, URLs, etc.)
66+
- `systems/` - Meteor Systems (singleton managers with NBT persistence)
67+
- `gui/` - All GUI code organized by type (tabs, screens, widgets)
68+
- `util/` - Utility classes with static helper methods
69+
- `models/` - Data classes mapping to JSON structures
70+
2671
## Architecture
2772

2873
### Threading Model (CRITICAL)
@@ -33,7 +78,7 @@ This is a **Meteor Client addon** that provides an in-game GUI for browsing, ins
3378
- Use `mc.execute(() -> { ... })` to schedule GUI updates back on the render thread
3479
- See `AddonManager.fetchAddonMetadata()` for the pattern
3580

36-
**Icon Cache Pattern**: `IconCache` uses async texture loading - always returns immediately with a default texture, then loads the real texture in the background and triggers a UI refresh callback.
81+
**Icon Cache Pattern**: Icons are preloaded during startup. `IconPreloadSystem` downloads PNG bytes in background threads, then converts them to GPU textures during resource reload (render thread). `IconCache.get(addon)` returns instantly - either the cached texture or a gray placeholder.
3782

3883
### Systems Architecture
3984

@@ -81,42 +126,67 @@ public MyWidget(GuiTheme theme, Data data) {
81126

82127
The `theme` field is set by the framework when the widget is added to the widget tree. Never set it manually or call `init()` from the constructor.
83128

129+
### Icon Sizing (IMPORTANT)
130+
131+
All addon icon sizes are centralized in `IconSizeConfig.java`:
132+
133+
```java
134+
public static final int ADDON_ICON_SIZE = 64; // Change here to adjust globally
135+
public static final int INSTALLED_INDICATOR_SIZE = 32;
136+
```
137+
138+
**All icons display at 64x64 pixels** across grid view, list view, detail screens, and installed addons. To change icon sizes:
139+
1. Edit `IconSizeConfig.ADDON_ICON_SIZE`
140+
2. Rebuild - all GUI components and texture creation automatically use the new size
141+
84142
### Texture Rendering
85143

86-
For custom textures (like addon icons):
144+
Icon textures are managed by `IconPreloadSystem`:
87145

88-
1. Extend `meteordevelopment.meteorclient.renderer.Texture` (NOT Minecraft's texture classes)
89-
2. Use `NativeImage.read()` to load images (handles any size)
90-
3. Resize to target dimensions using `NativeImage.resizeSubRectTo()`
91-
4. Convert to RGBA byte array via `makePixelArray()` and manual color conversion (ABGR → RGBA)
92-
5. Upload with `upload(byte[])`
146+
1. **Download Phase**: HTTP downloads cache raw PNG bytes (`iconDataCache`)
147+
2. **Resource Reload**: `reload()` converts cached PNGs to GPU textures on render thread
148+
3. **Texture Creation**: Uses `NativeImage.read()` → resize to `IconSizeConfig.ADDON_ICON_SIZE` → ABGR→RGBA conversion → `Texture.upload()`
149+
4. **Instant Lookup**: `IconCache.get(addon)` returns cached texture or default gray placeholder
93150

94-
See `AddonIconTexture` for the complete implementation. Icons are cached at multiple sizes (64x64 for grid view, 128x128 for list view).
151+
See `IconPreloadSystem.createTextureFromNativeImage()` for implementation. Icons are created at a single size (64x64 by default) and used everywhere.
95152

96153
### Data Flow
97154

98-
1. **Startup**: `AddonManager.init()` triggers background fetch of addons.json
99-
2. **Filtering**: Streams filter by MC version + verified status, deduplicate by name
100-
3. **Icon Caching**: IconCache loads textures asynchronously with default fallbacks
155+
1. **Startup**: `AddonManager.init()` triggers background fetch of addons.json and icon downloads
156+
2. **Icon Preload**: `IconPreloadSystem` downloads icons to byte cache, converts to textures on resource reload
157+
3. **Filtering**: Streams filter by MC version + verified status, deduplicate by name
101158
4. **GUI**: AddonsTab provides navigation to Browse/Installed screens
102159
5. **Details**: AddonDetailScreen modal shows full metadata + download button
103160
6. **Download**: `AddonManager.downloadAddon()` saves JAR to parent `mods/` folder
104161

105162
### Key Classes
106163

164+
**Configuration:**
165+
- **IconSizeConfig**: Centralized icon size constants (`ADDON_ICON_SIZE`, `INSTALLED_INDICATOR_SIZE`)
166+
167+
**Core Systems:**
107168
- **MeteorAddonsAddon**: Entry point, registers systems and tabs
108169
- **AddonManager**: System that manages addon state, fetching, filtering, downloading
109-
- **IconCache**: Async icon loading with callback-based UI refresh
170+
- **IconPreloadSystem**: System for async icon downloading and GPU texture creation
171+
- **IconCache**: Facade for instant icon texture lookups (delegates to IconPreloadSystem)
172+
173+
**Data Models:**
110174
- **AddonMetadata**: JSON model with helper methods for priority fields (custom.* over regular)
175+
- **Addon**: Base interface for online and installed addons
176+
177+
**GUI Screens:**
111178
- **AddonsTab**: Main GUI tab with navigation to Browse/Installed screens
112179
- **BrowseAddonsScreen**: Main screen with grid/list view of online addons
113180
- **InstalledAddonsScreen**: Shows locally installed Meteor addons
114-
- **WAddonCard**: Individual addon card widget (icon + title + button)
115-
- **WAddonListItem**: List view item for addons
116181
- **AddonDetailScreen**: Modal overlay with full addon info
117-
- **AddonIconTexture**: Texture implementation for resized addon icons
182+
183+
**GUI Widgets:**
184+
- **WAddonCard**: Individual addon card widget for grid view (icon + title + button)
185+
186+
**Utilities:**
118187
- **HttpClient**: OkHttp wrapper with fallback URL support
119188
- **VersionUtil**: Minecraft version detection via `SharedConstants.getGameVersion().id()`
189+
- **TimeUtil**: Relative time formatting for "updated 2 days ago" labels
120190

121191
## Version Filtering
122192

@@ -145,9 +215,9 @@ The `include()` directive in build.gradle.kts bundles dependencies into the addo
145215
- **Fix**: Always resize images to match declared texture dimensions (e.g., 64x64)
146216

147217
### Icons not loading
148-
- **Check**: IconCache callback is set for UI refresh (`IconCache.setOnTexturesLoadedCallback()`)
149-
- **Check**: Network operations on background thread
150-
- **Check**: Texture creation on render thread via `mc.execute()`
218+
- **Check**: Icons downloaded during `AddonManager.fetchAddonMetadata()` background phase
219+
- **Check**: `IconPreloadSystem.reload()` called during resource reload to convert to textures
220+
- **Check**: For installed addons with JAR icons, `IconCache.get()` loads them on-demand from JAR `InputStream`
151221

152222
### Duplicate addons in list
153223
- **Fix**: Deduplication via `Collectors.toMap()` by addon name (already implemented)
@@ -211,7 +281,8 @@ The `ai_reference/` folder (git-ignored) contains complete source code for:
211281
- **Command implementation**: See `meteor-rejects/commands/`
212282
- **Event handling**: See `meteor-client/events/` and `orbit/`
213283
- **Settings framework**: See `meteor-client/settings/`
214-
- **Texture rendering**: See current `AddonIconTexture.java` implementation
284+
- **Texture rendering**: See `IconPreloadSystem.java` in current codebase
285+
- **Icon sizing**: See `IconSizeConfig.java` for centralized size constants
215286

216287
## Build Output
217288

GEMINI.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# GEMINI.md - Project Context & Developer Guide
2+
3+
This file provides comprehensive context and guidelines for Gemini agents working on the **Meteor Addons** project.
4+
5+
## 1. Project Overview
6+
7+
**Meteor Addons** is a specialized addon for the [Meteor Client](https://meteorclient.com/) (a Minecraft utility mod). It functions as an in-game package manager, allowing users to browse, install, and update other Meteor Client addons directly from the client's GUI.
8+
9+
* **Type:** Java Project (Fabric Mod / Meteor Client Addon)
10+
* **Language:** Java 21
11+
* **Build System:** Gradle (Kotlin DSL)
12+
* **Dependencies:** Meteor Client, Fabric Loader, OkHttp, Gson
13+
* **Data Source:** Fetches metadata from the [meteor-addon-scanner](https://github.com/cqb13/meteor-addon-scanner) repository.
14+
15+
## 2. Critical Architecture & Patterns
16+
17+
### 2.1 Threading Model (STRICT)
18+
* **Render Thread:** exclusively for GUI updates and texture manipulation. **NEVER** block this thread.
19+
* **Background Threads:** All network operations (HTTP requests) and heavy file I/O **MUST** run on background threads.
20+
* Use `MeteorExecutor.execute(() -> { ... })` for background tasks.
21+
* **Synchronization:** To update the GUI from a background thread, schedule the task back to the render thread:
22+
* Use `mc.execute(() -> { ... })`.
23+
24+
### 2.2 Systems Architecture
25+
The project uses Meteor Client's `Systems` pattern for persistent, globally accessible singletons.
26+
* **Registration:** Systems are added in `MeteorAddonsAddon.onInitialize()` using `Systems.add(new MySystem())`.
27+
* **Access:** `MySystem.get()` (wrapper for `Systems.get(MySystem.class)`).
28+
* **Persistence:** Override `toTag()` and `fromTag()` to save/load state (NBT).
29+
30+
### 2.3 GUI Widget Lifecycle
31+
Meteor's GUI framework has a strict initialization order. Violating this causes "theme is null" crashes.
32+
33+
* **Constructor:** Initialize data fields only. **Do NOT** build UI or call `init()`.
34+
* **init():** Build your UI here. This method is called automatically by the framework *after* the widget is added to the tree and the `theme` is set.
35+
* **Theme:** Access the `theme` field (provided by parent) inside `init()`. Never accept `GuiTheme` in the constructor.
36+
37+
### 2.4 Icon Management
38+
* **Centralized Config:** Icon sizes are defined in `com.cope.meteoraddons.config.IconSizeConfig`.
39+
* `ADDON_ICON_SIZE`: Default 64x64.
40+
* **Preloading:** `IconPreloadSystem` handles async downloading of icon bytes.
41+
* **Texture Creation:** Occurs on the render thread (via `reload()` or `mc.execute()`) using `NativeImage`.
42+
* **Instant Lookup:** `IconCache` or `IconPreloadSystem.getTexture()` returns the texture immediately (or a default) to prevent rendering lag.
43+
44+
## 3. Project Structure
45+
46+
```
47+
src/main/java/com/cope/meteoraddons/
48+
├── MeteorAddonsAddon.java # Main entry point. Registers systems/tabs.
49+
├── addons/ # Data models
50+
│ ├── Addon.java # Base interface
51+
│ ├── InstalledAddon.java # Local addon wrapper (ModContainer)
52+
│ └── OnlineAddon.java # Remote addon wrapper (AddonMetadata)
53+
├── config/
54+
│ └── IconSizeConfig.java # Centralized dimension constants
55+
├── gui/
56+
│ ├── screens/ # Full-screen UIs (Browse, Installed)
57+
│ ├── tabs/ # Tab integration (AddonsTab)
58+
│ └── widgets/ # Reusable components (WAddonCard)
59+
├── models/
60+
│ └── AddonMetadata.java # JSON mapping for scanner data
61+
├── systems/
62+
│ ├── AddonManager.java # Core logic: fetching, filtering, downloading
63+
│ └── IconPreloadSystem.java # Async icon download & GPU texture management
64+
└── util/
65+
├── HttpClient.java # OkHttp wrapper
66+
└── VersionUtil.java # Minecraft version compatibility helpers
67+
```
68+
69+
## 4. Build & Execution
70+
71+
**Mandatory:** Use the `gradle-mcp-server` tools for all build tasks. Do NOT use `run_shell_command` with `./gradlew` or `gradle`.
72+
73+
* **List Tasks:** `gradle_list_tasks(projectPath=...)`
74+
* **Execute Task:** `gradle_execute(projectPath=..., tasks=["build"])`
75+
* **Quick Build:** `gradle_build(projectPath=...)`
76+
* **Project Info:** `gradle_project_info(projectPath=...)`
77+
* **Dependencies:** `gradle_dependencies(projectPath=...)`
78+
79+
## 5. Key Implementation Details
80+
81+
* **Data Flow:** `AddonManager.init()` -> Background Fetch -> Filter (Version/Verified) -> Deduplicate -> Async Icon Download -> Texture Creation -> GUI Render.
82+
* **Networking:** Uses `OkHttp` (bundled via `include` in Gradle). Always verify internet access before assuming success.
83+
* **File Operations:** Addons are downloaded to `MeteorClient.FOLDER.getParent().resolve("mods")`.
84+
* **Version Filtering:** Checks `custom.supported_versions` array first, then `mc_version`.
85+
86+
## 6. Common Pitfalls to Avoid
87+
1. **Calling `init()` manually:** Never do this for Widgets.
88+
2. **Blocking Render Thread:** Will freeze the game. Use `MeteorExecutor`.
89+
3. **Texture Size Mismatch:** Always resize `NativeImage` to match the texture dimensions defined in `IconSizeConfig` before uploading to prevent memory violations.
90+
4. **Theme Shadowing:** Do not create a `theme` field in your widget if extending a Meteor widget; use the protected field from the parent.
91+
92+
## 7. Tools & Reference
93+
94+
### 7.1 Code Search (Mandatory)
95+
Use `code-search-mcp` for all codebase exploration and navigation.
96+
1. **Initialize:** Always ensure the workspace is added via `add_workspace` (if not already detected/listed).
97+
2. **Search:** Prefer these tools over `grep` or basic file reading:
98+
* `search_symbols`: Find classes, methods, and variables.
99+
* `search_ast_pattern`: Find code based on structure (e.g., `Systems.add($$$)`).
100+
* `search_text`: Fast, regex-based text search (uses ripgrep).
101+
3. **Investigate:** Use `codebase_investigator` for complex, high-level architectural questions.
102+
103+
### 7.2 References
104+
* **AI Reference:** The `ai_reference/` directory contains decompiled/source code of Meteor Client and other addons. Index this directory if you need to search it deeply.
105+
* **Mappings:** The project uses Yarn mappings.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.cope.meteoraddons.config;
2+
3+
/**
4+
* Centralized configuration for icon sizes across the addon.
5+
* Change these values to adjust icon sizes globally.
6+
*/
7+
public final class IconSizeConfig {
8+
/**
9+
* Standard addon icon size used in all GUI views.
10+
* Default: 64x64 pixels
11+
*/
12+
public static final int ADDON_ICON_SIZE = 64;
13+
14+
/**
15+
* Installed indicator badge icon size.
16+
* Default: 32x32 pixels
17+
*/
18+
public static final int INSTALLED_INDICATOR_SIZE = 32;
19+
20+
private IconSizeConfig() {
21+
// Prevent instantiation
22+
}
23+
}

src/main/java/com/cope/meteoraddons/gui/screens/AddonDetailScreen.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.cope.meteoraddons.addons.Addon;
44
import com.cope.meteoraddons.addons.OnlineAddon;
5+
import com.cope.meteoraddons.config.IconSizeConfig;
56
import com.cope.meteoraddons.models.AddonMetadata;
67
import com.cope.meteoraddons.systems.AddonManager;
78
import com.cope.meteoraddons.util.IconCache;
@@ -43,7 +44,7 @@ public void initWidgets() {
4344

4445
// Icon
4546
Texture iconTexture = IconCache.get(addon);
46-
header.add(theme.texture(64, 64, 0, iconTexture)).widget();
47+
header.add(theme.texture(IconSizeConfig.ADDON_ICON_SIZE, IconSizeConfig.ADDON_ICON_SIZE, 0, iconTexture)).widget();
4748

4849
// Details (Name, Authors, Version, Verified)
4950
WVerticalList details = header.add(theme.verticalList()).expandX().widget();

src/main/java/com/cope/meteoraddons/gui/screens/BrowseAddonsScreen.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.cope.meteoraddons.addons.Addon;
44
import com.cope.meteoraddons.addons.OnlineAddon;
5+
import com.cope.meteoraddons.config.IconSizeConfig;
56
import com.cope.meteoraddons.gui.widgets.WAddonCard;
67
import com.cope.meteoraddons.models.AddonMetadata;
78
import com.cope.meteoraddons.systems.AddonManager;
@@ -101,7 +102,7 @@ private void initListView(List<Addon> addons) {
101102

102103
// Icon
103104
Texture icon = IconCache.get(addon);
104-
row.add(theme.texture(48, 48, 0, icon)).widget();
105+
row.add(theme.texture(IconSizeConfig.ADDON_ICON_SIZE, IconSizeConfig.ADDON_ICON_SIZE, 0, icon)).widget();
105106

106107
// Details
107108
WVerticalList details = row.add(theme.verticalList()).expandX().widget();

src/main/java/com/cope/meteoraddons/gui/screens/InstalledAddonsScreen.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cope.meteoraddons.gui.screens;
22

33
import com.cope.meteoraddons.addons.Addon;
4+
import com.cope.meteoraddons.config.IconSizeConfig;
45
import com.cope.meteoraddons.systems.AddonManager;
56
import com.cope.meteoraddons.util.IconCache;
67
import meteordevelopment.meteorclient.gui.GuiTheme;
@@ -44,9 +45,9 @@ public void initWidgets() {
4445
for (int i = 0; i < addons.size(); i++) {
4546
Addon addon = addons.get(i);
4647

47-
// Column 0: Icon (128x128)
48+
// Column 0: Icon
4849
Texture iconTexture = IconCache.get(addon);
49-
addonList.add(theme.texture(128, 128, 0, iconTexture)).pad(8);
50+
addonList.add(theme.texture(IconSizeConfig.ADDON_ICON_SIZE, IconSizeConfig.ADDON_ICON_SIZE, 0, iconTexture)).pad(8);
5051

5152
// Column 1: Details (expanding)
5253
WVerticalList details = addonList.add(theme.verticalList()).expandCellX().widget();

src/main/java/com/cope/meteoraddons/gui/widgets/WAddonCard.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cope.meteoraddons.gui.widgets;
22

33
import com.cope.meteoraddons.addons.Addon;
4+
import com.cope.meteoraddons.config.IconSizeConfig;
45
import com.cope.meteoraddons.util.IconCache;
56
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
67
import meteordevelopment.meteorclient.gui.widgets.containers.WVerticalList;
@@ -30,7 +31,7 @@ protected void onCalculateSize() {
3031
@Override
3132
public void init() {
3233
Texture iconTexture = IconCache.get(addon);
33-
add(theme.texture(64, 64, 0, iconTexture)).centerX();
34+
add(theme.texture(IconSizeConfig.ADDON_ICON_SIZE, IconSizeConfig.ADDON_ICON_SIZE, 0, iconTexture)).centerX();
3435

3536
WHorizontalList titleRow = add(theme.horizontalList()).centerX().widget();
3637
titleRow.add(theme.label(addon.getName()));

0 commit comments

Comments
 (0)