|
2 | 2 |
|
3 | 3 | This repository contains the components and automation tools for building and managing RetroDECK components. |
4 | 4 |
|
5 | | -## Creating a New Component |
6 | | - |
7 | | -Follow these steps to create a new emulator or tool component for RetroDECK: |
8 | | - |
9 | | -### 1. Plan Your Component |
10 | | - |
11 | | -- **Choose a name**: Use lowercase, no spaces (e.g., `myemulator`) |
12 | | -- **Identify the source**: GitHub releases, direct downloads, Flatpak, etc. We always prefer Flatpak as main source if it's updated. We always prefer Flatpak as main source if it's updated. |
13 | | -- **Determine requirements**: Libraries, configurations, presets needed |
14 | | -- **Check existing components**: Look at similar components for reference |
15 | | - |
16 | | -### 2. Create Component Directory Structure |
17 | | - |
18 | | -Create a new directory for your component: |
19 | | - |
20 | | -```bash |
21 | | -mkdir myemulator |
22 | | -cd myemulator |
23 | | -mkdir -p assets/rd_config |
24 | | -``` |
25 | | - |
26 | | -### 3. Add Version to Desired Versions |
27 | | - |
28 | | -Edit `automation-tools/alchemist/desired_versions.sh` and add your component's desired version: |
29 | | - |
30 | | -```bash |
31 | | -# MyEmulator – Description |
32 | | -export MYEMULATOR_DESIRED_VERSION="latest" |
33 | | -``` |
34 | | - |
35 | | -### 4. Create Component Recipe |
36 | | - |
37 | | -Create `component_recipe.json` based on the source type. Use templates from `automation-tools/alchemist/templates/`: |
38 | | - |
39 | | -**For GitHub releases:** |
40 | | -```json |
41 | | -{ |
42 | | - "myemulator": [ |
43 | | - { |
44 | | - "source_url": "https://github.com/developer/myemulator/releases/download/{VERSION}/*.AppImage", |
45 | | - "source_type": "github-release", |
46 | | - "version": "$MYEMULATOR_DESIRED_VERSION", |
47 | | - "extraction_type": "appimage", |
48 | | - "assets": [ |
49 | | - { |
50 | | - "type": "dir", |
51 | | - "source": "usr/bin", |
52 | | - "dest": "bin" |
53 | | - }, |
54 | | - { |
55 | | - "type": "dir", |
56 | | - "source": "$REPO_ROOT/$COMPONENT_NAME/assets/rd_config", |
57 | | - "dest": "rd_config" |
58 | | - } |
59 | | - ], |
60 | | - "libs": [ |
61 | | - { |
62 | | - "library": "libQt6Widgets.so.6", |
63 | | - "runtime_name": "org.kde.Platform", |
64 | | - "runtime_version": "$DESIRED_QT6_RUNTIME_VERSION", |
65 | | - "dest": "shared-libs" |
66 | | - } |
67 | | - ] |
68 | | - } |
69 | | - ] |
70 | | -} |
71 | | -``` |
72 | | - |
73 | | -**For direct downloads:** |
74 | | -```json |
75 | | -{ |
76 | | - "myemulator": [ |
77 | | - { |
78 | | - "source_url": "https://example.com/myemulator-{VERSION}-linux.tar.gz", |
79 | | - "source_type": "http", |
80 | | - "version": "1.0.0", |
81 | | - "extraction_type": "archive", |
82 | | - "assets": [ |
83 | | - { |
84 | | - "type": "dir", |
85 | | - "source": "myemulator/bin", |
86 | | - "dest": "bin" |
87 | | - }, |
88 | | - { |
89 | | - "type": "dir", |
90 | | - "source": "$REPO_ROOT/$COMPONENT_NAME/assets/rd_config", |
91 | | - "dest": "rd_config" |
92 | | - } |
93 | | - ] |
94 | | - } |
95 | | - ] |
96 | | -} |
97 | | -``` |
98 | | - |
99 | | -**For Flatpak:** |
100 | | -```json |
101 | | -{ |
102 | | - "myemulator": [ |
103 | | - { |
104 | | - "source_url": "org.example.MyEmulator", |
105 | | - "source_type": "flatpak_id", |
106 | | - "version": "$MYEMULATOR_DESIRED_VERSION", |
107 | | - "extraction_type": "flatpak", |
108 | | - "assets": [ |
109 | | - { |
110 | | - "type": "dir", |
111 | | - "source": "bin", |
112 | | - "dest": "bin" |
113 | | - }, |
114 | | - { |
115 | | - "type": "dir", |
116 | | - "source": "$REPO_ROOT/$COMPONENT_NAME/assets/rd_config", |
117 | | - "dest": "rd_config" |
118 | | - } |
119 | | - ] |
120 | | - } |
121 | | - ] |
122 | | -} |
123 | | -``` |
124 | | - |
125 | | -### 5. Create Component Manifest |
126 | | - |
127 | | -Create `component_manifest.json` with metadata and configuration presets. The RetroDECK configurator automatically parses this file to provide preset options to users: |
128 | | - |
129 | | -```json |
130 | | -{ |
131 | | - "myemulator": { |
132 | | - "name": "MyEmulator", |
133 | | - "url_rdwiki": "https://retrodeck.readthedocs.io/en/latest/wiki_emulator_guides/myemulator/myemulator-guide/", |
134 | | - "url_webpage": "https://example.com/myemulator", |
135 | | - "url_source": "https://github.com/developer/myemulator", |
136 | | - "description": "MyEmulator is an awesome emulator for System X.", |
137 | | - "system_friendly_name": "System X", |
138 | | - "system": "systemx", |
139 | | - "compatible_presets": { |
140 | | - "ask_to_exit": ["false", "true"] |
141 | | - }, |
142 | | - "preset_actions": { |
143 | | - "config_file_format": "ini", |
144 | | - "ask_to_exit": { |
145 | | - "confirm_exit": { |
146 | | - "action": "change", |
147 | | - "new_setting_value": "true", |
148 | | - "section": "General", |
149 | | - "target_file": "$myemulator_config", |
150 | | - "defaults_file": "$config/myemulator/config.ini" |
151 | | - } |
152 | | - } |
153 | | - } |
154 | | - } |
155 | | -} |
156 | | -``` |
157 | | - |
158 | | -**Note**: The `preset_actions` are automatically handled by the RetroDECK configurator - you don't need to implement preset logic in your component scripts. |
159 | | - |
160 | | -### 6. Create Component Functions |
161 | | - |
162 | | -Create `component_functions.sh` to define configuration paths and helper functions: |
163 | | - |
164 | | -```bash |
165 | | -#!/bin/bash |
166 | | - |
167 | | -# Configuration file paths |
168 | | -myemulator_config="$XDG_CONFIG_HOME/myemulator/config.ini" |
169 | | -myemulator_data="$XDG_DATA_HOME/myemulator" |
170 | | - |
171 | | -# Add any component-specific functions here |
172 | | -myemulator_special_function() { |
173 | | - # Function implementation |
174 | | - echo "Special function for MyEmulator" |
175 | | -} |
176 | | -``` |
177 | | - |
178 | | -### 7. Create Component Launcher |
179 | | - |
180 | | -Create `component_launcher.sh` to launch the emulator with proper environment: |
181 | | - |
182 | | -```bash |
183 | | -#!/bin/bash |
184 | | - |
185 | | -# Setting component name and path based on the directory name |
186 | | -component_name="$(basename "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")" |
187 | | -component_path="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd)" |
188 | | - |
189 | | -# Set up library paths |
190 | | -export LD_LIBRARY_PATH="$component_path/lib:$ffmpeg_path/25.08:$rd_shared_libs:${LD_LIBRARY_PATH}" |
191 | | - |
192 | | -# Set up Qt paths if needed |
193 | | -export QT_PLUGIN_PATH="${QT_PLUGIN_PATH}" |
194 | | -export QT_QPA_PLATFORM_PLUGIN_PATH="${QT_QPA_PLATFORM_PLUGIN_PATH}" |
195 | | - |
196 | | -log i "RetroDECK is now launching $component_name" |
197 | | -log d "Library path is: $LD_LIBRARY_PATH" |
198 | | -log d "AppDir is: $component_path" |
199 | | - |
200 | | -# Launch the emulator |
201 | | -exec "$component_path/bin/myemulator" "$@" |
202 | | -``` |
203 | | - |
204 | | -### 8. Create Component Prepare Script |
205 | | - |
206 | | -Create `component_prepare.sh` for configuration setup and directory creation. This script handles the `retrodeck --reset mycomponent` command: |
207 | | - |
208 | | -```bash |
209 | | -#!/bin/bash |
210 | | - |
211 | | -# Setting component name and path based on the directory name |
212 | | -component_name="$(basename "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")" |
213 | | -component_config="/app/retrodeck/components/$component_name/rd_config" |
214 | | - |
215 | | -if [[ "$action" == "reset" ]]; then # Run reset-only commands |
216 | | - |
217 | | - log i "----------------------" |
218 | | - log i "Preparing $component_name" |
219 | | - log i "----------------------" |
220 | | - |
221 | | - # Create config directory |
222 | | - create_dir -d "$XDG_CONFIG_HOME/myemulator/" |
223 | | - |
224 | | - # Copy default config |
225 | | - cp -fT "$component_config/config.ini" "$myemulator_config" |
226 | | - |
227 | | - # Set up directories |
228 | | - set_setting_value "$myemulator_config" "roms_path" "$roms_path/systemx" "myemulator" |
229 | | - set_setting_value "$myemulator_config" "saves_path" "$saves_path/systemx/myemulator" "myemulator" |
230 | | - set_setting_value "$myemulator_config" "screenshots_path" "$screenshots_path/systemx/myemulator" "myemulator" |
231 | | - |
232 | | - # Create necessary directories |
233 | | - create_dir "$saves_path/systemx/myemulator" |
234 | | - create_dir "$screenshots_path/systemx/myemulator" |
235 | | -fi |
236 | | -``` |
237 | | - |
238 | | -### 9. Add Default Configuration |
239 | | - |
240 | | -Create default configuration files in `assets/rd_config/` directory. These should be "RetroDECK defaults" - configure the component to best fit RetroDECK usage by: |
241 | | - |
242 | | -## CI: Force rebuild and per-component detection |
243 | | - |
244 | | -- **Force rebuild**: When running the `Alchemic Circle: Build RetroDECK Components` workflow manually you can set the `force_rebuild` input to `true` to force rebuilding all components. CI or other runners can also set the environment variable `FORCE_REBUILD=true` to achieve the same effect. |
245 | | -- **Per-component rebuilds**: The workflow runs `automation-tools/detect_component_changes.sh` for each component. If files in a component folder changed (PR or pushed commits), the workflow will force rebuilding that component even if the cooker reference version matches. |
246 | | - |
247 | | - |
248 | | -- Removing personal paths (home directories, user-specific locations) |
249 | | -- Setting appropriate default settings for RetroDECK environment |
250 | | -- Configuring paths to use RetroDECK variables ($roms_path, $saves_path, etc.) |
251 | | -- Setting up any RetroDECK-specific presets |
252 | | - |
253 | | -```bash |
254 | | -mkdir -p assets/rd_config |
255 | | -# Create default config files with RetroDECK-optimized settings |
256 | | -# Example: config.ini, qt-config.ini, etc. |
257 | | -``` |
258 | | - |
259 | | -### 9.5. Check and Configure Libraries |
260 | | - |
261 | | -To determine which libraries your component needs: |
262 | | - |
263 | | -1. **Enter Flatpak shell**: |
264 | | - ```bash |
265 | | - flatpak run --command=sh net.retrodeck.retrodeck |
266 | | - ``` |
267 | | - |
268 | | -2. **Temporarily modify the launcher** to check libraries: |
269 | | - - Edit `component_launcher.sh` |
270 | | - - Change `exec "$component_path/bin/myemulator" "$@"` |
271 | | - - To: `ldd "$component_path/bin/myemulator" | grep "not found"` |
272 | | - |
273 | | -3. **Clean environment for testing**: |
274 | | - - Delete other components and shared libraries temporarily |
275 | | - - Each component should be self-contained |
276 | | - - This prevents `ldd` from finding libraries from other components |
277 | | - |
278 | | -4. **Run the modified launcher** to see missing libraries: |
279 | | - ```bash |
280 | | - flatpak run --command=sh net.retrodeck.retrodeck |
281 | | - retrodeck --open mycomponent |
282 | | - ``` |
283 | | - |
284 | | -5. **Add missing libraries** to your `component_recipe.json` in the `libs` section |
285 | | - |
286 | | -**Tip**: You can edit files directly in the Flatpak location (e.g., `/home/$USER/.local/share/flatpak/app/net.retrodeck.retrodeck/current/active/files/components/mycomponent`) and save in place to test changes without rebuilding everything. |
287 | | - |
288 | | -### 10. Build and Test |
289 | | - |
290 | | -Use the Alchemist to build your component: |
291 | | - |
292 | | -```bash |
293 | | -cd /path/to/components |
294 | | -./automation-tools/alchemist/alchemist.sh myemulator/component_recipe.json |
295 | | -``` |
296 | | - |
297 | | -Check the `artifacts/` directory for the built component. For testing, extract the component to the Flatpak components directory: |
298 | | - |
299 | | -```bash |
300 | | -# Extract the built artifact to Flatpak components directory for testing |
301 | | -tar -xzf artifacts/myemulator-artifact.tar.gz -C /home/$USER/.local/share/flatpak/app/net.retrodeck.retrodeck/current/active/files/components/mycomponent |
302 | | -``` |
303 | | - |
304 | | -### 11. Test Integration |
305 | | - |
306 | | -- Test launching the component within Flatpak: |
307 | | - ```bash |
308 | | - flatpak run --command=sh net.retrodeck.retrodeck |
309 | | - retrodeck --open mycomponent |
310 | | - ``` |
311 | | -- Verify that `retrodeck --reset mycomponent` works correctly |
312 | | -- Verify configurations are applied correctly |
313 | | -- Test preset actions through the RetroDECK configurator (presets are automatically handled) |
314 | | -- Ensure paths are set up properly |
315 | | - |
316 | | -### 12. Update Framework |
317 | | - |
318 | | -If needed, update the RetroDECK framework to recognize your new component by adding entries to: |
319 | | -- Component lists |
320 | | -- System mappings |
321 | | -- Menu configurations |
322 | | - |
323 | | -### Additional Tips |
324 | | - |
325 | | -- **Use existing components as templates**: Copy and modify similar components |
326 | | -- **Test with small changes**: Build and test incrementally |
327 | | -- **Check the HOWTO**: Read `automation-tools/alchemist/templates/HOWTO.txt` for detailed recipe information |
328 | | -- **Use the hunt_libraries script**: Run `automation-tools/hunt_libraries.sh` to find required libraries |
329 | | -- **Follow naming conventions**: Use consistent naming throughout all files |
330 | | -- **Document your component**: Update the RetroDECK wiki with usage instructions |
331 | | -- **Self-contained components**: Each component should be self-contained with its own libraries to avoid conflicts |
332 | | - |
333 | 5 | ## Documentation |
334 | 6 |
|
335 | | -Please visit the [The RetroDECK Wiki](https://retrodeck.readthedocs.io/) and go to the RetroDECK Development 🧪 section. |
| 7 | +Please visit the [How-to: Add a Component to RetroDECK - A Cooking Philosophy](https://retrodeck.readthedocs.io/en/latest/wiki_development/components/component-guide/creating-components-guide/). |
336 | 8 |
|
337 | 9 | ## Contributing |
338 | 10 |
|
339 | 11 | Contributions are welcome! Please follow these steps: |
| 12 | + |
340 | 13 | 1. Fork the repository. |
341 | 14 | 2. Create a new branch for your changes. |
342 | 15 | 3. Submit a pull request. |
|
0 commit comments