├── .github └── workflows │ └── publish.yml ├── .gitignore ├── .vitepress ├── config.mts └── theme │ ├── index.ts │ └── style.css ├── assets └── icon.svg ├── blocks ├── _assets │ ├── blockstates_0_large.png │ ├── blockstates_1.png │ ├── blockstates_2.webp │ ├── condensed_oak_log_textures.zip │ ├── first_block_0.png │ ├── first_block_1.png │ ├── first_block_1_small.png │ └── first_block_4.png ├── block-entities.md ├── blockstates.md └── index.md ├── components └── ColorSwatch.vue ├── contributing.md ├── data-generation ├── index.md ├── loot-tables.md ├── tags.md └── translations.md ├── events ├── _assets │ └── creating_events_0.png ├── creation.md └── index.md ├── getting-started ├── _assets │ ├── access-wideners_0.png │ ├── analyzing_01.png │ ├── analyzing_02.png │ ├── basic_problem_solving_01.png │ ├── basic_problem_solving_02.png │ ├── basic_problem_solving_03.png │ ├── basic_problem_solving_04.png │ ├── basic_problem_solving_05.png │ ├── basic_problem_solving_06.png │ ├── basic_problem_solving_07.png │ ├── basic_problem_solving_08.png │ ├── basic_problem_solving_09.png │ ├── basic_problem_solving_10.png │ ├── clients-and-servers_1.png │ ├── clients-and-servers_10.png │ ├── clients-and-servers_2.png │ ├── clients-and-servers_3.png │ ├── clients-and-servers_4.png │ ├── clients-and-servers_5.png │ ├── clients-and-servers_6.png │ ├── clients-and-servers_7.png │ ├── clients-and-servers_8.png │ ├── clients-and-servers_9.png │ ├── comments_01.png │ ├── comments_02.png │ ├── comments_03.png │ ├── comments_04.png │ ├── comments_05.png │ ├── comments_06.png │ ├── comments_07.png │ ├── creating-a-project_0.png │ ├── launching-the-game_0.png │ ├── launching-the-game_1.png │ ├── launching-the-game_2.png │ ├── launching-the-game_3.png │ ├── launching-the-game_4.png │ ├── refactoring_01.png │ ├── search-and-replace_01.png │ ├── traversing_01.png │ ├── traversing_02.png │ ├── traversing_03.png │ ├── traversing_04.png │ ├── traversing_05.png │ ├── traversing_06.png │ ├── util_01.png │ └── util_02.png ├── access-wideners.md ├── basic-problem-solving.md ├── creating-project.md ├── index.md ├── launching-servers.md ├── launching-the-game.md ├── mixins.md └── using-the-ide.md ├── index.md ├── items ├── _assets │ ├── armor_0.png │ ├── armor_1.png │ ├── armor_2.png │ ├── armor_3.png │ ├── example_armor_item_textures.zip │ ├── example_armor_layer_textures.zip │ ├── first_item_0.png │ ├── first_item_1.png │ ├── first_item_1_small.png │ ├── first_item_2.png │ ├── food_0.webp │ ├── interactive_0.webp │ ├── itemgroups_0.png │ ├── itemgroups_1.png │ ├── tools_0.png │ ├── tools_0_small.png │ └── tools_1.png ├── armor.md ├── food.md ├── index.md ├── interactivity.md ├── item-groups.md └── tools.md ├── misc-topics ├── codecs.md ├── index.md └── text-and-translations.md ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico └── icon.png ├── rendering ├── _assets │ ├── basics_0.png │ ├── matrices_0.png │ ├── matrices_1.png │ ├── matrices_2.png │ ├── matrices_3.png │ ├── matrices_4.webp │ ├── matrices_5.png │ ├── world_0.png │ ├── world_1.png │ ├── world_2.png │ └── world_3.png ├── index.md ├── matrices.md ├── particles │ ├── _assets │ │ ├── creating_particle_factories_1.png │ │ ├── creating_particle_factories_2.png │ │ ├── creating_particles_0.png │ │ ├── creating_particles_0_small.png │ │ └── creating_particles_1.png │ ├── factories.md │ └── index.md └── world.md └── sounds ├── _assets ├── custom_sounds_0.png ├── custom_sounds_1.png ├── custom_sounds_2.png └── custom_sounds_3.png ├── index.md └── using.md /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a VitePress site to GitHub Pages 2 | # 3 | name: Deploy VitePress site to Pages 4 | 5 | on: 6 | # Runs on pushes targeting the `main` branch. Change this to `master` if you're 7 | # using the `master` branch as the default branch. 8 | push: 9 | branches: [main] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | 20 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 21 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 22 | concurrency: 23 | group: pages 24 | cancel-in-progress: false 25 | 26 | jobs: 27 | # Build job 28 | build: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v3 33 | with: 34 | fetch-depth: 0 # Not needed if lastUpdated is not enabled 35 | - uses: pnpm/action-setup@v2 36 | with: 37 | version: 8 38 | - name: Setup Node 39 | uses: actions/setup-node@v3 40 | with: 41 | node-version: 18 42 | cache: pnpm # or pnpm / yarn 43 | - name: Setup Pages 44 | uses: actions/configure-pages@v3 45 | - name: Install dependencies 46 | run: pnpm install # or pnpm install / yarn install / bun install 47 | - name: Build with VitePress 48 | run: | 49 | pnpm run docs:build 50 | touch .vitepress/dist/.nojekyll 51 | - name: Upload artifact 52 | uses: actions/upload-pages-artifact@v2 53 | with: 54 | path: .vitepress/dist 55 | 56 | # Deployment job 57 | deploy: 58 | environment: 59 | name: github-pages 60 | url: ${{ steps.deployment.outputs.page_url }} 61 | needs: build 62 | runs-on: ubuntu-latest 63 | name: Deploy 64 | steps: 65 | - name: Deploy to GitHub Pages 66 | id: deployment 67 | uses: actions/deploy-pages@v2 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vitepress/cache 2 | node_modules 3 | .vitepress/dist -------------------------------------------------------------------------------- /.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | const allCategoriesSection = [ 4 | { 5 | text: "Guides", 6 | items: [ 7 | { text: "Getting Started", link: "/getting-started/" }, 8 | { text: "Items", link: "/items/" }, 9 | { text: "Blocks", link: "/blocks/" }, 10 | { text: "Sounds", link: "/sounds/" }, 11 | { text: "Data Generation", link: "/data-generation/" }, 12 | { text: "Events", link: "/events/" }, 13 | { text: "Rendering", link: "/rendering/" }, 14 | { text: "Miscellaneous Topics", link: "/misc-topics/" } 15 | ] 16 | } 17 | ] 18 | 19 | // https://vitepress.dev/reference/site-config 20 | export default defineConfig({ 21 | title: "Fabric Modding Wiki", 22 | description: "An open source guide-book for creating mods using Fabric.", 23 | 24 | head: [ 25 | ['link', { rel: 'icon', href: '/favicon.ico' }], 26 | ['meta', { name: 'theme-color', content: '#f0430e' }], 27 | ['meta', { name: 'twitter:card', content: 'summary' }], 28 | ['meta', { name: 'og:image', content: '/icon.png' }] 29 | ], 30 | 31 | transformPageData(pageData) { 32 | pageData.frontmatter.head ??= [] 33 | pageData.frontmatter.head.push([ 34 | 'meta', 35 | { 36 | name: 'og:title', 37 | content: 38 | pageData.frontmatter.layout === 'home' 39 | ? `Fabric Modding Wiki` 40 | : `${pageData.title} | Fabric Modding Wiki` 41 | } 42 | ]) 43 | 44 | pageData.frontmatter.head.push([ 45 | 'meta', 46 | { 47 | name: 'og:description', 48 | content: pageData.frontmatter.description || "An open source guide-book for creating mods using Fabric." 49 | } 50 | ]) 51 | }, 52 | 53 | sitemap: { 54 | hostname: 'https://fabric.moddedmc.wiki/' 55 | }, 56 | 57 | cleanUrls: true, 58 | 59 | themeConfig: { 60 | search: { 61 | provider: 'local', 62 | // options: { 63 | // appId: 'DHC900L06Z', 64 | // apiKey: '31c0bbd55f94c659a48a53a671bb8971', 65 | // indexName: 'fabric' 66 | // } 67 | }, 68 | 69 | logo: "/icon.png", 70 | 71 | // https://vitepress.dev/reference/default-theme-config 72 | nav: [ 73 | { text: 'Home', link: '/' }, 74 | { text: 'Getting Started', link: '/getting-started/' }, 75 | { text: 'Contribute', link: '/contributing' } 76 | ], 77 | 78 | sidebar: { 79 | // index.md, creating-project.md, launching-the-game.md, launching-servers.md, access-wideners.md, mixins.md 80 | '/getting-started/': [ 81 | ...allCategoriesSection, 82 | { 83 | text: 'Getting Started', 84 | items: [ 85 | { text: 'Introduction', link: '/getting-started/' }, 86 | { text: 'Creating a Project', link: '/getting-started/creating-project' }, 87 | { text: 'Launching the Game', link: '/getting-started/launching-the-game' }, 88 | { text: 'Launching Servers', link: '/getting-started/launching-servers' }, 89 | { text: 'Access Wideners', link: '/getting-started/access-wideners' }, 90 | { text: 'Mixins', link: '/getting-started/mixins' }, 91 | { text: 'Basic Problem Solving', link: '/getting-started/basic-problem-solving' }, 92 | { text: 'Using The IDE Effectively', link: '/getting-started/using-the-ide' } 93 | ] 94 | } 95 | ], 96 | // index.md, using.md 97 | '/sounds/': [ 98 | ...allCategoriesSection, 99 | { 100 | text: "Sounds", 101 | items: [ 102 | { text: "Creating Custom Sounds", link: "/sounds/" }, 103 | { text: "Playing SoundEvents", link: "/sounds/using" } 104 | ] 105 | } 106 | ], 107 | // index.md (Creating Your First Item), food.md, tools.md, armor.md, item-groups.md, interactivity.md 108 | '/items/': [ 109 | ...allCategoriesSection, 110 | { 111 | text: 'Items', 112 | items: [ 113 | { text: 'Creating Your First Item', link: '/items/' }, 114 | { text: 'Food', link: '/items/food' }, 115 | { text: 'Tools and Weapons', link: '/items/tools' }, 116 | { text: 'Armor', link: '/items/armor' }, 117 | { text: 'Custom Item Groups', link: '/items/item-groups' }, 118 | { text: 'Item Interactivity', link: '/items/interactivity' } 119 | ] 120 | } 121 | ], 122 | // index.md, blockstates.md, block-entities.md 123 | '/blocks/': [ 124 | ...allCategoriesSection, 125 | { 126 | text: 'Blocks', 127 | items: [ 128 | { text: 'Creating Your First Block', link: '/blocks/' }, 129 | { text: 'Blockstates', link: '/blocks/blockstates' }, 130 | { text: 'Block Entities', link: '/blocks/block-entities' } 131 | ] 132 | } 133 | ], 134 | 135 | // index.md, loot-tables.md, tags.md, translations.md 136 | '/data-generation/': [ 137 | ...allCategoriesSection, 138 | { 139 | text: "Data Generation", 140 | items: [ 141 | { text: 'Data Generation Setup', link: '/data-generation/' }, 142 | { text: 'Loot Table Provider', link: '/data-generation/loot-tables' }, 143 | { text: 'Tag Provider', link: '/data-generation/tags' }, 144 | { text: 'Translation Provider', link: '/data-generation/translations' } 145 | ] 146 | } 147 | ], 148 | 149 | // index.md, creation.md 150 | '/events/': [ 151 | ...allCategoriesSection, 152 | { 153 | text: 'Events', 154 | items: [ 155 | { text: 'Using Custom Events', link: '/events/' }, 156 | { text: 'Creating Custom Events', link: '/events/creation' } 157 | ] 158 | } 159 | ], 160 | 161 | '/rendering/': [ 162 | ...allCategoriesSection, 163 | { 164 | text: 'Rendering', 165 | items: [ 166 | { text: 'Introduction To Rendering', link: '/rendering/' }, 167 | { text: 'Matrices', link: '/rendering/matrices' }, 168 | { text: "Worldspace Rendering", link: '/rendering/world' }, 169 | { 170 | text: "Particles", 171 | items: [ 172 | { text: "Creating Custom Particles", link: '/rendering/particles/' }, 173 | { text: "Creating Particle Factories", link: '/rendering/particles/factories' } 174 | ] 175 | } 176 | ] 177 | } 178 | ], 179 | '/misc-topics/': [ 180 | ...allCategoriesSection, 181 | { 182 | text: 'Miscellaneous Topics', 183 | items: [ 184 | { text: 'About This Section', link: '/misc-topics/' }, 185 | { text: 'Codecs', link: '/misc-topics/codecs' }, 186 | { text: 'Text and Translations', link: '/misc-topics/text-and-translations' }, 187 | ] 188 | } 189 | ] 190 | }, 191 | 192 | footer: { 193 | message: 'Not affiliated with Mojang Studios or the Fabric Project.', 194 | copyright: 'Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International 2023 © Calum H. (IMB11)' 195 | }, 196 | 197 | socialLinks: [ 198 | { icon: 'github', link: 'https://github.com/moddedmc-wiki/fabric-modding-wiki' }, 199 | { icon: 'discord', link: 'https://discord.gg/5tmestARuU' } 200 | ] 201 | } 202 | }) 203 | -------------------------------------------------------------------------------- /.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | // https://vitepress.dev/guide/custom-theme 2 | import { h, nextTick, onMounted, watch } from 'vue' 3 | import { useRoute, type Theme } from 'vitepress' 4 | import DefaultTheme from 'vitepress/theme' 5 | import mediumZoom from 'medium-zoom'; 6 | import './style.css' 7 | 8 | export default { 9 | extends: DefaultTheme, 10 | Layout: () => { 11 | return h(DefaultTheme.Layout, null, { 12 | // https://vitepress.dev/guide/extending-default-theme#layout-slots 13 | }) 14 | }, 15 | enhanceApp({ app, router, siteData }) { 16 | // ... 17 | }, 18 | setup() { 19 | const route = useRoute(); 20 | const initZoom = () => { 21 | mediumZoom('.main img', { background: 'var(--vp-c-bg)' }); 22 | }; 23 | onMounted(() => { 24 | initZoom(); 25 | }); 26 | watch( 27 | () => route.path, 28 | () => nextTick(() => initZoom()) 29 | ); 30 | }, 31 | } satisfies Theme 32 | -------------------------------------------------------------------------------- /.vitepress/theme/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Customize default theme styling by overriding CSS variables: 3 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css 4 | */ 5 | 6 | /** 7 | * Colors 8 | * 9 | * Each colors have exact same color scale system with 3 levels of solid 10 | * colors with different brightness, and 1 soft color. 11 | * 12 | * - `XXX-1`: The most solid color used mainly for colored text. It must 13 | * satisfy the contrast ratio against when used on top of `XXX-soft`. 14 | * 15 | * - `XXX-2`: The color used mainly for hover state of the button. 16 | * 17 | * - `XXX-3`: The color for solid background, such as bg color of the button. 18 | * It must satisfy the contrast ratio with pure white (#ffffff) text on 19 | * top of it. 20 | * 21 | * - `XXX-soft`: The color used for subtle background such as custom container 22 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors 23 | * on top of it. 24 | * 25 | * The soft color must be semi transparent alpha channel. This is crucial 26 | * because it allows adding multiple "soft" colors on top of each other 27 | * to create a accent, such as when having inline code block inside 28 | * custom containers. 29 | * 30 | * - `default`: The color used purely for subtle indication without any 31 | * special meanings attched to it such as bg color for menu hover state. 32 | * 33 | * - `brand`: Used for primary brand colors, such as link text, button with 34 | * brand theme, etc. 35 | * 36 | * - `tip`: Used to indicate useful information. The default theme uses the 37 | * brand color for this by default. 38 | * 39 | * - `warning`: Used to indicate warning to the users. Used in custom 40 | * container, badges, etc. 41 | * 42 | * - `danger`: Used to show error, or dangerous message to the users. Used 43 | * in custom container, badges, etc. 44 | * -------------------------------------------------------------------------- */ 45 | 46 | :root { 47 | --vp-c-default-1: var(--vp-c-gray-1); 48 | --vp-c-default-2: var(--vp-c-gray-2); 49 | --vp-c-default-3: var(--vp-c-gray-3); 50 | --vp-c-default-soft: var(--vp-c-gray-soft); 51 | 52 | --vp-c-brand-1: #f0430e; 53 | --vp-c-brand-2: #dd5d36; 54 | --vp-c-brand-3: #b65439; 55 | --vp-c-brand-soft: #a15138; 56 | 57 | --vp-c-tip-1: var(--vp-c-brand-1); 58 | --vp-c-tip-2: var(--vp-c-brand-2); 59 | --vp-c-tip-3: var(--vp-c-brand-3); 60 | --vp-c-tip-soft: var(--vp-c-brand-soft); 61 | 62 | --vp-c-warning-1: var(--vp-c-yellow-1); 63 | --vp-c-warning-2: var(--vp-c-yellow-2); 64 | --vp-c-warning-3: var(--vp-c-yellow-3); 65 | --vp-c-warning-soft: var(--vp-c-yellow-soft); 66 | 67 | --vp-c-danger-1: var(--vp-c-red-1); 68 | --vp-c-danger-2: var(--vp-c-red-2); 69 | --vp-c-danger-3: var(--vp-c-red-3); 70 | --vp-c-danger-soft: var(--vp-c-red-soft); 71 | } 72 | 73 | ::-webkit-scrollbar { 74 | width: 10px; 75 | } 76 | 77 | ::-webkit-scrollbar-track { 78 | background-color: var(--vp-c-bg-alt); 79 | } 80 | 81 | .medium-zoom-overlay { 82 | z-index: 10000; 83 | } 84 | 85 | .medium-zoom-image { 86 | z-index: 10001; 87 | } 88 | 89 | .VPNavBar:not(.top):not(.has-sidebar) { 90 | border-bottom: none !important; 91 | animation: nav-box-shadow 200ms ease-out forwards; 92 | } 93 | 94 | .VPNavBar.top:not(.has-sidebar) { 95 | animation: nav-box-shadow-fade-out 200ms ease-out forwards; 96 | } 97 | 98 | @keyframes nav-box-shadow { 99 | 100% { 100 | box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px 0px; 101 | } 102 | } 103 | 104 | @keyframes nav-box-shadow-fade-out { 105 | 0% { 106 | box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px 0px; 107 | } 108 | 100% { 109 | box-shadow: none; 110 | } 111 | } 112 | 113 | ::-webkit-scrollbar-thumb { 114 | background-color: var(--vp-c-bg-soft); 115 | border-radius: 10px; 116 | box-shadow: 0 0 6px rgba(0, 0, 0, 0.3); 117 | } 118 | 119 | /** 120 | * Component: Button 121 | * -------------------------------------------------------------------------- */ 122 | 123 | :root { 124 | --vp-button-brand-border: transparent; 125 | --vp-button-brand-text: var(--vp-c-white); 126 | --vp-button-brand-bg: var(--vp-c-brand-3); 127 | --vp-button-brand-hover-border: transparent; 128 | --vp-button-brand-hover-text: var(--vp-c-white); 129 | --vp-button-brand-hover-bg: var(--vp-c-brand-2); 130 | --vp-button-brand-active-border: transparent; 131 | --vp-button-brand-active-text: var(--vp-c-white); 132 | --vp-button-brand-active-bg: var(--vp-c-brand-1); 133 | } 134 | 135 | /** 136 | * Component: Home 137 | * -------------------------------------------------------------------------- */ 138 | 139 | :root { 140 | --vp-home-hero-name-color: transparent; 141 | --vp-home-hero-name-background: -webkit-linear-gradient( 142 | 120deg, 143 | #bd5738 30%, 144 | #e24514 145 | ); 146 | 147 | --vp-home-hero-image-background-image: linear-gradient( 148 | -45deg, 149 | #bd5738 50%, 150 | #e24514 50% 151 | ); 152 | --vp-home-hero-image-filter: blur(44px); 153 | } 154 | 155 | @media (min-width: 640px) { 156 | :root { 157 | --vp-home-hero-image-filter: blur(56px); 158 | } 159 | } 160 | 161 | @media (min-width: 960px) { 162 | :root { 163 | --vp-home-hero-image-filter: blur(68px); 164 | } 165 | } 166 | 167 | /** 168 | * Component: Custom Block 169 | * -------------------------------------------------------------------------- */ 170 | 171 | :root { 172 | --vp-custom-block-tip-border: transparent; 173 | --vp-custom-block-tip-text: var(--vp-c-text-1); 174 | --vp-custom-block-tip-bg: var(--vp-c-brand-soft); 175 | --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); 176 | } 177 | 178 | /** 179 | * Component: Algolia 180 | * -------------------------------------------------------------------------- */ 181 | 182 | .DocSearch { 183 | --docsearch-primary-color: var(--vp-c-brand-1) !important; 184 | } 185 | 186 | .vp-doc table { 187 | width: 100%; 188 | max-width: -moz-fit-content; 189 | max-width: fit-content; 190 | } 191 | 192 | p > img { 193 | margin-left: auto; 194 | margin-right: auto; 195 | border-radius: 8px; 196 | 197 | /* Dropshadow */ 198 | box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px 0px; 199 | } 200 | 201 | .VPButton, 202 | .custom-block, 203 | div[class*="language-"], 204 | .VPTeamMembersItem, 205 | .pager-link, 206 | .VPFeature, 207 | .VPLocalSearchBox > .shell { 208 | box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px 0px; 209 | } 210 | 211 | .VPLocalSearchBox > .backdrop { 212 | backdrop-filter: blur(5px); 213 | } 214 | 215 | .pager-link { 216 | background-color: var(--vp-c-bg-alt); 217 | } 218 | 219 | .VPFooter { 220 | border-top: none !important; 221 | } 222 | 223 | .VPLocalSearchBox > .backdrop { 224 | opacity: 0; 225 | animation: show 200ms 100ms cubic-bezier(0.38, 0.97, 0.56, 0.76) forwards; 226 | } 227 | 228 | .VPLocalSearchBox > .shell { 229 | animation: show 400ms 100ms cubic-bezier(0.38, 0.97, 0.56, 0.76) forwards; 230 | opacity: 0; 231 | transform: rotateX(-90deg); 232 | transform-origin: top center; 233 | } 234 | 235 | @keyframes show { 236 | 100% { 237 | opacity: 1; 238 | transform: none; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /blocks/_assets/blockstates_0_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/blockstates_0_large.png -------------------------------------------------------------------------------- /blocks/_assets/blockstates_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/blockstates_1.png -------------------------------------------------------------------------------- /blocks/_assets/blockstates_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/blockstates_2.webp -------------------------------------------------------------------------------- /blocks/_assets/condensed_oak_log_textures.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/condensed_oak_log_textures.zip -------------------------------------------------------------------------------- /blocks/_assets/first_block_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/first_block_0.png -------------------------------------------------------------------------------- /blocks/_assets/first_block_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/first_block_1.png -------------------------------------------------------------------------------- /blocks/_assets/first_block_1_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/first_block_1_small.png -------------------------------------------------------------------------------- /blocks/_assets/first_block_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/blocks/_assets/first_block_4.png -------------------------------------------------------------------------------- /blocks/blockstates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Block States 3 | description: Learn why blockstates are a great way to add visual functionality to your blocks. 4 | prev: 5 | text: "Creating Your First Block" 6 | link: "/blocks/" 7 | next: 8 | text: "Block Entities" 9 | link: "/blocks/block-entities" 10 | --- 11 | 12 | # Block States 13 | 14 | A block state is a piece of data attached to a singular block in the Minecraft world containing information on the block in the form of properties - some examples of properties vanilla stores in block states: 15 | 16 | - Rotation: Mostly used for logs and other natural blocks. 17 | - Activated: Heavily used in redstone devices, and blocks such as the furnace or smoker. 18 | - Age: Used in crops, plants, saplings, kelp etc. 19 | 20 | You can probably see why they are useful - they avoid the need to store NBT data in a block entity - reducing the world size, and preventing TPS issues! 21 | 22 | Blockstate definitions are found in the `assets//blockstates` folder. 23 | 24 | ## Example: Pillar Block 25 | 26 | Minecraft has some custom classes already that allow you quickly create certain types of blocks - this example goes through the creation of a block with the `axis` property by creating a "Condensed Oak Log" block. 27 | 28 | The vanilla `PillarBlock` class allows the block to be placed in the X, Y or Z axis. 29 | 30 | ```java 31 | public static final PillarBlock CONDENSED_OAK_LOG = register( 32 | new PillarBlock( 33 | AbstractBlock.Settings.create().sounds(BlockSoundGroup.WOOD) 34 | ), "condensed_oak_log", true 35 | ); 36 | ``` 37 | 38 | Pillar blocks have two textures, top and side - they use the `block/cube_column` model. 39 | 40 | As always, with all block textures, the texture files can be found in `assets//textures/block` 41 | 42 |
43 | 44 | ![](./_assets/blockstates_0_large.png) 45 | 46 | 47 | Download Textures 48 | 49 | 50 |
51 | 52 | Since the pillar block has two positons, horizontal and vertical, we'll need to make two seperate model files: 53 | 54 | - `condensed_oak_log_horizontal.json` which extends the `block/cube_column_horizontal` model. 55 | - `condensed_oak_log.json` which extends the `block/cube_column` model. 56 | 57 | ```json 58 | { 59 | "parent": "block/cube_column", 60 | "textures": { 61 | "end": "mod_id:block/condensed_oak_log_top", 62 | "side": "mod_id:block/condensed_oak_log" 63 | } 64 | } 65 | ``` 66 | 67 | The blockstate file is where the magic happens - pillar blocks have three axis, so we'll use these models accordingly. 68 | 69 | ```jsonc 70 | { 71 | "variants": { 72 | "axis=x": { 73 | "model": "mod_id:block/condensed_oak_log_horizontal", 74 | // We'll rotate the model so that it faces towards the positive-x direction 75 | "x": 90, 76 | "y": 90 77 | }, 78 | "axis=y": { 79 | "model": "mod_id:block/condensed_oak_log" 80 | }, 81 | "axis=z": { 82 | "model": "mod_id:block/condensed_oak_log_horizontal", 83 | // Rotate the model so it faces towards the positive-x direction. 84 | "x": 90 85 | } 86 | } 87 | } 88 | ``` 89 | 90 | As always, you'll need to create a translation for your block, and an item model which parents either of the two models. 91 | 92 | ![](./_assets/blockstates_1.png) 93 | 94 | ## Custom Block States 95 | 96 | Custom block states are great if your block has unique properties - sometimes you may find that your block can re-use vanilla properties. 97 | 98 | This example will create a unique boolean property called `activated` - when a player right clicks on the block, the block will go from `activated=false` to `activated=true` - changing it's texture accordingly. 99 | 100 | ### Creating the property 101 | 102 | Firstly, you'll need to create the property itself - since this is a boolean, we'll use the `BooleanProperty.of` method. 103 | 104 | ```java 105 | public class PrismarineLampBlock extends Block { 106 | public static final BooleanProperty ACTIVATED = BooleanProperty.of("activated"); 107 | 108 | // ... 109 | } 110 | ``` 111 | 112 | Next, we have to append the property to the blockstate manager in the `appendProperties` method. You'll need to override the method to access the builder: 113 | 114 | ```java 115 | @Override 116 | protected void appendProperties(StateManager.Builder builder) { 117 | builder.add(ACTIVATED); 118 | } 119 | ``` 120 | 121 | You'll also have to set a default state for the `activated` property in the constructor of your custom block. 122 | 123 | ```java 124 | public PrismarineLampBlock(...) { 125 | // ... super() etc. 126 | 127 | setDefaultState(getDefaultState().with(ACTIVATED, false)); 128 | } 129 | ``` 130 | 131 | ### Using the property 132 | 133 | This example flips the boolean `activated` property when the player interacts with the block. We can override the `onUse` method for this: 134 | 135 | ```java 136 | @Override 137 | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { 138 | // Ignore the interaction if it was run on the client. 139 | if (world.isClient) { 140 | return ActionResult.SUCCESS; 141 | } 142 | 143 | // Get the current value of the "activated" property 144 | boolean activated = state.get(ACTIVATED); 145 | 146 | // Flip the value of activated and save the new blockstate. 147 | world.setBlockState(pos, state.with(ACTIVATED, !activated)); 148 | 149 | return ActionResult.SUCCESS; 150 | } 151 | ``` 152 | 153 | ### Visualizing the property 154 | 155 | Since you created a new property, you will have to update the blockstate file for the block to account for that property. 156 | 157 | If you have multiple properties on a block, you'll have to account for all possible combinations, eg: `activated` and `axis` would lead to `6` combinations (two possible values for `activated` and three possible values for `axis`) 158 | 159 | Since this block only has two possible variants - due to the fact it only has one property, `activated` - the blockstate JSON will look something like this: 160 | 161 | ```jsonc 162 | { 163 | "variants": { 164 | "activated=false": { 165 | "model": "mod_id:block/prismarine_lamp" 166 | }, 167 | "activated=true": { 168 | "model": "mod_id:block/prismarine_lamp_activated" 169 | } 170 | } 171 | } 172 | ``` 173 | 174 | ![](./_assets/blockstates_2.webp) 175 | 176 |
177 | 178 | Since the example block is a lamp, we also need to make it emit light when the activated property is true - this can be done through the block settings passed to the constructor: 179 | 180 | ```java 181 | AbstractBlock.Settings.of(...) 182 | .luminance((state) -> { 183 | // Get the value of the "activated" property. 184 | boolean activated = state.get(ACTIVATED); 185 | 186 | // Return a light level if activated = true 187 | return activated ? 15 : 0; 188 | }); 189 | ``` -------------------------------------------------------------------------------- /blocks/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating Your First Block 3 | description: Learn how to register a simple block and block item, texture and model it. 4 | next: 5 | text: Block States 6 | link: /blocks/blockstates 7 | --- 8 | 9 | # Creating Your First Block 10 | 11 | If you have not already noticed, the Minecraft world consists of blocks - this page will guide you through the registration, texturing and modeling of a basic block. 12 | 13 | ## Preparing your Blocks class. 14 | 15 | Similarly to items, you can create a method that automatically registers a block and it's block item. 16 | 17 | You should put this method in a class called `ModBlocks` (or whatever you want to name it) 18 | 19 | Mojang does this with their own blocks, see the `Blocks` class to see how they do it. 20 | 21 | ```java 22 | public class ModBlocks { 23 | public static T register(T block, String name, boolean shouldRegisterItem) { 24 | Identifier id = new Identifier("mod_id", name); 25 | 26 | if(shouldRegisterItem) { 27 | BlockItem blockItem = new BlockItem(block, new Item.Settings()); 28 | Registry.register(Registries.ITEM, id, blockItem); 29 | } 30 | 31 | return Registry.register(Registries.BLOCK, id, block); 32 | } 33 | } 34 | ``` 35 | 36 | The registering of a block item has been togglable, as sometimes you don't want players to be able to get the item in their inventory - for example: `minecraft:air` does not have a block item. 37 | 38 | You should also create an empty method that can be used to statically initialize the blocks class - which causes all final fields to be evaluated, this will be called from your `ModInitializer` class: 39 | 40 | ```java 41 | public class ModBlocks { 42 | // ... 43 | 44 | public static void initialize() {} 45 | } 46 | ``` 47 | 48 | ```java 49 | public class MyMod implements ModInitializer { 50 | @Override 51 | public void onInitialize() { 52 | // Statically initialize the blocks class. 53 | ModBlocks.initialize(); 54 | } 55 | } 56 | ``` 57 | 58 | ## Creating and registering a block. 59 | 60 | Similarly to items, blocks take in a `Blocks.Settings` class in their constructor which tells the game certain properties about the block - from it's sound effects to mining level. 61 | 62 | I will not touch on all of the options here - you can view the class yourself to see all the different options, the methods should be self explanatory. 63 | 64 | This example will be for a condensed dirt block. 65 | 66 | ```java 67 | public static final Block CONDENSED_DIRT = register( 68 | new Block( 69 | AbstractBlock.Settings.create().sounds(BlockSoundGroup.GRASS) 70 | ), "condensed_dirt", true); 71 | ``` 72 | 73 | To automatically create the block item, we can pass `true` to the `shouldRegisterItem` parameter. 74 | 75 | ### Item Group 76 | 77 | Since the `BlockItem` is automatically created and registered, to add it to an item group, you must use the `Block.asItem()` method to get the `BlockItem` instance: 78 | 79 | ```java 80 | ItemGroupEvents.modifyEntriesEvent(ITEM_GROUP).register((itemGroup) -> { 81 | itemGroup.add(ModBlocks.CONDENSED_DIRT.asItem()); 82 | }); 83 | ``` 84 | 85 |
86 | 87 | When you go in-game, you should see that your block exists in the creative menu, and is placeable. 88 | 89 | ![](./_assets/first_block_0.png) 90 | 91 | However, some things are missing that will need to be created: 92 | 93 | - Translation (Block name) 94 | - Model 95 | - Texture 96 | 97 | ## Naming the block. 98 | 99 | To add a translation, you must create a translation key in your translation file - `assets//lang/en_us.json` 100 | 101 | ```json 102 | { 103 | "block.mod_id.condensed_dirt": "Condensed Dirt" 104 | } 105 | ``` 106 | 107 | You can either restart the game or build your mod and press F3 + T to apply changes - and you should see that the block has a name in the creative inventory and other places such as the statistics screen. 108 | 109 | ## Modeling and texturing the block. 110 | 111 | All block textures can be found in the `assets//textures/block` folder - an example texture for the "Condensed Dirt" block is free to use. 112 | 113 |
114 | 115 | ![](./_assets/first_block_1.png) 116 | 117 | 118 | Download Texture 119 | 120 | 121 |
122 | 123 | To make the texture show up in-game, you must create a block and item model which can be found in the respective locations for the "Condensed Dirt" block: 124 | 125 | - `assets/mod_id/models/block/condensed_dirt.json` 126 | - `assets/mod_id/models/item/condensed_dirt.json` 127 | 128 | The item model is pretty simple, it can just use the block model as a parent - since most block models have support for being rendered in a GUI: 129 | 130 | ```json 131 | { 132 | "parent": "mod_id:block/condensed_dirt" 133 | } 134 | ``` 135 | 136 | The block model however, in our case, must parent the `block/cube_all` model: 137 | 138 | ```jsonc 139 | { 140 | "parent": "block/cube_all", 141 | "textures": { 142 | // A reference to the actual texture. 143 | "all": "mod_id:block/condensed_dirt" 144 | } 145 | } 146 | ``` 147 | 148 | When you load into the game though, you may see that the texture still isn't present - this is because you will need to add a blockstate definition. 149 | 150 | ## Creating the blockstate definition. 151 | 152 | The blockstate definition is used to tell the game what model should be rendered depending on the current state of the block. 153 | 154 | Since the example block does not have a complex blockstate, only one entry is required in the definition which can be found in the `assets/mod_id/blockstates` folder - the name of the file should correspond to the name of the block you used to register your block in your `ModBlocks` class: `condensed_dirt.json` 155 | 156 | ```json 157 | { 158 | "variants": { 159 | "": { "model": "mod_id:block/condensed_dirt" } 160 | } 161 | } 162 | ``` 163 | 164 | Blockstates are really complex, which is why they are addressed in an upcoming page: [Block States](/blocks/blockstates) 165 | 166 | Restarting the game, or reloading via F3 + T to apply changes - you should be able to see the block texture in the inventory and physically in the world: 167 | 168 | ![](./_assets/first_block_4.png) 169 | 170 | ## Adding block drops. 171 | 172 | When breaking the block in survival, you may see that the block does not drop - you might want this functionality, however to make your block drop as an item on break you must implement it's loot table - the loot table file should be placed in the `data/mod_id/loot_tables./_assets/condensed_dirt.json` 173 | 174 | ```json 175 | { 176 | "type": "minecraft:block", 177 | "pools": [ 178 | { 179 | "rolls": 1, 180 | "entries": [ 181 | { 182 | "type": "minecraft:item", 183 | "name": "tutorial:example_block" 184 | } 185 | ], 186 | "conditions": [ 187 | { 188 | "condition": "minecraft:survives_explosion" 189 | } 190 | ] 191 | } 192 | ] 193 | } 194 | ``` 195 | 196 | This will be explained more in-depth in a future page. 197 | 198 | ## Setting the recommended harvesting tool and level. 199 | 200 | Your block will be really slow to break, regardless of what tool is used - to make it quicker, you must place your block in the suitable block tag for the harvesting tool, and what level of tool should be used: 201 | 202 | ### Harvesting Tool 203 | 204 | All the tool tags should be placed in the `data/minecraft/tags./_assets/mineable/` folder - where the name of the file depends on the type of tool used, one of the following: 205 | 206 | - `hoe.json` 207 | - `axe.json` 208 | - `pickaxe.json` 209 | - `shovel.json` 210 | 211 | The contents of the file are quite simple - it is a list of items that should be added to the tag. 212 | 213 | This example adds the "Condensed Dirt" block to the `shovel` tag. 214 | 215 | ```json 216 | { 217 | "replace": false, 218 | "values": [ 219 | "mod_id:condensed_dirt" 220 | ] 221 | } 222 | ``` 223 | 224 | ### Mining Level 225 | 226 | Similarly, the mining level tag can be found in the same folder, and respects the following format: 227 | 228 | - `needs_stone_tool.json` - A minimum level of stone tools 229 | - `needs_iron_tool.json` - A minimum level of iron tools 230 | - `needs_diamond_tool.json` - A minimum level of diamond tools. 231 | 232 | The file has the same format as the harvesting tool file - a list of items to be added to the tag. -------------------------------------------------------------------------------- /components/ColorSwatch.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contributing 3 | --- 4 | 5 | # Contributing 6 | 7 | If you wish to contribute to the wiki, you are more than welcome! 8 | 9 | ## Content Guidelines 10 | 11 | 1. **Future-proof Content**: All contributed content should be easily updatable to accommodate future versions of Minecraft. Avoid using version-specific features or APIs that might become outdated quickly. 12 | 13 | 2. **Clear and Cohesive Writing**: Ensure that the content is easy to understand and follows a logical flow. While it doesn't have to be strictly step-by-step, it should present information in a coherent manner, allowing readers to follow along smoothly. 14 | 15 | 3. **Latest Minecraft Version**: All content should be based on the latest version of Minecraft. This helps maintain relevance and provides accurate information to users. 16 | 17 | 4. **Fabric API Usage**: If your contribution relies on the Fabric API, explicitly mention it in your content. You can do this either briefly, like "This page utilizes Fabric API's Y module," or directly state, "This page uses Fabric API." 18 | 19 | ## Contributing Process 20 | 21 | 1. **Fork the Repository**: To contribute, start by forking the Fabric Modding Wiki repository on GitHub. This will create a copy of the project in your GitHub account. 22 | 23 | 2. **Make Changes**: Create a new branch in your forked repository and make the necessary changes to the content. Ensure that your changes adhere to the contribution guidelines mentioned above. 24 | 25 | 3. **Test Your Changes**: If your contribution involves code snippets, test it thoroughly to confirm that it works as intended in the latest version of Minecraft. 26 | 27 | 4. **Create a Pull Request (PR)**: Once you are satisfied with your changes, open a Pull Request from your branch to the main repository's `master` branch. Provide a clear and concise description of your changes in the PR to help reviewers understand your contribution better. 28 | 29 | 5. **Review Process**: Your PR will be reviewed by the community members or the maintainers of the Fabric Modding Wiki. Be prepared to make further changes based on their feedback or suggestions. 30 | 31 | 6. **Merge and Publication**: If your PR meets the contribution guidelines and aligns with the objectives of the Fabric Modding Wiki, it will be approved and merged into the main repository. 32 | 33 | If you have any questions or need further assistance, don't hesitate to reach out to us on GitHub or via Discord. 34 | 35 | ## Markdown Extension Examples 36 | 37 | This section demonstrates some of the built-in markdown extensions provided by VitePress. 38 | 39 | ### Syntax Highlighting 40 | 41 | VitePress provides Syntax Highlighting powered by [Shikiji](https://github.com/antfu/shikiji), with additional features like line-highlighting: 42 | 43 | **Input** 44 | 45 | ````md 46 | ```js{4} 47 | export default { 48 | data () { 49 | return { 50 | msg: 'Highlighted!' 51 | } 52 | } 53 | } 54 | ``` 55 | ```` 56 | 57 | **Output** 58 | 59 | ```js{4} 60 | export default { 61 | data () { 62 | return { 63 | msg: 'Highlighted!' 64 | } 65 | } 66 | } 67 | ``` 68 | 69 | ### Custom Containers 70 | 71 | **Input** 72 | 73 | ```md 74 | ::: info 75 | This is an info box. 76 | ::: 77 | 78 | ::: tip 79 | This is a tip. 80 | ::: 81 | 82 | ::: warning 83 | This is a warning. 84 | ::: 85 | 86 | ::: danger 87 | This is a dangerous warning. 88 | ::: 89 | 90 | ::: details 91 | This is a details block. 92 | ::: 93 | ``` 94 | 95 | **Output** 96 | 97 | ::: info 98 | This is an info box. 99 | ::: 100 | 101 | ::: tip 102 | This is a tip. 103 | ::: 104 | 105 | ::: warning 106 | This is a warning. 107 | ::: 108 | 109 | ::: danger 110 | This is a dangerous warning. 111 | ::: 112 | 113 | ::: details 114 | This is a details block. 115 | ::: 116 | 117 | ### More 118 | 119 | Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). -------------------------------------------------------------------------------- /data-generation/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Data Generation Setup 3 | description: This page will show you how to setup your project with Fabric API's data generation API. 4 | --- 5 | 6 | # Data Generation Setup 7 | 8 | Data Generation is used by many mods, and mojang themselves, to quickly create JSON files such as blockstates, translations and other various files that can be found in the `assets//data` folder of your project. 9 | 10 | ## Why should you use Data Generation? 11 | 12 | Although Data Generation is not really quicker for small projects with 1-2 JSON files, when you start expanding your mod and adding more blocks, biomes, dimensions etc. you might find yourself overwhelmed with JSON files. 13 | 14 | Data Generation ensures those JSON files are kept in the correct format between game versions, and is easier to edit. It also allows you to create complex algorithms that would have been impossible to do by hand, eg: generating 100s of variants of a model due to different combinations of materials used to craft a block. 15 | 16 | ## What are Data Providers? 17 | 18 | Data Providers are where the actual data is consumed and converted into JSON, some examples include: 19 | 20 | - `FabricTranslationProvider` 21 | - `FabricAdvancementProvider` 22 | - `FabricCodecProvider` 23 | 24 | A full list of providers that Fabric API provides *hah pun!* can be found [here on their GitHub repository.](https://github.com/FabricMC/fabric/tree/1.20.1/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider) 25 | 26 | Vanilla also has it's own providers, from the `ModelProvider` to the bare-bones `DataProvider` which can be used to produce custom JSON files. 27 | 28 | ## Creating the Loom run configuration 29 | 30 | Loom doesn't create the data generation run configuration by default, so you'll need to create it in your `build.gradle` like so: 31 | 32 | ::: info 33 | Make sure to replace `` with your mod's ID! 34 | ::: 35 | 36 | ```groovy 37 | // Add the datagen output to the jar resources. 38 | sourceSets { 39 | main { 40 | resources { 41 | srcDirs += [ 42 | 'src/main/generated' 43 | ] 44 | } 45 | } 46 | } 47 | 48 | // Create the datagen runs. 49 | loom { 50 | // ... 51 | runs { 52 | datagenClient { 53 | client() 54 | name "Data Generation Client" 55 | vmArg "-Dfabric-api.datagen" 56 | vmArg "-Dfabric-api.datagen.output-dir=${file("src/main/generated")}" 57 | vmArg "-Dfabric-api.datagen.modid=" 58 | 59 | ideConfigGenerated = true 60 | runDir "build/datagen" 61 | } 62 | } 63 | // ... 64 | } 65 | ``` 66 | 67 | ## Creating the Entrypoint 68 | 69 | You'll need to create a class that implements the `DataGeneratorEntrypoint` interface, this is an entrypoint, similar to the `ModInitializer` and `ClientModInitializer` entrypoints. 70 | 71 | It's recommended you keep this in a sub-package called `datagen` to stay organized. 72 | 73 | ```java 74 | public class MyModDatagen implements DataGeneratorEntrypoint { 75 | @Override 76 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 77 | 78 | } 79 | } 80 | ``` 81 | 82 | As with all entrypoints, you'll need to register it in your `fabric.mod.json` file. 83 | 84 | ```json 85 | { 86 | // ... 87 | "entrypoints": { 88 | "fabric-datagen": [ 89 | "com.examplemod.datagen.MyModDatagen" 90 | ], 91 | }, 92 | // ... 93 | } 94 | ``` 95 | 96 | ## Testing 97 | 98 | Before continuing, it is really helpful to quickly test the Data Generation entrypoint without any providers registered, this can prevent you scratching your head in the future when you don't realize you have messed up the configuration. 99 | 100 | To check if you have implemented Data Generation correctly into your project, run the `runDatagenClient` command, after it has completed, the `src/main/generated` folder should appear. 101 | 102 | ## Registering Data Providers 103 | 104 | To register **any** provider, you must first create a `Pack` instance using the `fabricDataGenerator.createPack();` method in your entrypoint: 105 | 106 | ```java 107 | @Override 108 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 109 | final FabricDataGenerator.Pack pack = dataGenerator.createPack(); 110 | 111 | // ... 112 | } 113 | ``` 114 | 115 | ::: info 116 | You should check the sidebar for a full list of providers, the `MyModSoundProvider` does not exist, and is used here for example purposes. 117 | ::: 118 | 119 | This pack can be used to register (add) providers, any providers added to the pack will be executed during data generation. You can then call the `addProvider` method to add providers. 120 | 121 | ```java 122 | final FabricDataGenerator.Pack pack = dataGenerator.createPack(); 123 | 124 | // MyModSoundProvider will be executed on data generation, and should produce a lovely sound.json file! 125 | pack.addProvider(new MyModSoundProvider(fabricDataGenerator)); 126 | ``` -------------------------------------------------------------------------------- /data-generation/loot-tables.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Loot Table Provider 3 | description: Learn how to generate loot table JSON using data generation. 4 | --- 5 | 6 | # Loot Table Provider 7 | 8 | The loot table provider is super convenient if you forget to create loot tables for your modded blocks! It opens many options when generating loot tables: 9 | 10 | - If your mod doesn't have any blocks with non-special loot tables, you can iterate all your blocks and quickly generate generic loot tables. 11 | - You can create complex loot tables that would take too long to create using JSON. 12 | 13 | ## Using The Provider 14 | 15 | First, you must create a class that extends `FabricBlockLootTableProvider`: 16 | 17 | ```java 18 | public class MyBlockLootTableProvider extends FabricBlockLootTableProvider { 19 | private MyBlockLootTableProvider(FabricDataOutput output) { 20 | super(output); 21 | } 22 | 23 | @Override 24 | public void generate() { 25 | // ... 26 | } 27 | } 28 | ``` 29 | 30 | Don't forget to register your provider in your mod entrypoint: 31 | 32 | ```java 33 | @Override 34 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 35 | final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack(); 36 | 37 | // ... 38 | 39 | pack.addProvider(MyBlockLootTableProvider::new); 40 | } 41 | ``` 42 | 43 | ## Simple Loot Tables 44 | 45 | If you want to generate a loot table that simply drops blocks when a block is mined/blew up you can use the `addDrop` and `drops` methods in the `generate` method of your provider. 46 | 47 | It is assumed you have a block item automatically generated, if not, you can pass an alternative item into the `drops` method. 48 | 49 | ::: code-group 50 | 51 | ```java [Provider] 52 | public static final Block CONDENSED_DIRT = register("mod_id:condensed_dirt", ...); 53 | 54 | @Override 55 | public void generate() { 56 | addDrop(CONDENSED_DIRT, drops(CONDENSED_DIRT.asItem())) 57 | } 58 | ``` 59 | 60 | ```jsonc [Output JSON] 61 | // generated/data/mod_id/loot_tables/blocks/condensed_dirt.json 62 | { 63 | "type": "minecraft:block", 64 | "pools": [ 65 | { 66 | "bonus_rolls": 0.0, 67 | "conditions": [ 68 | { 69 | "condition": "minecraft:survives_explosion" 70 | } 71 | ], 72 | "entries": [ 73 | { 74 | "type": "minecraft:item", 75 | "name": "mod_id:condensed_dirt" 76 | } 77 | ], 78 | "rolls": 1.0 79 | } 80 | ] 81 | } 82 | ``` 83 | 84 | ::: 85 | 86 | Here is an example if you don't have a block item registered for your block (or you dont want the block item to drop) 87 | 88 | ::: code-group 89 | 90 | ```java [Provider] 91 | public static final PillarBlock CONDENSED_OAK_LOG = register("mod_id:condensed_oak_log", ...); 92 | public static final Item POOP = register("mod_id:poop", ...); 93 | 94 | @Override 95 | public void generate() { 96 | addDrop(CONDENSED_OAK_LOG, drops(POOP)); 97 | } 98 | 99 | ``` 100 | 101 | ```jsonc [Output JSON] 102 | // generated/data/mod_id/loot_tables/blocks/condensed_oak_log.json 103 | { 104 | "type": "minecraft:block", 105 | "pools": [ 106 | { 107 | "bonus_rolls": 0.0, 108 | "conditions": [ 109 | { 110 | "condition": "minecraft:survives_explosion" 111 | } 112 | ], 113 | "entries": [ 114 | { 115 | "type": "minecraft:item", 116 | "name": "mod_id:poop" 117 | } 118 | ], 119 | "rolls": 1.0 120 | } 121 | ] 122 | } 123 | ``` 124 | 125 | ::: 126 | 127 | ## Complex Loot Tables 128 | 129 | If you want to add some randomness or bias to your loot tables, you can pass an instance of the `LootTable.Builder` class instead. 130 | 131 | You can use common premade builders via the `BlockLootTableGenerator` class - this is a vanilla class and contains methods for silk touch, fortune, ect. 132 | 133 | This example drops a diamond if the player breaks the block with an item with the silk touch enchantment, but drops the normal condensed dirt block if the item does not have the enchantment. 134 | 135 | ::: code-group 136 | 137 | ```java [Provider] 138 | public static final Block CONDENSED_DIRT = register("mod_id:condensed_dirt", ...); 139 | 140 | @Override 141 | public void generate() { 142 | // Gives a positive result if the item has silk touch on it. 143 | LootCondition.Builder HAS_SILK_TOUCH = MatchToolLootCondition.builder(ItemPredicate.Builder.create() 144 | .enchantment(new EnchantmentPredicate(Enchantments.SILK_TOUCH, NumberRange.IntRange.ANY))); 145 | 146 | LootTable.Builder builder = LootTable.builder().pool( 147 | LootPool.builder() 148 | // If silk touch is used, drop a diamond. 149 | .with(ItemEntry.builder(Items.DIAMOND) 150 | .conditionally(HAS_SILK_TOUCH) 151 | .apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(1)))) 152 | 153 | // If silk touch is not used (invert of with silk touch), drop the normal block. 154 | .with(ItemEntry.builder(ModBlocks.CONDENSED_DIRT.asItem()).conditionally(HAS_SILK_TOUCH.invert())) 155 | ); 156 | 157 | addDrop(ModBlocks.CONDENSED_DIRT, builder); 158 | } 159 | ``` 160 | 161 | ```jsonc [Output JSON] 162 | { 163 | "type": "minecraft:block", 164 | "pools": [ 165 | { 166 | "bonus_rolls": 0.0, 167 | "entries": [ 168 | { 169 | "type": "minecraft:item", 170 | "conditions": [ 171 | { 172 | "condition": "minecraft:match_tool", 173 | "predicate": { 174 | "enchantments": [ 175 | { 176 | "enchantment": "minecraft:silk_touch" 177 | } 178 | ] 179 | } 180 | } 181 | ], 182 | "functions": [ 183 | { 184 | "add": false, 185 | "count": 1.0, 186 | "function": "minecraft:set_count" 187 | } 188 | ], 189 | "name": "minecraft:diamond" 190 | }, 191 | { 192 | "type": "minecraft:item", 193 | "conditions": [ 194 | { 195 | "condition": "minecraft:inverted", 196 | "term": { 197 | "condition": "minecraft:match_tool", 198 | "predicate": { 199 | "enchantments": [ 200 | { 201 | "enchantment": "minecraft:silk_touch" 202 | } 203 | ] 204 | } 205 | } 206 | } 207 | ], 208 | "name": "mod_id:condensed_dirt" 209 | } 210 | ], 211 | "rolls": 1.0 212 | } 213 | ] 214 | } 215 | ``` 216 | 217 | ::: 218 | -------------------------------------------------------------------------------- /data-generation/tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tag Provider 3 | description: Learn how to utilize the FabricTagProvider class to automatically populate tags with blocks, items, and other content. 4 | --- 5 | 6 | # Tag Provider 7 | 8 | The `FabricTagProvider` class allows you to automatically add content to existing or new tags. 9 | 10 | This is useful as it removes the need for you to create the nessecary tag files yourself, alongside any directories - you would also have to manually write the identifiers of all the content you want to add to the tag. 11 | 12 | With the tag provider, you can just pass an instance of the object you want to add to the tag. 13 | 14 | ## Using The Provider 15 | 16 | This example will use the `FabricTagProvider.BlockTagProvider` class to generate block tags. 17 | 18 | There are other types available to use as well: 19 | 20 | - `EnchantmentTagProvider` 21 | - `EntityTypeTagProvider` 22 | - `FluidTagProvider` 23 | - `GameEventTagProvider` 24 | - `ItemTagProvider` 25 | 26 | You should create a new class that extends the TagProvider that you want to use: 27 | 28 | ```java 29 | public class MyBlockTagProvider extends FabricTagProvider.BlockTagProvider { 30 | public MyBlockTagProvider(FabricDataOutput output, CompletableFuture registriesFuture) { 31 | super(output, registriesFuture); 32 | } 33 | 34 | @Override 35 | protected void configure(RegistryWrapper.WrapperLookup arg) { 36 | // ... 37 | } 38 | } 39 | ``` 40 | 41 | Make sure to register the class in your entrypoint! 42 | 43 | ```java 44 | @Override 45 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 46 | final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack(); 47 | 48 | // ... 49 | 50 | pack.addProvider(MyBlockTagProvider::new); 51 | } 52 | ``` 53 | 54 | ## Adding/Creating Tags 55 | 56 | To create a new tag, you need to create a reference to the tag in the form of a `TagKey`: 57 | 58 | ```java 59 | public static final TagKey AWESOME_BLOCKS = TagKey.of( 60 | RegistryKeys.BLOCK, 61 | new Identifier("mod_id:awesome_blocks") 62 | ); 63 | ``` 64 | 65 | Once you've created the TagKey instance, you can call the `getOrCreateTagBuilder()` method in the `configure` method of your tag provider, passing the instance as the argument or you can use an already existing tag instance instead. 66 | 67 | ::: code-group 68 | 69 | ```java [Provider] 70 | @Override 71 | protected void configure(RegistryWrapper.WrapperLookup arg) { 72 | getOrCreateTagBuilder(AWESOME_BLOCKS) 73 | .add(Blocks.DIAMOND_BLOCK, ModBlocks.CONDENSED_OAK_LOG) 74 | .addOptionalTag(BlockTags.DIRT) 75 | // An optional tag value does not cause the tag to fail when loading if the 76 | // ID in question doesn't exist in the registry. 77 | .addOptional(new Identifier("create:cogwheel")) 78 | // You can add existing tags to your tag, ignoring whether its unloaded or invalid. 79 | // It's recommened to use addOptionalTag instead of this. 80 | .forceAddTag(BlockTags.BUTTONS); 81 | } 82 | ``` 83 | 84 | ```jsonc [Output JSON] 85 | // Found at generated/data/mod_id/tags/blocks/awesome_blocks.json 86 | { 87 | "replace": false, 88 | "values": [ 89 | "minecraft:diamond_block", 90 | "mod_id:condensed_oak_log", 91 | { 92 | "id": "#minecraft:dirt", 93 | "required": false 94 | }, 95 | { 96 | "id": "create:cogwheel", 97 | "required": false 98 | }, 99 | "#minecraft:buttons" 100 | ] 101 | } 102 | ``` 103 | 104 | ::: -------------------------------------------------------------------------------- /data-generation/translations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Translation Provider 3 | description: Learn how to utilize the FabricLanguageProvider class to generate language files. 4 | --- 5 | 6 | # Translation Provider 7 | 8 | The `FabricLanguageProvider` class allows you to generate translations by passing blocks, entities, enchantments and much more. 9 | 10 | ## Why generate translations? 11 | 12 | Translation generation useful for mods with dynamically generated blocks, items or entities. It is also useful when the language file is too large to maintain. 13 | 14 | Programmatically generating translations is usually the go-to in their case. 15 | 16 | ### Programmatic Translation Example 17 | 18 | You can often convert any `Identifier` into a human readable string programmatically. This means that whenever you register something to a registry where it's translation is visible in-game, you can likely convert it's registry ID into an actual string. 19 | 20 | If `minecraft:orange_flying_boat` is passed into this method, it undergoes the following transformation: 21 | 22 | - `minecraft:orange_flying_boat` 23 | - `orange_flying_boat` 24 | - `orange flying boat` 25 | - `Orange Flying Boat` 26 | 27 | ```java 28 | public static String generateHumanReadable(Identifier identifier) { 29 | // Remove the namespace, it's irrelevant. 30 | String identifier_path = identifier.getPath(); 31 | 32 | // Replace all '_' with spaces. 33 | String lowercase = identifier_path.replace("_", " "); 34 | 35 | // Capitalize all words in the string. 36 | String capitalized = WordUtils.capitalize(lowercase); 37 | 38 | return capitalized; 39 | } 40 | ``` 41 | 42 | Many mods use this already in their English language provider classes. Feel free to use it if it is of any interest to you. 43 | 44 | ## Using the Provider 45 | 46 | ::: warning 47 | When creating language providers, make sure that the language file you are generating doesn't already exist in your resources folder!
48 | If it does, you will need to rename the file and merge it via the `TranslationBuilder` class. 49 | ::: 50 | 51 | To use the provider, create a new class that extends the `FabricLanguageProvider` class. In this example, we'll create an English language provider: 52 | 53 | ```java 54 | public class EnglishTranslationProvider extends FabricLanguageProvider { 55 | protected EnglishTranslationProvider(FabricDataOutput dataOutput) { 56 | // Specifying the language code is optional in this case! 57 | // 'en_us' is always the default. 58 | super(dataOutput, "en_us"); 59 | } 60 | 61 | @Override 62 | public void generateTranslations(TranslationBuilder translationBuilder) { 63 | // ... 64 | } 65 | } 66 | ``` 67 | 68 | Make sure to register the class in your entrypoint! 69 | 70 | ```java 71 | @Override 72 | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { 73 | final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack(); 74 | 75 | // ... 76 | 77 | pack.addProvider(EnglishTranslationProvider::new); 78 | } 79 | ``` 80 | 81 | ## Generating Translations 82 | 83 | The `TranslationBuilder` class can automatically create translation keys from the following classes: 84 | 85 | - `Item` 86 | - `Block` 87 | - `ItemGroup` 88 | - `EntityType` 89 | - `Enchantment` 90 | - `EntityAttribute` 91 | - `StatType` 92 | - `StatusEffect` 93 | - `Identifier` 94 | 95 | The provider will automatically sort the translation keys in alphabetical order in the output JSON file. 96 | 97 | ```java 98 | public static final Block PRISMARINE_LAMP = register("mod_id:prismarine_lamp", ...); 99 | 100 | @Override 101 | public void generateTranslations(TranslationBuilder translationBuilder) { 102 | // An example for the Prismarine Lamp block from the blockstates guide. 103 | translationBuilder.add(PRISMARINE_LAMP, "Prismarine Lamp"); 104 | } 105 | ``` 106 | 107 | It can also accept existing language files - this is particularly useful if you wish to merge your existing language files with the final datagen language files: 108 | 109 | ::: code-group 110 | 111 | ```java [Provider] 112 | public static final Block PRISMARINE_LAMP = register("mod_id:prismarine_lamp", ...); 113 | 114 | @Override 115 | public void generateTranslations(TranslationBuilder translationBuilder) { 116 | translationBuilder.add(PRISMARINE_LAMP, "Prismarine Lamp"); 117 | 118 | // Because it's reading from a file, it's recommended you surround it in a try/catch statement. 119 | try { 120 | Optional path = dataOutput.getModContainer().findPath("assets/mod_id/lang/en_us.unmerged.json"); 121 | translationBuilder.add(path.get()); 122 | } catch (Exception e) { 123 | LOGGER.info("Failed to merge language file: " + e); 124 | } 125 | } 126 | ``` 127 | 128 | ```jsonc [en_us.unmerged.json] 129 | // assets/mod_id/lang/en_us.unmerged.json 130 | { 131 | "item.mod_id.poop": "Poop", 132 | "block.mod_id.condensed_dirt": "Condensed Dirt", 133 | "itemGroup.mod_id.item_group": "Fabric Community Wiki Items" 134 | } 135 | ``` 136 | 137 | ```jsonc [Output JSON] 138 | // generated/assets/mod_id/lang/en_us.json 139 | { 140 | "block.mod_id.condensed_dirt": "Condensed Dirt", 141 | "block.mod_id.prismarine_lamp": "Prismarine Lamp", 142 | "item.mod_id.poop": "Poop", 143 | "itemGroup.my_mod.item_group": "Fabric Community Wiki Items" 144 | } 145 | ``` 146 | 147 | ::: 148 | 149 | -------------------------------------------------------------------------------- /events/_assets/creating_events_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/events/_assets/creating_events_0.png -------------------------------------------------------------------------------- /events/creation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating Fabric API Events 3 | description: Learn how to create your own events which allow compatability with other mods. 4 | prev: 5 | text: "Using Fabric API Events" 6 | link: "/events/" 7 | --- 8 | 9 | # Creating Fabric API Events 10 | 11 | Fabric API exposes it's event classes so you can use them in your own mod. 12 | 13 | This is useful if you want to allow other mods to add compatability with yours - or you want to create a library of events that are specific to your usage. 14 | 15 | ## Creating the functional interface. 16 | 17 | A functional interface in Java is an interface that contains only a single abstract (unimplemented) method. 18 | 19 | You'll use this functional interface to register event handlers and invoke the event. 20 | 21 | In this example, we'll create an event that is called when the client player dies. 22 | 23 | ```java 24 | @FunctionalInterface 25 | public interface PlayerDiedCallback { 26 | void invoke(PlayerEntity player, Text deathMessage); 27 | } 28 | ``` 29 | 30 | ## Creating the event instance. 31 | 32 | Next, you can use the `EventFactory` class provided by Fabric API to create an event that uses the `PlayerDiedCallback` class. 33 | 34 | The `EventFactory.createArrayBacked` takes in a class reference to a functional interface, and a consumer which takes in all the registered listeners and the current values that are passed when the event is invoked. 35 | 36 | We'll store the returned event in a field called `EVENT` 37 | 38 | ```java 39 | public interface PlayerDiedCallback { 40 | Event EVENT = EventFactory.createArrayBacked(PlayerDiedCallback.class, 41 | (listeners) -> (player, deathMessage) -> { 42 | for (PlayerDiedCallback listener : listeners) { 43 | // Invoke all event listeners with the provided player and death message. 44 | listener.invoke(player, deathMessage); 45 | } 46 | }); 47 | 48 | // ... 49 | } 50 | ``` 51 | 52 | ## Invoking the event via mixins 53 | 54 | We'll hook into the `DeathScreen` class constructor to get the cause of death. We can get the player from the `MinecraftClient` instance. 55 | 56 | ```java 57 | @Mixin(DeathScreen.class) 58 | public class DeathScreenMixin { 59 | @Inject(method = "", at = @At("TAIL"), cancellable = false) 60 | private void initDeathScreen(Text message, boolean isHardcore, CallbackInfo ci) { 61 | // Get the client player. 62 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 63 | 64 | // Invoke the event for all listeners! 65 | PlayerDiedCallback.EVENT.invoker().invoke(player, message); 66 | } 67 | } 68 | ``` 69 | 70 | Remember to register your mixins in the right location! This mixin would be registered in the client section of `mixins.json` 71 | 72 | ## Wrapping It Up 73 | 74 | You can now add listeners to this event - if you wanted to, you could even pass the death screen as a parameter of the callback if you want to be able to edit the screen from inside any event listeners. 75 | 76 | In this example, I send `{Username}... you're an absolute idiot.` into the chat when the event is fired: 77 | 78 | ```java 79 | PlayerDiedCallback.EVENT.register((player, deathMessage) -> { 80 | MinecraftClient client = MinecraftClient.getInstance(); 81 | ChatHud chat = client.inGameHud.getChatHud(); 82 | 83 | chat.addMessage(Text.literal(player.getEntityName() + "... you're an absolute idiot.")); 84 | }); 85 | ``` 86 | 87 | ![](./_assets/creating_events_0.png) -------------------------------------------------------------------------------- /events/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using Fabric API Events 3 | description: Learn how to use Fabric API's event system. 4 | next: 5 | text: "Creating Fabric API Events" 6 | link: "/events/creation" 7 | --- 8 | 9 | # Using Fabric API Events 10 | 11 | Fabric API contains **many** events that you can use instead of creating mixins - if everyone made the same mixin, to do the same task, it would get messy. 12 | 13 | You can simply [search for events](https://github.com/search?q=repo%3AFabricMC%2Ffabric%20Events&type=code) on the Fabric API GitHub repository to find an event that suits your usage. 14 | 15 | In this page, you'll utilize the `AttackEntityCallback` to send sound effects into the chat (POW! BANG! SNAP!) when the player attacks. 16 | 17 | ## Registering a listener. 18 | 19 | Registering listeners are the easy part! Simply use the `register(listener)` method on the event and either pass a method reference or a lambda function. 20 | 21 | ```java 22 | AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { 23 | ... 24 | }); 25 | ``` 26 | 27 | ## Utilizing event data. 28 | 29 | Different events will provide different data - some even ask for data back, such as an integer or boolean. 30 | 31 | In the case of our example, the event requires an `ActionResult`, the javadoc states the following `ActionResult` types can be used: 32 | 33 | | Type | Affect | 34 | | ---------------------- | -------------------------------------------------------------------- | 35 | | `ActionResult.SUCCESS` | Cancels further processing and sends a packet to the server. | 36 | | `ActionResult.PASS` | Falls back to further processing. | 37 | | `ActionResult.FAIL` | Cancels further processing and does not send a packet to the server. | 38 | 39 | ::: info 40 | When `ActionResult.FAIL` is returned, the server will not be informed about the Event, and as a result, the server will not process it. 41 | ::: 42 | 43 | Since we don't actually care why the player is attacking, we'll simply return a pass result. 44 | 45 | ```java 46 | AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { 47 | return ActionResult.PASS; 48 | }); 49 | ``` 50 | 51 | We also need to take note of the name of the player, and the name of the entity they are attacking: 52 | 53 | ```java 54 | var playerName = player.getDisplayName().copy(); 55 | var entityName = entity.getDisplayName().copy(); 56 | ``` 57 | 58 | Finally, we can send the sound effect text into the chat: 59 | 60 | ```java 61 | MinecraftClient client = MinecraftClient.getInstance(); 62 | ChatHud chat = client.inGameHud.getChatHud(); 63 | 64 | chat.addMessage(Text.of("SNAP!!!!")); 65 | chat.addMessage(playerName.append(" attacked ").append(entityName)); 66 | ``` 67 | 68 | Some events may be client-only, or server-only - please be careful when using those events that you're not using server or client specific methods. 69 | 70 | ## Event Phases 71 | 72 | Some events may have different phases - these phases are ran in a certain order depending on their **priority**. 73 | 74 | If you want to run your listener last, you register it to a later phase. If you want to run it first, register it to a earlier phase. 75 | 76 | Different phases might provide different data. For example, the final phase of the resource events do not let you modify the resource pack, because you are too late! 77 | 78 | ## Next Steps 79 | 80 | This page is relatively short, mostly because it isn't a complex topic. 81 | 82 | If you're interested in creating your own events - specifically for mod compatability or for library usage, you should see the [Creating Your Own Events](/events/creation) page. 83 | 84 | - Why don't you make it so an actual sound plays when the player attacks something, instead of putting it in the chat? 85 | - Can you use events to make it so the player drops a random item out of their inventory when they recieve damage? 86 | - Try implement the example without events using mixins, see why it's so annoying and difficult! -------------------------------------------------------------------------------- /getting-started/_assets/access-wideners_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/access-wideners_0.png -------------------------------------------------------------------------------- /getting-started/_assets/analyzing_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/analyzing_01.png -------------------------------------------------------------------------------- /getting-started/_assets/analyzing_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/analyzing_02.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_01.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_02.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_03.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_04.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_05.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_06.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_07.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_08.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_09.png -------------------------------------------------------------------------------- /getting-started/_assets/basic_problem_solving_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/basic_problem_solving_10.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_1.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_10.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_2.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_3.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_4.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_5.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_6.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_7.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_8.png -------------------------------------------------------------------------------- /getting-started/_assets/clients-and-servers_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/clients-and-servers_9.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_01.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_02.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_03.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_04.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_05.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_06.png -------------------------------------------------------------------------------- /getting-started/_assets/comments_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/comments_07.png -------------------------------------------------------------------------------- /getting-started/_assets/creating-a-project_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/creating-a-project_0.png -------------------------------------------------------------------------------- /getting-started/_assets/launching-the-game_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/launching-the-game_0.png -------------------------------------------------------------------------------- /getting-started/_assets/launching-the-game_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/launching-the-game_1.png -------------------------------------------------------------------------------- /getting-started/_assets/launching-the-game_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/launching-the-game_2.png -------------------------------------------------------------------------------- /getting-started/_assets/launching-the-game_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/launching-the-game_3.png -------------------------------------------------------------------------------- /getting-started/_assets/launching-the-game_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/launching-the-game_4.png -------------------------------------------------------------------------------- /getting-started/_assets/refactoring_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/refactoring_01.png -------------------------------------------------------------------------------- /getting-started/_assets/search-and-replace_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/search-and-replace_01.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_01.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_02.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_03.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_04.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_05.png -------------------------------------------------------------------------------- /getting-started/_assets/traversing_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/traversing_06.png -------------------------------------------------------------------------------- /getting-started/_assets/util_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/util_01.png -------------------------------------------------------------------------------- /getting-started/_assets/util_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/getting-started/_assets/util_02.png -------------------------------------------------------------------------------- /getting-started/access-wideners.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Access Wideners 3 | description: Learn how to access parts of Minecraft's code you're not meant to. 4 | order: 5 5 | --- 6 | 7 | # Access Wideners 8 | 9 | Access wideners are used to remove protections from private, protected or final fields so you can access them. 10 | 11 | They can act as an alternative to the `@Accessor` mixin annotation. 12 | 13 | ## Creating your Access Widener 14 | 15 | Your mod can only have one access widener file - create one in your `src/main/resources` folder - it should have the `.accesswidener` extension. 16 | 17 | To load the access widener, add the following property to your `fabric.mod.json` file: 18 | 19 | ```json 20 | "accessWidener" : "file-name-here.accesswidener" 21 | ``` 22 | 23 | You will also need to configure Fabric Loom to load the access widener - or your mod will not compile if you use anything that has been modified. 24 | 25 | ```gradle 26 | loom { 27 | accessWidenerPath = file("src/main/resources/file-name-here.accesswidener") 28 | } 29 | ``` 30 | 31 | ## Syntax 32 | 33 | ::: info 34 | **Notice For Minecraft Development IntelliJ Plugin Users** 35 | 36 | As of version `1.5.22` you can simply right click any field, method or class and click the `Copy AW Entry` button in the dropdown - you can paste the copied entry into your access widener file. 37 | ::: 38 | 39 | The access widener file syntax is pretty simple to understand. 40 | 41 | ### Access Widener Declaration 42 | 43 | At the top of the file is the access widener declaration - this must always exist as it tells Fabric Loader how to parse the access widener entries. 44 | 45 | The most common declaration is `accessWidener v1 named` 46 | The declaration format is as follows: 47 | 48 | ``` 49 | accessWidener {version} {mappings namespace} 50 | ``` 51 | 52 | Mappings type refers to one of the following: 53 | 54 | - `named` - Mappings are named, eg: `TitleScreen` 55 | - `intermediary` - Mappings are not named, eg: `class_2920` 56 | 57 | ::: warning 58 | The namespace is usually always `named` for normal mods. 59 | ::: 60 | 61 | ### Comments 62 | 63 | Comments are supported, the line must start with a hashtag: 64 | 65 | ``` 66 | # This is a comment. 67 | ``` 68 | 69 | ### Class Access 70 | 71 | To widen access to a class, the following format must be used: 72 | 73 | ``` 74 | {access type} class {class name} 75 | ``` 76 | 77 | Only two access types can be used on class entries: 78 | 79 | - `accessible` - Used when you want to access the class from another class. 80 | + The class itself becomes public. 81 | + All methods in the class are made public - if the method is private, the method is made final. 82 | + All fields in the class become public. 83 | - `extendable` - Used when you want to extend the class or override a method. 84 | + The class itself becomes public and final is removed if it exists on the class. 85 | + All methods are made protected and final is removed if it exists on the method. 86 | 87 | ``` 88 | # This is an example of a class entry. 89 | accessible class net/minecraft/item/FoodComponent 90 | ``` 91 | 92 | ### Method Access 93 | 94 | Similarly, to widen access to a method, the following format must be used: 95 | 96 | ``` 97 | {access type} method {class name} {method name} {method descriptor} 98 | ``` 99 | 100 | Only two access types can be used on method entries: 101 | 102 | - `accessible` 103 | - `extendable` 104 | 105 | More information on method descriptors [can be found here](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3) - usually you can use [Linkie](https://linkie.shedaniel.me/mappings) or the IntelliJ Minecraft Development plugin to automatically generate it for you. 106 | 107 | ``` 108 | # This is an example of a method entry. 109 | # FoodComponent.getHunger() returns integer 110 | accessible method net/minecraft/item/FoodComponent getHunger ()I 111 | ``` 112 | 113 | ### Field Access 114 | 115 | Finally, to widen access to a field, the following format must be used: 116 | 117 | ``` 118 | {access type} field {class name} {field name} {field descriptor} 119 | ``` 120 | 121 | Only two access types can be used on field entries: 122 | 123 | - `accessible` 124 | - `mutable` - Removes final from the field. 125 | 126 | If you want to make a field non-final and accessible, you must create two seperate entries: 127 | 128 | ``` 129 | # This is an example of a field entry - the field is private and final. 130 | # MinecraftClient.soundManager 131 | accessible field net/minecraft/client/MinecraftClient soundManager Lnet/minecraft/client/sound/SoundManager; 132 | mutable field net/minecraft/client/MinecraftClient soundManager Lnet/minecraft/client/sound/SoundManager; 133 | ``` 134 | 135 | More information on field descriptors [can be found here.](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2) 136 | 137 | ## Linkie 138 | 139 | Linkie is an underrated tool that allows you to browse the classes, fields and methods of all the major mappings - it also lets you generate access wideners and mixin targets: 140 | 141 | https://linkie.shedaniel.dev/mappings 142 | 143 | ![](./_assets/access-wideners_0.png) -------------------------------------------------------------------------------- /getting-started/basic-problem-solving.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic Problem Solving 3 | description: Learn how to solve simple issues and mistakes on your own. 4 | order: 6 5 | --- 6 | 7 | # Basic Problem Solving 8 | 9 | Issues, mistakes and bugs can happen even to the best programmer. You can develop a basic set of steps to potentially identify and resolve those issues without the help of others. Problems solved on your own can teach you many things and also feel rewarding. However, if you are stuck without being able to fix the problems by yourself, there is no shame in asking others for help. 10 | 11 | This page focuses mostly on functionality which is provided by IntelliJ (and many other IDEs) such as Logging and how to use the Debugger. 12 | 13 | ## Console and LOGGER 14 | 15 | The most basic but also fastest tool to identify problems is the console. Values can be printed there at "run-time" which can inform the developer about the current state of the code and makes it easy to analyze changes and potential mistakes. 16 | 17 | In the `ModInitializer` implementing entry point class of the mod, a `LOGGER` is used by default, to print the desired output to the console. 18 | 19 | ```java 20 | public class MyMod implements ModInitializer { 21 | public static final String MOD_ID = "mod_id"; 22 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 23 | 24 | @Override 25 | public void onInitialize() { 26 | // ... 27 | } 28 | } 29 | ``` 30 | 31 | Whenever you need to know a value for something at a specific point in the code, use this `LOGGER` by passing the `String` value to its `info(...)` method. 32 | 33 | ```java 34 | public class TestItem extends Item { 35 | 36 | public TestItem(Settings settings) { 37 | super(settings); 38 | } 39 | 40 | @Override 41 | public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { 42 | // Values are used in a String to provide more information 43 | TestMod.LOGGER.info("Is Client World: " + user.getWorld().isClient() 44 | + " | Health: " + entity.getHealth() + " / " + entity.getMaxHealth() 45 | + " | The item was used with the " + hand.name() 46 | ); 47 | 48 | return ActionResult.SUCCESS; 49 | } 50 | } 51 | ``` 52 | 53 | When, in this case, the `TestItem` is used on an Entity it will provide the values at this current state of the mod in the console of the currently used instance. If your `Run` window for the console is missing, you can open a new one in the toolbar at the top (`View > Tool Windows > Run`), if you are working with IntelliJ. 54 | 55 | ![LOGGER output](./_assets/basic_problem_solving_01.png) 56 | 57 | ### Keeping the console clean 58 | 59 | Keep in mind that this will also be printed if the mod is used in any other environment. This is completely optional, but I like to create a custom `LOGGER` method and use that, instead of the `LOGGER` itself to prevent printing data, which is only needed in a development environment. 60 | 61 | ```java 62 | public class MyMod implements ModInitializer { 63 | public static final String MOD_ID = "mod_id"; 64 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 65 | 66 | @Override 67 | public void onInitialize() { 68 | // ... 69 | } 70 | 71 | public static void devLogger(String loggerInput) { 72 | // prevent usage if the Instance is not run in a development environment 73 | if (!FabricLoader.getInstance().isDevelopmentEnvironment()) return; 74 | 75 | // customize that message however you want... 76 | TestMod.LOGGER.info("DEV - [" + loggerInput + "]"); 77 | } 78 | } 79 | ``` 80 | 81 | Otherwise clean up the `LOGGER` usage as much as you can, to prevent causing a headache for Modpack developers and curious users. 82 | 83 | ### Locating the issues 84 | 85 | The Logger prints the `MOD-ID` in front of the line. The Search function CTRL / CMD + F can be used to highlight it, making it easier to spot the problem. Missing assets, such as the Purple & Black placeholder when a texture is missing, also print their errors in the console and mention their missing files. You can also use the Search function here and look for the asset name in question. 86 | 87 | 88 | 89 | ![missing assets](./_assets/basic_problem_solving_02.png) 90 | 91 | ## Debugging 92 | 93 | ### Breakpoint 94 | 95 | A more "sophisticated" way of debugging is the usage of Breakpoints in an IDE. As their name suggests, they are used to halt the executed code at specific locations and make it possible to inspect and modify the state of the software with a variety of tools. 96 | 97 | When working with Breakpoints, the Instance needs to be executed using the `Debug` option instead of the `Run` option. 98 | 99 | ![Debugging](./_assets/basic_problem_solving_03.png) 100 | 101 | Let's use a custom Item as an example again. The Item is supposed to increase its efficiency level, whenever it has been used. But whenever this happens all the remaining enchantments get removed. How can this issue be resolved? 102 | 103 | ```java 104 | // problematic example code: 105 | 106 | public class TestItem extends Item { 107 | 108 | public TestItem(Settings settings) { 109 | super(settings); 110 | } 111 | 112 | @Override 113 | public ActionResult useOnBlock(ItemUsageContext context) { 114 | ItemStack itemStack = context.getStack(); 115 | World world = context.getWorld(); 116 | BlockPos pos = context.getBlockPos(); 117 | 118 | if (world.isClient()) return super.useOnBlock(context); 119 | 120 | int levelOfEfficiency = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, itemStack); 121 | 122 | itemStack.removeSubNbt("Enchantments"); 123 | itemStack.addEnchantment(Enchantments.EFFICIENCY, levelOfEfficiency + 1); 124 | 125 | if (levelOfEfficiency > 10) { 126 | world.createExplosion(context.getPlayer(), pos.getX(), pos.getY(), pos.getZ(), 2, true, World.ExplosionSourceType.MOB); 127 | } 128 | 129 | return ActionResult.SUCCESS; 130 | } 131 | } 132 | ``` 133 | 134 | Place a Breakpoint by clicking right next to the line number. You can place more than one at once if needed. 135 | 136 | ![basic breakpoint](./_assets/basic_problem_solving_04.png) 137 | 138 | Then let the instance execute this part of the code. In this case, the custom Item needs to be used on a Block. The Instance should freeze and in IntelliJ a yellow arrow right next to the Breakpoint appears. This indicates at which point the Debugger is currently. In the `Debug` window the controls can be used to move the current execution point using the blue arrow icons. This way the code can be processed step by step. 139 | 140 | ![move execution point](./_assets/basic_problem_solving_05.png) 141 | 142 | The "Step over" function is the most common one so try to get used to its Keybind (F8) 143 | 144 | If you are done with the current inspection you can press the `Resume Program` button at the left side of the `Debug` window. This will un-freeze the Minecraft instance and further testing can be done. 145 | 146 | Currently, loaded values and objects are listed on the right side of this window, while a complete Stacktrace is on the left side. You can also hover, with the Mouse Cursor, over the values in the code. If they are in scope and are still loaded a window will show their specific values too. 147 | 148 | ![loaded values](./_assets/basic_problem_solving_06.png) 149 | 150 | Not loaded Integer vs. loaded Integer 151 | 152 | If we inspect the `ItemStack` object we can see that the enchantments are stored as NBT values. The `removeSubNbt()` method removes all SubNbt values with the "Enchantments" key. 153 | 154 | ![itemstack](./_assets/basic_problem_solving_07.png) 155 | 156 | To avoid that, only the specific enchantment needs to be removed. This can be done using the `EnchantmentHelper` in combination with filtering a `Stream`. 157 | 158 | ```java 159 | @Override 160 | public ActionResult useOnBlock(ItemUsageContext context) { 161 | ItemStack itemStack = context.getStack(); 162 | World world = context.getWorld(); 163 | BlockPos pos = context.getBlockPos(); 164 | 165 | if (world.isClient()) return super.useOnBlock(context); 166 | 167 | int levelOfEfficiency = EnchantmentHelper.getLevel(Enchantments.EFFICIENCY, itemStack); 168 | 169 | 170 | // Get a list of the itemStack's enchantments 171 | var enchantments = EnchantmentHelper.fromNbt(itemStack.getOrCreateNbt().getList("Enchantments", NbtElement.COMPOUND_TYPE)); 172 | var filteredEnchantments = enchantments.entrySet().stream() 173 | // Keep only enchantments which aren't EFFICIENCY 174 | .filter(entry -> !(entry.getKey().equals(Enchantments.EFFICIENCY))) 175 | // collect the entries of the stream for the final itemStack's enchantments Map 176 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 177 | 178 | // put the changed enchantments Map (without the efficiency) back on the itemStack 179 | EnchantmentHelper.set(filteredEnchantments, itemStack); 180 | 181 | // add the efficiency enchantment back with the new level 182 | itemStack.addEnchantment(Enchantments.EFFICIENCY, levelOfEfficiency + 1); 183 | 184 | if (levelOfEfficiency > 10) { 185 | world.createExplosion(context.getPlayer(), pos.getX(), pos.getY(), pos.getZ(), 186 | 2, true, World.ExplosionSourceType.MOB); 187 | } 188 | 189 | return ActionResult.SUCCESS; 190 | } 191 | ``` 192 | 193 | ### Breakpoints with conditions 194 | 195 | Sometimes it is necessary to only halt the code when certain conditions are met. Create a basic Breakpoint and right-click it to open the Breakpoint's settings. In there, you can use boolean statements for the condition. 196 | 197 | ![Breakpoint with conditions](./_assets/basic_problem_solving_08.png) 198 | 199 | ### Reloading an active Instance 200 | 201 | It is possible to make limited changes to the code, while a Minecraft instance is running. Method bodies can be rewritten at run-time using the `Debug` option instead of the `Run` option. This way, the Minecraft instance doesn't need to be restarted again. This makes e.g. testing Screen element alignment and other feature balancing faster. 202 | 203 | ![Debugging](./_assets/basic_problem_solving_03.png) 204 | 205 | When the instance is running and changes to the code have been made, use `Build Project` to reload the changes. This process is also known as "Hotswap". If the changes were applied to the current instance, a green notification will be shown. 206 | 207 | ![build project](./_assets/basic_problem_solving_09.png) 208 | 209 | ![hotswap](./_assets/basic_problem_solving_10.png) 210 | 211 | Correct Hotswap vs. failed Hotswap 212 | 213 | Other changes can be reloaded in-game. 214 | 215 | - changes to the `assets/` folder -> press `[F3 + T]` 216 | - changes to the `data/` folder -> use the `/reload` command 217 | 218 | ## Logs and crash report files 219 | 220 | The console of a previously executed instance helps with finding the issues. They are exported into the log files, located in the Minecraft instance's `logs` directory. The newest log is usually called `latest.log`. Users can send this file, for further inspection, to the mod developer or host the file content on code-hosting websites. 221 | 222 | In the development environment you can find the logs in the project's `run > logs` folder and the crash reports in the `run > crash-reports` folder. 223 | 224 | ## Still couldn't solve the problem? 225 | 226 | Join the community and ask for help! 227 | 228 | - [Official Fabric Wiki](https://fabricmc.net/wiki/start) and their [Discord server](https://discord.com/invite/v6v4pMv) -------------------------------------------------------------------------------- /getting-started/creating-project.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating a project 3 | description: Learn how to create a project by either using the Fabric CLI or using MCDev's project wizard. 4 | order: 1 5 | prev: 6 | text: Prerequisites 7 | link: /getting-started/ 8 | next: 9 | text: Launching The Game 10 | link: /getting-started/launching-the-game 11 | --- 12 | 13 | # Creating A Project 14 | 15 | There are many ways to create a mod project, however we recommend you either use the Fabric CLI or the built-in MCDev Plugin project wizard. 16 | 17 | ## Fabric CLI 18 | 19 | ### Installing Deno 20 | 21 | The Fabric CLI uses Deno - you will need to install Deno to use Fabric CLI. 22 | 23 | ::: code-group 24 | 25 | ```sh [Windows (Powershell)] 26 | irm https://deno.land/install.ps1 | iex 27 | ``` 28 | 29 | ```sh [MacOS/Linux (Shell/Bash)] 30 | curl -fsSL https://deno.land/x/install/install.sh | sh 31 | ``` 32 | 33 | ::: 34 | 35 | ### Installing Fabric CLI 36 | 37 | Once you have installed Deno, you can install the Fabric CLI through the `deno install` command: 38 | 39 | ```sh 40 | deno install -A -n fabric https://fabricmc.net/cli 41 | ``` 42 | 43 | ### Using Fabric CLI 44 | 45 | When you're ready, run the `fabric init` command to create your mod project. 46 | 47 | It will ask you various questions, such as your mod name, mod ID and package name. 48 | 49 | ::: warning 50 | When asked about "Advanced Options" make sure to disable "Split client and common sources" as this will overcomplicate tutorials on this wiki. You can leave it enabled **if you know what you're doing.** 51 | ::: 52 | 53 | ## MCDev Project Wizard 54 | 55 | To create a project using the MCDev project wizard, press "New Project" on the "Welcome to IntelliJ IDEA" window. 56 | 57 | You'll want to select the "Minecraft" generator in the left sidebar. 58 | 59 | Make sure that you have selected "Mod" for the Platform Type toggle, "Fabric" for the loader toggle, and that a Java 17 JDK is selected at the bottom: 60 | 61 | ![](./_assets/creating-a-project_0.png) 62 | 63 | Click "Create" to start the project creation process - this may take a few minutes, don't close the IDE or cancel during this process or you will have to delete the folder your project was created in and restart! -------------------------------------------------------------------------------- /getting-started/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prerequisites 3 | description: Learn how to set up a development environment for creating mods using the Fabric toolchain. 4 | order: 0 5 | next: 6 | text: Creating a project 7 | link: "/getting-started/creating-project" 8 | --- 9 | 10 | # Introduction 11 | 12 | Before you can even start programming, you need to check that you have the following: 13 | 14 | ## Java Knowledge 15 | 16 | The majority of pages in this wiki use Java instead of Kotlin, Scala or Groovy - we expect that you have a moderate understanding of Java. 17 | 18 | If you do not know what Java is, or how to program in it, you should check out the following guides and tutorials: 19 | 20 | - [W3Schools: Java Tutorial](https://www.w3schools.com/java/) 21 | - [TutorialsPoint: Java](https://www.tutorialspoint.com/java/index.htm) 22 | - [Java Tutorial For Beginners: Programming With Mosh](https://www.youtube.com/watch?v=eIrMbAQSU34) 23 | 24 | You are also expected to know what Gradle is and some terminology about it. You can find [a brief explanation on the official Gradle documentation.](https://docs.gradle.org/current/userguide/userguide.html) 25 | 26 | ## IntelliJ IDEA 27 | 28 | Although you are welcome to use Eclipse or Visual Studio Code, all of the Fabric Community Wiki pages use IntellIJ IDEA and the reference mod is set up to utilize IntellIJ IDEA features such as run configurations. 29 | 30 | You can download the latest version of [IntellIJ IDEA: Community Edition here.](https://www.jetbrains.com/idea/download/?section=linux) 31 | 32 | ## Minecraft Development Plugin 33 | 34 | The Minecraft Development Plugin, also known as MCDev, provides quality of life improvements to the IntelliJ IDEA IDE when developing Minecraft mods, it is recommended you install the plugin. 35 | 36 | You can find more [information on the plugin here.](https://mcdev.io/) -------------------------------------------------------------------------------- /getting-started/launching-servers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Launching Multiple Clients and Servers 3 | description: Learn how to launch multiple clients and a server instance of Minecraft. 4 | order: 4 5 | --- 6 | 7 | # Launching Multiple Clients and Servers 8 | 9 | If your mod requires a multiplayer environment, you will need to test it with multiple clients. This guide will show you how to launch multiple clients and a server instance of the development version of Minecraft. 10 | 11 | Keep in mind that you will run a server and the clients at the same time. This may be taxing on your computer's performance - if your computer isn't powerful, why don't you ask friends to help you test, or ask in the [Fabric Discord](https://fabricmc.net/discuss) for some aid? 12 | 13 | ## Launching the Server 14 | 15 | ### Start the Server 16 | 17 | You can use the `Minecraft Server` run configuration to launch the server. 18 | 19 | ![runServer Gradle Task](./_assets/clients-and-servers_1.png) 20 | 21 | New files are generated in your project's `run` folder. However, an error should appear in your console about the EULA, this is expected. 22 | 23 | ### Agree to EULA 24 | 25 | When launching the server for the first time, you need to agree to [Mojang's EULA](https://account.mojang.com/documents/minecraft_eula). A file called `eula.txt` has been created for that in the project's `run` folder. Change the EULA value to `true` in this file. 26 | 27 | ``` 28 | #By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula). 29 | #Sat Sep 03 12:03:44 CEST 2022 30 | eula=true 31 | ``` 32 | 33 | ### Disable Server Online Mode 34 | 35 | In the development environment, the clients usually aren't logged in to any online accounts, so you will need to disable the server's online mode. If you don't, the server will try to authenticate the client accounts who are joining the server. This will result in an error in the client console. 36 | 37 | ![server IP](./_assets/clients-and-servers_2.png) 38 | 39 | You can find this option in the `server.properties` file: 40 | 41 | ```properties 42 | # ... 43 | online-mode=false 44 | # ... 45 | ``` 46 | 47 | Now, the server won't try to authenticate the client accounts who are joining the server. 48 | 49 | The set-up of the server is finished. The `Minecraft Server` Run Configuration is used to launch the server, and the usual server files are located in the project's `run` folder. You can interact with the server by using the server console. 50 | 51 | ![server console](./_assets/clients-and-servers_3.png) 52 | 53 | Use the `Minecraft Server` run configuration to launch the server again. The server should start without any errors. 54 | 55 | ## Connecting to the Server 56 | 57 | The server is running on your computer, so you can use `localhost` as the server IP. If you want to connect to the server from another computer, you will need to use your computer's IP address instead and potentially even need to port forward the server if you're testing with friends or people not on your network. 58 | 59 | ## Running multiple Clients at the same time. 60 | 61 | Some testing requires multiple clients to interact in a multiplayer environment. Edit the `Minecraft Client` Run Configuration by pressing the white arrow. And modify the options to run multiple instances of this profile at the same time. 62 | 63 | ![edit client configuration](./_assets/clients-and-servers_4.png) 64 | 65 | ![allow multiple instances](./_assets/clients-and-servers_5.png) 66 | 67 | Now you can launch your client profile as many times as you want and connect multiple clients to your server. To check out all the instances and their consoles for logging and other purposes, switch the consoles with the tabs at the top of the console window. 68 | 69 | ![consoles](./_assets/clients-and-servers_6.png) 70 | 71 | ## Avoiding file issues 72 | 73 | ::: info 74 | This section is optional since in many cases the mentioned error won't occur. 75 | ::: 76 | 77 | When installing external mods, which are not listed in the `build.gradle` file, using the `/run` directory, the following error may prevent multiple instances from starting. 78 | 79 | ``` 80 | java.nio.file.FileSystemException: ... : The process cannot access the file because it is being used by another process. 81 | ``` 82 | 83 | To avoid this issue, you will have to create additional `Run Configuration` entries. 84 | 85 | ### 1. Prepare new directories 86 | 87 | Create new folders for the new entries in your repository and name them. In this case it will be `runClientPrimary`, `runClientSecondary` and `runServer`, 88 | but create as many as you need and name them properly. You will need their file paths later on. 89 | 90 | ![New Directories](./_assets/clients-and-servers_8.png) 91 | 92 | ::: info 93 | Get the file paths with (Right Click > Copy Path/Reference > Absolute Path) or find them in your file explorer of choice. 94 | ::: 95 | 96 | ### 2. Copy the original `Run Configuration` 97 | 98 | Go into the `Configuration Settings` and create copies of the existing `Run Configuration` entries. 99 | Name them properly, and make sure to change their `Working Directory` to their new file paths. 100 | 101 | ![Run Config Settings](./_assets/clients-and-servers_9.png) 102 | 103 | ![Settings overview](./_assets/clients-and-servers_10.png) 104 | 105 | ### 3. Populate the directories 106 | 107 | Start the new `Run Confgiurations` and they will populate their necessary files by themselves. If you want to keep your data from the original instance, 108 | copy the files from the original `run` directory to keep things like the world saves, options, Ressourcepacks and other instance related data. 109 | 110 | ### 4. Modify the .gitignore file 111 | 112 | Add the new directories to the repository's `.gitignore` file. This will prevent commits which contain files from those local instances. 113 | 114 | ```sh 115 | # ... 116 | 117 | # Common working directories 118 | run/ 119 | runClientPrimary/ 120 | runClientSecondary/ 121 | runServer/ 122 | 123 | # ... 124 | ``` 125 | 126 | Now you can start multiple instances at the same time with running the seperate `Run Configuration` entries. 127 | 128 | ::: warning 129 | Keep in mind that all instances have their own directory now! You will have to install the same mods and change the same settings serveral times. 130 | ::: 131 | 132 | -------------------------------------------------------------------------------- /getting-started/launching-the-game.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Launching The Game 3 | description: Learn how to launch a development version of Minecraft to debug your mods with. 4 | order: 3 5 | --- 6 | 7 | # Launching Minecraft 8 | 9 | To launch Minecraft with your mod installed, you can choose the "Minecraft Client" task in your Run Configurations list - it's recommended you launch in "Debug" mode as this will allow you to [hotswap](/getting-started/basic-problem-solving#reloading-an-active-instance) methods and create [breakpoints](/getting-started/basic-problem-solving#breakpoint) where possible. 10 | 11 | ![](./_assets/launching-the-game_0.png) 12 | 13 | If the run configurations don't exist, reload the project. If they still dont exist, you can alternatively use the `gradlew runClient` command instead. This is not recommended though as hotswapping and various debug tools are not available. 14 | 15 | You should see the game launch in development mode - you are unauthenticated and cannot join any online servers in this mode: 16 | 17 | ![](./_assets/launching-the-game_1.png) 18 | 19 | ## Authentication 20 | 21 | If you need to log into an actual account instead of being stuck in offline mode, you can utilize the ["DevLogin" library by PlanetTeamSpeakk](https://github.com/PlanetTeamSpeakk/DevLogin) 22 | 23 | Simply add the following to the `build.gradle` file found in the root of your mod project: 24 | 25 | ```groovy 26 | repositories { 27 | mavenCentral() 28 | 29 | // ... 30 | } 31 | 32 | dependencies { 33 | modImplementation "com.ptsmods:devlogin:3.3" 34 | 35 | // ... 36 | } 37 | ``` 38 | 39 | Next, you'll need to add the `--msa-nostore` argument to your "Minecraft Client" run configuration: 40 | 41 | ![](./_assets/launching-the-game_2.png) 42 | 43 | Now, when launching the game, you will be prompted to authenticate with Microsoft. 44 | 45 | If you wish to store the authentication token, simply replace `--msa-nostore` with the `--msa` argument. This is not recommended though. 46 | 47 | ## Hot Swapping 48 | 49 | Hot Swapping is only available when the run configurations are ran in "Debug" mode - even then, you're still quite limited: 50 | 51 | - You can't add or remove methods 52 | - You can't change method parameters 53 | - You can't add or remove fields 54 | 55 | ## Hot Swapping Mixins 56 | 57 | If you wish to hot-swap mixins, you need to mark the mixin jar library as a java agent. 58 | 59 | ### 1. Locate the Mixin library jar. 60 | 61 | In IntelliJ IDEA, you can find the mixin library jar in the "External Libraries" section of the "Project" section: 62 | 63 | ![](./_assets/launching-the-game_3.png) 64 | 65 | You will need to copy the jar's "Absolute Path" 66 | 67 | ### 2. Add the `-javaagent` VM argument. 68 | 69 | In your "Minecraft Client" and or "Minecraft Server" run configuration, add the following to the VM Arguments option: 70 | 71 | ``` 72 | -javaagent:"path to mixin library jar here" 73 | ``` 74 | 75 | ![](./_assets/launching-the-game_4.png) 76 | 77 | Now, you should be able to modify the contents of your mixin methods. -------------------------------------------------------------------------------- /getting-started/mixins.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mixins 3 | description: Mixins are essential for modding in the Fabric ecosystem, enabling the injection of custom code into existing Minecraft classes while maintaining compatibility with other mods. 4 | order: 6 5 | --- 6 | 7 | # Mixins 8 | 9 | ::: info 10 | For advanced techniques and in-depth documentation, you can refer to official resources such as the [SpongePowered Mixin Wiki](https://github.com/SpongePowered/Mixin/wiki), join the [Fabric Discord](https://discord.gg/SYaxVkfU3v), or explore the [Fabric Wiki](https://fabricmc.net/wiki/tutorial:mixin_introduction). 11 | 12 | Additionally, [MixinExtras by LlamaLad7](https://github.com/LlamaLad7/MixinExtras) provides useful annotations like `@WrapWithCondition` for further mixin capabilities. 13 | ::: 14 | 15 | Mixins are a powerful tool that allows mod you to modify existing Minecraft code. By injecting custom logic, removing mechanics, or modifying values, mixins enable a wide range of possibilities for enhancing gameplay and extending functionality. 16 | 17 | Fabric Loader loads Mixins for you! You can skip the mixin environment set up and can get straight into creating mixins. 18 | 19 | ## The `@Mixin` Annotation 20 | 21 | The `@Mixin` annotation is a crucial element in defining a class as a mixin. Any properties or methods inherited or contained within the mixin class will be injected into the target class. This provides a seamless way to extend and modify the base game behavior without directly modifying the original Minecraft source code. 22 | 23 | Example of using the `@Mixin` annotation: 24 | 25 | ```java 26 | 27 | @Mixin(MinecraftServer.class) 28 | public class ExampleMixin { 29 | // Custom code to be injected into MinecraftServer class 30 | } 31 | ``` 32 | 33 | 34 | ## The `@Inject` Annotation 35 | 36 | The `@Inject` annotation plays a central role in mixins, allowing you to modify code at specific injection points. By using various parameters such as `at`, `method`, and `slice`, you can control the precise location and conditions of code injections. 37 | 38 | Example of using the `@Inject` annotation: 39 | 40 | ```java 41 | 42 | @Inject(at = @At("HEAD"), method = "loadWorld", cancellable = false) 43 | private void init(CallbackInfo info) { 44 | // Custom code to be injected at the start of MinecraftServer.loadWorld() 45 | } 46 | ``` 47 | 48 | 49 | ## The `@Shadow` Annotation 50 | 51 | The `@Shadow` annotation grants access to fields and methods from the target class within the mixin. This allows you to interact with the target class properties while preserving compile-time type safety without requiring explicit casts. 52 | 53 | Example of using the `@Shadow` annotation: 54 | 55 | ```java 56 | 57 | @Mixin(MinecraftServer.class) 58 | public abstract class MinecraftServerMixin { 59 | @Shadow 60 | @Final 61 | public long[] tickTimes; 62 | } 63 | ``` 64 | 65 | 66 | ## Registering Mixins 67 | 68 | Mixins must be registered to be active in the mod. This is accomplished through the `.mixin.json` file, which is located in the `src/main/resources` folder. You need to specify the package, mixins to load, and applicable environments (`client`, `server`, or both). 69 | 70 | Sample `.mixin.json` configuration: 71 | 72 | ```jsonc 73 | 74 | { 75 | "required": true, 76 | "package": "com.yourmodpackage.mixin", 77 | "compatibilityLevel": "JAVA_17", 78 | "injectors": { 79 | "defaultRequire": 1 80 | }, 81 | "mixins": [ 82 | "ExampleMixin" 83 | ], 84 | "client": [], 85 | "server": [] 86 | } 87 | ``` 88 | 89 | 90 | ## Additional Mixin Applications 91 | 92 | Apart from injecting code, mixins can be used for various other purposes. 93 | 94 | For example, the `@Pseudo` annotation allows mixins to work with other mods without causing crashes if the target is unavailable. 95 | 96 | However, you need to exercise caution with certain annotations like `@Redirect` and `@Overwrite` to ensure compatibility with other mods. -------------------------------------------------------------------------------- /getting-started/using-the-ide.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using the IDE to the fullest 3 | description: Useful information to handle and traverse your Project using the IDE. 4 | order: 7 5 | --- 6 | 7 | # Using the IDE to the fullest 8 | 9 | This page gives useful bits of information, to speed up and ease the workflow of developers. Incorporate them into yours, to your liking. 10 | It may take some time to learn and get used to the shortcuts and other options. You can use this page as a reference for that. 11 | 12 | :::info 13 | Key binds in the text are listed as Windows shortcuts. 14 | Refer to the `File > Setings > Keymap` Settings or search for the functionality elsewhere if you are using a different Keyboard layout. 15 | ::: 16 | 17 | ## Traversing projects 18 | 19 | ### Manually 20 | 21 | IntelliJ has many different ways of traversing projects. If you have generated sources using the `./gradlew genSources` command in the terminal or used the `Tasks > fabric > genSources` Gradle Task in the Gradle Window, you can manually go through the source files of Minecraft in the 22 | Project Window's External Libraries. 23 | 24 | ![Gradle Task](./_assets/traversing_01.png) 25 | 26 | The Minecraft Source code can be found if you look for `net.minecraft`, but also other sources of projects, libraries and dependencies, which are imported using the `build.gradle` file 27 | are located in there. This method is often used when browsing for assets, tags and other files. 28 | 29 | ![External Library](./_assets/traversing_02.png) 30 | 31 | ### Search 32 | 33 | Pressing `Shift` twice opens up a Search window. In there you can search for your project's files and classes. When Activating the checkbox `include non-project items` 34 | or by pressing `Shift` two times again, the search will look not only in your own project, but also in other's, such as the External Libraries. 35 | 36 | ![Search Window](./_assets/traversing_03.png) 37 | 38 | ### Recent Window 39 | 40 | Another useful tool in IntelliJ is the `Recent` window. You can open it with the Shortcut `CTRL + E`. In there you can jump to the files, which you have already visited and open tool windows, such as the [`Structure`](#structure-of-a-class) or [`Bookmarks`](#bookmarks) window. 41 | 42 | ![Recent window](./_assets/traversing_04.png) 43 | 44 | ## Traversing code 45 | 46 | ### Jump to Definition / Usage 47 | 48 | If you need to check out either the definition or the usage of variables, methods, classes, and other things, you can press `CTRL + Left Click` 49 | or use `Middle Mouse Button` (pressing mouse wheel) on their name. This way you can avoid long scrolling sessions or a manual 50 | search for a definition which is located in another file. 51 | 52 | ### Bookmarks 53 | 54 | You can bookmark lines of code, files or even opened Editor tabs. 55 | Especially when researching source codes, it can help out to mark spots which you want to find again quickly in the future. 56 | 57 | Either right click a file in the `Project` window, an editor tab or the line number in a file. 58 | Creating `Mnemonic Bookmarks` enables you to quickly switch back to those bookmarks using their hotkeys, `CTRL` and the digit, which you have chosen for it. 59 | 60 | ![set Bookmark](./_assets/traversing_05.png) 61 | 62 | It is possible to create multiple Bookmark lists at the same time if you need to separate or order them, in the `Bookmarks` window. 63 | [`Breakpoints`](basic-problem-solving#breakpoint) will also be displayed in there. 64 | 65 | ![Bookmark window](./_assets/traversing_06.png) 66 | 67 | ## Analyzing classes 68 | 69 | ### Structure of a class 70 | 71 | By opening the `Structure` window (`Alt + 7`) you will get an overview of your currently active class. You can see which Classes and Enums 72 | are located in that file, which methods have been implemented and which fields / variables are declared. 73 | 74 | Sometimes it can be helpful, 75 | to activate the `Inherited` option at the top as well, when looking for potential methods to `@Override`. 76 | 77 | ![Structure window](./_assets/analyzing_01.png) 78 | 79 | ### Type Hierarchy of a class 80 | 81 | By placing the cursor on a class name and pressing `CTRL + H` you can open a new Type Hierarchy window, which shows all parent and child classes. 82 | 83 | ![Type Hierarchy window](./_assets/analyzing_02.png) 84 | 85 | ## Code utility 86 | 87 | ### Code completion 88 | 89 | Code completion should be activated by default. You will automatically get the recommendations while writing your code. If you closed it by 90 | accident or just moved your cursor to a new place, you can use `CTRL + Space` to open them up again. 91 | 92 | For example, when using Lambdas, you can write them quickly using this method. 93 | 94 | ![Lambda with many parameters](./_assets/util_01.png) 95 | 96 | ### Displaying parameters 97 | 98 | Displaying parameters should be activated by default. You will automatically get the types and names of the parameters while writing your code. 99 | If you closed them by accident or just moved your cursor to a new place, you can use `CTRL + P` to open them up again. 100 | 101 | Methods and classes can have multiple implementations with different parameters (also known as Overloading). This way you can decide on which 102 | implementation you want to use, while writing the method call. 103 | 104 | ![Displaying method parameters](./_assets/util_02.png) 105 | 106 | ### Refactoring 107 | 108 | Refactoring is the process of restructuring code without changing its functionality. Renaming and Deleting parts of the code safely is a part of that, 109 | but things like extracting parts of the code into separate methods and introducing new variables for repeated code statements are also called "refactoring". 110 | 111 | Many IDEs have an extensive tool kit to aid in this process. In IntelliJ simply right click files or parts of the code to get access to the available refactoring tools. 112 | 113 | ![Refactoring](./_assets/refactoring_01.png) 114 | 115 | It is especially useful to get used to the `Rename` refactoring tool's key bind, `SHIFT + F6`, since you will rename many things in the future. Using this feature, 116 | every code occurrence of the renamed code will be renamed and will stay functionally the same. 117 | 118 | ### Search and Replace file content 119 | 120 | Sometimes simpler tools are needed to edit code occurrences. 121 | 122 | | Key bind | Function | 123 | | ------------------ | ----------------------------------------------------------- | 124 | | `CTRL + F` | Find in current file | 125 | | `CTRL + R` | Replace in current file | 126 | | `CTRL + SHIFT + F` | Find in a bigger scope (can set specific file type mask) | 127 | | `CTRL + SHIFT + R` | Replace in a bigger scope (can set specific file type mask) | 128 | 129 | If enabled, all of those tools allow for a more specific pattern matching using "[Regex](https://regex101.com/)" (regular expression). 130 | 131 | ![Regex-replace](./_assets/search-and-replace_01.png) 132 | 133 | 134 | ## Comments 135 | 136 | ### Prepare Shortcuts 137 | 138 | Good code should be easily readable and [self-documenting](https://bytedev.medium.com/code-comment-anti-patterns-and-why-the-comment-you-just-wrote-is-probably-not-needed-919a92cf6758). Picking expressive names for variables, classes and methods can help a lot, but sometimes 139 | comments are necessary to leave notes or temporarily disable code for testing. 140 | 141 | To comment out code faster, open IntelliJ's Settings, look for the `Comment with Line Comment` 142 | and the `Comment with Block Comment` entries, and set their Key binds to your preferences. 143 | 144 | ![Keymap settings](./_assets/comments_01.png) 145 | 146 | Now you can highlight the necessary code and use the shortcuts, to comment the section out. 147 | 148 | ```java 149 | // private static final int PROTECTION_BOOTS = 2; 150 | private static final int PROTECTION_LEGGINGS = 5; 151 | // private static final int PROTECTION_CHESTPLATE = 6; 152 | private static final int PROTECTION_HELMET = 1; 153 | ``` 154 | 155 | ```java 156 | /* 157 | ModItems.initialize(); 158 | ModSounds.initializeSounds(); 159 | ModParticles.initialize(); 160 | */ 161 | 162 | private static int secondsToTicks(float seconds) { 163 | return (int) (seconds * 20 /*+ 69*/); 164 | } 165 | ``` 166 | 167 | ### Region comments 168 | 169 | In IntelliJ, right next to the line numbers, you can have small [+] and [-] icons. Those can be used to temporarily collapse methods, if-statements, classes and many other things 170 | if you are not actively working on them. To create a custom block which can be collapsed, use the `region` and `endregion` comments. 171 | 172 | ```java 173 | // region collapse block name 174 | ModBlocks.initialize(); 175 | ModBlockEntities.registerBlockEntityTypes(); 176 | ModItems.initialize(); 177 | ModSounds.initializeSounds(); 178 | ModParticles.initialize(); 179 | // endregion 180 | ``` 181 | 182 | ![Keymap settings](./_assets/comments_02.png) 183 | 184 | ::: warning 185 | This feature may not be supported in other editors and IDEs. 186 | If you notice that you are using too many of them, consider refactoring your code to make it more readable! 187 | ::: 188 | 189 | ### TODO and FIXME notes 190 | 191 | When working on code, it can come in handy to leave notes, on what still needs to be taken care of. Sometimes you may also spot 192 | a potential issue in the code, but you don't want to stop focusing on the current problem. In this case, use the 193 | `TODO` or `FIXME` comments. 194 | 195 | ![TODO and FIXME comments](./_assets/comments_03.png) 196 | 197 | IntelliJ will keep track of them in the `TODO` window and may notify you, if you commit code, 198 | which uses those type of comments. 199 | 200 | ![TODO and FIXME comments](./_assets/comments_04.png) 201 | 202 | ![Commit with TODO](./_assets/comments_05.png) 203 | 204 | ::: warning 205 | This feature may not be supported in other editors and IDEs. 206 | ::: 207 | 208 | ### Javadocs 209 | 210 | A great way of documenting your code is the usage of JavaDoc. JavaDocs not only provide useful information for implementation of methods and classes, but are also 211 | deeply integrated into IntelliJ. 212 | 213 | When hovering over method or class names, which have JavaDoc comments added to them, they will display this information in their information window. 214 | 215 | ![JavaDoc](./_assets/comments_06.png) 216 | 217 | To get started, simply write `/**` above the method or class definition and press enter. IntelliJ will automatically generate lines for the return value 218 | and the parameters but you can change them however you want. There are many custom functionalities available and you can also use HTML if needed. 219 | 220 | Minecraft's `ScreenHandler` class has some examples. To toggle the render view, use the pen button near the line numbers. 221 | 222 | ![JavaDoc editing](./_assets/comments_07.png) 223 | 224 | ## Optimizing IntelliJ further 225 | 226 | There are many more shortcuts and handy little tricks which would go above the scope of this wiki. 227 | Jetbrains has many good talks and videos about how to further customize your workspace. 228 | 229 | --- 230 | 231 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | title: "Fabric Modding Wiki" 6 | description: "An open source guide-book for creating mods using Fabric." 7 | 8 | hero: 9 | name: "Fabric Modding Wiki" 10 | tagline: "An open source guide-book for creating mods using Fabric." 11 | actions: 12 | - theme: brand 13 | text: Getting Started 14 | link: /getting-started/ 15 | - theme: alt 16 | text: Contribute 17 | link: /contributing 18 | 19 | features: 20 | - title: Items 21 | details: "Discover how to register a simple item and how to texture, model and name it." 22 | link: /items/ 23 | - title: Blocks 24 | details: "Learn how to register a simple block and block item, texture and model it." 25 | link: /blocks/ 26 | - title: Data Generation 27 | details: "Find out how you can setup your project to utilize Fabric API's data generation helpers." 28 | link: /data-generation/ 29 | - title: Events 30 | details: "Learn how to use Fabric API's event system." 31 | link: /events/ 32 | - title: Rendering 33 | details: Learn the basics of rendering in Minecraft, both 3D and 2D. 34 | link: /rendering/ 35 | - title: Sounds 36 | details: Learn how to utilize Minecraft's sound systems to add and play your own sounds. 37 | link: /sounds/ 38 | - title: Miscellaneous Topics 39 | details: "Learn about other topics such as codecs, text and more." 40 | link: /misc-topics/ 41 | --- 42 | 43 | 65 | 66 | 154 | 155 |
156 | 157 | ::: info 158 | These pages have been tested and verified to work with Minecraft `1.20.4`, if you encounter any issues, please report them on the [Discord](https://discord.gg/5tmestARuU) or [GitHub](https://github.com/moddedmc-wiki/fabric-modding-wiki). 159 | ::: 160 | 161 |
162 | 163 | # Writers 164 | 165 | These people have written the many guides and resources on this website, you should go and support them! If you want to contribute guides and resources, check out the [Contributing](/contributing) page. 166 | 167 | 170 | 171 |
172 | -------------------------------------------------------------------------------- /items/_assets/armor_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/armor_0.png -------------------------------------------------------------------------------- /items/_assets/armor_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/armor_1.png -------------------------------------------------------------------------------- /items/_assets/armor_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/armor_2.png -------------------------------------------------------------------------------- /items/_assets/armor_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/armor_3.png -------------------------------------------------------------------------------- /items/_assets/example_armor_item_textures.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/example_armor_item_textures.zip -------------------------------------------------------------------------------- /items/_assets/example_armor_layer_textures.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/example_armor_layer_textures.zip -------------------------------------------------------------------------------- /items/_assets/first_item_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/first_item_0.png -------------------------------------------------------------------------------- /items/_assets/first_item_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/first_item_1.png -------------------------------------------------------------------------------- /items/_assets/first_item_1_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/first_item_1_small.png -------------------------------------------------------------------------------- /items/_assets/first_item_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/first_item_2.png -------------------------------------------------------------------------------- /items/_assets/food_0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/food_0.webp -------------------------------------------------------------------------------- /items/_assets/interactive_0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/interactive_0.webp -------------------------------------------------------------------------------- /items/_assets/itemgroups_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/itemgroups_0.png -------------------------------------------------------------------------------- /items/_assets/itemgroups_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/itemgroups_1.png -------------------------------------------------------------------------------- /items/_assets/tools_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/tools_0.png -------------------------------------------------------------------------------- /items/_assets/tools_0_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/tools_0_small.png -------------------------------------------------------------------------------- /items/_assets/tools_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/items/_assets/tools_1.png -------------------------------------------------------------------------------- /items/armor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Armor 3 | description: Learn how to create your own armor sets. 4 | order: 3 5 | --- 6 | 7 | # Armor 8 | 9 | Armor provides the player with increased defense against attacks from mobs and other players. 10 | 11 | ## Creating an armor material. 12 | 13 | All armor items - like tools - have an armor material. 14 | 15 | The armor material tells the game what protection and durability the armor item should have depending on the slot. 16 | 17 | You'll need to create a class that inherits `ArmorMaterial` - and add the following fields. 18 | 19 | ```java 20 | // I'll be creating guide-ite armor, to pair with the tools I created in the previous page. 21 | public class GuiditeArmorMaterial extends ArmorMaterial { 22 | // Base durability values for all the slots. 23 | // Boots, Leggings, Chestplate, Helmet 24 | private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11}; 25 | 26 | // Protection values for all the slots. 27 | // For reference, diamond uses 3 for boots, 6 for leggings, 8 for chestplate 28 | // and 3 for helmet. 29 | private static final int PROTECTION_BOOTS = ...; 30 | private static final int PROTECTION_LEGGINGS = ...; 31 | private static final int PROTECTION_CHESTPLATE = ...; 32 | private static final int PROTECTION_HELMET = ...; 33 | 34 | // Storing the protection and durability values in an array allows 35 | // you to quickly get them by slot ID. 36 | private static final int[] PROTECTION_VALUES = new int[] { 37 | PROTECTION_BOOTS, 38 | PROTECTION_LEGGINGS, 39 | PROTECTION_CHESTPLATE, 40 | PROTECTION_HELMET 41 | }; 42 | } 43 | ``` 44 | 45 | The following methods will have to be implemented as well - these methods tell the game vital information on your armor items. 46 | 47 | - #### Durability - `getDurability(ArmorItem.Type type)` 48 | 49 | Returns the durability for a specific armor type - in hit points. 50 | 51 | The hit points specify the amount of hits the armor item can take before breaking. 52 | 53 | **Example** 54 | 55 | ```java 56 | @Override 57 | public int getDurability(ArmorItem.Type type) { 58 | // Replace X with a multiplier that you see fit! 59 | // For reference, diamond uses a multiplier of 33, whilst 60 | // leather uses 11. 61 | return BASE_DURABILITY[type.getEquipmentSlot().getEntitySlotId()] * X; 62 | } 63 | ``` 64 | 65 | - #### Protection - `getProtection(ArmorItem.Type type)` 66 | 67 | Returns the protection value for a specific armor type. 68 | 69 | Usually this is always the same, regardless of your armor material. 70 | 71 | **Example** 72 | 73 | ```java 74 | @Override 75 | public int getProtection(ArmorItem.Type type) { 76 | // This will get the protection value for the slot from 77 | // our array. 78 | return PROTECTION_VALUES[type.getEquipmentSlot().getEntitySlotId()]; 79 | } 80 | ``` 81 | 82 | - #### Enchantability - `getEnchantability()` 83 | 84 | How easy is it to get better and higher level enchantments with this item? 85 | 86 | **Example** 87 | 88 | ```java 89 | @Override 90 | public int getEnchantability() { 91 | return 5; 92 | } 93 | ``` 94 | 95 | - #### Equip Sound - `getEquipsound()` 96 | 97 | What sound should be played when the armor is equipped? 98 | 99 | **Example** 100 | 101 | ```java 102 | @Override 103 | public SoundEvent getEquipSound() { 104 | // Example for Iron Armor 105 | return SoundEvents.ITEM_ARMOR_EQUIP_IRON; 106 | } 107 | ``` 108 | 109 | - #### Repair Ingredient - `getRepairIngredient()` 110 | 111 | What item or items can be used in an anvil to repair the armor items? 112 | 113 | **Example** 114 | 115 | ```java 116 | @Override 117 | public Ingredient getRepairIngredient() { 118 | return Ingredient.ofItems(ModItems.POOP); 119 | } 120 | ``` 121 | 122 | - #### Name - `getName()` 123 | 124 | The name of the armor material - must be lowercase. 125 | 126 | **Example** 127 | 128 | ```java 129 | @Override 130 | public String getName() { 131 | return "guidite"; 132 | } 133 | ``` 134 | 135 | - #### Toughness - `getToughness()` 136 | 137 | How much protection should be given for high-damage attacks? 138 | 139 | For reference, everything except diamond (`2.0F`) and netherite (`4.0F`) have a toughness of zero. 140 | 141 | **Example** 142 | 143 | ```java 144 | @Override 145 | public float getToughness() { 146 | return 2.0F; 147 | } 148 | ``` 149 | 150 | - #### Knockback Resistance - `getKnockbackResistance()` 151 | 152 | How much knockback resistance should the armor give the entity? 153 | 154 | **Example** 155 | 156 | ```java 157 | @Override 158 | public float getKnockbackResistance() { 159 | // I do not want Guidite Armor to give knockback resistance. 160 | return 0; 161 | } 162 | ``` 163 | 164 | ## Creating an instance of the ArmorMaterial 165 | 166 | To use the armor material with the armor items, you'll need to create an instance of it - similar to a tool material: 167 | 168 | ```java 169 | public static final GuiditeArmorMaterial INSTANCE = new GuiditeArmorMaterial(); 170 | ``` 171 | 172 | You can place this instance in the armor material class itself. 173 | 174 | ## Creating the Armor Items 175 | 176 | Now that you've created an instance of the material, you can create the armor items in your `ModItems` class: 177 | 178 | Obviously, an armor set doesn't need every type to be satisfied, you can have a set with just boots, or leggings etc. - the vanilla turtle shell helmet is a good example of an armor set with missing slots. 179 | 180 | ```java 181 | public static final Item GUIDITE_HELMET = register(new ArmorItem(GuiditeArmorMaterial.INSTANCE, ArmorItem.Type.HELMET, new Item.Settings()), "guidite_helmet"); 182 | public static final Item GUIDITE_BOOTS = register(new ArmorItem(GuiditeArmorMaterial.INSTANCE, ArmorItem.Type.BOOTS, new Item.Settings(), "guidite_boots"); 183 | // ... chestplate, leggings, etc. 184 | ``` 185 | 186 | You will also need to add the items to an item group if you want them to be accessible from the creative inventory. 187 | 188 | As with all items, you should create translation keys for them as well. 189 | 190 | ## Texturing and Modelling 191 | 192 | You will need to create two sets of textures: 193 | 194 | - Textures and models for the items themselves. 195 | - The actual armor texture that is visible when an entity wears the armor. 196 | 197 | ### Item Textures And Model 198 | 199 | These textures are no different to other items - you must create the textures, and create a generic generated item model - which was covered in the [Creating Your First Item](/items/#adding-a-texture-and-model) guide. 200 | 201 | For the sake of it, I have supplied example armor item textures you can use, and an example model json: 202 | 203 |
204 | 205 | ![](./_assets/armor_0.png) 206 | 207 | 208 | Download Textures 209 | 210 | 211 |
212 | 213 | ```json 214 | { 215 | "parent": "item/generated", 216 | "textures": { 217 | "layer0": "mod_id:item/guidite_helmet" 218 | } 219 | } 220 | ``` 221 | 222 | As you can see, in-game the armor items should have suitable models: 223 | 224 | ![](./_assets/armor_1.png) 225 | 226 | ## Armor Textures And Model 227 | 228 | When an entity wears your armor, currently the missing texture will appear: 229 | 230 | ![](./_assets/armor_2.png) 231 | 232 | This is because all armor textures are hardcoded by vanilla, to create our own, we'll have to place the texture in the vanilla armor texture folder. 233 | 234 | There are two layers for the armor texture, both must be present. 235 | 236 | Since the armor material name in our case is `guidite`, the locations of the textures will be: 237 | 238 | - `assets/minecraft/textures/models/armor/guidite_layer_1.png` 239 | - `assets/minecraft/textures/models/armor/guidite_layer_2.png` 240 | 241 | 248 | 249 | The first layer contains textures for the helmet and chestplate, whilst the second layer contains textures for leggings and boots. 250 | 251 | When these textures are present, you should be able to see your armor on entities that wear it: 252 | 253 | ![](./_assets/armor_3.png) 254 | -------------------------------------------------------------------------------- /items/food.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Food 3 | description: Learn how to add a FoodComponent to an item to make it edible, and configure it. 4 | order: 1 5 | --- 6 | 7 | # Food Items 8 | 9 | Food is a core aspect of survival Minecraft, so when creating edible items you have to consider the food's usage with other edible items. 10 | 11 | Unless you're making a mod with overpowered items, you should consider: 12 | 13 | - How much hunger your edible item adds or removes. 14 | - What potion effect(s) does it grant? 15 | - Is it early-game or endgame accessible? 16 | 17 | ## Adding the food component. 18 | 19 | To add a food component to an item, we can pass it to the `Item.Settings` instance: 20 | 21 | ```java 22 | new Item.Settings().food(new FoodComponent.Builder().build()) 23 | ``` 24 | 25 | Right now, this just makes the item edible and nothing more. 26 | 27 | The `FoodComponent.Builder` class has many methods that allow you to modify what happens when a player eats your item: 28 | 29 | | Method | Description | 30 | | -------------------- | -------------------------------------------------------------- | 31 | | `hunger` | Sets the amount of hunger points your item will replenish. | 32 | | `saturationModifier` | Sets the amount of saturation points your item will add. | 33 | | `meat` | Declares your item as meat. Carnivourous entities will eat it. | 34 | | `alwaysEdible` | Allows your item to be eaten regardless of hunger level. | 35 | | `snack` | Declares your item as a snack. | 36 | | `statusEffect` | Adds a status effect when you eat your item. | 37 | 38 | When you've modified the builder to your likings, you can call the `build()` method to get the `FoodComponent` 39 | 40 | For the example created in the previous page, I'll be using the following options for the builder: 41 | 42 | ```java 43 | new FoodComponent.Builder() 44 | .alwaysEdible() 45 | .snack() 46 | // The duration is in ticks, 20 ticks = 1 second 47 | .statusEffect(new StatusEffectInstance(StatusEffects.POISON, 6*20, 1), 1.0f) 48 | .build(); 49 | ``` 50 | 51 | This makes the item: 52 | 53 | - Always edible, it can be eaten regardless of hunger level. 54 | - A snack. 55 | - Always give Poision II for 6 seconds when eaten. 56 | 57 | ![](./_assets/food_0.webp) -------------------------------------------------------------------------------- /items/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating Your First Item 3 | description: Learn how to register a simple item and how to texture, model and name it. 4 | order: 0 5 | --- 6 | 7 | # Creating Your First Item 8 | 9 | This page will introduce you into some key concepts relating to items, and how you can register, texture, model and name them. 10 | 11 | If you aren't aware, everything in Minecraft is stored in registries, and items are no exception to that. 12 | 13 | ## Preparing your items class 14 | 15 | To simplify the registering of items, you can create a method that accepts an instance of an item and a string identifier. 16 | 17 | You can put this method in a class called `ModItems` (or whatever you want to name the class!). 18 | 19 | Mojang does this with their items as well! Check out the `Items` class for inspiration. 20 | 21 | ```java 22 | public class ModItems { 23 | // We can use generics to make it so we dont need to 24 | // cast to an item when using this method. 25 | public static T register(T item, String ID) { 26 | // Create the identifier for the item. 27 | Identifier itemID = new Identifier("mod_id", ID); 28 | 29 | // Register the item. 30 | T registeredItem = Registry.register(Registries.ITEM, itemID, item); 31 | 32 | // Return the registered item! 33 | return registeredItem; 34 | } 35 | } 36 | ``` 37 | 38 | ## Registering an item 39 | 40 | You can now register an item using the method now. 41 | 42 | The item constructor takes in an instance of the `Items.Settings` class as a parameter. This class allows you to: 43 | 44 | - Assign the item's `ItemGroup`. 45 | - Make the item edible by passing a `FoodComponent`. 46 | - Set the item's durability. 47 | - and other miscelaneous properties. 48 | 49 | ```java 50 | // Registers a blank item with the ID of "modid:poop" 51 | // I use FabricItemSettings - for the sake of it. 52 | // You can use Item.Settings if you wish. 53 | public static final Item POOP = register( 54 | new Item(new FabricItemSettings()), 55 | "poop" 56 | ); 57 | ``` 58 | 59 | However, when you go in-game, you can see that our item doesn't exist! This is because you don't statically initialize the class. 60 | 61 | To do this, you can add a public static initialize method to your class and call it from your `ModInitializer` class. Currently, this method doesn't need anything inside of it. 62 | 63 | ```java 64 | public static void initialize() {} 65 | ``` 66 | 67 | ```java 68 | public class MyMod implements ModInitializer { 69 | @Override 70 | public void onInitialize() { 71 | // Statically initialize the class. 72 | ModItems.initialize(); 73 | } 74 | } 75 | ``` 76 | 77 | Calling a method on a class statically initializes it if it hasn't been used before - this means that all `final` fields are evaluated. 78 | 79 | ## Adding the item to an item group 80 | 81 | ::: info 82 | The traditional way to register an Item to an ItemGroup was to pass it to the Item.Settings instance, but this has changed in 1.19.3 because you can now specifically order items! 83 | ::: 84 | 85 | You can append your item into the ingredients item group - a later page will describe how to create your own item group. 86 | 87 | To add to the group, you will need to use Fabric API's item group events - specifically `ItemGroupEvents.modifyEntriesEvent` 88 | 89 | This can be done in the `initialize` method of your items class. 90 | 91 | ```java 92 | public static void initialize() { 93 | ItemGroupEvents 94 | // Register a "modify" event for the Ingredients item group. 95 | .modifyEntriesEvent(ItemGroups.INGREDIENTS) 96 | // Add the item to the group when you get access to it. 97 | .register((itemGroup) -> itemGroup.add(ModItems.POOP)); 98 | } 99 | ``` 100 | 101 | Loading into the game, you can see that our item has been registered, and is in the Ingredients item group: 102 | 103 | ![](./_assets/first_item_0.png) 104 | 105 | However, it's missing the following: 106 | 107 | - Item Model 108 | - Texture 109 | - Translation (name) 110 | 111 | ## Naming the item 112 | 113 | The item currently doesn't have a translation, so you will need to add one. The translation key has already been provided by Minecraft: `item.mod_id.poop` 114 | 115 | Create a new JSON file at: `src/main/resources/assets//lang/en_us.json` and put in the translation key and it's value: 116 | 117 | ```json 118 | { 119 | "item.mod_id.poop": "Poop" 120 | } 121 | ``` 122 | 123 | You can either restart the game or build your mod and press F3 + T to apply changes. 124 | 125 | ## Adding a texture and model 126 | 127 | The item will still have the placeholder purple and black checkerboard texture until you create a texture and model for it. 128 | 129 | To do this, place a 16x16 texture in the `assets//textures/item` folder that has the same name of the item you've just registered. 130 | 131 | For the example, the texture is called `poop.png`; I just used the poop emoji as a texture for now. 132 | 133 |
134 | 135 | ![](./_assets/first_item_1.png) 136 | 137 | 138 | Download Texture 139 | 140 | 141 |
142 | 143 | When restarting/reloading the game - you should see that the item still has no texture, that's because you will need to add a model that uses this texture. 144 | 145 | You're going to create a simple `item/generated` model, which takes in an input texture and nothing else. 146 | 147 | Create the model JSON in the `assets//models/item` folder, with the same name as the item; `poop.json` 148 | 149 | ```json 150 | { 151 | "parent": "item/generated", 152 | "textures": { 153 | "layer0": "mod_id:item/poop" 154 | } 155 | } 156 | ``` 157 | 158 | If you now reload the game (F3 + T) you can now see your item texture! 159 | 160 | ![](./_assets/first_item_2.png) -------------------------------------------------------------------------------- /items/interactivity.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Item Interactivity 3 | description: Learn how to create an item that uses built-in vanilla events. 4 | order: 5 5 | --- 6 | 7 | # Interactivity 8 | 9 | Basic items can only go so far - eventually you will need an item that interacts with the world when it is used. 10 | 11 | There are some key classes you must understand before taking a look at the vanilla item events. 12 | 13 | ## TypedActionResult 14 | 15 | For items, the most common `TypedActionResult` you'll see is for `ItemStacks` - this class tells the game what to replace the item stack (or not to replace) after the event has occured. 16 | 17 | If nothing has occured in the event, you should use the `TypedActionResult#pass(stack)` method where `stack` is the current item stack. 18 | 19 | You can get the current item stack by getting the stack in the player's hand. Usually events that require a `TypedActionResult` pass the hand to the event method. 20 | 21 | ```java 22 | TypedActionResult.pass(user.getStackInHand(hand)) 23 | ``` 24 | 25 | If you pass the current stack - nothing will change, regardless of if you declare the event as failed, passed/ignored or successful. 26 | 27 | If you want to delete the current stack, you should pass an empty one. The same can be said about decrementing, you fetch the current stack and decrement it by the amount you want: 28 | 29 | ```java 30 | ItemStack heldStack = user.getStackInHand(hand); 31 | heldStack.decrement(1); 32 | TypedActionResult.success(heldStack); 33 | ``` 34 | 35 | ## ActionResult 36 | 37 | Similarly, an `ActionResult` tells the game the status of the event, whether it was passed/ignored, failed or successful. 38 | 39 | ## Overridable Events 40 | 41 | Luckily, the Item class has many methods that can be overriden to add extra functionality to your items. 42 | 43 | | Method | Information | 44 | | --------------- | ------------------------------------------------------- | 45 | | `postHit` | Ran when the player hits an entity. | 46 | | `postMine` | Ran when the player mines a block. | 47 | | `inventoryTick` | Ran every tick whilst the item is in an inventory. | 48 | | `onCraft` | Ran when the item is crafted. | 49 | | `useOnBlock` | Ran when the player right clicks a block with the item. | 50 | | `use` | Ran when the player right clicks the item. | 51 | 52 | ## The "use" event. 53 | 54 | Let's say you want to make an item that summons a lightning bolt infront of the player - you would need to create a custom class. 55 | 56 | ```java 57 | public class LightningStick extends Item { 58 | public LightningStick(Settings settings) { 59 | super(settings); 60 | } 61 | } 62 | ``` 63 | 64 | The `use` event is probably the most useful out of them all - you can use this event to spawn our lightning bolt, you should spawn it 10 blocks in front of the players facing direction. 65 | 66 | ```java 67 | @Override 68 | public TypedActionResult use(World world, PlayerEntity user, Hand hand) { 69 | // Ensure we don't spawn the lightning only on the client. 70 | // This is to prevent desync. 71 | if(world.isClient) { 72 | return TypedActionResult.pass(user.getStackInHand(hand)); 73 | } 74 | 75 | BlockPos frontOfPlayer = user.getBlockPos().offset(user.getHorizontalFacing(), 10); 76 | 77 | // Spawn the lightning bolt. 78 | LightningEntity lightningBolt = new LightningEntity(EntityType.LIGHTNING_BOLT, world); 79 | lightningBolt.setPosition(frontOfPlayer.toCenterPos()); 80 | world.spawnEntity(lightningBolt); 81 | 82 | // Nothing has changed to the item stack, 83 | // so we just return it how it was. 84 | return TypedActionResult.success(user.getStackInHand(hand)); 85 | } 86 | ``` 87 | 88 | As usual, you should register your item, add a model and texture. 89 | 90 | As you can see, the lightning bolt should spawn 10 blocks infront of you - the player. 91 | 92 | ![](./_assets/interactive_0.webp) -------------------------------------------------------------------------------- /items/item-groups.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Custom Item Groups 3 | description: Now that you've added many items - they should probably be put together. 4 | order: 4 5 | --- 6 | 7 | # Custom Item Groups 8 | 9 | In the last few pages - you've added quite a few items, it's time to consider making your own item group. 10 | 11 | ## Creating the item group. 12 | 13 | It's surprisingly easy to create an item group. Simply create a new static final field in your items class to store the item group. 14 | 15 | I'll be using the "Guidite Sword" from the previous tools tutorial as the icon for the group. 16 | 17 | ```java 18 | public static final ItemGroup MY_MOD_ITEMGROUP = FabricItemGroup.builder() 19 | .icon(() -> new ItemStack(ModItems.GUIDITE_SWORD)) 20 | .displayName(Text.translatable("itemGroup.my_mod")) 21 | .build(); 22 | ``` 23 | 24 | You will need to register your item group as well to the `ITEM_GROUP` registry: 25 | 26 | ```java 27 | Registry.register(Registries.ITEM_GROUP, new Identifier("my_mod", "item_group"), MY_MOD_ITEMGROUP); 28 | ``` 29 | 30 | ## Adding items. 31 | 32 | To add items to the group, you can use the modify item group event similarly to how you added your items to the vanilla item groups: 33 | 34 | ```java 35 | var groupRegistryKey = RegistryKey.of(Registries.ITEM_GROUP.getKey(), new Identifier("my_mod", "item_group")) 36 | ItemGroupEvents.modifyEntriesEvent(groupRegistryKey).register(itemGroup -> { 37 | itemGroup.add(ModItems.POOP); 38 | itemGroup.add(ModItems.GUIDITE_SWORD); 39 | // .. other items you've made 40 | }); 41 | ``` 42 | 43 |
44 | 45 | You should see the item group is now in the creative inventory menu. However, it is untranslated - you must add a translation key to your translations file - similarly to how you translated your first item. 46 | 47 | ![](./_assets/itemgroups_0.png) 48 | 49 | ## Adding a translation key. 50 | 51 | If you used `Text.translatable` for the `displayName` method of the item group builder, you will need to add the translation to your language file. 52 | 53 | ```json 54 | { 55 | "itemGroup.my_mod": "Fabric Community Wiki Items" 56 | } 57 | ``` 58 | 59 | Now, as you can see, the item group should be correctly named: 60 | 61 | ![](./_assets/itemgroups_1.png) -------------------------------------------------------------------------------- /items/tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tools and Weapons 3 | description: Learn how to create your own tools and set their durability and mining levels. 4 | order: 2 5 | --- 6 | 7 | # Tools 8 | 9 | Tools are essential for survival and progression, allowing players to gather resources, construct buildings, and defend themselves. 10 | 11 | ## Creating a tool material. 12 | 13 | You can create a tool material by creating a new class that inherits it - in this example, I'll be creating "Guidite" tools: 14 | 15 | ```java 16 | public class GuiditeMaterial implements ToolMaterial { 17 | // Your IDE should override the interface's methods for you. 18 | } 19 | ``` 20 | 21 | The tool material tells the game the following information: 22 | 23 | - #### Durability - `getDurability()` 24 | 25 | How many times the tool can be used before breaking. 26 | 27 | **Example** 28 | 29 | ```java 30 | @Override 31 | public int getDurability() { 32 | return 455; 33 | } 34 | ``` 35 | 36 | - #### Mining Speed - `getMiningSpeedMultiplier()` 37 | 38 | If the tool is used to break blocks, how fast should it break the blocks? 39 | 40 | For reference purposes, the diamond tool material has a mining speed of `8.0F` whilst the stone tool material has a mining speed of `4.0F`. 41 | 42 | **Example** 43 | 44 | ```java 45 | @Override 46 | public float getMiningSpeedMultiplier() { 47 | return 5.0F; 48 | } 49 | ``` 50 | 51 | - #### Attack Damage - `getAttackDamage()` 52 | 53 | How many points of damage should the tool do when used as a weapon against another entity? 54 | 55 | **Example** 56 | 57 | ```java 58 | @Override 59 | public float getAttackDamage() { 60 | return 1.5F; 61 | } 62 | ``` 63 | 64 | - #### Mining Level - `getMiningLevel()` 65 | 66 | What blocks can be broken by this tool? Can it mine diamonds? 67 | 68 | A mining level of 3+ is needed to require obsidian whilst a level of 2 is required to mine diamonds. 69 | 70 | **Example** 71 | 72 | ```java 73 | @Override 74 | public int getMiningLevel() { 75 | return 3; 76 | } 77 | ``` 78 | 79 | - #### Enchantability - `getEnchantability()` 80 | 81 | How easy is it to get better and higher level enchantments with this item? 82 | 83 | **Example** 84 | 85 | ```java 86 | @Override 87 | public int getEnchantability() { 88 | return 22; 89 | } 90 | ``` 91 | 92 | - #### Repair Ingredient(s) - `getRepairIngredient()` 93 | 94 | What item or items are used to repair the tool? 95 | 96 | **Example** 97 | 98 | ```java 99 | @Override 100 | public Ingredient getRepairIngredient() { 101 | return Ingredient.ofItems(ModItems.POOP); 102 | } 103 | ``` 104 | 105 | Once you have created your tool material and tweaked it to your likings, you can create an instance of it to be used in the tool item constructors. 106 | 107 | ```java 108 | public class GuiditeMaterial implements ToolMaterial { 109 | public static final GuiditeMaterial INSTANCE = new GuiditeMaterial(); 110 | 111 | // ... override methods etc. 112 | } 113 | ``` 114 | 115 | ## Creating tool items. 116 | 117 | Using the same way you registered your first item, you should register each tool similarly: 118 | 119 | ```java 120 | public class ModItems { 121 | // Each tool item takes in different parameters. 122 | // Make sure to read what they are! 123 | public static final Item GUIDITE_SWORD = register(new SwordItem(GuiditeMaterial.INSTANCE, 2, 0.5F, new FabricItemSettings()), "guidite_sword"); 124 | 125 | // ... GUIDITE_AXE etc. 126 | } 127 | ``` 128 | 129 | Remember to add them to an item group if you want to access them from the creative inventory! 130 | 131 | ```java 132 | public static void initialize() { 133 | ItemGroupEvents 134 | // Register a "modify" event for the Tools item group. 135 | .modifyEntriesEvent(ItemGroups.TOOLS) 136 | // Add the item to the group when you get access to it. 137 | .register((itemGroup) -> itemGroup.add(ModItems.GUIDITE_SWORD)); 138 | } 139 | ``` 140 | 141 | You will also have to add a texture, item translation and item model. However, for the item model, you'll want to use the `item/handheld` model as your parent. For example, I will be using the following model and texture for the "Guidite Sword" item: 142 | 143 | ```json 144 | { 145 | "parent": "item/handheld", 146 | "textures": { 147 | "layer0": "mod_id:item/guidite_sword" 148 | } 149 | } 150 | ``` 151 | 152 |
153 | 154 | ![](./_assets/tools_0.png) 155 | 156 | 157 | Download Texture 158 | 159 | 160 |
161 | 162 |
163 | 164 | That's pretty much it! If you go in-game you should see your tool item(s) in the tools tab of the creative inventory menu. 165 | 166 | ![](./_assets/tools_1.png) 167 | 168 | ## Next Steps 169 | 170 | - Can you make another tool material? 171 | - Can you repair your tool in the anvil using the repair ingredient(s)? -------------------------------------------------------------------------------- /misc-topics/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Miscellaneous Topics 3 | prev: false 4 | next: false 5 | --- 6 | 7 | # Miscellaneous Topics - About This Section 8 | 9 | The miscellaneous topics section contains a variety of topics that don't fit into any other category, or are too small to warrant their own section but are still considered worthy of being documented on the wiki. 10 | 11 | These topics are not ordered in any particular way, and can be read in any order, and usually aren't version specific. -------------------------------------------------------------------------------- /misc-topics/text-and-translations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Text and Translations 3 | description: Comprehensive documentation for Minecraft's handling of formatted text and translations. 4 | prev: false 5 | next: false 6 | --- 7 | 8 | 11 | 12 | # Text and Translations 13 | 14 | Whenever Minecraft displays text ingame, it's probably defined using a `Text` object. 15 | This custom type is used instead of a `String` to allow for more advanced formatting, 16 | including colors, boldness, obfuscation, and click events. They also allow easy access 17 | to the translation system, making it simple to translate any interface elements into 18 | different languages. 19 | 20 | If you've worked with datapacks or functions before, you may see parallels with the 21 | json text format used for displayNames, books, and signs among other things. As you 22 | can probably guess, this is just a json representation of a `Text` object, and can be 23 | converted to and from using `Text.Serializer`. 24 | 25 | When making a mod, it is generally preferred to construct your `Text` objects directly 26 | in code, making use of translations whenever possible. 27 | 28 | ## Text literals 29 | 30 | The simplest way to create a `Text` object is to make a literal. This is just a string 31 | that will be displayed as-is, by default without any formatting. 32 | 33 | These are created using the `Text.of` or `Text.literal` methods, which both act slightly 34 | differently. `Text.of` accepts nulls as input, and will return a `Text` instance. In 35 | contrast, `Text.literal` should not be given a null input, but returns a `MutableText`, 36 | this being a subclass of `Text` that can be easily styled and concatenated. More about 37 | this later. 38 | 39 | ```java 40 | Text literal = Text.of("Hello, world!"); 41 | MutableText mutable = Text.literal("Hello, world!"); 42 | // Keep in mind that a MutableText can be used as a Text, making this valid: 43 | Text mutableAsText = mutable; 44 | ``` 45 | 46 | ## Translatable Text 47 | 48 | When you want to provide multiple translations for the same string of text, you can use the `Text.translatable` method to reference a translation key in any language file. If the key doesn't exist, the translation key is converted to a literal. 49 | 50 | ```java 51 | Text translatable = Text.translatable("my_mod.text.hello"); 52 | 53 | // Similarly to literals, translatable text can be easily made mutable. 54 | MutableText mutable = Text.translatable("my_mod.text.bye"); 55 | ``` 56 | 57 | The language file, `en_us.json`, looks like the following: 58 | 59 | ```json 60 | { 61 | "my_mod.text.hello": "Hello!", 62 | "my_mod.text.bye": "Goodbye :(" 63 | } 64 | ``` 65 | 66 | ## Serializing Text 67 | 68 | As mentioned before, you can serialize text to JSON using the `Text.Serializer` class: 69 | 70 | ```java 71 | MutableText mutable = Text.translatable("my_mod.text.bye"); 72 | String jsonString = Text.Serializer.toJson(mutable); 73 | ``` 74 | 75 | This produces JSON that can be used datapacks, commands and other places that accept the JSON format of text instead of literal or translatable text. 76 | 77 | ## Deserializing Text 78 | 79 | Furthermore, to deserialize a JSON text object into an actual `Text` class, you can use the `fromJson` method: 80 | 81 | ```java 82 | String jsonString = Text.Serializer.toJson(mutable); 83 | 84 | // Deserializing from JSON will always produce a mutable text object. 85 | MutableText result = Text.Serializer.fromJson(jsonString); 86 | ``` 87 | 88 | ## Formatting 89 | 90 | You may be familiar with Minecraft's formatting standards: 91 | 92 | You can apply these formattings using the `Formatting` enum on the `MutableText` class: 93 | 94 | ```java 95 | MutableText result = Text.literal("Hello World!") 96 | .formatted(Formatting.AQUA, Formatting.BOLD, Formatting.UNDERLINE); 97 | ``` 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 |
ColorNameChat CodeMOTD CodeHex Code
Black (black)§0\u00A70#000000
Dark Blue (dark_blue)§1\u00A71#0000AA
Dark Green (dark_green)§2\u00A72#00AA00
Dark Aqua (dark_aqua)§3\u00A73#00AAAA
Dark Red (dark_red)§4\u00A74#AA0000
Dark Purple (dark_purple)§5\u00A75#AA00AA
Gold (gold)§6\u00A76#FFAA00
Gray (gray)§7\u00A77#AAAAAA
Dark Gray (dark_gray)§8\u00A78#555555
Blue (blue)§9\u00A79#5555FF
Green (green)§a\u00A7a#55FF55
Aqua (aqua)§b\u00A7b#55FFFF
Red (red)§c\u00A7c#FF5555
Light Purple (light_purple)§d\u00A7d#FF55FF
Yellow (yellow)§e\u00A7e#FFFF55
White (white)§f\u00A7f#FFFFFF
Reset§r
**Bold**§l
~~Strikethrough~~§m
Underline§n
*Italic*§o
Obfuscated§k
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "docs:dev": "vitepress dev", 4 | "docs:build": "vitepress build", 5 | "docs:preview": "vitepress preview" 6 | }, 7 | "devDependencies": { 8 | "vitepress-sidebar": "^1.18.0", 9 | "vue": "^3.3.11" 10 | }, 11 | "dependencies": { 12 | "medium-zoom": "^1.1.0", 13 | "vitepress": "1.0.0-rc.31" 14 | } 15 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/public/icon.png -------------------------------------------------------------------------------- /rendering/_assets/basics_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/basics_0.png -------------------------------------------------------------------------------- /rendering/_assets/matrices_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_0.png -------------------------------------------------------------------------------- /rendering/_assets/matrices_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_1.png -------------------------------------------------------------------------------- /rendering/_assets/matrices_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_2.png -------------------------------------------------------------------------------- /rendering/_assets/matrices_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_3.png -------------------------------------------------------------------------------- /rendering/_assets/matrices_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_4.webp -------------------------------------------------------------------------------- /rendering/_assets/matrices_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/matrices_5.png -------------------------------------------------------------------------------- /rendering/_assets/world_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/world_0.png -------------------------------------------------------------------------------- /rendering/_assets/world_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/world_1.png -------------------------------------------------------------------------------- /rendering/_assets/world_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/world_2.png -------------------------------------------------------------------------------- /rendering/_assets/world_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/_assets/world_3.png -------------------------------------------------------------------------------- /rendering/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction To Rendering 3 | description: Learn the basics of rendering in Minecraft. 4 | next: 5 | text: "Matrices" 6 | link: "/rendering/matrices" 7 | --- 8 | 9 | # Introduction To Rendering 10 | 11 | ## First things first 12 | 13 | You **cannot** use legacy OpenGL rendering on modern versions of Minecraft anymore. Doing so will crash the game, due to the context not being set properly. Instead, all versions beyond (and including) 1.17 use `BufferBuilder`s, which format rendering data for themselves and upload it to OpenGL to draw. 14 | 15 | This means that you **must** use the rendering system Minecraft already provides, or implement your own phone line to `GL.glDrawElements()`. 16 | 17 | ## Basic Rendering 18 | 19 | We're going to go slow at first, let's start on the HUD. Since there are no transformations to be done, this should be easy. Right? *Right?* 20 | 21 | Fabric API is needed for this example. 22 | 23 | Let's start by making an event listener: 24 | ```java 25 | @Override 26 | public void onInitializeClient() { 27 | HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { 28 | // See below 29 | }); 30 | } 31 | ``` 32 | 33 | This will just make a new event listener for the HudRender event, nothing special just yet. 34 | 35 | It gets interesting when we actually make use of the rendering API: 36 | 37 | ### 1. The Tessellator 38 | The tessellator manages the main `BufferBuilder` of the game. It's used everywhere, where content is drawn. To get the tessellator, you can call `Tessellator.getInstance()`: `Tessellator tessellator = Tessellator.getInstance();` 39 | 40 | ### 2. The BufferBuilder 41 | The buffer builder holds all the important data we need for rendering. Luckily for us, the Tessellator already has a BufferBuilder, so let's use it: `BufferBuilder buffer = tessellator.getBuffer();` 42 | 43 | ### 3. Initializing the buffer 44 | Once we have the buffer, we obviously want to draw something to it. This is where we call `buffer.begin(VertexFormat.DrawMode, VertexFormat)`. The DrawMode specifies how many vertecies we want to have per face, and how they get drawn by OpenGL: 45 | - **`DrawMode.LINES`**: 2 vertecies per element, connected by a single line. 46 | - **`DrawMode.LINE_STRIP`**: 2 vertecies for the first element, 1 vertecie for additional ones, all vertecies are connected by one, continuous line. 47 | - **`DrawMode.DEBUG_LINES`**: 2 vertecies per element, connected by a single line, which is always exactly one pixel wide on the screen 48 | - **`DrawMode.DEBUG_LINE_STRIP`**: See **`DrawMode.LINE_STRIP`** 49 | - **`DrawMode.TRIANGLES`**: 3 vertecies per element, a regular "nacho" tri. 50 | - **`DrawMode.TRIANGLE_STRIP`**: *at least* 3 vertecies, a "strip" of vertecies. A bit hard to explain, we'll see an example of this one later 51 | - **`DrawMode.TRIANGLE_FAN`**: *at least* 3 vertecies, draws the convex hull of the given vertecies. 52 | - **`DrawMode.QUADS`**: 4 vertecies per element, a regular quad. 53 | 54 | The VertexFormat specifies which elements we specify in our data buffer, and how they should be sent to OpenGL: 55 | - **`VertexFormats.BLIT_SCREEN`**: Position (3 floats), UV (2 floats), Color (4 ubytes) 56 | - **`POSITION_COLOR_TEXTURE_LIGHT_NORMAL`**: Position, Color, Texture UV, Texture Light (2 shorts), Texture Normal (3 sbytes) 57 | - **`POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL`**: Position, Color, Texture UV, Overlay (2 shorts), Texture Light, Normal (3 sbytes) 58 | - **`POSITION_TEXTURE_COLOR_LIGHT`**: Position, Texture UV, Color, Texture Light 59 | - **`POSITION`**: Just a Position 60 | - **`POSITION_COLOR`**: Position, a solid Color 61 | - **`LINES`**: Position, Color, Normal 62 | - **`POSITION_COLOR_LIGHT`**: Position, Color, Light 63 | - **`POSITION_TEXTURE`**: Position, UV 64 | - **`POSITION_COLOR_TEXTURE`**: Position, Color, UV 65 | - **`POSITION_TEXTURE_COLOR`**: Position, UV, Color 66 | - **`POSITION_COLOR_TEXTURE_LIGH`T**: Position, Color, UV, Light 67 | - **`POSITION_TEXTURE_LIGHT_COLOR`**: Position, UV, Light, Color 68 | - **`POSITION_TEXTURE_COLOR_NORMAL`**: Position, UV, Color, Normal 69 | 70 | This example uses the draw mode `QUADS` and vertex format `POSITION_COLOR_TEXTURE`, to draw a simple square texture onto the screen: `buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE);` 71 | 72 | ### 4. Actually drawing to the buffer 73 | 74 | We can build up the buffer vertex by vertex. To do this, we just call `buffer.vertex(matrix, float, float, float)`, the matrix being the transformation matrix (we'll see this one later), and the 3 floats being the position on the hud in (x, y, z) coordinates. 75 | 76 | This returns a vertex builder, which we can use to specify additional information. It's important to follow our defined VertexFormat **in order**, else opengl may not entirely understand what we want to do. After building the vertex, we call `.next()` to finish and move on to the next vertex. 77 | 78 | It's also recommended to know what `culling` is, since faces might not render if ordered incorrectly. 79 | 80 | #### 4.1. The transformation matrix 81 | 82 | ::: info 83 | This is a brief TLDR on the MatrixStack classes. For more information, see the [Matrices](/rendering/matrices) page. 84 | ::: 85 | 86 | A transformation matrix is just transforming the coordinates we give into the vertex call. The transformations can scale our model, move it around and rotate it. To obtain the current transformation matrix, you can call `drawContext.getMatrices().peek().getPositionMatrix()`: `Matrix4f positionMatrix = drawContext.getMatrices().peek().getPositionMatrix();` 87 | 88 | #### 4.2: Actually drawing 89 | 90 | We'll just make 4 vertecies at (20, 20), (20, 60), (60, 60) and (60, 20) to specify the corners of our image, then specify the color of that specific vertex, followed by the correct UV coordinates for the texture we want to draw: 91 | ```java 92 | buffer.vertex(positionMatrix, 20, 20, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 93 | buffer.vertex(positionMatrix, 20, 60, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 94 | buffer.vertex(positionMatrix, 60, 60, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 95 | buffer.vertex(positionMatrix, 60, 20, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 96 | ``` 97 | The UV coordinates specify the position of the image at that vertex, (0, 0) means the top left corner, (1, 1) the bottom right, (1, 0) the top right corner, etc. Changing these coordinates at random might distort the image. 98 | 99 | The color we set in .color changes as well, changing the texture color inbetween vertecies. This results in a fun color shift effect we'll observe later. To disable that effect, you can set all of the colors to 1f (max). 100 | 101 | ### 5. Finishing 102 | After drawing the vertecies, we need to actually draw them to the screen. This is where `tessellator.draw()` comes in: It ends the buffer, draws it to the screen and prepares everything to be used again. 103 | 104 | This is the point where we need to actually define a texture to draw, and prepare the GL flags. For this example, we want to draw the "icon.png" texture, so we'll point the renderer at our icon.png image, using `RenderSystem.setShaderTexture`: `RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png"))` 105 | 106 | The 0 in setShaderTexture specifies the main texture of the drawing shader (more to that later). There are other textures you can use, but they might not do what you expect them to. 107 | 108 | The identifier just points to our icon.png texture. For it to work properly though, you need to install the fabric-resource-loader fabric api component, if it isn't already installed by default. 109 | 110 | We also need to set the drawing shader, that actually renders our contents. We can use `RenderSystem.setShader` for this. The shader can be obtained from `GameRenderer`, and usually has the same name as the VertexFormat specified earlier: `RenderSystem.setShader(GameRenderer::getPositionColorTexProgram)` 111 | 112 | It's also recommended to clear the preset color, else your rendered content might look slightly tinted: `RenderSystem.setShaderColor(1f, 1f, 1f, 1f)` 113 | 114 | After all of this, we finally call `tessellator.draw()`. 115 | 116 | ## Finished Example 117 | ```java 118 | HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { 119 | Matrix4f positionMatrix = drawContext.getMatrices().peek().getPositionMatrix(); 120 | Tessellator tessellator = Tessellator.getInstance(); 121 | BufferBuilder buffer = tessellator.getBuffer(); 122 | 123 | buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 124 | buffer.vertex(positionMatrix, 20, 20, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 125 | buffer.vertex(positionMatrix, 20, 60, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 126 | buffer.vertex(positionMatrix, 60, 60, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 127 | buffer.vertex(positionMatrix, 60, 20, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 128 | 129 | RenderSystem.setShader(GameRenderer::getPositionColorTexProgram); 130 | RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png")); 131 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 132 | 133 | tessellator.draw(); 134 | }); 135 | ``` 136 | 137 | ### Rendered content 138 | 139 | ::: info 140 | Changing the color of the texture will multiply the actual pixel color with the tint color, which is why the black text is still black in this image, and the white background is entirely tinted 141 | ::: 142 | 143 | ![](./_assets/basics_0.png) -------------------------------------------------------------------------------- /rendering/matrices.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Matrices 3 | description: Learn how to transform rendered content using Matrices 4 | next: 5 | text: "Worldspace Rendering" 6 | link: "/rendering/world" 7 | prev: 8 | text: "Introduction To Rendering" 9 | link: "/rendering" 10 | --- 11 | 12 | # Matrices 13 | 14 | Matrices provide an easy way to transform rendered elements. They also allow content to be transformed into world space properly. 15 | 16 | Assuming you're coming from the [Introduction To Rendering](/rendering/) page, you've already met them. In fact, they're everywhere, which is a good thing, since that means that we can transform about anything. 17 | 18 | ## The Minecraft Implementation 19 | Minecraft has a wrapper around this entire mechanism, called the `MatrixStack`. It's a stack of matrices, which means that you can `push()` and `pop()` from it. These 2 methods will come in very handy later, since they essentially allow you to back up (`push()`) the current state, and then restore the correct backup later (`pop()`). 20 | 21 | ## Using a MatrixStack 22 | When rendering anything, you usually have to pass in a MatrixStack from somewhere else. Since we also have access to the MatrixStack, we can make a backup of it (`push()`), transform it in any way we want, render with it, then restore it before passing it along to the next component (`pop()`). 23 | 24 | Let's take our old example from the [Introduction To Rendering](/rendering/) page for this example: 25 | 26 | ```java 27 | HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { 28 | MatrixStack matrixStack = drawContext.getMatrices(); 29 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 30 | Tessellator tessellator = Tessellator.getInstance(); 31 | BufferBuilder buffer = tessellator.getBuffer(); 32 | 33 | buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 34 | buffer.vertex(positionMatrix, 20, 20, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 35 | buffer.vertex(positionMatrix, 20, 60, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 36 | buffer.vertex(positionMatrix, 60, 60, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 37 | buffer.vertex(positionMatrix, 60, 20, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 38 | 39 | RenderSystem.setShader(GameRenderer::getPositionColorTexProgram); 40 | RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png")); 41 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 42 | 43 | tessellator.draw(); 44 | }); 45 | ``` 46 | 47 | We can already see a Matrix4f being made from our MatrixStack we got from the event, so let's try modifying it. 48 | 49 | We have 3 ways to modify a MatrixStack: `translate(x, y, z)`, `scale(x, y, z)` and `multiply(Quaternion)`. `multiply` is just a fancy word for "rotate the entire stack with the given quaternion". 50 | 51 | ::: info 52 | If you're struggling to understand what quaternions are, [checkout this video by 3Blue1Brown](https://www.youtube.com/watch?v=d4EgbgTm0Bg) 53 | ::: 54 | 55 | ## Scaling & Translating 56 | 57 | Before anything, let's wrap our code in `matrixStack.push()` and `.pop()`: 58 | 59 | ```java 60 | // ... 61 | matrixStack.push(); 62 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 63 | // ... 64 | tessellator.draw(); 65 | matrixStack.pop(); 66 | // ... 67 | ``` 68 | 69 | Then, let's try scaling the matrixStack on the x axis, to stretch the image out: 70 | 71 | ```java 72 | // ... 73 | matrixStack.push(); 74 | matrixStack.scale(2, 1, 1); 75 | // ... 76 | ``` 77 | 78 | Doing this results in the following render: 79 | ![](./_assets/matrices_0.png) 80 | 81 | If you're looking really close, you might've noticed that the spacing on the left looks a little... off? 82 | 83 | You're correct, scaling all of the vertecies has the side effect that any precomputed padding is ruined. To fix this, we need to either 84 | 1. Translate the Matrix to position the element correctly (positioning the element itself at 0, 0, 0), or 85 | 2. Translate the Matrix to account for the added padding 86 | 87 | Let's look at option 2 for now. 88 | 89 | Since we have doubled the scale on the x axis, we have added 20 additional pixels to the padding. To remove them, we just need to translate the matrix 20 px to the left: `translate(-20, 0, 0)`. 90 | 91 | It's important to do this **before** scaling the matrix, since matrices will apply previous transformations to new transformations as well. 92 | 93 | Adding the translate call before the scale call results in this result: 94 | ![](./_assets/matrices_1.png) 95 | 96 | Since that looks good, let's try to rotate it instead. 97 | 98 | ## Rotation 99 | 100 | Assuming you know what a quaternion is, we can use them to rotate our drawn content. Lucky for us, minecraft has an utility to help with quaternions: `RotationAxis`. 101 | 102 | We'll be using `RotationAxis.POSITIVE_Z` to rotate the image clockwise on the screen. The reason we're using `POSITIVE_Z`, is because `RotationAxis` generates quaternions based on the axis we rotate around, which is the Z axis in our case: 103 | 104 | ![](./_assets/matrices_5.png) 105 | 106 | By calling `multiply(RotationAxis.POSITIVE_Z.rotationDegrees(45))`, we can effectively rotate the entire drawn content by 45 degrees clockwise, but something goes horribly wrong: 107 | ![](./_assets/matrices_2.png) 108 | 109 | Looking at the previous attempt, we can easily connect the dots here: We're rotating the element positioned at (20, 20) from the origin (0, 0), which will rotate the element in an orbit $\sqrt{20^2 + 20^2}$ pixels from the origin. 110 | 111 | To fix this, we have to 112 | 1. Translate the Matrix to shift the entire element into the right position 113 | 2. Rotate it 114 | 3. Translate the Matrix to shift the entire element onto (0, 0), where we want to rotate it from 115 | 116 | Remember: previous transformations apply to the future ones, so the 3rd step is rotated from the 2nd, which is translated from the 1st 117 | 118 | All in all, an example of this would look like this: 119 | 120 | ```java 121 | matrixStack.translate(40, 40, 0); // shift the entire image back 122 | matrixStack.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(45)); // rotate the image 123 | matrixStack.translate(-40, -40, 0); // shift the entire element -40 pixels to the left and top, so the center of the image is at (0, 0) 124 | ``` 125 | 126 | After doing this, we finally get a proper result: 127 | 128 | ![](./_assets/matrices_3.png) 129 | 130 | And since this is rendered each frame, we can easily animate it: 131 | 132 | ![](./_assets/matrices_4.webp) 133 | 134 | ## Full Example 135 | 136 | ```java 137 | HudRenderCallback.EVENT.register((drawContext, tickDelta) -> { 138 | MatrixStack matrixStack = drawContext.getMatrices(); 139 | matrixStack.push(); 140 | 141 | matrixStack.translate(40, 40, 0); 142 | matrixStack.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((System.currentTimeMillis() % 5000) / 5000f * 360f)); 143 | matrixStack.translate(-40, -40, 0); 144 | 145 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 146 | Tessellator tessellator = Tessellator.getInstance(); 147 | BufferBuilder buffer = tessellator.getBuffer(); 148 | 149 | buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 150 | buffer.vertex(positionMatrix, 20, 20, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 151 | buffer.vertex(positionMatrix, 20, 60, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 152 | buffer.vertex(positionMatrix, 60, 60, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 153 | buffer.vertex(positionMatrix, 60, 20, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 154 | 155 | RenderSystem.setShader(GameRenderer::getPositionColorTexProgram); 156 | RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png")); 157 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 158 | 159 | tessellator.draw(); 160 | matrixStack.pop(); 161 | }); 162 | ``` -------------------------------------------------------------------------------- /rendering/particles/_assets/creating_particle_factories_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/particles/_assets/creating_particle_factories_1.png -------------------------------------------------------------------------------- /rendering/particles/_assets/creating_particle_factories_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/particles/_assets/creating_particle_factories_2.png -------------------------------------------------------------------------------- /rendering/particles/_assets/creating_particles_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/particles/_assets/creating_particles_0.png -------------------------------------------------------------------------------- /rendering/particles/_assets/creating_particles_0_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/particles/_assets/creating_particles_0_small.png -------------------------------------------------------------------------------- /rendering/particles/_assets/creating_particles_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/rendering/particles/_assets/creating_particles_1.png -------------------------------------------------------------------------------- /rendering/particles/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating Custom Particles 3 | description: Learn how to add and use a new particle with the registry. 4 | next: 5 | text: "Creating Particle Factories" 6 | link: "/rendering/particles/factories" 7 | --- 8 | 9 | # Creating Custom Particles 10 | 11 | Particles are a powerful tool if used correctly. It can add ambience to a beautiful scene, or add tension to an edge of your seat boss battle. Let's add one! 12 | 13 | ## Register a custom particle 14 | 15 | 16 | To add a custom particle to your mod, you first need to register a ParticleType in your mod initializer class. 17 | 18 | ```java 19 | public class MyMod implements ModInitializer { 20 | 21 | public static final String MOD_ID = "mod_id"; 22 | public static final DefaultParticleType MY_PARTICLE = FabricParticleTypes.simple(); 23 | 24 | @Override 25 | public void onInitialize() { 26 | Registry.register(Registries.PARTICLE_TYPE, new Identifier(MOD_ID, "my_particle"), MY_PARTICLE); 27 | } 28 | } 29 | ``` 30 | 31 | The "my_particle" in lowercase letters is the json path for the particle's texture. You will be creating a new json file with that exact name later. 32 | 33 | ## Client-side registration 34 | 35 | After you have registered the particle in the `ModInitializer` entrypoint, you will also need to register the particle in the `ClientModInitializer` entrypoint. 36 | 37 | ```java 38 | public class MyModClient implements ClientModInitializer { 39 | 40 | @Override 41 | public void onInitializeClient() { 42 | ParticleFactoryRegistry.getInstance().register(MyMod.MY_PARTICLE, EndRodParticle.Factory::new); 43 | } 44 | } 45 | ``` 46 | 47 | In this example, we are registering our particle client-side. We are then giving it some life with the end rod particle's factory. This means that the particle will behave exactly like the end rod particle would. You can replace the particle's factory with another particle's factory, or even your own particle factory! 48 | 49 | ## Creating a json file and adding textures 50 | 51 | You will need to create 3 folders in your resources folder. 52 | 53 | Let's begin with creating the folders necessary for the particle's texture(s). Add the new `resources/assets//textures/particle` folders to your directory. Place the particle's textures that you want to use in the `particle` folder. 54 | 55 | For this example, we will only be adding one texture, named "myparticletexture.png". It'll be a simple pixel art smiley face. 56 | 57 |
58 | 59 | ![](./_assets/creating_particles_0.png) 60 | 61 | Download Texture 62 | 63 |
64 | 65 | In the `resources/assets//particles` folder, create a new json file named `my_particle.json` - this contains the textures that your particle will use. 66 | 67 | In this file, you will need some code to help Minecraft know which texture(s) to put onto your particle. 68 | 69 | ```json 70 | { 71 | "textures": [ 72 | ":myparticletexture" 73 | ] 74 | } 75 | ``` 76 | 77 | You can add more textures to animate the particle as well! 78 | 79 | ```json 80 | { 81 | "textures": [ 82 | ":myparticletexture1", 83 | ":myparticletexture2", 84 | ":myparticletexture3" 85 | ] 86 | } 87 | ``` 88 | 89 | ## Testing the new particle 90 | 91 | Once you have completed the json file and saved your work, you are good to go! Load up minecraft and test everything out! 92 | 93 | You can see if everything has worked by typing the command `/particle :my_particle ~ ~1 ~`. The particle will spawn inside the player with this command, so you may need to walk backwards to actually see it. You can also use a command block to summon the particle with the exact same command! 94 | 95 | ![](./_assets/creating_particles_1.png) 96 | -------------------------------------------------------------------------------- /rendering/world.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Worldspace Rendering 3 | description: Learn how to render content in the world. 4 | prev: 5 | text: "Matrices" 6 | link: "/rendering/matrices" 7 | --- 8 | 9 | # Worldspace Rendering 10 | 11 | ::: warning 12 | This page assumes you have a basic understanding of [matrices.](/rendering/matrices) 13 | ::: 14 | 15 | ## What's the challenge? 16 | 17 | Lets say you want to mark a location in the world. How are you going to do that? 18 | 19 | You could look for existing implementations for this in the minecraft source code, but techniques like that are sparse and don't show up often. That's why this tutorial exists. 20 | 21 | ## How? 22 | 23 | Let's break the problem down first. "We want to draw content in the world" can be simplified down to "We want to render content relative to the camera's look angle", and that already sums it up perfectly: We want to draw content relative to where the camera is looking. 24 | 25 | When thinking about the problem, the camera's yaw and pitch might come into mind. In fact, that's what we're going to be using. Assuming that the player is always at the world origin (0, 0, 0), and that the content around the player moves instead of the player himself, we can easily figure out what we need to do: 26 | 1. Multiply the Matrix to face into the right direction 27 | 2. Render the content relative to the camera's position 28 | 29 | ## Actually implementing 30 | 31 | First, we need an event listener to actually render anything. I'm using `WorldRenderEvents.END` here: 32 | 33 | ```java 34 | WorldRenderEvents.END.register(context -> { 35 | // see below 36 | }); 37 | ``` 38 | 39 | Next, we will re-use the example from the [Introduction To Rendering](/rendering/) page: 40 | 41 | ```java 42 | WorldRenderEvents.END.register(context -> { 43 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 44 | Tessellator tessellator = Tessellator.getInstance(); 45 | BufferBuilder buffer = tessellator.getBuffer(); 46 | 47 | buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 48 | buffer.vertex(positionMatrix, 20, 20, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 49 | buffer.vertex(positionMatrix, 20, 60, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 50 | buffer.vertex(positionMatrix, 60, 60, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 51 | buffer.vertex(positionMatrix, 60, 20, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 52 | 53 | RenderSystem.setShader(GameRenderer::getPositionColorTexProgram); 54 | RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png")); 55 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 56 | 57 | tessellator.draw(); 58 | }); 59 | ``` 60 | 61 | At this point you've probably noticed that the matrixStack no longer exists. We could either use the one from the context (for ease of use), but we'll make our own this time, to walk through what actually happens: 62 | 63 | ```java 64 | // ... 65 | MatrixStack matrixStack = new MatrixStack(); 66 | // TODO: Modify matrixStack to place element properly 67 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 68 | // ... 69 | ``` 70 | 71 | If you now run this code, nothing seems to appear..? 72 | 73 | Correct, our code still has issues that need fixing. The first of those being that the matrixStack isn't transformed correctly. To fix that, we have to rotate it: 74 | 75 | ```java 76 | // ... 77 | Camera camera = context.camera(); 78 | MatrixStack matrixStack = new MatrixStack(); 79 | matrixStack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); 80 | matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); 81 | // ... 82 | ``` 83 | 84 | We've seen `RotationAxis` before, we're just rotating the rendered content around the X axis based on the pitch, then following that up with rotating it by the yaw **+ 180** on the Y axis. But why + 180? 85 | 86 | The yaw ranges from -180 to +180. We need to normalize it prior to actually rendering the content. When we add 180 to the yaw, we get a range from 0 to 360, instead of -180 to +180. 87 | 88 | Applying this, we still don't see anything. What's wrong this time? 89 | 90 | Well, we haven't really specified any position for the content to render in. Currently, it's just rendering the image 20 blocks above the camera at all times, perfectly perpendicular. That's why you don't see it. 91 | 92 | To fix this, let's start by specifying where we actually want to render the image: 93 | 94 | ```java 95 | // ... 96 | Camera camera = context.camera(); 97 | Vec3d targetPosition = new Vec3d(0, 100, 0); 98 | // ... 99 | ``` 100 | 101 | This indicates that we want to render at (0, 100, 0). To actually apply this position tho, we need to do the following things: 102 | 1. Subtract the camera's position from the target position 103 | 2. Transform the Matrix with that new delta 104 | 105 | We need to subtract the camera's position, because we're rendering relative to it. We need to calculate the position delta between the camera and the target render position in the world to correcly position the element relative to the camera. 106 | 107 | Adding those 2 things: 108 | 109 | ```java 110 | // ... 111 | Vec3d targetPosition = new Vec3d(0, 100, 0); 112 | Vec3d transformedPosition = targetPosition.subtract(camera.getPos()); 113 | // ... 114 | matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); 115 | matrixStack.translate(transformedPosition.x, transformedPosition.y, transformedPosition.z); 116 | // ... 117 | ``` 118 | 119 | 120 | Matrix transformations are subject to transformation by previous entry. 121 | 122 | 123 | After this, we have to change the vertex coordinates from absolute coordinates to relative coordinates, to render it correctly (and make it easier to work with): 124 | 125 | ```java 126 | buffer.vertex(positionMatrix, 0, 0, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 127 | buffer.vertex(positionMatrix, 0, 1, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 128 | buffer.vertex(positionMatrix, 1, 1, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 129 | buffer.vertex(positionMatrix, 1, 0, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 130 | ``` 131 | 132 | Replacing the old vertex calls with these ones, then running the code will finally render something at (0, 100, 0)! But there are still some issues. First of all, why is it upside down? 133 | ![](./_assets/world_0.png) 134 | 135 | The Y coordinate space on the hud is from top to bottom, increasing as you go down. In the world however, this is flipped upside down (literally): Instead of (for example) 0-100 top to bottom, we have 100-0 top to bottom. But when we flip our Y coordinates in the vertex calls, it disappears..? 136 | 137 | That is the 2nd issue: Culling. 138 | 139 | You've probably heard about it, it basically prevents faces from rendering when their vertecies are in clockwise order. It exists to prevent faces facing away from the camera from rendering, to save performance. 140 | 141 | That is not what we want tho, so we need to disable it with `RenderSystem.disableCull();`. Don't forget to re-enable it again with `RenderSystem.enableCull();` after `tessellator.draw();`! 142 | 143 | After doing that, our image finally renders correctly: 144 | ![](./_assets/world_1.png) 145 | 146 | There are a few remaining minor issues, such as the image not rendering through water, only inside of it and outside of it: 147 | ![](./_assets/world_2.png) 148 | 149 | And the fact that it doesn't render through walls at all. 150 | 151 | This might be undesireable for some applications, but luckily for you, you can fix that as well. Just prefix `tessellator.draw();` with `RenderSystem.depthFunc(GL11.GL_ALWAYS);`, and postfix it with `RenderSystem.depthFunc(GL11.GL_LEQUAL);`, to reset it. 152 | 153 | Why this works is out of the scope of this tutorial, but a tldr is that it basically disables the depth check while rendering our element. Resetting it back to `LEQUAL` (short for "less than or equal") will restore the default behaviour of not rendering pixels if their depth value is not less than or equal to the one already in the buffer. 154 | 155 | After applying those changes as well, this is how it looks: 156 | ![](./_assets/world_3.png) 157 | 158 | ## Full Example 159 | 160 | ```java 161 | WorldRenderEvents.END.register(context -> { 162 | Camera camera = context.camera(); 163 | 164 | Vec3d targetPosition = new Vec3d(0, 100, 0); 165 | Vec3d transformedPosition = targetPosition.subtract(camera.getPos()); 166 | 167 | MatrixStack matrixStack = new MatrixStack(); 168 | matrixStack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(camera.getPitch())); 169 | matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(camera.getYaw() + 180.0F)); 170 | matrixStack.translate(transformedPosition.x, transformedPosition.y, transformedPosition.z); 171 | 172 | Matrix4f positionMatrix = matrixStack.peek().getPositionMatrix(); 173 | Tessellator tessellator = Tessellator.getInstance(); 174 | BufferBuilder buffer = tessellator.getBuffer(); 175 | 176 | buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); 177 | buffer.vertex(positionMatrix, 0, 1, 0).color(1f, 1f, 1f, 1f).texture(0f, 0f).next(); 178 | buffer.vertex(positionMatrix, 0, 0, 0).color(1f, 0f, 0f, 1f).texture(0f, 1f).next(); 179 | buffer.vertex(positionMatrix, 1, 0, 0).color(0f, 1f, 0f, 1f).texture(1f, 1f).next(); 180 | buffer.vertex(positionMatrix, 1, 1, 0).color(0f, 0f, 1f, 1f).texture(1f, 0f).next(); 181 | 182 | RenderSystem.setShader(GameRenderer::getPositionColorTexProgram); 183 | RenderSystem.setShaderTexture(0, new Identifier("examplemod", "icon.png")); 184 | RenderSystem.setShaderColor(1f, 1f, 1f, 1f); 185 | RenderSystem.disableCull(); 186 | RenderSystem.depthFunc(GL11.GL_ALWAYS); 187 | 188 | tessellator.draw(); 189 | 190 | RenderSystem.depthFunc(GL11.GL_LEQUAL); 191 | RenderSystem.enableCull(); 192 | }); 193 | ``` -------------------------------------------------------------------------------- /sounds/_assets/custom_sounds_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/sounds/_assets/custom_sounds_0.png -------------------------------------------------------------------------------- /sounds/_assets/custom_sounds_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/sounds/_assets/custom_sounds_1.png -------------------------------------------------------------------------------- /sounds/_assets/custom_sounds_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/sounds/_assets/custom_sounds_2.png -------------------------------------------------------------------------------- /sounds/_assets/custom_sounds_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moddedmc-wiki/fabric-modding-wiki/285a342752fe7f771ea813904e5e44b634289c13/sounds/_assets/custom_sounds_3.png -------------------------------------------------------------------------------- /sounds/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Creating Custom Sounds 3 | description: Learn how to add and use a new sound with the registry. 4 | next: 5 | text: Playing SoundEvents 6 | link: "/sounds/using" 7 | --- 8 | 9 | # Creating Custom Sounds 10 | 11 | ## Preparing the audio file 12 | 13 | Your audio files need to be formatted in a specific way. OGG Vorbis is an open container format for multimedia data, such as audio, and is used in case of Minecraft's sound files. To avoid problems with how Minecraft handles distance of sound the audio data needs to have only a single channel (Mono). 14 | 15 | Many modern DAWs (Digital Audio Workstation) software can import and export using this file format. In the following example the free and open-source software "Audacity" will be used to bring the audio file into the right shape, however any other DAW should suffice as well. 16 | 17 | ![unprepared audio file in Audacity](./_assets/custom_sounds_0.png) 18 | 19 | In this example, a sound of a [whistle](https://freesound.org/people/strongbot/sounds/568995/) is imported into Audacity. It currently is saved as a `.wav` file and has two audio channels (Stereo). Edit the sound to your liking and make sure to delete one of the channels using the drop-down element at the top of the "track head". 20 | 21 | ![splitting Stereo track](./_assets/custom_sounds_1.png) 22 | 23 | ![deleting one of the channels](./_assets/custom_sounds_2.png) 24 | 25 | When exporting or rendering the audio file, make sure to choose the OGG file format. Some DAWs like REAPER might support multiple OGG audio layer formats. In this case OGG Vorbis should work just fine. 26 | 27 | ![exporting as OGG file](./_assets/custom_sounds_3.png) 28 | 29 | Also keep in mind that audio files can increase the file size of your mod drastically. If needed, compress the audio when editing and exporting the file to keep the file size of your finished product to a minimum. 30 | 31 | ## Adding the audio file to the mod 32 | 33 | Add the new `resources/assets//sounds` directory for the sounds in your mod, and put the exported audio file `metal_whistle.ogg` in there. 34 | 35 | Continue with creating the `resources/assets//sounds.json` file if it doesn't exist yet and add your sound to the sound entries. 36 | 37 | ```json 38 | { 39 | "metal_whistle": { 40 | "subtitle": "sound.mod_id.metal_whistle", 41 | "sounds": [ 42 | "mod_id:metal_whistle" 43 | ] 44 | } 45 | } 46 | ``` 47 | 48 | The subtitle entry provides more context for the player. The subtitle name is used in the language files in the `resources/assets//lang` directory and will be displayed if the in-game subtitle setting is turned on and this custom sound is being played. 49 | 50 | ## Register the custom sound 51 | 52 | To add the custom sound to the mod, register a SoundEvent in the class which implements the `ModInitializer` entrypoint. 53 | 54 | ```java 55 | public class MyMod implements ModInitializer { 56 | 57 | public static final String MOD_ID = "mod_id"; 58 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 59 | 60 | @Override 61 | public void onInitialize() { 62 | Registry.register(Registries.SOUND_EVENT, new Identifier(MyMod.MOD_ID, "metal_whistle"), SoundEvent.of(new Identifier(MyMod.MOD_ID, "metal-whistle"))); 63 | } 64 | } 65 | ``` 66 | 67 | ## Cleaning up the mess 68 | 69 | Depending on how many Registry entries there are, this can get messy quickly. To avoid that, we can create a helper class called `ModSounds` 70 | 71 | Add two new methods. One, which registers all the sounds and one which is used to initialize this class in the first place. After that you can comfortably add new custom SoundEvents as needed. 72 | 73 | ```java 74 | public class ModSounds { 75 | // ITEM_METAL_WHISTLE is the name of the custom sound event 76 | // and is called in the mod to use the custom sound 77 | public static SoundEvent ITEM_METAL_WHISTLE = registerSound("metal_whistle"); 78 | 79 | // actual registration of all the custom SoundEvents 80 | static SoundEvent registerSound(String id) { 81 | SoundEvent sound = SoundEvent.of(new Identifier(MyMod.MOD_ID, id)); 82 | return Registry.register(Registries.SOUND_EVENT, new Identifier(MyMod.MOD_ID, id), sound); 83 | } 84 | 85 | // called in the ModInitializer implementing class 86 | // to initialize the ModSounds class 87 | public static void initializeSounds() { 88 | MyMod.LOGGER.info("Registering " + MyMod.MOD_ID + " Sounds"); 89 | } 90 | } 91 | ``` 92 | 93 | This way, the `ModInitializer` implementing entrypoint class needs to only implement one line to register all custom SoundEvents. 94 | 95 | ```java 96 | public class MyMod implements ModInitializer { 97 | 98 | public static final String MOD_ID = "mod_id"; 99 | public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); 100 | 101 | @Override 102 | public void onInitialize() { 103 | MyModSounds.initializeSounds(); 104 | } 105 | } 106 | ``` 107 | 108 | ## Using the custom SoundEvent 109 | 110 | Use the `ModSounds` class to access the custom SoundEvent. 111 | 112 | Checkout the [Playing SoundEvents](/sounds/using) page to learn how to play sounds. -------------------------------------------------------------------------------- /sounds/using.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Playing SoundEvents 3 | description: Learn how to play sound events. 4 | prev: 5 | text: Creating Custom Sounds 6 | link: "/sounds/" 7 | --- 8 | 9 | # Playing SoundEvents 10 | 11 | Minecraft has a big selection of sounds which you can choose from. Check out the `SoundEvents` class to view all the vanilla sound event instances that Mojang has provided. 12 | 13 | ## Using sounds in your mod 14 | 15 | Make sure to execute the `playSound()` method on the logical server side when using sounds! 16 | 17 | In this example, the `useOnEntity()` and `useOnBlock()` method for a custom [interactive Item](/items/interactivity) is used to play a "placing copper block" and a pillager sound. 18 | 19 | ```java 20 | @Override 21 | public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { 22 | // As stated above, don't use the playSound() mothod on the client side - it wont work! 23 | if (!entity.getWorld().isClient()) { 24 | // Play the sound as if it was coming from the entity. 25 | entity.playSound(SoundEvents.ENTITY_PILLAGER_AMBIENT, 2f, 0.7f); 26 | } 27 | return super.useOnEntity(stack, user, entity, hand); 28 | } 29 | 30 | ``` 31 | 32 | The `playSound()` method is used with the `LivingEntity` object. Only the SoundEvent, the volume and the pitch need to be specified. You can also use the `playSound()` method from the world instance to have a higher level of control. 33 | 34 | ```java 35 | @Override 36 | public ActionResult useOnBlock(ItemUsageContext context) { 37 | // Tipp of the day: Check out "Guard Clauses" to keep your code clean. 38 | if (!context.getWorld().isClient()) { 39 | // Play the sound and specify location, category and who made the sound. 40 | // No entity made the sound, so we specify null. 41 | context.getWorld().playSound(null, context.getBlockPos(), 42 | SoundEvents.BLOCK_COPPER_PLACE, SoundCategory.PLAYERS, 43 | 1f, 1f); 44 | } 45 | return super.useOnBlock(context); 46 | } 47 | ``` 48 | 49 | ### SoundEvent and SoundCategory 50 | 51 | The SoundEvent defines which sound will be played. You can also [register your own SoundEvents](/sounds/) to include your own sound. 52 | 53 | Minecraft has several audio sliders in the in-game settings. The `SoundCategory` enum is used to determine which slider will adjust your sound's volume. 54 | 55 | ### Volume and Pitch 56 | 57 | The volume parameter can be a bit misleading. In the range of `0.0f - 1.0f` the actual volume of the sound can be changed. If the number gets bigger than that, the volume of `1.0f` will be used and only the distance, in which your sound can be heard, gets adjusted. The block distance can be roughly calculated by `volume * 16`. 58 | 59 | The pitch parameter increases or decreases the pitch value and also changes the duration of the sound. In the range of `(0.5f - 1.0f)` the pitch and the speed gets decreased, while bigger numbers will increase the pitch and the speed. Numbers below `0.5f` will stay at the pitch value of `0.5f`. --------------------------------------------------------------------------------