├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ ├── gradle.yml │ ├── matrix_prep.yml │ ├── release.yml │ └── scripts │ ├── matrix.py │ └── summary.py ├── .gitignore ├── CODEOWNERS ├── README.md ├── assets ├── Inventorio Gradle Modules.drawio ├── Inventorio Gradle Modules.png └── Inventorio Gradle Modules.svg ├── build.gradle.kts ├── common.gradle.kts ├── eclipse-prefs.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── settings.gradle.kts ├── settings.json ├── src └── main │ ├── java │ ├── de │ │ └── rubixdev │ │ │ └── inventorio │ │ │ ├── api │ │ │ ├── InventorioAPI.java │ │ │ ├── InventorioAddonSection.java │ │ │ └── InventorioTickHandler.java │ │ │ └── mixin │ │ │ ├── ExperienceOrbEntityMixin.java │ │ │ ├── PlayerEntityMixin.java │ │ │ ├── PlayerInventoryMixin.java │ │ │ ├── PlayerManagerMixin.java │ │ │ ├── ServerPlayNetworkHandlerMixin.java │ │ │ ├── ServerPlayerEntity_ScreenHandlerSyncHandlerMixin.java │ │ │ ├── accessor │ │ │ ├── CraftingScreenHandlerAccessor.java │ │ │ ├── ScreenHandlerAccessor.java │ │ │ ├── SimpleInventoryAccessor.java │ │ │ └── SlotAccessor.java │ │ │ ├── client │ │ │ ├── ClientPlayNetworkHandlerMixin.java │ │ │ ├── ClientPlayerInteractionManagerMixin.java │ │ │ ├── HandledScreenMixin.java │ │ │ ├── InGameHudMixinHP.java │ │ │ ├── InGameHudMixinLP.java │ │ │ ├── InventoryScreenMixin.java │ │ │ ├── MinecraftClientMixin.java │ │ │ ├── RecipeBookWidgetMixin.java │ │ │ └── accessor │ │ │ │ ├── HandledScreenAccessor.java │ │ │ │ ├── MinecraftClientAccessor.java │ │ │ │ └── ScreenAccessor.java │ │ │ └── optional │ │ │ ├── bowfix │ │ │ └── BowItemMixin.java │ │ │ ├── enderchest │ │ │ ├── EnderChestBlockMixin.java │ │ │ └── PlayerEntityMixin.java │ │ │ └── totem │ │ │ └── LivingEntityMixin.java │ └── me │ │ └── lizardofoz │ │ └── inventorio │ │ └── api │ │ ├── InventorioAPI.java │ │ ├── InventorioAddonSection.java │ │ └── InventorioTickHandler.java │ ├── kotlin │ ├── de │ │ └── rubixdev │ │ │ └── inventorio │ │ │ ├── InventorioMixinPlugin.kt │ │ │ ├── ScreenTypeProvider.kt │ │ │ ├── api │ │ │ └── ToolBeltSlotTemplate.kt │ │ │ ├── client │ │ │ ├── configscreen │ │ │ │ ├── GlobalSettingsScreen.kt │ │ │ │ ├── GlobalSettingsSyncPrompt.kt │ │ │ │ └── PlayerSettingsScreen.kt │ │ │ ├── control │ │ │ │ ├── InventorioControls.kt │ │ │ │ ├── InventorioKeyHandler.kt │ │ │ │ └── KeyCoBinding.kt │ │ │ └── ui │ │ │ │ ├── HotbarHUDRenderer.kt │ │ │ │ └── InventorioScreen.kt │ │ │ ├── config │ │ │ ├── AbstractSettings.kt │ │ │ ├── GlobalSettings.kt │ │ │ ├── PlayerSettings.kt │ │ │ └── SettingsEntry.kt │ │ │ ├── duck │ │ │ └── RecipeBookLeftOffsetOverride.kt │ │ │ ├── enchantment │ │ │ ├── DeepPocketsBookRecipe.kt │ │ │ └── DeepPocketsEnchantment.kt │ │ │ ├── integration │ │ │ ├── InventorioModIntegration.kt │ │ │ └── ModIntegration.kt │ │ │ ├── packet │ │ │ └── InventorioNetworking.kt │ │ │ ├── player │ │ │ ├── InventorioScreenHandler.kt │ │ │ ├── PlayerAddonSerializer.kt │ │ │ ├── PlayerInventoryAddon.kt │ │ │ └── inventory │ │ │ │ ├── PlayerInventoryExtension.kt │ │ │ │ ├── PlayerInventoryExtraStuff.kt │ │ │ │ ├── PlayerInventoryHandFeatures.kt │ │ │ │ └── PlayerInventoryInjects.kt │ │ │ ├── slot │ │ │ ├── ArmorSlot.kt │ │ │ ├── BlockedSlot.kt │ │ │ ├── DeepPocketsSlot.kt │ │ │ └── ToolBeltSlot.kt │ │ │ └── util │ │ │ ├── GeneralConstants.kt │ │ │ ├── HUDConstants.kt │ │ │ ├── MixinHelpers.kt │ │ │ ├── MixinTesters.kt │ │ │ ├── PlatformApi.kt │ │ │ ├── RandomStuff.kt │ │ │ ├── RangeIterator.kt │ │ │ └── UIConstants.kt │ └── me │ │ └── lizardofoz │ │ └── inventorio │ │ ├── api │ │ └── ToolBeltSlotTemplate.kt │ │ ├── client │ │ └── ui │ │ │ └── InventorioScreen.kt │ │ └── player │ │ ├── InventorioScreenHandler.kt │ │ └── PlayerInventoryAddon.kt │ └── resources │ ├── assets │ └── inventorio │ │ ├── lang │ │ ├── de_de.yml │ │ ├── en_us.yml │ │ ├── fr_fr.yml │ │ └── pt_br.yml │ │ └── textures │ │ └── gui │ │ ├── empty │ │ ├── axe.png │ │ ├── hoe.png │ │ ├── pickaxe.png │ │ ├── shovel.png │ │ └── sword.png │ │ ├── player_inventory.png │ │ ├── player_inventory_dark.png │ │ ├── sprites │ │ ├── lock_button.png │ │ ├── lock_button_active.png │ │ ├── lock_button_active_dark.png │ │ ├── lock_button_dark.png │ │ ├── toggle_button_active_off.png │ │ ├── toggle_button_active_off_dark.png │ │ ├── toggle_button_active_on.png │ │ ├── toggle_button_active_on_dark.png │ │ ├── toggle_button_off.png │ │ ├── toggle_button_off_dark.png │ │ ├── toggle_button_on.png │ │ └── toggle_button_on_dark.png │ │ ├── widgets.png │ │ └── widgets_dark.png │ ├── data │ ├── inventorio │ │ └── recipes │ │ │ └── deep_pockets_book.json │ └── minecraft │ │ └── advancements │ │ └── unlock_deep_pockets_book.json │ ├── icon.png │ ├── inventorio.mixins.json │ └── pack.mcmeta └── versions ├── 1.20.1-common └── gradle.properties ├── 1.20.1-fabric └── gradle.properties ├── 1.20.1-forge ├── gradle.properties └── src │ └── main │ ├── java │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ └── mixin │ │ └── forge │ │ └── curios │ │ ├── CPacketScrollMixin.java │ │ ├── CurioStacksHandlerMixin.java │ │ ├── CuriosEventHandlerMixin.java │ │ ├── HandledScreenMixin.java │ │ ├── InventorioScreenHandlerMixin.java │ │ ├── InventorioScreenMixin.java │ │ ├── InventorioScreenMixin_alternative.java │ │ ├── SPacketScrollMixin.java │ │ ├── SPacketSyncCuriosMixin.java │ │ ├── SPacketSyncModifiersMixinV1.java │ │ └── SPacketSyncModifiersMixinV2.java │ ├── kotlin │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ ├── ForgeEvents.kt │ │ ├── InventorioForge.kt │ │ ├── ScreenTypeProviderForge.kt │ │ ├── integration │ │ ├── ClumpsIntegration.kt │ │ └── curios │ │ │ ├── CustomCuriosButton.kt │ │ │ ├── ICuriosContainer.kt │ │ │ ├── ICuriosScreen.kt │ │ │ ├── InventorioScreenHandlerMixinHelper.kt │ │ │ └── InventorioScreenMixinHelper.kt │ │ ├── packet │ │ ├── GlobalSettingsS2CPacket.kt │ │ ├── InventorioNetworkingForge.kt │ │ ├── MoveItemToUtilityBeltC2SPacket.kt │ │ ├── OpenInventorioScreenC2SPacket.kt │ │ ├── SelectUtilitySlotPacket.kt │ │ ├── SwapItemsInHandsKeyC2SPacket.kt │ │ ├── SwappedHandsModeC2SPacket.kt │ │ ├── UpdateAddonStacksS2CPacket.kt │ │ └── UseBoostRocketC2SPacket.kt │ │ └── util │ │ └── PlatformApi.kt │ └── resources │ ├── META-INF │ └── mods.toml │ └── inventorio-forge.mixins.json ├── 1.20.2-fabric └── gradle.properties ├── 1.20.2-neoforge ├── gradle.properties └── src │ └── main │ ├── java │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ └── mixin │ │ └── neoforge │ │ └── curios │ │ ├── CPacketScrollMixin.java │ │ ├── CuriosClientPayloadHandlerMixin.java │ │ ├── CuriosServerPayloadHandlerMixin.java │ │ ├── SPacketScrollMixin.java │ │ ├── SPacketSyncCuriosMixin.java │ │ └── SPacketSyncModifiersMixin.java │ ├── kotlin │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ └── packet │ │ ├── GlobalSettingsS2CPacket.kt │ │ ├── InventorioNetworkingNeoForge.kt │ │ ├── MoveItemToUtilityBeltC2SPacket.kt │ │ ├── OpenInventorioScreenC2SPacket.kt │ │ ├── SelectUtilitySlotPacket.kt │ │ ├── SwapItemsInHandsKeyC2SPacket.kt │ │ ├── SwappedHandsModeC2SPacket.kt │ │ ├── UpdateAddonStacksS2CPacket.kt │ │ └── UseBoostRocketC2SPacket.kt │ └── resources │ ├── META-INF │ └── mods.toml │ └── inventorio-neoforge-12002.mixins.json ├── 1.20.4-common └── gradle.properties ├── 1.20.4-fabric ├── gradle.properties └── src │ └── main │ ├── java │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ └── mixin │ │ └── fabric │ │ └── trinkets │ │ ├── InventorioScreenHandlerMixin.java │ │ ├── InventorioScreenMixin.java │ │ └── SlotGroupMixin.java │ ├── kotlin │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ ├── InventorioFabric.kt │ │ ├── ScreenTypeProviderFabric.kt │ │ ├── integration │ │ ├── ClumpsIntegration.kt │ │ ├── ModMenuIntegration.kt │ │ └── trinkets │ │ │ └── InventorioScreenHandlerMixinHelper.kt │ │ ├── packet │ │ ├── GlobalSettingsS2CPacket.kt │ │ ├── InventorioNetworkingFabric.kt │ │ ├── MoveItemToUtilityBeltC2SPacket.kt │ │ ├── OpenInventorioScreenC2SPacket.kt │ │ ├── SelectUtilitySlotPacket.kt │ │ ├── SwapItemsInHandsKeyC2SPacket.kt │ │ ├── SwappedHandsModeC2SPacket.kt │ │ ├── UpdateAddonStacksS2CPacket.kt │ │ └── UseBoostRocketC2SPacket.kt │ │ └── util │ │ └── PlatformApi.kt │ └── resources │ ├── fabric.mod.json │ └── inventorio-fabric.mixins.json ├── 1.20.4-neoforge ├── gradle.properties └── src │ └── main │ ├── java │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ └── mixin │ │ └── neoforge │ │ └── curios │ │ ├── CurioStacksHandlerMixin.java │ │ ├── CuriosClientPayloadHandlerMixin.java │ │ ├── CuriosEventHandlerMixin.java │ │ ├── CuriosServerPayloadHandlerMixin.java │ │ ├── HandledScreenMixin.java │ │ ├── InventorioScreenHandlerMixin.java │ │ ├── InventorioScreenMixin.java │ │ └── InventorioScreenMixin_alternative.java │ ├── kotlin │ └── de │ │ └── rubixdev │ │ └── inventorio │ │ ├── InventorioNeoForge.kt │ │ ├── NeoForgeEvents.kt │ │ ├── ScreenTypeProviderNeoForge.kt │ │ ├── integration │ │ ├── ClumpsIntegration.kt │ │ └── curios │ │ │ ├── CustomCuriosButton.kt │ │ │ ├── ICuriosContainer.kt │ │ │ ├── ICuriosScreen.kt │ │ │ ├── InventorioScreenHandlerMixinHelper.kt │ │ │ └── InventorioScreenMixinHelper.kt │ │ ├── packet │ │ ├── GlobalSettingsS2CPacket.kt │ │ ├── InventorioNetworkingNeoForge.kt │ │ ├── MoveItemToUtilityBeltC2SPacket.kt │ │ ├── OpenInventorioScreenC2SPacket.kt │ │ ├── SelectUtilitySlotPacket.kt │ │ ├── SwapItemsInHandsKeyC2SPacket.kt │ │ ├── SwappedHandsModeC2SPacket.kt │ │ ├── UpdateAddonStacksS2CPacket.kt │ │ └── UseBoostRocketC2SPacket.kt │ │ └── util │ │ └── PlatformApi.kt │ └── resources │ ├── META-INF │ └── mods.toml │ └── inventorio-neoforge.mixins.json ├── mainProject ├── mappings-common-forge.txt └── mappings-common-neoforge.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: rubixdev 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: step.build 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | release: 7 | type: boolean 8 | required: false 9 | default: false 10 | target_subproject: 11 | description: see release.yml, leave it empty to build all 12 | type: string 13 | required: false 14 | default: '' 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up JDK 17 23 | uses: actions/setup-java@v4 24 | with: 25 | distribution: 'temurin' 26 | java-version: 17 27 | 28 | - name: Cache gradle files 29 | uses: actions/cache@v4 30 | with: 31 | path: | 32 | ~/.gradle/caches 33 | ~/.gradle/wrapper 34 | ./.gradle/loom-cache 35 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts', '**/gradle.properties', '**/*.accesswidener', 'settings.json') }} 36 | restore-keys: | 37 | ${{ runner.os }}-gradle- 38 | 39 | - name: Build with Gradle 40 | run: | 41 | chmod +x gradlew 42 | if [ -z "${{ inputs.target_subproject }}" ]; then 43 | echo "Building all subprojects" 44 | ./gradlew build --no-daemon 45 | else 46 | args=$(echo "${{ inputs.target_subproject }}" | tr ',' '\n' | sed 's/$/:build/' | paste -sd ' ') 47 | echo "Building $args" 48 | ./gradlew "$args" --no-daemon 49 | fi 50 | env: 51 | BUILD_ID: ${{ github.run_number }} 52 | BUILD_RELEASE: ${{ inputs.release }} 53 | 54 | - uses: actions/upload-artifact@v4 55 | with: 56 | name: build-artifacts 57 | path: versions/*/build/libs/ 58 | 59 | summary: 60 | runs-on: ubuntu-22.04 61 | needs: 62 | - build 63 | 64 | steps: 65 | - uses: actions/checkout@v4 66 | 67 | - name: Download build artifacts 68 | uses: actions/download-artifact@v4 69 | with: 70 | name: build-artifacts 71 | path: build-artifacts 72 | 73 | - name: Make build summary 74 | run: python3 .github/workflows/scripts/summary.py # ubuntu-22.04 uses Python 3.10.6 75 | env: 76 | TARGET_SUBPROJECT: ${{ inputs.target_subproject }} 77 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Dev Builds 2 | 3 | on: 4 | push: 5 | paths: 6 | - "*.gradle" 7 | - "gradle.properties" 8 | - "src/**" 9 | - "versions/**" 10 | - ".github/**" 11 | pull_request: 12 | 13 | 14 | jobs: 15 | build: 16 | uses: ./.github/workflows/build.yml 17 | -------------------------------------------------------------------------------- /.github/workflows/matrix_prep.yml: -------------------------------------------------------------------------------- 1 | name: step.matrix_prepare 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | target_subproject: 7 | description: see release.yml, for generating matrix entries 8 | type: string 9 | required: false 10 | default: '' 11 | outputs: 12 | matrix: 13 | description: The generated run matrix 14 | value: ${{ jobs.matrix_prep.outputs.matrix }} 15 | 16 | 17 | jobs: 18 | matrix_prep: 19 | runs-on: ubuntu-22.04 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - id: setmatrix 24 | run: python3 .github/workflows/scripts/matrix.py # ubuntu-22.04 uses Python 3.10.6 25 | env: 26 | TARGET_SUBPROJECT: ${{ inputs.target_subproject }} 27 | 28 | outputs: 29 | matrix: ${{ steps.setmatrix.outputs.matrix }} 30 | -------------------------------------------------------------------------------- /.github/workflows/scripts/matrix.py: -------------------------------------------------------------------------------- 1 | """ 2 | A script to scan through the versions directory and collect all folder names as the subproject list, 3 | then output a json as the github action include matrix 4 | """ 5 | __author__ = 'Fallen_Breath' 6 | 7 | import json 8 | import os 9 | import sys 10 | 11 | 12 | def main(): 13 | target_subproject_env = os.environ.get('TARGET_SUBPROJECT', '') 14 | target_subprojects = list(filter(None, target_subproject_env.split(',') if target_subproject_env != '' else [])) 15 | print('target_subprojects: {}'.format(target_subprojects)) 16 | 17 | with open('settings.json') as f: 18 | settings: dict = json.load(f) 19 | 20 | if len(target_subprojects) == 0: 21 | subprojects = [s for s in settings['versions'] if not s.endswith('-common')] 22 | else: 23 | subprojects = [] 24 | for subproject in settings['versions']: 25 | if subproject in target_subprojects and not subproject.endswith('-common'): 26 | subprojects.append(subproject) 27 | target_subprojects.remove(subproject) 28 | if len(target_subprojects) > 0: 29 | print('Unexpected subprojects: {}'.format(target_subprojects), file=sys.stderr) 30 | sys.exit(1) 31 | 32 | matrix_entries = [] 33 | for subproject in subprojects: 34 | matrix_entries.append({ 35 | 'subproject': subproject, 36 | }) 37 | matrix = {'include': matrix_entries} 38 | with open(os.environ['GITHUB_OUTPUT'], 'w') as f: 39 | f.write('matrix={}\n'.format(json.dumps(matrix))) 40 | 41 | print('matrix:') 42 | print(json.dumps(matrix, indent=2)) 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /.github/workflows/scripts/summary.py: -------------------------------------------------------------------------------- 1 | """ 2 | A script to scan through all valid mod jars in build-artifacts.zip/$version/build/libs, 3 | and generate an artifact summary table for that to GitHub action step summary 4 | """ 5 | __author__ = 'Fallen_Breath' 6 | 7 | import functools 8 | import glob 9 | import hashlib 10 | import json 11 | import os 12 | 13 | 14 | def read_prop(file_name: str, key: str) -> str: 15 | with open(file_name) as prop: 16 | return next(filter( 17 | lambda l: l.split('=', 1)[0].strip() == key, 18 | prop.readlines() 19 | )).split('=', 1)[1].lstrip() 20 | 21 | 22 | def get_sha256_hash(file_path: str) -> str: 23 | sha256_hash = hashlib.sha256() 24 | 25 | with open(file_path, 'rb') as f: 26 | for buf in iter(functools.partial(f.read, 4096), b''): 27 | sha256_hash.update(buf) 28 | 29 | return sha256_hash.hexdigest() 30 | 31 | 32 | def main(): 33 | target_subproject_env = os.environ.get('TARGET_SUBPROJECT', '') 34 | target_subprojects = list(filter(None, target_subproject_env.split(',') if target_subproject_env != '' else [])) 35 | print('target_subprojects: {}'.format(target_subprojects)) 36 | 37 | with open('settings.json') as f: 38 | settings: dict = json.load(f) 39 | 40 | with open(os.environ['GITHUB_STEP_SUMMARY'], 'w') as f: 41 | f.write('## Build Artifacts Summary\n\n') 42 | f.write('| Subproject | for Minecraft | File | Size | SHA-256 |\n') 43 | f.write('| --- | --- | --- | --- | --- |\n') 44 | 45 | warnings = [] 46 | for subproject in settings['versions']: 47 | if subproject.endswith('-common'): 48 | continue 49 | if len(target_subprojects) > 0 and subproject not in target_subprojects: 50 | print('skipping {}'.format(subproject)) 51 | continue 52 | game_versions = read_prop('versions/{}/gradle.properties'.format(subproject), 'game_versions') 53 | game_versions = game_versions.strip().replace('\\n', ', ') 54 | file_paths = glob.glob('build-artifacts/{}/build/libs/*.jar'.format(subproject)) 55 | file_paths = list(filter(lambda fp: not fp.endswith('-sources.jar') and not fp.endswith('-dev.jar'), file_paths)) 56 | if len(file_paths) == 0: 57 | file_name = '*not found*' 58 | sha256 = '*N/A*' 59 | else: 60 | file_name = '`{}`'.format(os.path.basename(file_paths[0])) 61 | file_size = '{} B'.format(os.path.getsize(file_paths[0])) 62 | sha256 = '`{}`'.format(get_sha256_hash(file_paths[0])) 63 | if len(file_paths) > 1: 64 | warnings.append('Found too many build files in subproject {}: {}'.format(subproject, ', '.join(file_paths))) 65 | 66 | f.write('| {} | {} | {} | {} | {} |\n'.format(subproject, game_versions, file_name, file_size, sha256)) 67 | 68 | if len(warnings) > 0: 69 | f.write('\n### Warnings\n\n') 70 | for warning in warnings: 71 | f.write('- {}\n'.format(warning)) 72 | 73 | 74 | if __name__ == '__main__': 75 | main() 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run*/ 34 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @RubixDev 2 | -------------------------------------------------------------------------------- /assets/Inventorio Gradle Modules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/assets/Inventorio Gradle Modules.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Gradle Properties 2 | org.gradle.jvmargs=-Xmx4G 3 | org.gradle.daemon=false 4 | 5 | # Minecraft Properties 6 | # https://fabricmc.net/develop/ 7 | fabric_loader_version=0.15.7 8 | 9 | # Mod Properties 10 | mod_id=inventorio 11 | mod_name=Inventorio 12 | mod_authors=RubixDev,LizardOfOz,Favorlock 13 | mod_version=1.10.4 14 | mod_description=My vision of the Inventory Update. Includes Deep Pockets Enchantment, Tool Belt, Utility Belt and more. 15 | maven_group=de.rubixdev.inventorio 16 | archives_base_name=inventorio 17 | license=All Rights Reserved 18 | homepage_url=https://github.com/RubixDev/Inventorio 19 | sources_url=https://github.com/RubixDev/Inventorio 20 | issues_url=https://github.com/RubixDev/Inventorio/issues 21 | 22 | # Global Dependencies 23 | # https://maven.fabricmc.net/net/fabricmc/fabric-language-kotlin/ 24 | fabric_kotlin_version=1.9.6+kotlin.1.8.22 25 | # https://github.com/thedarkcolour/KotlinForForge/blob/site/thedarkcolour/kotlinforforge/maven-metadata.xml 26 | forge_kotlin_version=4.10.0 27 | # https://mvnrepository.com/artifact/io.github.llamalad7/mixinextras-common 28 | mixinextras_version=0.3.5 29 | # https://github.com/Fallen-Breath/conditional-mixin/tags 30 | conditional_mixin_version=0.6.4 31 | 32 | # Other 33 | run_with_compat_mods=false 34 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 3 | before_install: 4 | - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh 5 | - source install-jdk.sh --feature 17 6 | - jshell --version -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonSlurper 2 | 3 | pluginManagement { 4 | repositories { 5 | maven("https://maven.architectury.dev/") 6 | maven("https://maven.fabricmc.net/") 7 | maven("https://maven.minecraftforge.net/") 8 | maven("https://jitpack.io") 9 | mavenCentral() 10 | gradlePluginPortal() 11 | } 12 | resolutionStrategy { 13 | eachPlugin { 14 | when (requested.id.id) { 15 | "com.replaymod.preprocess" -> { 16 | useModule("com.github.Fallen-Breath:preprocessor:${requested.version}") 17 | } 18 | } 19 | } 20 | } 21 | } 22 | 23 | @Suppress("UNCHECKED_CAST") 24 | val settings = JsonSlurper().parseText(rootDir.resolve("settings.json").readText()) as Map> 25 | for (version in settings["versions"]!!) { 26 | include(":$version") 27 | project(":$version").apply { 28 | projectDir = file("versions/$version") 29 | buildFileName = "../../common.gradle.kts" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "versions": [ 3 | "1.20.1-common", 4 | "1.20.1-fabric", 5 | "1.20.1-forge", 6 | "1.20.2-fabric", 7 | "1.20.2-neoforge", 8 | "1.20.4-common", 9 | "1.20.4-fabric", 10 | "1.20.4-neoforge" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/api/InventorioAddonSection.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.api; 2 | 3 | public enum InventorioAddonSection { 4 | DEEP_POCKETS, 5 | TOOLBELT, 6 | UTILITY_BELT 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/api/InventorioTickHandler.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.api; 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon; 4 | import net.minecraft.item.ItemStack; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | @FunctionalInterface 8 | public interface InventorioTickHandler { 9 | /** 10 | * Note: The size of the ToolBelt and the order of slots is persistent ONLY 11 | * within the current play session.
12 | * The size of the ToolBelt may depend on the mods currently installed and 13 | * can change across restarts. 14 | */ 15 | void tick( 16 | @NotNull PlayerInventoryAddon playerInventoryAddon, 17 | @NotNull InventorioAddonSection addonSection, 18 | @NotNull ItemStack itemStack, 19 | int indexWithinSection 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/ExperienceOrbEntityMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin; 2 | 3 | import de.rubixdev.inventorio.util.MixinHelpers; 4 | import net.minecraft.entity.ExperienceOrbEntity; 5 | import net.minecraft.entity.player.PlayerEntity; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(ExperienceOrbEntity.class) 13 | public class ExperienceOrbEntityMixin { 14 | @Shadow 15 | private int amount; 16 | 17 | /** 18 | * This inject allows items in the ToolBelt to be Mended 19 | */ 20 | @Inject( 21 | method = "onPlayerCollision", 22 | at = @At(value = "FIELD", target = "Lnet/minecraft/entity/ExperienceOrbEntity;amount:I"), 23 | require = 0 24 | ) 25 | private void inventorioMendToolBeltItems(PlayerEntity player, CallbackInfo ci) { 26 | MixinHelpers.withInventoryAddon(player, addon -> this.amount = addon.mendToolBeltItems(this.amount)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/PlayerManagerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin; 2 | 3 | import de.rubixdev.inventorio.packet.InventorioNetworking; 4 | import de.rubixdev.inventorio.util.MixinHelpers; 5 | import net.minecraft.network.ClientConnection; 6 | import net.minecraft.server.PlayerManager; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | //#if MC >= 12002 15 | import net.minecraft.server.network.ConnectedClientData; 16 | //#endif 17 | 18 | @Mixin(PlayerManager.class) 19 | public class PlayerManagerMixin { 20 | /** 21 | * This injection sends the last utility slot, saved by the server, from the 22 | * server to the client 23 | */ 24 | @Inject(method = "onPlayerConnect", at = @At(value = "RETURN"), require = 0) 25 | private void inventorioSetPlayerSettings(/* #if <- hack around formatter */ 26 | ClientConnection connection, 27 | ServerPlayerEntity player, 28 | //#if MC >= 12002 29 | ConnectedClientData clientData, 30 | //#endif 31 | CallbackInfo ci 32 | ) { 33 | InventorioNetworking.getInstance().s2cSelectUtilitySlot(player); 34 | InventorioNetworking.getInstance().s2cGlobalSettings(player); 35 | } 36 | 37 | /** 38 | * This inject sends the last utility slot, saved by the server, from the 39 | * server to the client 40 | */ 41 | @Inject(method = "respawnPlayer", at = @At(value = "RETURN"), require = 0) 42 | private void inventorioSetPlayerSettings( 43 | ServerPlayerEntity oldPlayer, 44 | boolean alive, 45 | CallbackInfoReturnable cir 46 | ) { 47 | ServerPlayerEntity newPlayer = cir.getReturnValue(); 48 | MixinHelpers.withInventoryAddon(newPlayer, newAddon -> MixinHelpers.withInventoryAddon(oldPlayer, oldAddon -> { 49 | newAddon.setSwappedHands(oldAddon.getSwappedHands()); 50 | newAddon.setSelectedUtility(oldAddon.getSelectedUtility()); 51 | })); 52 | InventorioNetworking.getInstance().s2cSelectUtilitySlot(newPlayer); 53 | } 54 | 55 | @Inject(method = "sendPlayerStatus", at = @At("RETURN")) 56 | private void sendSelectedUtility(ServerPlayerEntity player, CallbackInfo ci) { 57 | InventorioNetworking.getInstance().s2cSelectUtilitySlot(player); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/ServerPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin; 2 | 3 | import de.rubixdev.inventorio.util.MixinHelpers; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket; 6 | import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket; 7 | import net.minecraft.server.network.ServerPlayNetworkHandler; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | import net.minecraft.util.Hand; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(ServerPlayNetworkHandler.class) 17 | public class ServerPlayNetworkHandlerMixin { 18 | @Shadow 19 | public ServerPlayerEntity player; 20 | 21 | /** 22 | * These two injections remove the display tool (server-side) when a player 23 | * tries to use (right-click) something from the main hand, so that the item 24 | * that's ACTUALLY in the main hand can be used immediately 25 | */ 26 | @Inject(method = "onPlayerInteractBlock", at = @At(value = "HEAD")) 27 | private void inventorioRemoveDisplayHand(PlayerInteractBlockC2SPacket packet, CallbackInfo ci) { 28 | if (packet.getHand() == Hand.MAIN_HAND) 29 | MixinHelpers.withInventoryAddon(player, addon -> addon.setDisplayTool(ItemStack.EMPTY)); 30 | } 31 | 32 | @Inject(method = "onPlayerInteractItem", at = @At(value = "HEAD")) 33 | private void inventorioRemoveDisplayHand(PlayerInteractItemC2SPacket packet, CallbackInfo ci) { 34 | if (packet.getHand() == Hand.MAIN_HAND) 35 | MixinHelpers.withInventoryAddon(player, addon -> addon.setDisplayTool(ItemStack.EMPTY)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/ServerPlayerEntity_ScreenHandlerSyncHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin; 2 | 3 | import de.rubixdev.inventorio.player.inventory.PlayerInventoryExtension; 4 | import de.rubixdev.inventorio.util.MixinHelpers; 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraft.screen.ScreenHandler; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import net.minecraft.util.collection.DefaultedList; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(targets = "net.minecraft.server.network.ServerPlayerEntity$1") 17 | public class ServerPlayerEntity_ScreenHandlerSyncHandlerMixin { 18 | @Shadow 19 | @Final 20 | ServerPlayerEntity field_29182; 21 | 22 | @Inject(method = "updateState", at = @At("HEAD")) 23 | private void updateAddonState( 24 | ScreenHandler handler, 25 | DefaultedList stacks, 26 | ItemStack cursorStack, 27 | int[] properties, 28 | CallbackInfo ci 29 | ) { 30 | MixinHelpers.withInventoryAddon(this.field_29182, PlayerInventoryExtension::updateState); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/accessor/CraftingScreenHandlerAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.accessor; 2 | 3 | import net.minecraft.entity.player.PlayerEntity; 4 | import net.minecraft.inventory.CraftingResultInventory; 5 | import net.minecraft.inventory.RecipeInputInventory; 6 | import net.minecraft.screen.CraftingScreenHandler; 7 | import net.minecraft.screen.ScreenHandler; 8 | import net.minecraft.world.World; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.gen.Invoker; 11 | 12 | @Mixin(CraftingScreenHandler.class) 13 | public interface CraftingScreenHandlerAccessor { 14 | @Invoker("updateResult") 15 | static void updateTheResult( 16 | ScreenHandler handler, 17 | World world, 18 | PlayerEntity player, 19 | RecipeInputInventory craftingInventory, 20 | CraftingResultInventory resultInventory 21 | ) {} 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/accessor/ScreenHandlerAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.accessor; 2 | 3 | import net.minecraft.item.ItemStack; 4 | import net.minecraft.screen.ScreenHandler; 5 | import net.minecraft.screen.slot.Slot; 6 | import net.minecraft.util.collection.DefaultedList; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | import org.spongepowered.asm.mixin.gen.Invoker; 10 | 11 | @SuppressWarnings("unused") 12 | @Mixin(ScreenHandler.class) 13 | public interface ScreenHandlerAccessor { 14 | @Accessor 15 | DefaultedList getTrackedStacks(); 16 | 17 | @Accessor 18 | DefaultedList getPreviousTrackedStacks(); 19 | 20 | @Invoker 21 | Slot callAddSlot(Slot slot); 22 | 23 | @Invoker 24 | boolean callInsertItem(ItemStack stack, int firstIndex, int lastIndex, boolean fromLast); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/accessor/SimpleInventoryAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.accessor; 2 | 3 | import net.minecraft.inventory.SimpleInventory; 4 | import net.minecraft.item.ItemStack; 5 | import net.minecraft.util.collection.DefaultedList; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Mutable; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | @Mixin(SimpleInventory.class) 11 | public interface SimpleInventoryAccessor { 12 | @Accessor("size") 13 | @Mutable 14 | void setSize(int size); 15 | 16 | @Accessor("heldStacks") 17 | @Mutable 18 | void setHeldStacks(DefaultedList stacks); 19 | 20 | @Accessor("heldStacks") 21 | DefaultedList getHeldStacks(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/accessor/SlotAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.accessor; 2 | 3 | import net.minecraft.screen.slot.Slot; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Mutable; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @SuppressWarnings("unused") 9 | @Mixin(Slot.class) 10 | public interface SlotAccessor { 11 | @Accessor("x") 12 | int getX(); 13 | 14 | @Accessor("x") 15 | @Mutable 16 | void setX(int x); 17 | 18 | @Accessor("y") 19 | int getY(); 20 | 21 | @Accessor("y") 22 | @Mutable 23 | void setY(int y); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import de.rubixdev.inventorio.packet.InventorioNetworking; 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon; 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.api.Environment; 7 | import net.minecraft.client.network.ClientPlayNetworkHandler; 8 | import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Environment(EnvType.CLIENT) 15 | @Mixin(ClientPlayNetworkHandler.class) 16 | public class ClientPlayNetworkHandlerMixin { 17 | /** 18 | * When a player joins, this mixin sends a packet to the server, telling 19 | * whether the player uses Swapped Hands or not 20 | */ 21 | @Inject(method = "onGameJoin", at = @At(value = "RETURN")) 22 | private void inventorioSendSwappedHandsStatus(GameJoinS2CPacket packet, CallbackInfo ci) { 23 | PlayerInventoryAddon addon = PlayerInventoryAddon.Client.INSTANCE.getLocal(); 24 | if (addon != null) InventorioNetworking.getInstance().c2sSetSwappedHandsMode(addon.getSwappedHands()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/ClientPlayerInteractionManagerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import de.rubixdev.inventorio.client.control.InventorioControls; 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon; 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.api.Environment; 7 | import net.minecraft.client.network.ClientPlayerInteractionManager; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Environment(EnvType.CLIENT) 15 | @Mixin(ClientPlayerInteractionManager.class) 16 | public class ClientPlayerInteractionManagerMixin { 17 | /** 18 | * The default implementation stops an item from being used if the vanilla 19 | * "use" key isn't pressed. This mod adds an optional secondary use key, and 20 | * this prevents the secondary item usage from being cancelled 21 | */ 22 | @Inject(method = "stopUsingItem", at = @At(value = "HEAD"), cancellable = true) 23 | private void inventorioStopUsingItem(PlayerEntity player, CallbackInfo ci) { 24 | if (PlayerInventoryAddon.Client.isUsingUtility) { 25 | if (InventorioControls.keyUseUtility.isPressed()) ci.cancel(); 26 | else PlayerInventoryAddon.Client.isUsingUtility = false; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/InGameHudMixinHP.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import de.rubixdev.inventorio.client.ui.HotbarHUDRenderer; 4 | import net.fabricmc.api.EnvType; 5 | import net.fabricmc.api.Environment; 6 | import net.minecraft.client.gui.DrawContext; 7 | import net.minecraft.client.gui.hud.InGameHud; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import net.minecraft.item.ItemStack; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.Redirect; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(value = InGameHud.class, priority = 1500) 17 | @Environment(EnvType.CLIENT) 18 | public class InGameHudMixinHP { 19 | /** 20 | * This mixin calls the renderer of hotbar addons. Note: this mixin doesn't 21 | * work in (Neo)Forge and is substituted with a (Neo)Forge event. 22 | */ 23 | @Inject(method = "render", at = @At(value = "RETURN")) 24 | private void inventorioRenderHotbarAddons(DrawContext context, float tickDelta, CallbackInfo ci) { 25 | HotbarHUDRenderer.INSTANCE.renderHotbarAddons(context); 26 | } 27 | 28 | /** 29 | * This mixin removes the vanilla offhand display (both the item frame and 30 | * the item) 31 | */ 32 | @Redirect( 33 | method = "renderHotbar", 34 | at = @At( 35 | value = "INVOKE", 36 | target = "Lnet/minecraft/entity/player/PlayerEntity;getOffHandStack()Lnet/minecraft/item/ItemStack;" 37 | ) 38 | ) 39 | private ItemStack inventorioRemoveOffhandDisplayFromHotbar(PlayerEntity playerEntity) { 40 | return ItemStack.EMPTY; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/InGameHudMixinLP.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import de.rubixdev.inventorio.client.ui.HotbarHUDRenderer; 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon; 6 | import net.fabricmc.api.EnvType; 7 | import net.fabricmc.api.Environment; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.client.gui.hud.InGameHud; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraft.item.Items; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(value = InGameHud.class, priority = 99) 18 | @Environment(EnvType.CLIENT) 19 | public class InGameHudMixinLP { 20 | /** 21 | * This mixin redirects rendering the hotbar itself in case Segmented Hotbar 22 | * is selected. 23 | */ 24 | @Inject(method = "renderHotbar", at = @At(value = "HEAD"), cancellable = true, require = 0) 25 | private void inventorioRenderSegmentedHotbar(float tickDelta, DrawContext context, CallbackInfo ci) { 26 | if (HotbarHUDRenderer.INSTANCE.renderSegmentedHotbar(context)) ci.cancel(); 27 | } 28 | 29 | @Inject(method = "renderHotbar", at = @At(value = "RETURN"), require = 0) 30 | private void inventorioRenderFunctionOnlySelector(float tickDelta, DrawContext context, CallbackInfo ci) { 31 | HotbarHUDRenderer.INSTANCE.renderFunctionOnlySelector(context); 32 | } 33 | 34 | /** 35 | * In vanilla, when you look at an entity with a sword, it shows an attack 36 | * indicator. This mixin restores this feature if you have a sword in your 37 | * tool belt. 38 | */ 39 | @ModifyExpressionValue( 40 | method = "renderCrosshair", 41 | at = @At( 42 | value = "INVOKE", 43 | target = "Lnet/minecraft/client/network/ClientPlayerEntity;getAttackCooldownProgressPerTick()F" 44 | ), 45 | require = 0 46 | ) 47 | private float inventorioShowAttackIndicator(float original) { 48 | PlayerInventoryAddon addon = PlayerInventoryAddon.Client.INSTANCE.getLocal(); 49 | if (addon != null && !addon.findFittingToolBeltStack(new ItemStack(Items.DIAMOND_SWORD)).isEmpty()) 50 | return 20.0f; 51 | return original; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/InventoryScreenMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import de.rubixdev.inventorio.client.ui.InventorioScreen; 4 | import net.fabricmc.api.EnvType; 5 | import net.fabricmc.api.Environment; 6 | import net.minecraft.client.gui.screen.ingame.InventoryScreen; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | 12 | @Mixin(value = InventoryScreen.class) 13 | @Environment(EnvType.CLIENT) 14 | public class InventoryScreenMixin { 15 | @Inject(method = "init", at = @At(value = "RETURN")) 16 | private void inventorioAddToggle(CallbackInfo ci) { 17 | InventorioScreen.addToggleButton((InventoryScreen) (Object) this); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/RecipeBookWidgetMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 5 | import de.rubixdev.inventorio.duck.RecipeBookLeftOffsetOverride; 6 | import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget; 7 | import org.jetbrains.annotations.Nullable; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.Unique; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | 13 | @Mixin(RecipeBookWidget.class) 14 | public class RecipeBookWidgetMixin implements RecipeBookLeftOffsetOverride { 15 | @Shadow 16 | private int leftOffset; 17 | 18 | @Unique private Integer backgroundWidth = null; 19 | 20 | @ModifyExpressionValue(method = "reset", at = @At(value = "CONSTANT", args = "intValue=86")) 21 | private int modifyLeftOffset(int original) { 22 | if (backgroundWidth != null) { return (backgroundWidth + 2) / 2; } 23 | return original; 24 | } 25 | 26 | @ModifyReturnValue(method = "isWide", at = @At("RETURN")) 27 | private boolean correctIsWide(boolean original) { 28 | return original || leftOffset > 0; 29 | } 30 | 31 | @Override 32 | public void inventorio$setBackgroundWidth(@Nullable Integer backgroundWidth) { 33 | this.backgroundWidth = backgroundWidth; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/accessor/HandledScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client.accessor; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 6 | import net.minecraft.screen.ScreenHandler; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Accessor; 9 | 10 | @SuppressWarnings("unused") 11 | @Mixin(HandledScreen.class) 12 | @Environment(EnvType.CLIENT) 13 | public interface HandledScreenAccessorextends ScreenAccessor { 14 | @Accessor("backgroundWidth") 15 | int getBackgroundWidth(); 16 | 17 | @Accessor("x") 18 | int getX(); 19 | 20 | @Accessor("x") 21 | void setX(int x); 22 | 23 | @Accessor("y") 24 | int getY(); 25 | 26 | @Accessor("y") 27 | void setY(int y); 28 | 29 | @Accessor 30 | T getHandler(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/accessor/MinecraftClientAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client.accessor; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.MinecraftClient; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | import org.spongepowered.asm.mixin.gen.Invoker; 9 | 10 | @Mixin(MinecraftClient.class) 11 | @Environment(EnvType.CLIENT) 12 | public interface MinecraftClientAccessor { 13 | @Invoker("doItemUse") 14 | void invokeDoItemUse(); 15 | 16 | @Accessor("itemUseCooldown") 17 | int getItemUseCooldown(); 18 | 19 | @Accessor("itemUseCooldown") 20 | void setItemUseCooldown(int value); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/client/accessor/ScreenAccessor.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.client.accessor; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.font.TextRenderer; 7 | import net.minecraft.client.gui.Drawable; 8 | import net.minecraft.client.gui.Element; 9 | import net.minecraft.client.gui.Selectable; 10 | import net.minecraft.client.gui.screen.Screen; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.gen.Accessor; 14 | import org.spongepowered.asm.mixin.gen.Invoker; 15 | 16 | import java.util.List; 17 | 18 | @Mixin(Screen.class) 19 | @Environment(EnvType.CLIENT) 20 | public interface ScreenAccessor { 21 | @Accessor("children") 22 | List getChildren(); 23 | 24 | @Accessor("drawables") 25 | List getDrawables(); 26 | 27 | @Accessor("selectables") 28 | List getSelectables(); 29 | 30 | @Accessor 31 | @Nullable MinecraftClient getClient(); 32 | 33 | @Accessor 34 | TextRenderer getTextRenderer(); 35 | 36 | @Invoker 37 | T callAddDrawableChild(T drawableElement); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/optional/bowfix/BowItemMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.optional.bowfix; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 4 | import com.llamalad7.mixinextras.sugar.Local; 5 | import de.rubixdev.inventorio.util.BowTester; 6 | import de.rubixdev.inventorio.util.RandomStuff; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 8 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 9 | import net.minecraft.enchantment.Enchantments; 10 | import net.minecraft.item.BowItem; 11 | import net.minecraft.item.ItemStack; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | 15 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = BowTester.class)) 16 | @Mixin(BowItem.class) 17 | public class BowItemMixin { 18 | /** 19 | * This fixes a bug (yes, it's a bug! check out 20 | * {@link BowItem#onStoppedUsing} method!) that an Infinity Bow requires an 21 | * arrow to shoot. 22 | */ 23 | @ModifyExpressionValue( 24 | method = "use", 25 | at = @At(value = "FIELD", target = "Lnet/minecraft/entity/player/PlayerAbilities;creativeMode:Z") 26 | ) 27 | private boolean inventorioFixInfinityBow(boolean original, @Local ItemStack bow) { 28 | return original || RandomStuff.getLevelOn(Enchantments.INFINITY, bow) > 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/optional/enderchest/EnderChestBlockMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.optional.enderchest; 2 | 3 | import de.rubixdev.inventorio.util.EnderChestTester; 4 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 6 | import net.minecraft.block.EnderChestBlock; 7 | import net.minecraft.entity.player.PlayerInventory; 8 | import net.minecraft.inventory.Inventory; 9 | import net.minecraft.screen.GenericContainerScreenHandler; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Redirect; 13 | 14 | /** 15 | * This mixin enlarges the Ender Chest's Inventory Screen to 6 rows. To enlarge 16 | * the actual storage, {@link PlayerEntityMixin#inventorioResizeEnderChest} is 17 | * used 18 | */ 19 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = EnderChestTester.class)) 20 | @Mixin(value = EnderChestBlock.class) 21 | public class EnderChestBlockMixin { 22 | @Redirect( 23 | method = "method_17468", 24 | at = @At( 25 | value = "INVOKE", 26 | target = "Lnet/minecraft/screen/GenericContainerScreenHandler;createGeneric9x3(ILnet/minecraft/entity/player/PlayerInventory;Lnet/minecraft/inventory/Inventory;)Lnet/minecraft/screen/GenericContainerScreenHandler;" 27 | ) 28 | ) 29 | private static GenericContainerScreenHandler inventorioOnEnderChestOpen( 30 | int syncId, 31 | PlayerInventory playerInventory, 32 | Inventory inventory 33 | ) { 34 | return GenericContainerScreenHandler.createGeneric9x6(syncId, playerInventory, inventory); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/optional/enderchest/PlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.optional.enderchest; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import de.rubixdev.inventorio.mixin.accessor.SimpleInventoryAccessor; 5 | import de.rubixdev.inventorio.util.EnderChestTester; 6 | import de.rubixdev.inventorio.util.GeneralConstants; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 8 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 9 | import net.minecraft.entity.player.PlayerEntity; 10 | import net.minecraft.inventory.EnderChestInventory; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.util.collection.DefaultedList; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.world.World; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.Shadow; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 20 | 21 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = EnderChestTester.class)) 22 | @Mixin(PlayerEntity.class) 23 | public abstract class PlayerEntityMixin { 24 | @Shadow 25 | public abstract EnderChestInventory getEnderChestInventory(); 26 | 27 | /** 28 | * This inject enlarges the Ender Chest's capacity to 6 rows. 29 | */ 30 | @Inject(method = "", at = @At(value = "RETURN")) 31 | private void inventorioResizeEnderChest( 32 | World world, 33 | BlockPos pos, 34 | float yaw, 35 | GameProfile gameProfile, 36 | CallbackInfo ci 37 | ) { 38 | SimpleInventoryAccessor accessor = ((SimpleInventoryAccessor) getEnderChestInventory()); 39 | accessor.setSize(GeneralConstants.VANILLA_ROW_LENGTH * 6); 40 | accessor.setHeldStacks(DefaultedList.ofSize(GeneralConstants.VANILLA_ROW_LENGTH * 6, ItemStack.EMPTY)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/rubixdev/inventorio/mixin/optional/totem/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.optional.totem; 2 | 3 | import de.rubixdev.inventorio.util.MixinHelpers; 4 | import de.rubixdev.inventorio.util.TotemTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.entity.Entity; 8 | import net.minecraft.entity.EntityType; 9 | import net.minecraft.entity.LivingEntity; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.item.Items; 13 | import net.minecraft.world.World; 14 | import org.objectweb.asm.Opcodes; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 18 | import org.spongepowered.asm.mixin.injection.Slice; 19 | 20 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = TotemTester.class)) 21 | @Mixin(value = LivingEntity.class, priority = 500) 22 | public abstract class LivingEntityMixin extends Entity { 23 | public LivingEntityMixin(EntityType type, World world) { 24 | super(type, world); 25 | } 26 | 27 | /** 28 | * This optional mixin allows a Totem of Undying to be used automatically 29 | * from any Utility Slot. 30 | */ 31 | @SuppressWarnings("InvalidInjectorMethodSignature") 32 | // @ModifyVariable( 33 | // method = "tryUseTotem", 34 | // at = @At(value = "JUMP", ordinal = 2, shift = At.Shift.BEFORE), 35 | // slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;decrement(I)V")), 36 | // ordinal = 0 37 | // ) 38 | @ModifyVariable( 39 | method = "tryUseTotem", 40 | at = @At(value = "JUMP", opcode = Opcodes.IFNULL, shift = At.Shift.BEFORE), 41 | slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;decrement(I)V")), 42 | ordinal = 0 43 | ) 44 | private ItemStack inventorioGetTotemFromUtilityBar(ItemStack original) { 45 | // noinspection ConstantValue 46 | if (original != null || !((Entity) this instanceof PlayerEntity player)) return original; 47 | return MixinHelpers.withInventoryAddonReturning( 48 | player, 49 | addon -> addon.utilityBelt.stream() 50 | .filter(stack -> stack.isOf(Items.TOTEM_OF_UNDYING)) 51 | .findFirst() 52 | .map(totem -> { 53 | ItemStack copy = totem.copy(); 54 | totem.decrement(1); 55 | return copy; 56 | }) 57 | .orElse(original) 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/me/lizardofoz/inventorio/api/InventorioAddonSection.java: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.api; 2 | 3 | /** 4 | * @deprecated Use {@link de.rubixdev.inventorio.api.InventorioAddonSection} 5 | * instead. 6 | */ 7 | @Deprecated(forRemoval = true, since = "1.10.0") 8 | public enum InventorioAddonSection { 9 | DEEP_POCKETS, 10 | TOOLBELT, 11 | UTILITY_BELT; 12 | 13 | static InventorioAddonSection from(de.rubixdev.inventorio.api.InventorioAddonSection section) { 14 | return switch (section) { 15 | case DEEP_POCKETS -> DEEP_POCKETS; 16 | case TOOLBELT -> TOOLBELT; 17 | case UTILITY_BELT -> UTILITY_BELT; 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/me/lizardofoz/inventorio/api/InventorioTickHandler.java: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.api; 2 | 3 | import me.lizardofoz.inventorio.player.PlayerInventoryAddon; 4 | import net.minecraft.item.ItemStack; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * @deprecated Use {@link de.rubixdev.inventorio.api.InventorioTickHandler} 9 | * instead. 10 | */ 11 | @SuppressWarnings("removal") 12 | @Deprecated(forRemoval = true, since = "1.10.0") 13 | @FunctionalInterface 14 | public interface InventorioTickHandler { 15 | /** 16 | * Note: The size of the ToolBelt and the order of slots is persistent ONLY 17 | * within the current play session.
18 | * The size of the ToolBelt may depend on the mods currently installed and 19 | * can change across restarts. 20 | * 21 | * @deprecated Use 22 | * {@link de.rubixdev.inventorio.api.InventorioTickHandler#tick} 23 | * instead. 24 | */ 25 | @Deprecated(forRemoval = true, since = "1.10.0") 26 | void tick( 27 | @NotNull PlayerInventoryAddon playerInventoryAddon, 28 | @NotNull InventorioAddonSection addonSection, 29 | @NotNull ItemStack itemStack, 30 | int indexWithinSection 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/InventorioMixinPlugin.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import me.fallenbreath.conditionalmixin.api.mixin.RestrictiveMixinConfigPlugin 4 | 5 | class InventorioMixinPlugin : RestrictiveMixinConfigPlugin() { 6 | override fun getRefMapperConfig(): String? = null 7 | override fun acceptTargets(myTargets: MutableSet?, otherTargets: MutableSet?) {} 8 | override fun getMixins(): MutableList? = null 9 | } 10 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/ScreenTypeProvider.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import net.minecraft.screen.ScreenHandlerType 5 | 6 | interface ScreenTypeProvider { 7 | fun getScreenHandlerType(): ScreenHandlerType 8 | 9 | companion object { 10 | // TODO: custom ktlint rule to allow lateinit var in caps 11 | @Suppress("ktlint:standard:property-naming") 12 | lateinit var INSTANCE: ScreenTypeProvider 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/api/ToolBeltSlotTemplate.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.api 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import java.util.function.BiPredicate 5 | import net.minecraft.item.ItemStack 6 | import net.minecraft.util.Identifier 7 | 8 | /** 9 | * Note: **Do not extend this class!** It is only marked as `open` for compatibility purposes. 10 | */ 11 | // TODO: remove `open` modifier once old api package is removed 12 | open class ToolBeltSlotTemplate(val name: String, val emptyIcon: Identifier) { 13 | private val isAllowed: MutableList> = ArrayList() 14 | private val isDenied: MutableList> = ArrayList() 15 | 16 | fun test(itemStack: ItemStack, playerInventoryAddon: PlayerInventoryAddon): Boolean { 17 | return isAllowed.any { it.test(itemStack, playerInventoryAddon) } && isDenied.none { it.test(itemStack, playerInventoryAddon) } 18 | } 19 | 20 | fun addAllowingCondition(predicate: BiPredicate): ToolBeltSlotTemplate { 21 | isAllowed.add(predicate) 22 | return this 23 | } 24 | 25 | fun addAllowingTag(tag: Identifier): ToolBeltSlotTemplate { 26 | isAllowed.add { itemStack, _ -> testTag(itemStack, tag) } 27 | return this 28 | } 29 | 30 | fun addDenyingCondition(predicate: BiPredicate): ToolBeltSlotTemplate { 31 | isDenied.add(predicate) 32 | return this 33 | } 34 | 35 | fun addDenyingTag(tag: Identifier): ToolBeltSlotTemplate { 36 | isDenied.add { itemStack, _ -> testTag(itemStack, tag) } 37 | return this 38 | } 39 | 40 | private fun testTag(itemStack: ItemStack, identifier: Identifier): Boolean { 41 | return itemStack.streamTags().anyMatch { it.id == identifier } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/client/configscreen/GlobalSettingsScreen.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.client.configscreen 2 | 3 | import de.rubixdev.inventorio.client.configscreen.PlayerSettingsScreen.addBoolEntry 4 | import de.rubixdev.inventorio.client.configscreen.PlayerSettingsScreen.addEnumEntry 5 | import de.rubixdev.inventorio.config.GlobalSettings 6 | import de.rubixdev.inventorio.util.PlatformApi 7 | import de.rubixdev.inventorio.util.ToolBeltMode 8 | import me.shedaniel.clothconfig2.api.ConfigBuilder 9 | import net.fabricmc.api.EnvType 10 | import net.fabricmc.api.Environment 11 | import net.minecraft.client.MinecraftClient 12 | import net.minecraft.client.gui.screen.Screen 13 | import net.minecraft.text.Text 14 | 15 | @Environment(EnvType.CLIENT) 16 | object GlobalSettingsScreen { 17 | fun get(parent: Screen?): Screen { 18 | val builder = ConfigBuilder.create() 19 | .setParentScreen(parent) 20 | .setSavingRunnable(GlobalSettings::save) 21 | .setTitle(Text.translatable("inventorio.settings.global.title")) 22 | val entryBuilder = builder.entryBuilder() 23 | val category = builder.getOrCreateCategory(Text.translatable("inventorio.settings.global.title")) 24 | 25 | category.addEntry(entryBuilder.startTextDescription(Text.translatable("inventorio.settings.global.description")).build()) 26 | 27 | val isNotLocal = MinecraftClient.getInstance().networkHandler?.connection?.isLocal != true 28 | if (isNotLocal) { 29 | category.addEntry(entryBuilder.startTextDescription(Text.translatable("inventorio.settings.global.disabled_by_server")).build()) 30 | } 31 | 32 | addBoolEntry(category, entryBuilder, GlobalSettings.expandedEnderChest, true, isNotLocal) 33 | addBoolEntry(category, entryBuilder, GlobalSettings.infinityBowNeedsNoArrow, true, isNotLocal) 34 | addBoolEntry(category, entryBuilder, GlobalSettings.totemFromUtilityBelt, true, isNotLocal) 35 | addBoolEntry(category, entryBuilder, GlobalSettings.allowSwappedHands, true, isNotLocal) 36 | addBoolEntry(category, entryBuilder, GlobalSettings.allow2x2CraftingGrid, true, isNotLocal) 37 | //#if FABRIC 38 | addBoolEntry(category, entryBuilder, GlobalSettings.trinketsIntegration, true, isNotLocal) { PlatformApi.isModLoaded("trinkets") } 39 | //#elseif FORGELIKE 40 | addBoolEntry(category, entryBuilder, GlobalSettings.curiosIntegration, true, isNotLocal) { PlatformApi.isModLoaded("curios") } 41 | //#endif 42 | 43 | addEnumEntry(category, entryBuilder, GlobalSettings.toolBeltMode, true, isNotLocal, ToolBeltMode::class.java, ToolBeltMode.ENABLED) 44 | addBoolEntry(category, entryBuilder, GlobalSettings.utilityBeltShortDefaultSize, true, isNotLocal) 45 | addBoolEntry(category, entryBuilder, GlobalSettings.deepPocketsBookCraft, true, isNotLocal) 46 | addBoolEntry(category, entryBuilder, GlobalSettings.deepPocketsInTrades, true, isNotLocal) 47 | addBoolEntry(category, entryBuilder, GlobalSettings.deepPocketsInRandomSelection, true, isNotLocal) 48 | 49 | return builder.build() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/client/control/InventorioControls.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.client.control 2 | 3 | import net.fabricmc.api.EnvType 4 | import net.fabricmc.api.Environment 5 | import net.minecraft.client.MinecraftClient 6 | import net.minecraft.client.option.KeyBinding 7 | import net.minecraft.client.util.InputUtil 8 | import org.lwjgl.glfw.GLFW 9 | 10 | @Environment(EnvType.CLIENT) 11 | object InventorioControls { 12 | @JvmField val keyUseUtility = KeyCoBinding( 13 | "inventorio.keys.combined.with_use_item", 14 | { MinecraftClient.getInstance()?.options?.useKey }, 15 | "inventorio.keys.use_utility", 16 | InputUtil.Type.KEYSYM, 17 | GLFW.GLFW_KEY_UNKNOWN, 18 | "inventorio.keys.category", 19 | ) 20 | 21 | @JvmField val keyNextUtility = KeyBinding( 22 | "inventorio.keys.next_utility", 23 | InputUtil.Type.MOUSE, 24 | GLFW.GLFW_MOUSE_BUTTON_4, 25 | "inventorio.keys.category", 26 | ) 27 | 28 | @JvmField val keyPrevUtility = KeyBinding( 29 | "inventorio.keys.prev_utility", 30 | InputUtil.Type.MOUSE, 31 | GLFW.GLFW_MOUSE_BUTTON_5, 32 | "inventorio.keys.category", 33 | ) 34 | 35 | @JvmField val keyEmptyUtility = KeyBinding( 36 | "inventorio.keys.empty_utility", 37 | InputUtil.Type.KEYSYM, 38 | GLFW.GLFW_KEY_UNKNOWN, 39 | "inventorio.keys.category", 40 | ) 41 | 42 | @JvmField val keyFireBoostRocket = KeyCoBinding( 43 | "inventorio.keys.combined.with_jump", 44 | { MinecraftClient.getInstance()?.options?.jumpKey }, 45 | "inventorio.keys.rocket_boost", 46 | InputUtil.Type.KEYSYM, 47 | GLFW.GLFW_KEY_UNKNOWN, 48 | "inventorio.keys.category", 49 | ) 50 | 51 | @JvmField val keyOpenPlayerSettingsMenu = KeyBinding( 52 | "inventorio.keys.open_player_settings", 53 | InputUtil.Type.KEYSYM, 54 | GLFW.GLFW_KEY_I, 55 | "inventorio.keys.category", 56 | ) 57 | 58 | @JvmField val keyOpenGlobalSettingsMenu = KeyBinding( 59 | "inventorio.keys.open_global_settings", 60 | InputUtil.Type.KEYSYM, 61 | GLFW.GLFW_KEY_O, 62 | "inventorio.keys.category", 63 | ) 64 | 65 | @JvmField val keys = arrayOf( 66 | keyUseUtility, 67 | keyNextUtility, 68 | keyPrevUtility, 69 | keyEmptyUtility, 70 | keyFireBoostRocket, 71 | 72 | keyOpenPlayerSettingsMenu, 73 | keyOpenGlobalSettingsMenu, 74 | ) 75 | } 76 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/client/control/KeyCoBinding.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.client.control 2 | 3 | import net.fabricmc.api.EnvType 4 | import net.fabricmc.api.Environment 5 | import net.minecraft.client.option.KeyBinding 6 | import net.minecraft.client.util.InputUtil 7 | import net.minecraft.text.Text 8 | 9 | /** 10 | * The usecase: when you bind "Use Item" and "Use Utility" to the same key, the intended behavior is them merging together. 11 | * It works on NeoForge, but FABRIC allows only one bindings per key. 12 | * This is the fix: the co-bound binding will unbind itself if binded to the same key. 13 | */ 14 | @Environment(EnvType.CLIENT) 15 | open class KeyCoBinding(protected val coBindTranslationKey: String, protected val vanillaBinging: () -> KeyBinding?, translationKey: String, type: InputUtil.Type, code: Int, category: String) : KeyBinding(translationKey, type, code, category) { 16 | open val isThisOrVanillaPressed: Boolean 17 | get() = (isUnbound && vanillaBinging()?.isPressed == true) || super.isPressed() 18 | 19 | override fun setBoundKey(boundKey: InputUtil.Key) { 20 | super.setBoundKey(boundKey) 21 | if (!this.isUnbound && vanillaBinging() != null && this.equals(vanillaBinging())) { 22 | super.setBoundKey(InputUtil.UNKNOWN_KEY) 23 | } 24 | } 25 | 26 | override fun getBoundKeyLocalizedText(): Text { 27 | return if (isUnbound) { 28 | Text.translatable(coBindTranslationKey) 29 | } else { 30 | super.getBoundKeyLocalizedText() 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/config/AbstractSettings.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.config 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import java.io.File 6 | import java.io.FileReader 7 | import java.io.FileWriter 8 | 9 | abstract class AbstractSettings { 10 | private lateinit var configFile: File 11 | var entries = emptyList() 12 | protected set 13 | 14 | fun asJson(): JsonObject { 15 | val configRoot = JsonObject() 16 | entries.forEach { configRoot.add(it.configKey, it.valueAsElement(it.value)) } 17 | return configRoot 18 | } 19 | 20 | /** 21 | * Returns true if there's an option not covered by an input json. 22 | * (Used in [load] to write automatically write new entries into the config) 23 | */ 24 | fun fromJson(jsonObject: JsonObject): Boolean { 25 | val missingEntries = entries.any { !jsonObject.has(it.configKey) } 26 | for (option in entries) 27 | option.value = option.tryElementAsValue(jsonObject.get(option.configKey)) 28 | return missingEntries 29 | } 30 | 31 | fun anyChanges(jsonObject: JsonObject): Boolean { 32 | return entries.any { option -> option.value != option.tryElementAsValue(jsonObject.get(option.configKey)) } 33 | } 34 | 35 | fun save() { 36 | try { 37 | FileWriter(configFile).use { Gson().toJson(asJson(), it) } 38 | } catch (ignored: Exception) { 39 | } 40 | } 41 | 42 | fun load(configFile: File) { 43 | try { 44 | this.configFile = configFile 45 | if (!configFile.exists() || FileReader(configFile).use { fromJson(Gson().fromJson(it, JsonObject::class.java)) }) { 46 | save() 47 | } 48 | } catch (ignored: Exception) { 49 | save() 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/config/SettingsEntry.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.config 2 | 3 | import com.google.gson.JsonElement 4 | import com.google.gson.JsonPrimitive 5 | 6 | open class SettingsEntry( 7 | @JvmField val defaultValue: Any, 8 | @JvmField val configKey: String, 9 | @JvmField val displayText: String, 10 | @JvmField val tooltipText: String?, 11 | @JvmField val valueAsElement: (Any) -> JsonElement, 12 | private val elementAsValue: (JsonElement?) -> Any, 13 | @JvmField val onChange: (Any) -> Unit = { }, 14 | ) { 15 | var value = defaultValue 16 | set(value) { 17 | field = value 18 | onChange(value) 19 | } 20 | 21 | fun tryElementAsValue(element: JsonElement?): Any { 22 | return try { 23 | elementAsValue(element) 24 | } catch (ignored: Throwable) { 25 | defaultValue 26 | } 27 | } 28 | 29 | override fun equals(other: Any?): Boolean { 30 | return other is SettingsEntry && configKey == other.configKey 31 | } 32 | 33 | override fun hashCode(): Int { 34 | return configKey.hashCode() 35 | } 36 | } 37 | 38 | class SettingsEntryBoolean(defaultValue: Boolean, configKey: String, displayText: String, tooltipText: String? = null, onChange: (Any) -> Unit = { }) : 39 | SettingsEntry(defaultValue, configKey, displayText, tooltipText, { JsonPrimitive(it == true) }, { it?.asBoolean ?: defaultValue }, onChange) { 40 | val boolValue get() = this.value == true 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/duck/RecipeBookLeftOffsetOverride.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.duck 2 | 3 | @Suppress("FunctionName") 4 | interface RecipeBookLeftOffsetOverride { 5 | fun `inventorio$setBackgroundWidth`(backgroundWidth: Int?) 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/enchantment/DeepPocketsEnchantment.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.enchantment 2 | 3 | import de.rubixdev.inventorio.config.GlobalSettings 4 | import de.rubixdev.inventorio.util.DEEP_POCKETS_MAX_LEVEL 5 | import net.minecraft.enchantment.Enchantment 6 | import net.minecraft.enchantment.EnchantmentTarget 7 | import net.minecraft.entity.EquipmentSlot 8 | 9 | object DeepPocketsEnchantment : Enchantment(Rarity.UNCOMMON, EnchantmentTarget.ARMOR_LEGS, arrayOf(EquipmentSlot.LEGS)) { 10 | override fun getMinLevel(): Int { 11 | return 1 12 | } 13 | 14 | override fun getMaxLevel(): Int { 15 | return DEEP_POCKETS_MAX_LEVEL 16 | } 17 | 18 | override fun getMinPower(level: Int): Int { 19 | return 5 + (level - 1) * 8 20 | } 21 | 22 | override fun getMaxPower(level: Int): Int { 23 | return super.getMinPower(level) + 50 24 | } 25 | 26 | override fun isAvailableForEnchantedBookOffer(): Boolean { 27 | return GlobalSettings.deepPocketsInTrades.boolValue 28 | } 29 | 30 | override fun isAvailableForRandomSelection(): Boolean { 31 | return GlobalSettings.deepPocketsInRandomSelection.boolValue 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/integration/InventorioModIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | import de.rubixdev.inventorio.util.logger 4 | 5 | /** 6 | * This class is intended for Inventorio to integrate with other mods, 7 | * _not_ for other mods to integrate with Inventorio. 8 | */ 9 | @Suppress("unused") 10 | object InventorioModIntegration { 11 | fun applyModIntegrations(modIntegrations: Collection) { 12 | for (modIntegration in modIntegrations) { 13 | try { 14 | if (modIntegration.shouldApply()) { 15 | modIntegration.apply() 16 | logger.info("Mod integration succeeded for ${modIntegration.displayName}") 17 | } else { 18 | logger.info("Skipping mod integration for ${modIntegration.displayName}") 19 | } 20 | } catch (e: Throwable) { 21 | logger.error("Failed to apply mod integration for ${modIntegration.displayName} (${modIntegration.name})", e) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/integration/ModIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | /** 4 | * This class is intended for Inventorio to integrate with other mods, 5 | * _not_ for other mods to integrate with Inventorio. 6 | */ 7 | abstract class ModIntegration { 8 | abstract val name: String 9 | abstract val displayName: String 10 | 11 | abstract fun shouldApply(): Boolean 12 | 13 | abstract fun apply() 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/packet/InventorioNetworking.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import net.fabricmc.api.EnvType 4 | import net.fabricmc.api.Environment 5 | import net.minecraft.item.ItemStack 6 | import net.minecraft.server.network.ServerPlayerEntity 7 | 8 | interface InventorioNetworking { 9 | fun s2cSelectUtilitySlot(player: ServerPlayerEntity) 10 | 11 | fun s2cGlobalSettings(player: ServerPlayerEntity) 12 | 13 | fun s2cUpdateAddonStacks(player: ServerPlayerEntity, updatedStacks: Map) 14 | 15 | @Environment(EnvType.CLIENT) 16 | fun c2sSelectUtilitySlot(selectedUtility: Int) 17 | 18 | @Environment(EnvType.CLIENT) 19 | fun c2sUseBoostRocket() 20 | 21 | @Environment(EnvType.CLIENT) 22 | fun c2sSetSwappedHandsMode(swappedHands: Boolean) 23 | 24 | @Environment(EnvType.CLIENT) 25 | fun c2sMoveItemToUtilityBelt(sourceSlot: Int) 26 | 27 | @Environment(EnvType.CLIENT) 28 | fun c2sOpenInventorioScreen() 29 | 30 | @Environment(EnvType.CLIENT) 31 | fun c2sSwapItemsInHands() 32 | 33 | companion object { 34 | @JvmStatic 35 | @get:JvmName("getInstance") 36 | @set:JvmName("setInstance") 37 | @Suppress("ktlint:standard:property-naming") 38 | lateinit var INSTANCE: InventorioNetworking 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/player/PlayerAddonSerializer.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.player 2 | 3 | import net.minecraft.item.ItemStack 4 | import net.minecraft.nbt.NbtCompound 5 | import net.minecraft.nbt.NbtList 6 | 7 | object PlayerAddonSerializer { 8 | fun serialize(inventoryAddon: PlayerInventoryAddon, inventorioTag: NbtCompound) { 9 | inventorioTag.putInt("SelectedUtilitySlot", inventoryAddon.selectedUtility) 10 | inventorioTag.put("DeepPockets", serializeSection(inventoryAddon.deepPockets)) 11 | inventorioTag.put("UtilityBelt", serializeSection(inventoryAddon.utilityBelt)) 12 | inventorioTag.put("ToolBelt", serializeSection(inventoryAddon.toolBelt)) 13 | } 14 | 15 | private fun serializeSection(section: List): NbtList { 16 | val resultTag = NbtList() 17 | for ((slotIndex, itemStack) in section.withIndex()) { 18 | if (itemStack.isEmpty) { 19 | continue 20 | } 21 | val itemTag = NbtCompound() 22 | itemTag.putInt("Slot", slotIndex) 23 | itemStack.writeNbt(itemTag) 24 | resultTag.add(itemTag) 25 | } 26 | return resultTag 27 | } 28 | 29 | fun deserialize(inventoryAddon: PlayerInventoryAddon, inventorioTag: NbtCompound) { 30 | inventoryAddon.selectedUtility = inventorioTag.getInt("SelectedUtilitySlot") 31 | 32 | deserializeSection(inventoryAddon, inventoryAddon.utilityBelt, inventorioTag.getList("UtilityBelt", 10)) 33 | deserializeSection(inventoryAddon, inventoryAddon.toolBelt, inventorioTag.getList("ToolBelt", 10)) 34 | deserializeSection(inventoryAddon, inventoryAddon.deepPockets, inventorioTag.getList("DeepPockets", 10)) 35 | } 36 | 37 | private fun deserializeSection(inventoryAddon: PlayerInventoryAddon, inventorySection: MutableList, sectionTag: NbtList) { 38 | for (i in inventorySection.indices) 39 | inventorySection[i] = ItemStack.EMPTY 40 | 41 | for (itemTag in sectionTag) { 42 | val compoundTag = itemTag as NbtCompound 43 | val itemStack = ItemStack.fromNbt(compoundTag) 44 | val slotIndex = compoundTag.getInt("Slot") 45 | if (slotIndex in inventorySection.indices) { 46 | inventorySection[slotIndex] = itemStack 47 | } else { 48 | inventoryAddon.player.dropItem(itemStack, false) 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/slot/ArmorSlot.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.slot 2 | 3 | import com.mojang.datafixers.util.Pair 4 | import net.minecraft.enchantment.EnchantmentHelper 5 | import net.minecraft.entity.EquipmentSlot 6 | import net.minecraft.entity.mob.MobEntity 7 | import net.minecraft.entity.player.PlayerEntity 8 | import net.minecraft.inventory.Inventory 9 | import net.minecraft.item.ItemStack 10 | import net.minecraft.screen.PlayerScreenHandler 11 | import net.minecraft.screen.slot.Slot 12 | import net.minecraft.util.Identifier 13 | 14 | class ArmorSlot(inventory: Inventory, index: Int, x: Int, y: Int, private val equipmentSlot: EquipmentSlot) : Slot(inventory, index, x, y) { 15 | override fun getMaxItemCount(): Int { 16 | return 1 17 | } 18 | 19 | override fun canInsert(stack: ItemStack): Boolean { 20 | return equipmentSlot == MobEntity.getPreferredEquipmentSlot(stack) 21 | } 22 | 23 | override fun canTakeItems(playerEntity: PlayerEntity): Boolean { 24 | val itemStack = this.stack 25 | return if (!itemStack.isEmpty && !playerEntity.isCreative && EnchantmentHelper.hasBindingCurse(itemStack)) false else super.canTakeItems(playerEntity) 26 | } 27 | 28 | override fun getBackgroundSprite(): Pair? { 29 | return Pair.of(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, EMPTY_ARMOR_SLOT_TEXTURES[equipmentSlot.entitySlotId]) 30 | } 31 | 32 | companion object { 33 | private val EMPTY_ARMOR_SLOT_TEXTURES = arrayOf( 34 | PlayerScreenHandler.EMPTY_BOOTS_SLOT_TEXTURE, 35 | PlayerScreenHandler.EMPTY_LEGGINGS_SLOT_TEXTURE, 36 | PlayerScreenHandler.EMPTY_CHESTPLATE_SLOT_TEXTURE, 37 | PlayerScreenHandler.EMPTY_HELMET_SLOT_TEXTURE, 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/slot/BlockedSlot.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.slot 2 | 3 | import net.minecraft.entity.player.PlayerEntity 4 | import net.minecraft.inventory.Inventory 5 | import net.minecraft.item.ItemStack 6 | import net.minecraft.screen.slot.Slot 7 | 8 | open class BlockedSlot(inventory: Inventory, index: Int, x: Int, y: Int) : Slot(inventory, index, x, y) { 9 | override fun canTakeItems(playerEntity: PlayerEntity): Boolean { 10 | return false 11 | } 12 | 13 | override fun canInsert(stack: ItemStack): Boolean { 14 | return false 15 | } 16 | 17 | override fun isEnabled(): Boolean { 18 | return false 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/slot/DeepPocketsSlot.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.slot 2 | 3 | import net.minecraft.entity.player.PlayerEntity 4 | import net.minecraft.inventory.Inventory 5 | import net.minecraft.item.ItemStack 6 | import net.minecraft.screen.slot.Slot 7 | 8 | open class DeepPocketsSlot(inventory: Inventory, index: Int, x: Int, y: Int) : Slot(inventory, index, x, y) { 9 | @JvmField var canTakeItems = true 10 | 11 | override fun canTakeItems(playerEntity: PlayerEntity): Boolean { 12 | return canTakeItems 13 | } 14 | 15 | override fun canInsert(stack: ItemStack): Boolean { 16 | return canTakeItems 17 | } 18 | 19 | override fun isEnabled(): Boolean { 20 | return canTakeItems 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/slot/ToolBeltSlot.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.slot 2 | 3 | import de.rubixdev.inventorio.api.ToolBeltSlotTemplate 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import de.rubixdev.inventorio.util.* 6 | import kotlin.math.min 7 | import net.minecraft.item.ItemStack 8 | import net.minecraft.screen.slot.Slot 9 | 10 | open class ToolBeltSlot(private val template: ToolBeltSlotTemplate, private val inventoryAddon: PlayerInventoryAddon, index: Int, x: Int, y: Int) : Slot(inventoryAddon, index, x, y) { 11 | override fun canInsert(stack: ItemStack): Boolean { 12 | return template.test(stack, inventoryAddon) 13 | } 14 | 15 | companion object { 16 | fun getGuiPosition(deepPocketsRows: Int, index: Int, totalCount: Int): Rectangle { 17 | val columnCapacity = getColumnCapacity(deepPocketsRows) 18 | val heightOffset = 177 - min(totalCount, columnCapacity) * SLOT_UI_SIZE + DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows) 19 | val relativeIndex = index % columnCapacity 20 | return Rectangle( 21 | 173 + (index / columnCapacity) * SLOT_UI_SIZE, 22 | heightOffset + (relativeIndex - 1) * SLOT_UI_SIZE, 23 | 18, 24 | 90, 25 | ) 26 | } 27 | 28 | fun getSlotPosition(deepPocketsRows: Int, index: Int, totalCount: Int): Rectangle { 29 | val guiPos = getGuiPosition(deepPocketsRows, index, totalCount) 30 | return Rectangle(guiPos.x + 1, guiPos.y + 1, guiPos.width, guiPos.height) 31 | } 32 | 33 | fun getColumnCapacity(deepPocketsRows: Int): Int { 34 | return 6 + deepPocketsRows 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/GeneralConstants.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("GeneralConstants") 2 | 3 | package de.rubixdev.inventorio.util 4 | 5 | const val DEEP_POCKETS_MAX_LEVEL = 3 6 | const val VANILLA_ROW_LENGTH = 9 7 | 8 | const val MAIN_INVENTORY_SIZE = VANILLA_ROW_LENGTH * 4 9 | const val DEEP_POCKETS_MAX_SIZE = DEEP_POCKETS_MAX_LEVEL * VANILLA_ROW_LENGTH 10 | const val CRAFTING_GRID_SIZE = 5 11 | const val ARMOR_SIZE = 4 12 | const val UTILITY_BELT_SMALL_SIZE = 4 13 | const val UTILITY_BELT_FULL_SIZE = 8 14 | 15 | @JvmField val INVENTORY_HOTBAR_RANGE = 0..8 16 | @JvmField val INVENTORY_ADDON_DEEP_POCKETS_RANGE = 0 expandBy DEEP_POCKETS_MAX_SIZE 17 | @JvmField val INVENTORY_ADDON_UTILITY_BELT_RANGE = INVENTORY_ADDON_DEEP_POCKETS_RANGE.last + 1 expandBy UTILITY_BELT_FULL_SIZE 18 | @JvmField val INVENTORY_ADDON_TOOL_BELT_INDEX_OFFSET = INVENTORY_ADDON_UTILITY_BELT_RANGE.last + 1 19 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/HUDConstants.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("HUDConstants") 2 | 3 | package de.rubixdev.inventorio.util 4 | 5 | @JvmField val CANVAS_VANILLA_SELECTION_FRAME_POS = Point2F(188f, 0f) 6 | @JvmField val CANVAS_VANILLA_SELECTION_FRAME_SIZE = Rectangle(0, 0, 24, 24) 7 | 8 | @JvmField val CANVAS_SECTION_SELECTION_FRAME = Point2F(0f, 0f) 9 | @JvmField val HUD_SECTION_SELECTION = Rectangle(62, 23, 64, 24) 10 | @JvmField val SLOT_HOTBAR_SIZE = Rectangle(0, 0, 20, 19) 11 | 12 | @JvmField val CANVAS_ACTIVE_TOOL_FRAME = Point2F(234f, 0f) 13 | @JvmField val HUD_ACTIVE_TOOL_FRAME = Rectangle(133, 22, 22, 22) 14 | @JvmField val SLOT_ACTIVE_TOOL_FRAME = Point2I(136, 19) 15 | 16 | @JvmField val CANVAS_UTILITY_BELT = Point2F(84f, 0f) 17 | @JvmField val CANVAS_UTILITY_BELT_BCG = Point2F(132f, 0f) 18 | @JvmField val HUD_UTILITY_BELT = Rectangle(121, 22, 48, 22) 19 | @JvmField val SLOT_UTILITY_BELT_1 = Point2I(147, 18) 20 | @JvmField val SLOT_UTILITY_BELT_2 = Point2I(110, 18) 21 | @JvmField val SLOT_UTILITY_BELT_3 = Point2I(105, 19) 22 | 23 | @JvmField val CANVAS_SEGMENTED_HOTBAR = Point2F(0f, 24f) 24 | @JvmField val HUD_SEGMENTED_HOTBAR = Rectangle(65, 22, 190, 22) 25 | 26 | const val HUD_SEGMENTED_HOTBAR_GAP = 4 27 | 28 | const val LEFT_HANDED_UTILITY_BELT_OFFSET = 254 29 | const val LEFT_HANDED_DISPLAY_TOOL_OFFSET = -228 30 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/MixinHelpers.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import de.rubixdev.inventorio.player.InventorioScreenHandler.Companion.inventorioScreenHandler 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 6 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 7 | import java.util.function.Consumer 8 | import net.minecraft.entity.player.PlayerEntity 9 | 10 | object MixinHelpers { 11 | @JvmStatic 12 | @JvmOverloads 13 | fun withInventoryAddonReturning( 14 | playerEntity: PlayerEntity?, 15 | consumer: (PlayerInventoryAddon) -> T?, 16 | ifNotPresent: (PlayerEntity?) -> T? = { null }, 17 | ): T? { 18 | val addon = playerEntity?.inventoryAddon 19 | return if (addon != null) { 20 | consumer(addon) 21 | } else { 22 | ifNotPresent(playerEntity) 23 | } 24 | } 25 | 26 | @JvmStatic 27 | @JvmOverloads 28 | fun withInventoryAddon( 29 | playerEntity: PlayerEntity?, 30 | consumer: Consumer, 31 | ifNotPresent: Consumer = Consumer {}, 32 | ) { 33 | withInventoryAddonReturning(playerEntity, { addon -> consumer.accept(addon) }, { player -> ifNotPresent.accept(player) }) 34 | } 35 | 36 | @JvmStatic 37 | @JvmOverloads 38 | fun withScreenHandler( 39 | playerEntity: PlayerEntity?, 40 | consumer: Consumer, 41 | ifNotPresent: Consumer = Consumer {}, 42 | ) { 43 | val addon = playerEntity?.inventorioScreenHandler 44 | if (addon != null) { 45 | consumer.accept(addon) 46 | } else { 47 | ifNotPresent.accept(playerEntity) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/MixinTesters.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | import de.rubixdev.inventorio.config.GlobalSettings 4 | import me.fallenbreath.conditionalmixin.api.mixin.ConditionTester 5 | 6 | @Suppress("unused") 7 | class Never : ConditionTester { 8 | override fun isSatisfied(mixinClassName: String) = false 9 | } 10 | 11 | class BowTester : ConditionTester { 12 | override fun isSatisfied(mixinClassName: String) = GlobalSettings.infinityBowNeedsNoArrow.boolValue 13 | } 14 | 15 | class EnderChestTester : ConditionTester { 16 | override fun isSatisfied(mixinClassName: String) = GlobalSettings.expandedEnderChest.boolValue 17 | } 18 | 19 | class TotemTester : ConditionTester { 20 | override fun isSatisfied(mixinClassName: String) = GlobalSettings.totemFromUtilityBelt.boolValue 21 | } 22 | 23 | //#if FABRIC 24 | //$$ class TrinketsTester : ConditionTester { 25 | //$$ override fun isSatisfied(mixinClassName: String) = GlobalSettings.trinketsIntegration.boolValue 26 | //$$ } 27 | //#elseif FORGELIKE 28 | //$$ class CuriosTester : ConditionTester { 29 | //$$ override fun isSatisfied(mixinClassName: String) = GlobalSettings.curiosIntegration.boolValue 30 | //$$ } 31 | //#endif 32 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/PlatformApi.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | @Suppress("UNUSED_PARAMETER") 4 | object PlatformApi { 5 | fun isModLoaded(modId: String): Boolean = throw IllegalStateException() 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/RandomStuff.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("RandomStuff") 2 | 3 | package de.rubixdev.inventorio.util 4 | 5 | import de.rubixdev.inventorio.config.PlayerSettings 6 | import de.rubixdev.inventorio.mixin.accessor.ScreenHandlerAccessor 7 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 8 | import java.util.function.Consumer 9 | import java.util.function.Supplier 10 | import kotlin.properties.ReadWriteProperty 11 | import kotlin.reflect.KProperty 12 | import net.minecraft.enchantment.Enchantment 13 | import net.minecraft.enchantment.EnchantmentHelper 14 | import net.minecraft.item.ItemStack 15 | import net.minecraft.item.TridentItem 16 | import net.minecraft.screen.ScreenHandler 17 | import org.apache.logging.log4j.LogManager 18 | 19 | data class Point2I(@JvmField val x: Int, @JvmField val y: Int) 20 | data class Point2F(@JvmField val x: Float, @JvmField val y: Float) 21 | data class Rectangle(@JvmField val x: Int, @JvmField val y: Int, @JvmField val width: Int, @JvmField val height: Int) 22 | 23 | enum class SegmentedHotbar { 24 | OFF, 25 | ONLY_VISUAL, 26 | ON, 27 | ONLY_FUNCTION, 28 | } 29 | 30 | enum class ScrollWheelUtilityBeltMode { 31 | OFF, 32 | REGULAR, 33 | REVERSE, 34 | } 35 | 36 | enum class ToolBeltMode { 37 | ENABLED, 38 | NO_VANILLA_SLOTS_ONLY, 39 | DISABLED, 40 | } 41 | 42 | interface PlayerDuck { 43 | @Suppress("INAPPLICABLE_JVM_NAME") // see https://stackoverflow.com/questions/47504279/java-interop-apply-jvmname-to-getters-of-properties-in-interface-or-abstract-c 44 | @get:JvmName("inventorio${'$'}getInventorioAddon") 45 | val inventorioAddon: PlayerInventoryAddon? 46 | } 47 | 48 | val logger = LogManager.getLogger("Inventorio")!! 49 | 50 | val ItemStack.isNotEmpty 51 | get() = !this.isEmpty 52 | 53 | fun canRMBItem(itemStack: ItemStack): Boolean { 54 | return PlayerSettings.canThrowUnloyalTrident.boolValue 55 | || itemStack.item !is TridentItem 56 | || EnchantmentHelper.getLoyalty(itemStack) > 0 57 | || EnchantmentHelper.getRiptide(itemStack) > 0 58 | } 59 | 60 | fun Enchantment.getLevelOn(stack: ItemStack): Int { 61 | //#if FORGELIKE 62 | //$$ return stack.getEnchantmentLevel(this) 63 | //#else 64 | return EnchantmentHelper.getLevel(this, stack) 65 | //#endif 66 | } 67 | 68 | fun MutableList.subList(indices: IntRange) = subList(indices.first, indices.last + 1) 69 | 70 | fun ScreenHandler.insertItem(stack: ItemStack, indices: IntRange, fromLast: Boolean = false): Boolean = 71 | (this as ScreenHandlerAccessor).callInsertItem(stack, indices.first, indices.last + 1, fromLast) 72 | 73 | class MixinDelegate( 74 | private val getter: Supplier, 75 | private val setter: Consumer, 76 | ) : ReadWriteProperty { 77 | override fun getValue(thisRef: Any?, property: KProperty<*>): T = getter.get() 78 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = setter.accept(value) 79 | } 80 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/RangeIterator.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | /** 4 | * This adds the ability to iterate over an IntProgression with both relative and absolute indices at the same time 5 | */ 6 | fun IntProgression.withRelativeIndex(): IntProgressionIterator { 7 | return IntProgressionIterator(this) 8 | } 9 | 10 | class IntProgressionIterator(intProgression: IntProgression) : Iterator { 11 | private val iterator = intProgression.iterator() 12 | private var absoluteStart = intProgression.first 13 | override fun hasNext() = iterator.hasNext() 14 | override fun next() = makeNext() 15 | 16 | private fun makeNext(): IntProgressionIndices { 17 | val offset = iterator.nextInt() 18 | return IntProgressionIndices(offset, offset - absoluteStart) 19 | } 20 | } 21 | 22 | data class IntProgressionIndices(@JvmField val absoluteIndex: Int, @JvmField val relativeIndex: Int) 23 | 24 | infix fun Int.expandBy(addition: Int): IntRange { 25 | if (addition < 0) return IntRange.EMPTY 26 | return this until this + addition 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/de/rubixdev/inventorio/util/UIConstants.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("UIConstants") 2 | @file:Suppress("FunctionName") 3 | 4 | package de.rubixdev.inventorio.util 5 | 6 | const val SLOT_UI_SIZE = 18 7 | const val INVENTORY_HEIGHT = 166 8 | const val INVENTORY_TITLE_X = 97 9 | 10 | @JvmField val CANVAS_INVENTORY_TOP = Point2F(0f, 0f) 11 | @JvmField val GUI_INVENTORY_TOP = Rectangle(0, 0, 198, 79) 12 | 13 | @JvmField val CANVAS_INVENTORY_MAIN = Point2F(0f, 79f) 14 | fun GUI_INVENTORY_MAIN(deepPocketsRows: Int) = Rectangle(0, 79 + DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows), 198, 87) 15 | fun SLOTS_INVENTORY_MAIN(deepPocketsRows: Int) = Point2I(8, 84 + DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows)) 16 | fun SLOTS_INVENTORY_HOTBAR(deepPocketsRows: Int) = Point2I(8, 142 + DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows)) 17 | 18 | @JvmField val CANVAS_INVENTORY_DEEP_POCKETS = Point2F(0f, 166f) 19 | fun GUI_INVENTORY_DEEP_POCKETS(deepPocketsRows: Int) = Rectangle(0, 79, 198, DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows)) 20 | @JvmField val SLOT_INVENTORY_DEEP_POCKETS = Point2I(8, 84) 21 | 22 | @JvmField val CANVAS_UTILITY_BELT_COLUMN_2 = Point2F(238f, 22f) 23 | @JvmField val GUI_UTILITY_BELT_COLUMN_2 = Rectangle(94, 7, 18, 72) 24 | @JvmField val SLOT_UTILITY_BELT_COLUMN_1 = Point2I(77, 8) 25 | 26 | @JvmField val CANVAS_TOOL_BELT = Point2F(238f, 95f) 27 | 28 | @JvmField val CANVAS_TOOL_BELT_UI_EXTENSION = Rectangle(200, 0, 25, 166) 29 | @JvmField val GUI_TOOL_BELT_UI_EXTENSION = Point2I(191, 0) 30 | 31 | @JvmField val CANVAS_UTILITY_BELT_FRAME = Rectangle(234, 0, 22, 22) 32 | @JvmField val GUI_UTILITY_BELT_FRAME_ORIGIN = Point2I(74, 5) 33 | 34 | fun DEEP_POCKETS_EXTRA_HEIGHT(deepPocketsRows: Int) = if (deepPocketsRows <= 0) 0 else 4 + deepPocketsRows * 18 35 | const val CRAFTING_GRID_OFFSET_X = 20 36 | 37 | @JvmField val GUI_RECIPE_WIDGET_BUTTON = Rectangle(125, 61, 20, 18) 38 | 39 | @JvmField val CANVAS_INVENTORY_TEXTURE_SIZE = Point2I(256, 256) 40 | @JvmField val CANVAS_WIDGETS_TEXTURE_SIZE = Point2I(256, 64) 41 | 42 | //#if MC < 12002 43 | //$$ @JvmField val CANVAS_TOGGLE_BUTTON_ON = Point2I(243, 114) 44 | //$$ @JvmField val CANVAS_TOGGLE_BUTTON_OFF = Point2I(243, 120) 45 | //$$ const val CANVAS_TOGGLE_BUTTON_HOVER_SHIFT = 12 46 | //$$ @JvmField val CANVAS_LOCKED_CRAFT_BUTTON = Point2I(236, 138) 47 | //#endif 48 | @JvmField val GUI_TOGGLE_BUTTON_OFFSET = Rectangle(-19, 5, 13, 6) 49 | @JvmField val GUI_LOCKED_CRAFTING_POS = Rectangle(125, 25, 20, 20) 50 | -------------------------------------------------------------------------------- /src/main/kotlin/me/lizardofoz/inventorio/api/ToolBeltSlotTemplate.kt: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.api 2 | 3 | import de.rubixdev.inventorio.api.ToolBeltSlotTemplate 4 | import net.minecraft.util.Identifier 5 | 6 | @Deprecated("Package has been moved", ReplaceWith("de.rubixdev.inventorio.api.ToolBeltSlotTemplate"), DeprecationLevel.ERROR) 7 | class ToolBeltSlotTemplate(name: String, emptyIcon: Identifier) : ToolBeltSlotTemplate(name, emptyIcon) { 8 | companion object { 9 | @JvmStatic 10 | @Suppress("DEPRECATION_ERROR", "DeprecatedCallableAddReplaceWith") 11 | @Deprecated("For internal use only", level = DeprecationLevel.ERROR) 12 | fun of(delegate: ToolBeltSlotTemplate?): me.lizardofoz.inventorio.api.ToolBeltSlotTemplate? { 13 | return delegate?.let { me.lizardofoz.inventorio.api.ToolBeltSlotTemplate(it.name, it.emptyIcon) } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/me/lizardofoz/inventorio/client/ui/InventorioScreen.kt: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.client.ui 2 | 3 | import de.rubixdev.inventorio.client.ui.InventorioScreen 4 | import de.rubixdev.inventorio.mixin.client.accessor.HandledScreenAccessor 5 | import de.rubixdev.inventorio.player.InventorioScreenHandler 6 | import net.minecraft.entity.player.PlayerInventory 7 | 8 | @Deprecated("Package has been moved", ReplaceWith("de.rubixdev.inventorio.client.ui.InventorioScreen"), DeprecationLevel.ERROR) 9 | class InventorioScreen(handler: InventorioScreenHandler, inventory: PlayerInventory) : 10 | InventorioScreen(handler, inventory) { 11 | companion object { 12 | @JvmStatic 13 | @Suppress("DEPRECATION_ERROR", "DeprecatedCallableAddReplaceWith") 14 | @Deprecated("For internal use only", level = DeprecationLevel.ERROR) 15 | fun of(delegate: InventorioScreen?): me.lizardofoz.inventorio.client.ui.InventorioScreen? { 16 | return delegate?.let { 17 | @Suppress("UNCHECKED_CAST") 18 | me.lizardofoz.inventorio.client.ui.InventorioScreen( 19 | (it as HandledScreenAccessor).handler, 20 | it.inventory, 21 | ) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/me/lizardofoz/inventorio/player/InventorioScreenHandler.kt: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.player 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import net.minecraft.entity.player.PlayerInventory 5 | 6 | @Deprecated("Package has been moved", ReplaceWith("de.rubixdev.inventorio.player.InventorioScreenHandler"), DeprecationLevel.ERROR) 7 | class InventorioScreenHandler(syncId: Int, inventory: PlayerInventory) : InventorioScreenHandler(syncId, inventory) { 8 | companion object { 9 | @JvmStatic 10 | @Suppress("DEPRECATION_ERROR") 11 | @Deprecated("For internal use only", level = DeprecationLevel.ERROR) 12 | fun of(delegate: InventorioScreenHandler?): me.lizardofoz.inventorio.player.InventorioScreenHandler? { 13 | return delegate?.let { 14 | me.lizardofoz.inventorio.player.InventorioScreenHandler(it.syncId, it.inventory).apply { 15 | slots.indices.forEach { idx -> slots[idx] = it.slots[idx] } 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/me/lizardofoz/inventorio/player/PlayerInventoryAddon.kt: -------------------------------------------------------------------------------- 1 | package me.lizardofoz.inventorio.player 2 | 3 | import de.rubixdev.inventorio.mixin.accessor.SimpleInventoryAccessor 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import net.minecraft.entity.player.PlayerEntity 6 | 7 | @Deprecated("Package has been moved", ReplaceWith("de.rubixdev.inventorio.player.PlayerInventoryAddon"), DeprecationLevel.ERROR) 8 | class PlayerInventoryAddon(player: PlayerEntity) : PlayerInventoryAddon(player) { 9 | companion object { 10 | @JvmStatic 11 | @Suppress("DEPRECATION_ERROR") 12 | @Deprecated("For internal use only", level = DeprecationLevel.ERROR) 13 | fun ofNonNull(delegate: PlayerInventoryAddon): me.lizardofoz.inventorio.player.PlayerInventoryAddon { 14 | return me.lizardofoz.inventorio.player.PlayerInventoryAddon(delegate.player).apply { 15 | copyFrom(delegate) 16 | @Suppress("CAST_NEVER_SUCCEEDS") 17 | (this as SimpleInventoryAccessor).heldStacks = delegate.stacks 18 | } 19 | } 20 | 21 | @JvmStatic 22 | @Suppress("DEPRECATION_ERROR", "DeprecatedCallableAddReplaceWith") 23 | @Deprecated("For internal use only", level = DeprecationLevel.ERROR) 24 | fun of(delegate: PlayerInventoryAddon?): me.lizardofoz.inventorio.player.PlayerInventoryAddon? { 25 | return delegate?.let { ofNonNull(delegate) } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/empty/axe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/empty/axe.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/empty/hoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/empty/hoe.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/empty/pickaxe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/empty/pickaxe.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/empty/shovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/empty/shovel.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/empty/sword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/empty/sword.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/player_inventory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/player_inventory.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/player_inventory_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/player_inventory_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/lock_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/lock_button.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_active.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_active_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_active_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/lock_button_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_off.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_off_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_off_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_on.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_on_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_active_on_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_off.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_off_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_off_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_on.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_on_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/sprites/toggle_button_on_dark.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/widgets.png -------------------------------------------------------------------------------- /src/main/resources/assets/inventorio/textures/gui/widgets_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/assets/inventorio/textures/gui/widgets_dark.png -------------------------------------------------------------------------------- /src/main/resources/data/inventorio/recipes/deep_pockets_book.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "inventorio:deep_pockets_book" 3 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/advancements/unlock_deep_pockets_book.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:recipes/root", 3 | "rewards": { 4 | "recipes": [ 5 | "inventorio:deep_pockets_book" 6 | ] 7 | }, 8 | "criteria": { 9 | "exists": { 10 | "trigger": "minecraft:tick" 11 | } 12 | }, 13 | "requirements": [ 14 | [ 15 | "exists" 16 | ] 17 | ] 18 | } -------------------------------------------------------------------------------- /src/main/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RubixDev/Inventorio/fa7f4025f566c0e6736402548bba2c379770d778/src/main/resources/icon.png -------------------------------------------------------------------------------- /src/main/resources/inventorio.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "de.rubixdev.inventorio.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "minVersion": "0.8", 6 | "plugin": "de.rubixdev.inventorio.InventorioMixinPlugin", 7 | "mixins": [ 8 | "ExperienceOrbEntityMixin", 9 | "PlayerEntityMixin", 10 | "PlayerInventoryMixin", 11 | "PlayerManagerMixin", 12 | "ServerPlayerEntity_ScreenHandlerSyncHandlerMixin", 13 | "ServerPlayNetworkHandlerMixin", 14 | "accessor.CraftingScreenHandlerAccessor", 15 | "accessor.ScreenHandlerAccessor", 16 | "accessor.SimpleInventoryAccessor", 17 | "accessor.SlotAccessor", 18 | "optional.bowfix.BowItemMixin", 19 | "optional.enderchest.EnderChestBlockMixin", 20 | "optional.enderchest.PlayerEntityMixin", 21 | "optional.totem.LivingEntityMixin" 22 | ], 23 | "client": [ 24 | "client.ClientPlayerInteractionManagerMixin", 25 | "client.ClientPlayNetworkHandlerMixin", 26 | "client.HandledScreenMixin", 27 | "client.InGameHudMixinHP", 28 | "client.InGameHudMixinLP", 29 | "client.InventoryScreenMixin", 30 | "client.MinecraftClientMixin", 31 | "client.accessor.HandledScreenAccessor", 32 | "client.accessor.MinecraftClientAccessor", 33 | "client.RecipeBookWidgetMixin", 34 | "client.accessor.ScreenAccessor" 35 | ], 36 | "injectors": { 37 | "defaultRequire": 1 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Resources for ${mod_id}", 4 | "pack_format": ${pack_format_number} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /versions/1.20.1-common/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | minecraft_version=1.20.1 3 | yarn_mappings=1.20.1+build.10 4 | game_versions=1.20\n1.20.1 5 | 6 | # (Neo)Forge and dependency version ranges 7 | minecraft_version_range_fabric= 8 | minecraft_version_range_forge= 9 | forge_version= 10 | forge_version_range= 11 | neoforge_version= 12 | neoforge_version_range= 13 | 14 | # Common Dependencies 15 | cloth_version=11.1.118 16 | # https://modrinth.com/mod/clumps/versions 17 | clumps_version=12.0.0.3-fabric,1.20.1 18 | 19 | # Fabric Dependencies 20 | # https://modrinth.com/mod/early-loading-screen/versions 21 | early_loading_screen_version= 22 | fabric_api_version= 23 | modmenu_version= 24 | # https://modrinth.com/mod/trinkets/versions?l=fabric 25 | trinkets_version= 26 | cca_version= 27 | 28 | # (Neo)Forge Dependencies 29 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 30 | curios_version= 31 | -------------------------------------------------------------------------------- /versions/1.20.1-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=fabric 3 | minecraft_version=1.20.1 4 | yarn_mappings=1.20.1+build.10 5 | game_versions=1.20\n1.20.1 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric=>=1.20 <=1.20.1 9 | minecraft_version_range_forge= 10 | forge_version= 11 | forge_version_range= 12 | neoforge_version= 13 | neoforge_version_range= 14 | 15 | # Common Dependencies 16 | cloth_version=11.1.118 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=12.0.0.3-fabric,1.20.1 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version=0.1.5+1.20.1 23 | fabric_api_version=0.92.0+1.20.1 24 | modmenu_version=7.2.2 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version=3.7.2 27 | cca_version=5.2.2 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version= 32 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=forge 3 | minecraft_version=1.20.1 4 | yarn_mappings=1.20.1+build.10 5 | game_versions=1.20\n1.20.1 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric= 9 | minecraft_version_range_forge=[1.20,1.20.1] 10 | forge_version=1.20.1-47.2.20 11 | forge_version_range=[47,) 12 | neoforge_version= 13 | neoforge_version_range= 14 | 15 | # Common Dependencies 16 | cloth_version=11.1.118 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=12.0.0.3-forge,1.20.1 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version= 23 | fabric_api_version= 24 | modmenu_version= 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version= 27 | cca_version= 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version=5.14.1+1.20.1 32 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/CPacketScrollMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 5 | import de.rubixdev.inventorio.util.CuriosTester; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 8 | import net.minecraft.screen.ScreenHandler; 9 | import net.minecraftforge.network.NetworkEvent; 10 | import org.objectweb.asm.Opcodes; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.Slice; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | import top.theillusivec4.curios.common.network.client.CPacketScroll; 18 | 19 | import java.util.function.Supplier; 20 | 21 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 22 | @Mixin(CPacketScroll.class) 23 | public abstract class CPacketScrollMixin { 24 | @Shadow 25 | private int index; 26 | 27 | @Shadow 28 | private int windowId; 29 | 30 | @Inject( 31 | method = "lambda$handle$0", 32 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 33 | slice = @Slice( 34 | from = @At( 35 | value = "FIELD", 36 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 37 | ) 38 | ) 39 | ) 40 | private static void inventorioScrollToIndex( 41 | Supplier ctx, 42 | CPacketScroll msg, 43 | CallbackInfo ci, 44 | @Local ScreenHandler container 45 | ) { 46 | CPacketScrollMixin accessor = ((CPacketScrollMixin) (Object) msg); 47 | // noinspection DataFlowIssue 48 | if (container instanceof ICuriosContainer curiosContainer && container.syncId == accessor.windowId) { 49 | curiosContainer.inventorio$scrollToIndex(accessor.index); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/CurioStacksHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import org.objectweb.asm.Opcodes; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.Slice; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 17 | import top.theillusivec4.curios.common.inventory.CurioStacksHandler; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(CurioStacksHandler.class) 21 | public class CurioStacksHandlerMixin { 22 | @Shadow 23 | @Final 24 | private ICuriosItemHandler itemHandler; 25 | 26 | @Inject( 27 | method = "update", 28 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 29 | slice = @Slice( 30 | from = @At( 31 | value = "INVOKE", 32 | target = "Lnet/minecraftforge/eventbus/api/IEventBus;post(Lnet/minecraftforge/eventbus/api/Event;)Z" 33 | ) 34 | ), 35 | remap = false 36 | ) 37 | private void inventorioResetSlots(CallbackInfo ci) { 38 | if ( 39 | itemHandler.getWearer() instanceof PlayerEntity player 40 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 41 | ) { 42 | curiosContainer.inventorio$resetSlots(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/CuriosEventHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import org.objectweb.asm.Opcodes; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.Slice; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 15 | import top.theillusivec4.curios.common.event.CuriosEventHandler; 16 | 17 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 18 | @Mixin(CuriosEventHandler.class) 19 | public class CuriosEventHandlerMixin { 20 | @Inject( 21 | method = "lambda$onDatapackSync$5", 22 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 23 | slice = @Slice( 24 | from = @At( 25 | value = "FIELD", 26 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 27 | ) 28 | ) 29 | ) 30 | private static void inventorioResetSlots2(ServerPlayerEntity player, ICuriosItemHandler handler, CallbackInfo ci) { 31 | if (player.currentScreenHandler instanceof ICuriosContainer curiosContainer) { 32 | curiosContainer.inventorio$resetSlots(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/HandledScreenMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosScreen; 5 | import de.rubixdev.inventorio.util.CuriosTester; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 11 | import net.minecraft.screen.slot.Slot; 12 | import net.minecraft.text.Text; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | import top.theillusivec4.curios.common.inventory.CurioSlot; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(HandledScreen.class) 21 | public class HandledScreenMixin extends Screen { 22 | protected HandledScreenMixin(Text title) { 23 | super(title); 24 | } 25 | 26 | @ModifyReturnValue(method = "isPointOverSlot", at = @At("RETURN")) 27 | private boolean dontRenderCuriosWhenClosed(boolean original, Slot slot) { 28 | if ( 29 | this instanceof ICuriosScreen curiosScreen 30 | && slot instanceof CurioSlot 31 | && !curiosScreen.getInventorio$isCuriosOpen() 32 | ) { 33 | return false; 34 | } 35 | return original; 36 | } 37 | 38 | @Inject(method = "drawSlot", at = @At("HEAD"), cancellable = true) 39 | private void dontRenderCuriosWhenClosed(DrawContext context, Slot slot, CallbackInfo ci) { 40 | if ( 41 | this instanceof ICuriosScreen curiosScreen 42 | && slot instanceof CurioSlot 43 | && !curiosScreen.getInventorio$isCuriosOpen() 44 | ) { 45 | ci.cancel(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/SPacketScrollMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 5 | import de.rubixdev.inventorio.integration.curios.ICuriosScreen; 6 | import de.rubixdev.inventorio.util.CuriosTester; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 8 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import net.minecraft.screen.ScreenHandler; 11 | import org.objectweb.asm.Opcodes; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Shadow; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.Slice; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import top.theillusivec4.curios.common.network.server.SPacketScroll; 19 | 20 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 21 | @Mixin(SPacketScroll.class) 22 | public abstract class SPacketScrollMixin { 23 | @Shadow 24 | private int windowId; 25 | 26 | @Shadow 27 | private int index; 28 | 29 | @Inject( 30 | method = "lambda$handle$0", 31 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 32 | slice = @Slice( 33 | from = @At( 34 | value = "INVOKE", 35 | target = "Ltop/theillusivec4/curios/common/inventory/container/CuriosContainer;scrollToIndex(I)V" 36 | ) 37 | ) 38 | ) 39 | private static void inventorioUpdateRenderButtons(SPacketScroll msg, CallbackInfo ci, @Local Screen screen) { 40 | if (screen instanceof ICuriosScreen curiosScreen) { 41 | curiosScreen.inventorio$updateRenderButtons(); 42 | } 43 | } 44 | 45 | @Inject( 46 | method = "lambda$handle$0", 47 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 48 | slice = @Slice( 49 | from = @At( 50 | value = "FIELD", 51 | target = "Lnet/minecraft/client/network/ClientPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 52 | ) 53 | ) 54 | ) 55 | private static void inventorioScrollToIndex(SPacketScroll msg, CallbackInfo ci, @Local ScreenHandler container) { 56 | SPacketScrollMixin accessor = ((SPacketScrollMixin) (Object) msg); 57 | // noinspection DataFlowIssue 58 | if (container instanceof ICuriosContainer curiosContainer && container.syncId == accessor.windowId) { 59 | curiosContainer.inventorio$scrollToIndex(accessor.index); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/SPacketSyncCuriosMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.client.network.ClientPlayerEntity; 8 | import net.minecraft.entity.Entity; 9 | import org.objectweb.asm.Opcodes; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.Slice; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 16 | import top.theillusivec4.curios.common.network.server.sync.SPacketSyncCurios; 17 | 18 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 19 | @Mixin(SPacketSyncCurios.class) 20 | public class SPacketSyncCuriosMixin { 21 | @Inject( 22 | method = "lambda$handle$0", 23 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 24 | slice = @Slice( 25 | from = @At( 26 | value = "INVOKE", 27 | target = "Ltop/theillusivec4/curios/api/type/capability/ICuriosItemHandler;setCurios(Ljava/util/Map;)V" 28 | ) 29 | ) 30 | ) 31 | private static void inventorioResetSlots( 32 | SPacketSyncCurios data, 33 | Entity entity, 34 | ICuriosItemHandler handler, 35 | CallbackInfo ci 36 | ) { 37 | if ( 38 | entity instanceof ClientPlayerEntity player 39 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 40 | ) { 41 | curiosContainer.inventorio$resetSlots(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/SPacketSyncModifiersMixinV1.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.client.network.ClientPlayerEntity; 8 | import net.minecraft.entity.Entity; 9 | import net.minecraft.entity.LivingEntity; 10 | import org.objectweb.asm.Opcodes; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.Slice; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 17 | import top.theillusivec4.curios.common.network.server.sync.SPacketSyncModifiers; 18 | 19 | @Restriction( 20 | require = { 21 | @Condition(value = "curios", versionPredicates = "(,5.11)"), 22 | @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) } 23 | ) 24 | @Mixin(SPacketSyncModifiers.class) 25 | public class SPacketSyncModifiersMixinV1 { 26 | @Inject( 27 | method = "lambda$handle$0(Ltop/theillusivec4/curios/common/network/server/sync/SPacketSyncModifiers;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/Entity;Ltop/theillusivec4/curios/api/type/capability/ICuriosItemHandler;)V", 28 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 29 | slice = @Slice( 30 | from = @At( 31 | value = "INVOKE", 32 | target = "Lnet/minecraftforge/eventbus/api/IEventBus;post(Lnet/minecraftforge/eventbus/api/Event;)Z" 33 | ) 34 | ) 35 | ) 36 | private static void inventorioResetSlots( 37 | SPacketSyncModifiers data, 38 | LivingEntity livingEntity, 39 | Entity entity, 40 | ICuriosItemHandler handler, 41 | CallbackInfo ci 42 | ) { 43 | if ( 44 | entity instanceof ClientPlayerEntity player 45 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 46 | ) { 47 | curiosContainer.inventorio$resetSlots(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/java/de/rubixdev/inventorio/mixin/forge/curios/SPacketSyncModifiersMixinV2.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.forge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.entity.LivingEntity; 11 | import org.objectweb.asm.Opcodes; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.Slice; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 18 | import top.theillusivec4.curios.common.network.server.sync.SPacketSyncModifiers; 19 | 20 | @Restriction( 21 | require = { 22 | @Condition(value = "curios", versionPredicates = "[5.11,)"), 23 | @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) } 24 | ) 25 | @Mixin(SPacketSyncModifiers.class) 26 | public class SPacketSyncModifiersMixinV2 { 27 | @Inject( 28 | method = "lambda$handle$0", 29 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 30 | slice = @Slice( 31 | from = @At( 32 | value = "INVOKE", 33 | target = "Lnet/minecraftforge/eventbus/api/IEventBus;post(Lnet/minecraftforge/eventbus/api/Event;)Z" 34 | ) 35 | ) 36 | ) 37 | private static void inventorioResetSlots( 38 | SPacketSyncModifiers data, 39 | LivingEntity livingEntity, 40 | Entity entity, 41 | MinecraftClient client, 42 | ICuriosItemHandler handler, 43 | CallbackInfo ci 44 | ) { 45 | if ( 46 | entity instanceof ClientPlayerEntity player 47 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 48 | ) { 49 | curiosContainer.inventorio$resetSlots(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/ForgeEvents.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.client.control.InventorioKeyHandler 4 | import de.rubixdev.inventorio.client.ui.HotbarHUDRenderer.renderHotbarAddons 5 | import net.minecraftforge.api.distmarker.Dist 6 | import net.minecraftforge.api.distmarker.OnlyIn 7 | import net.minecraftforge.client.event.RegisterGuiOverlaysEvent 8 | import net.minecraftforge.event.TickEvent 9 | import net.minecraftforge.eventbus.api.SubscribeEvent 10 | 11 | @OnlyIn(Dist.CLIENT) 12 | object ForgeEvents { 13 | @SubscribeEvent 14 | fun onClientTick(event: TickEvent.ClientTickEvent) { 15 | InventorioKeyHandler.tick() 16 | } 17 | } 18 | 19 | @OnlyIn(Dist.CLIENT) 20 | object ForgeModEvents { 21 | @SubscribeEvent 22 | fun onGuiRender(event: RegisterGuiOverlaysEvent) { 23 | event.registerBelowAll("inventorio_hotbar_addons") { _, guiGraphics, _, _, _ -> 24 | renderHotbarAddons(guiGraphics) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/ScreenTypeProviderForge.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.client.ui.InventorioScreen 4 | import de.rubixdev.inventorio.player.InventorioScreenHandler 5 | import net.minecraft.client.gui.screen.ingame.HandledScreens 6 | import net.minecraft.screen.ScreenHandlerType 7 | import net.minecraftforge.common.extensions.IForgeMenuType 8 | import net.minecraftforge.registries.DeferredRegister 9 | import net.minecraftforge.registries.ForgeRegistries 10 | import thedarkcolour.kotlinforforge.KotlinModLoadingContext 11 | 12 | object ScreenTypeProviderForge : ScreenTypeProvider { 13 | private val handlerProvider = IForgeMenuType.create { syncId, inv, _ -> 14 | InventorioScreenHandler(syncId, inv) 15 | } 16 | 17 | init { 18 | val registry = DeferredRegister.create(ForgeRegistries.MENU_TYPES, "inventorio") 19 | registry.register(KotlinModLoadingContext.get().getKEventBus()) 20 | registry.register("player_screen") { handlerProvider } 21 | } 22 | 23 | override fun getScreenHandlerType(): ScreenHandlerType { 24 | return handlerProvider 25 | } 26 | 27 | fun registerScreen() { 28 | HandledScreens.register(handlerProvider) { handler, inventory, _ -> InventorioScreen(handler, inventory) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/integration/ClumpsIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | import com.blamejared.clumps.api.events.RepairEvent 4 | import de.rubixdev.inventorio.api.InventorioAPI 5 | import net.minecraftforge.common.MinecraftForge 6 | import net.minecraftforge.fml.ModList 7 | 8 | object ClumpsIntegration : ModIntegration() { 9 | override val name = "clumps" 10 | override val displayName = "Clumps" 11 | 12 | override fun shouldApply() = ModList.get().isLoaded("clumps") 13 | 14 | override fun apply() { 15 | MinecraftForge.EVENT_BUS.addListener { event: RepairEvent -> 16 | event.value = InventorioAPI.getInventoryAddon(event.player)!!.mendToolBeltItems(event.value) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/CustomCuriosButton.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import net.minecraft.client.gui.DrawContext 5 | import net.minecraft.client.gui.screen.ingame.HandledScreen 6 | import net.minecraft.client.gui.widget.TexturedButtonWidget 7 | import net.minecraft.util.Identifier 8 | import top.theillusivec4.curios.client.gui.CuriosScreen 9 | 10 | class CustomCuriosButton( 11 | private val parentGui: HandledScreen<*>, 12 | x: Int, 13 | y: Int, 14 | width: Int, 15 | height: Int, 16 | textureOffsetX: Int, 17 | textureOffsetY: Int, 18 | yDiffText: Int, 19 | texture: Identifier, 20 | pressAction: PressAction?, 21 | ) : TexturedButtonWidget(x, y, width, height, textureOffsetX, textureOffsetY, yDiffText, texture, pressAction) { 22 | override fun renderButton(context: DrawContext?, mouseX: Int, mouseY: Int, delta: Float) { 23 | val offsets = CuriosScreen.getButtonOffset(false) 24 | x = parentGui.guiLeft + offsets.left 25 | y = parentGui.height / 2 + offsets.right - 9 * (PlayerInventoryAddon.Client.local?.getDeepPocketsRowCount() ?: 0) 26 | super.renderButton(context, mouseX, mouseY, delta) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/ICuriosContainer.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler 4 | 5 | @Suppress("FunctionName", "PropertyName") 6 | interface ICuriosContainer { 7 | fun `inventorio$resetSlots`() 8 | fun `inventorio$scrollTo`(pos: Float) 9 | fun `inventorio$scrollToIndex`(indexIn: Int) 10 | val `inventorio$hasCosmeticColumn`: Boolean 11 | val `inventorio$canScroll`: Boolean 12 | val `inventorio$curiosHandler`: ICuriosItemHandler? 13 | } 14 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/ICuriosScreen.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | @Suppress("FunctionName", "PropertyName") 4 | interface ICuriosScreen { 5 | fun `inventorio$updateRenderButtons`() 6 | val `inventorio$isCuriosOpen`: Boolean 7 | } 8 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/GlobalSettingsS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import de.rubixdev.inventorio.config.GlobalSettings 6 | import java.util.function.Supplier 7 | import net.minecraft.network.PacketByteBuf 8 | import net.minecraftforge.network.NetworkEvent 9 | 10 | class GlobalSettingsS2CPacket { 11 | private var settingsJson: JsonObject 12 | 13 | // Sender's constructor 14 | constructor() { 15 | this.settingsJson = GlobalSettings.asJson() 16 | } 17 | 18 | // Receiver's constructor 19 | constructor(buf: PacketByteBuf) { 20 | this.settingsJson = Gson().fromJson(buf.readString(), JsonObject::class.java) 21 | } 22 | 23 | // Sender's writer 24 | fun write(buf: PacketByteBuf) { 25 | buf.writeString(settingsJson.toString()) 26 | } 27 | 28 | // Receiver's consumer 29 | fun consume(supplier: Supplier) { 30 | supplier.get().enqueueWork { 31 | GlobalSettings.syncFromServer(settingsJson) 32 | } 33 | supplier.get().packetHandled = true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/MoveItemToUtilityBeltC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler.Companion.inventorioScreenHandler 4 | import java.util.function.Supplier 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraftforge.network.NetworkEvent 7 | 8 | class MoveItemToUtilityBeltC2SPacket { 9 | private var sourceSlot = 0 10 | 11 | // Sender's constructor 12 | constructor(sourceSlot: Int) { 13 | this.sourceSlot = sourceSlot 14 | } 15 | 16 | // Receiver's constructor 17 | constructor(buf: PacketByteBuf) { 18 | sourceSlot = buf.readByte().toInt() 19 | } 20 | 21 | // Sender's writer 22 | fun write(buf: PacketByteBuf) { 23 | buf.writeByte(sourceSlot) 24 | } 25 | 26 | // Receiver's consumer 27 | fun consume(supplier: Supplier) { 28 | val player = supplier.get().sender ?: return 29 | supplier.get().enqueueWork { 30 | val screenHandler = player.inventorioScreenHandler ?: return@enqueueWork 31 | screenHandler.tryTransferToUtilityBeltSlot(screenHandler.getSlot(sourceSlot)) 32 | } 33 | supplier.get().packetHandled = true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/OpenInventorioScreenC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import java.util.function.Supplier 5 | import net.minecraftforge.network.NetworkEvent 6 | 7 | class OpenInventorioScreenC2SPacket { 8 | fun consume(supplier: Supplier) { 9 | val sender = supplier.get().sender ?: return 10 | supplier.get().enqueueWork { 11 | InventorioScreenHandler.open(sender) 12 | } 13 | supplier.get().packetHandled = true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/SelectUtilitySlotPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.mojang.datafixers.util.Pair 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 6 | import java.util.function.Supplier 7 | import net.minecraft.entity.EquipmentSlot 8 | import net.minecraft.network.PacketByteBuf 9 | import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket 10 | import net.minecraft.server.world.ServerWorld 11 | import net.minecraftforge.network.NetworkDirection 12 | import net.minecraftforge.network.NetworkEvent 13 | 14 | class SelectUtilitySlotPacket { 15 | private var utilitySlot = 0 16 | 17 | // Sender's constructor 18 | constructor(utilitySlot: Int) { 19 | this.utilitySlot = utilitySlot 20 | } 21 | 22 | // Receiver's constructor 23 | constructor(buf: PacketByteBuf) { 24 | this.utilitySlot = buf.readByte().toInt() 25 | } 26 | 27 | // Sender's writer 28 | fun write(buf: PacketByteBuf) { 29 | buf.writeByte(utilitySlot) 30 | } 31 | 32 | // Receiver's consumer 33 | fun consume(supplier: Supplier) { 34 | if (supplier.get().direction == NetworkDirection.PLAY_TO_SERVER) { 35 | val player = supplier.get().sender ?: return 36 | supplier.get().enqueueWork { 37 | player.inventoryAddon?.selectedUtility = utilitySlot 38 | 39 | val broadcastPacket = EntityEquipmentUpdateS2CPacket(player.id, listOf(Pair(EquipmentSlot.OFFHAND, player.offHandStack))) 40 | (player.world as ServerWorld).chunkManager.sendToOtherNearbyPlayers(player, broadcastPacket) 41 | } 42 | } else { 43 | supplier.get().enqueueWork { 44 | PlayerInventoryAddon.Client.local?.selectedUtility = utilitySlot 45 | } 46 | } 47 | supplier.get().packetHandled = true 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/SwapItemsInHandsKeyC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import java.util.function.Supplier 5 | import net.minecraftforge.network.NetworkEvent 6 | 7 | class SwapItemsInHandsKeyC2SPacket { 8 | // Receiver's consumer 9 | fun consume(supplier: Supplier) { 10 | val sender = supplier.get().sender ?: return 11 | supplier.get().enqueueWork { 12 | sender.inventoryAddon?.swapItemsInHands() 13 | } 14 | supplier.get().packetHandled = true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/SwappedHandsModeC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import java.util.function.Supplier 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraftforge.network.NetworkEvent 7 | 8 | class SwappedHandsModeC2SPacket { 9 | private var swappedHands = false 10 | 11 | // Sender's constructor 12 | constructor(swappedHands: Boolean) { 13 | this.swappedHands = swappedHands 14 | } 15 | 16 | // Receiver's constructor 17 | constructor(buf: PacketByteBuf) { 18 | swappedHands = buf.readBoolean() 19 | } 20 | 21 | // Sender's writer 22 | fun write(buf: PacketByteBuf) { 23 | buf.writeBoolean(swappedHands) 24 | } 25 | 26 | // Receiver's consumer 27 | fun consume(supplier: Supplier) { 28 | val sender = supplier.get().sender ?: return 29 | supplier.get().enqueueWork { 30 | sender.inventoryAddon?.swappedHands = swappedHands 31 | } 32 | supplier.get().packetHandled = true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/UpdateAddonStacksS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import java.util.function.Supplier 5 | import net.minecraft.item.ItemStack 6 | import net.minecraft.network.PacketByteBuf 7 | import net.minecraftforge.network.NetworkEvent 8 | 9 | class UpdateAddonStacksS2CPacket { 10 | private var updatedStacks: Map 11 | 12 | // Sender's constructor 13 | constructor(updatedStacks: Map) { 14 | this.updatedStacks = updatedStacks 15 | } 16 | 17 | // Receiver's constructor 18 | constructor(buf: PacketByteBuf) { 19 | val size = buf.readInt() 20 | val updatedStacks = mutableMapOf() 21 | for (i in 0 until size) 22 | updatedStacks[buf.readInt()] = buf.readItemStack() 23 | this.updatedStacks = updatedStacks 24 | } 25 | 26 | // Sender's writer 27 | fun write(buf: PacketByteBuf) { 28 | buf.writeInt(updatedStacks.size) 29 | for ((index, stack) in updatedStacks) { 30 | buf.writeInt(index) 31 | buf.writeItemStack(stack) 32 | } 33 | } 34 | 35 | // Receiver's consumer 36 | fun consume(supplier: Supplier) { 37 | supplier.get().enqueueWork { 38 | PlayerInventoryAddon.Client.local?.receiveStacksUpdateS2C(updatedStacks) 39 | } 40 | supplier.get().packetHandled = true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/packet/UseBoostRocketC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import java.util.function.Supplier 5 | import net.minecraftforge.network.NetworkEvent 6 | 7 | class UseBoostRocketC2SPacket { 8 | fun consume(supplier: Supplier) { 9 | val sender = supplier.get().sender ?: return 10 | supplier.get().enqueueWork { 11 | sender.inventoryAddon?.fireRocketFromInventory() 12 | } 13 | supplier.get().packetHandled = true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/kotlin/de/rubixdev/inventorio/util/PlatformApi.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | import net.minecraftforge.fml.ModList 4 | 5 | object PlatformApi { 6 | fun isModLoaded(modId: String): Boolean = ModList.get().isLoaded(modId) 7 | } 8 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "kotlinforforge" 2 | loaderVersion = "[${forge_kotlin_version},)" 3 | issueTrackerURL = "${issues_url}" 4 | license = "${license}" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${version}" 9 | displayName = "${mod_name}" 10 | displayURL = "${homepage_url}" 11 | logoFile = "icon.png" 12 | authors = "${authors}" 13 | description = "${description}" 14 | 15 | [[dependencies.${mod_id}]] 16 | modId = "minecraft" 17 | mandatory = true 18 | versionRange = "${minecraft_version_range_forge}" 19 | ordering = "NONE" 20 | side = "BOTH" 21 | 22 | [[dependencies.${mod_id}]] 23 | modId = "forge" 24 | mandatory = true 25 | versionRange = "${forge_version_range}" 26 | ordering = "NONE" 27 | side = "BOTH" 28 | 29 | [[dependencies.${mod_id}]] 30 | modId = "cloth_config" 31 | mandatory = true 32 | versionRange = "[10,)" 33 | ordering = "NONE" 34 | side = "CLIENT" 35 | -------------------------------------------------------------------------------- /versions/1.20.1-forge/src/main/resources/inventorio-forge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "de.rubixdev.inventorio.mixin.forge", 4 | "compatibilityLevel": "JAVA_17", 5 | "minVersion": "0.8", 6 | "plugin": "de.rubixdev.inventorio.InventorioMixinPlugin", 7 | "mixins": [ 8 | "curios.CPacketScrollMixin", 9 | "curios.CuriosEventHandlerMixin", 10 | "curios.CurioStacksHandlerMixin", 11 | "curios.InventorioScreenHandlerMixin" 12 | ], 13 | "client": [ 14 | "curios.HandledScreenMixin", 15 | "curios.InventorioScreenMixin", 16 | "curios.InventorioScreenMixin_alternative", 17 | "curios.SPacketScrollMixin", 18 | "curios.SPacketSyncCuriosMixin", 19 | "curios.SPacketSyncModifiersMixinV1", 20 | "curios.SPacketSyncModifiersMixinV2" 21 | ], 22 | "injectors": { 23 | "defaultRequire": 1 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /versions/1.20.2-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=fabric 3 | minecraft_version=1.20.2 4 | yarn_mappings=1.20.2+build.4 5 | game_versions=1.20.2 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric=1.20.2 9 | minecraft_version_range_forge= 10 | forge_version= 11 | forge_version_range= 12 | neoforge_version= 13 | neoforge_version_range= 14 | 15 | # Common Dependencies 16 | cloth_version=12.0.119 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=13.0.0.6-fabric,1.20.2 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version=0.1.5+1.20.4 23 | fabric_api_version=0.91.6+1.20.2 24 | modmenu_version=8.0.1 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version=3.8.0 27 | cca_version=5.3.0 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version= 32 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=neoforge 3 | minecraft_version=1.20.2 4 | yarn_mappings=1.20.2+build.4 5 | game_versions=1.20.2 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric= 9 | minecraft_version_range_forge=[1.20.2] 10 | forge_version= 11 | forge_version_range= 12 | neoforge_version=20.2.88 13 | neoforge_version_range=[20.2.84,) 14 | 15 | # Common Dependencies 16 | cloth_version=12.0.119 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=13.0.0.6-neoforge,1.20.2 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version= 23 | fabric_api_version= 24 | modmenu_version= 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version= 27 | cca_version= 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version=6.1.0+1.20.2 32 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CPacketScrollMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 5 | import de.rubixdev.inventorio.util.CuriosTester; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 8 | import net.minecraft.screen.ScreenHandler; 9 | import net.neoforged.neoforge.network.NetworkEvent; 10 | import org.objectweb.asm.Opcodes; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.Slice; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | import top.theillusivec4.curios.common.network.client.CPacketScroll; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(CPacketScroll.class) 21 | public abstract class CPacketScrollMixin { 22 | @Shadow 23 | private int index; 24 | 25 | @Shadow 26 | private int windowId; 27 | 28 | @Inject( 29 | method = "lambda$handle$0", 30 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 31 | slice = @Slice( 32 | from = @At( 33 | value = "FIELD", 34 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 35 | ) 36 | ) 37 | ) 38 | private static void inventorioScrollToIndex( 39 | NetworkEvent.Context ctx, 40 | CPacketScroll msg, 41 | CallbackInfo ci, 42 | @Local ScreenHandler container 43 | ) { 44 | CPacketScrollMixin accessor = ((CPacketScrollMixin) (Object) msg); 45 | // noinspection DataFlowIssue 46 | if (container instanceof ICuriosContainer curiosContainer && container.syncId == accessor.windowId) { 47 | curiosContainer.inventorio$scrollToIndex(accessor.index); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CuriosClientPayloadHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.util.Never; 4 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 6 | import net.minecraft.SharedConstants; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | 9 | // this mixin is only valid in 1.20.4+ 10 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = Never.class)) 11 | @Mixin(SharedConstants.class) 12 | public class CuriosClientPayloadHandlerMixin {} 13 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CuriosServerPayloadHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.util.Never; 4 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 6 | import net.minecraft.SharedConstants; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | 9 | // this mixin is only valid in 1.20.4+ 10 | @Restriction(require = @Condition(type = Condition.Type.TESTER, tester = Never.class)) 11 | @Mixin(SharedConstants.class) 12 | public class CuriosServerPayloadHandlerMixin {} 13 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/SPacketScrollMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 5 | import de.rubixdev.inventorio.integration.curios.ICuriosScreen; 6 | import de.rubixdev.inventorio.util.CuriosTester; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 8 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import net.minecraft.screen.ScreenHandler; 11 | import org.objectweb.asm.Opcodes; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Shadow; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.Slice; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import top.theillusivec4.curios.common.network.server.SPacketScroll; 19 | 20 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 21 | @Mixin(SPacketScroll.class) 22 | public abstract class SPacketScrollMixin { 23 | @Shadow 24 | private int windowId; 25 | 26 | @Shadow 27 | private int index; 28 | 29 | @Inject( 30 | method = "lambda$handle$0", 31 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 32 | slice = @Slice( 33 | from = @At( 34 | value = "INVOKE", 35 | target = "Ltop/theillusivec4/curios/common/inventory/container/CuriosContainer;scrollToIndex(I)V" 36 | ) 37 | ) 38 | ) 39 | private static void inventorioUpdateRenderButtons(SPacketScroll msg, CallbackInfo ci, @Local Screen screen) { 40 | if (screen instanceof ICuriosScreen curiosScreen) { 41 | curiosScreen.inventorio$updateRenderButtons(); 42 | } 43 | } 44 | 45 | @Inject( 46 | method = "lambda$handle$0", 47 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 48 | slice = @Slice( 49 | from = @At( 50 | value = "FIELD", 51 | target = "Lnet/minecraft/client/network/ClientPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 52 | ) 53 | ) 54 | ) 55 | private static void inventorioScrollToIndex(SPacketScroll msg, CallbackInfo ci, @Local ScreenHandler container) { 56 | SPacketScrollMixin accessor = ((SPacketScrollMixin) (Object) msg); 57 | // noinspection DataFlowIssue 58 | if (container instanceof ICuriosContainer curiosContainer && container.syncId == accessor.windowId) { 59 | curiosContainer.inventorio$scrollToIndex(accessor.index); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/SPacketSyncCuriosMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.client.network.ClientPlayerEntity; 8 | import net.minecraft.entity.Entity; 9 | import org.objectweb.asm.Opcodes; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.Slice; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 16 | import top.theillusivec4.curios.common.network.server.sync.SPacketSyncCurios; 17 | 18 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 19 | @Mixin(SPacketSyncCurios.class) 20 | public class SPacketSyncCuriosMixin { 21 | @Inject( 22 | method = "lambda$handle$0", 23 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 24 | slice = @Slice( 25 | from = @At( 26 | value = "INVOKE", 27 | target = "Ltop/theillusivec4/curios/api/type/capability/ICuriosItemHandler;setCurios(Ljava/util/Map;)V" 28 | ) 29 | ) 30 | ) 31 | private static void inventorioResetSlots( 32 | SPacketSyncCurios data, 33 | Entity entity, 34 | ICuriosItemHandler handler, 35 | CallbackInfo ci 36 | ) { 37 | if ( 38 | entity instanceof ClientPlayerEntity player 39 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 40 | ) { 41 | curiosContainer.inventorio$resetSlots(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/SPacketSyncModifiersMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.client.network.ClientPlayerEntity; 8 | import net.minecraft.entity.Entity; 9 | import net.minecraft.entity.LivingEntity; 10 | import org.objectweb.asm.Opcodes; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.Slice; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 17 | import top.theillusivec4.curios.common.network.server.sync.SPacketSyncModifiers; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(SPacketSyncModifiers.class) 21 | public class SPacketSyncModifiersMixin { 22 | @Inject( 23 | method = "lambda$handle$0", 24 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 25 | slice = @Slice( 26 | from = @At( 27 | value = "INVOKE", 28 | target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;" 29 | ) 30 | ) 31 | ) 32 | private static void inventorioResetSlots( 33 | SPacketSyncModifiers data, 34 | LivingEntity livingEntity, 35 | Entity entity, 36 | ICuriosItemHandler handler, 37 | CallbackInfo ci 38 | ) { 39 | if ( 40 | entity instanceof ClientPlayerEntity player 41 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 42 | ) { 43 | curiosContainer.inventorio$resetSlots(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/GlobalSettingsS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import de.rubixdev.inventorio.config.GlobalSettings 6 | import net.minecraft.network.PacketByteBuf 7 | import net.neoforged.neoforge.network.NetworkEvent 8 | 9 | class GlobalSettingsS2CPacket { 10 | private var settingsJson: JsonObject 11 | 12 | // Sender's constructor 13 | constructor() { 14 | this.settingsJson = GlobalSettings.asJson() 15 | } 16 | 17 | // Receiver's constructor 18 | constructor(buf: PacketByteBuf) { 19 | this.settingsJson = Gson().fromJson(buf.readString(), JsonObject::class.java) 20 | } 21 | 22 | // Sender's writer 23 | fun write(buf: PacketByteBuf) { 24 | buf.writeString(settingsJson.toString()) 25 | } 26 | 27 | // Receiver's consumer 28 | fun consume(context: NetworkEvent.Context) { 29 | context.enqueueWork { 30 | GlobalSettings.syncFromServer(settingsJson) 31 | } 32 | context.packetHandled = true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/MoveItemToUtilityBeltC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler.Companion.inventorioScreenHandler 4 | import net.minecraft.network.PacketByteBuf 5 | import net.neoforged.neoforge.network.NetworkEvent 6 | 7 | class MoveItemToUtilityBeltC2SPacket { 8 | private var sourceSlot = 0 9 | 10 | // Sender's constructor 11 | constructor(sourceSlot: Int) { 12 | this.sourceSlot = sourceSlot 13 | } 14 | 15 | // Receiver's constructor 16 | constructor(buf: PacketByteBuf) { 17 | sourceSlot = buf.readByte().toInt() 18 | } 19 | 20 | // Sender's writer 21 | fun write(buf: PacketByteBuf) { 22 | buf.writeByte(sourceSlot) 23 | } 24 | 25 | // Receiver's consumer 26 | fun consume(context: NetworkEvent.Context) { 27 | val player = context.sender ?: return 28 | context.enqueueWork { 29 | val screenHandler = player.inventorioScreenHandler ?: return@enqueueWork 30 | screenHandler.tryTransferToUtilityBeltSlot(screenHandler.getSlot(sourceSlot)) 31 | } 32 | context.packetHandled = true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/OpenInventorioScreenC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import net.neoforged.neoforge.network.NetworkEvent 5 | 6 | class OpenInventorioScreenC2SPacket { 7 | fun consume(context: NetworkEvent.Context) { 8 | val sender = context.sender ?: return 9 | context.enqueueWork { 10 | InventorioScreenHandler.open(sender) 11 | } 12 | context.packetHandled = true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SelectUtilitySlotPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.mojang.datafixers.util.Pair 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 6 | import net.minecraft.entity.EquipmentSlot 7 | import net.minecraft.network.PacketByteBuf 8 | import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket 9 | import net.minecraft.server.world.ServerWorld 10 | import net.neoforged.neoforge.network.NetworkEvent 11 | import net.neoforged.neoforge.network.PlayNetworkDirection 12 | 13 | class SelectUtilitySlotPacket { 14 | private var utilitySlot = 0 15 | 16 | // Sender's constructor 17 | constructor(utilitySlot: Int) { 18 | this.utilitySlot = utilitySlot 19 | } 20 | 21 | // Receiver's constructor 22 | constructor(buf: PacketByteBuf) { 23 | this.utilitySlot = buf.readByte().toInt() 24 | } 25 | 26 | // Sender's writer 27 | fun write(buf: PacketByteBuf) { 28 | buf.writeByte(utilitySlot) 29 | } 30 | 31 | // Receiver's consumer 32 | fun consume(context: NetworkEvent.Context) { 33 | if (context.direction == PlayNetworkDirection.PLAY_TO_SERVER) { 34 | val player = context.sender ?: return 35 | context.enqueueWork { 36 | player.inventoryAddon?.selectedUtility = utilitySlot 37 | 38 | val broadcastPacket = EntityEquipmentUpdateS2CPacket(player.id, listOf(Pair(EquipmentSlot.OFFHAND, player.offHandStack))) 39 | (player.world as ServerWorld).chunkManager.sendToOtherNearbyPlayers(player, broadcastPacket) 40 | } 41 | } else { 42 | context.enqueueWork { 43 | PlayerInventoryAddon.Client.local?.selectedUtility = utilitySlot 44 | } 45 | } 46 | context.packetHandled = true 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SwapItemsInHandsKeyC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.neoforged.neoforge.network.NetworkEvent 5 | 6 | class SwapItemsInHandsKeyC2SPacket { 7 | // Receiver's consumer 8 | fun consume(context: NetworkEvent.Context) { 9 | val sender = context.sender ?: return 10 | context.enqueueWork { 11 | sender.inventoryAddon?.swapItemsInHands() 12 | } 13 | context.packetHandled = true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SwappedHandsModeC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.minecraft.network.PacketByteBuf 5 | import net.neoforged.neoforge.network.NetworkEvent 6 | 7 | class SwappedHandsModeC2SPacket { 8 | private var swappedHands = false 9 | 10 | // Sender's constructor 11 | constructor(swappedHands: Boolean) { 12 | this.swappedHands = swappedHands 13 | } 14 | 15 | // Receiver's constructor 16 | constructor(buf: PacketByteBuf) { 17 | swappedHands = buf.readBoolean() 18 | } 19 | 20 | // Sender's writer 21 | fun write(buf: PacketByteBuf) { 22 | buf.writeBoolean(swappedHands) 23 | } 24 | 25 | // Receiver's consumer 26 | fun consume(context: NetworkEvent.Context) { 27 | val sender = context.sender ?: return 28 | context.enqueueWork { 29 | sender.inventoryAddon?.swappedHands = swappedHands 30 | } 31 | context.packetHandled = true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/UpdateAddonStacksS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import net.minecraft.item.ItemStack 5 | import net.minecraft.network.PacketByteBuf 6 | import net.neoforged.neoforge.network.NetworkEvent 7 | 8 | class UpdateAddonStacksS2CPacket { 9 | private var updatedStacks: Map 10 | 11 | // Sender's constructor 12 | constructor(updatedStacks: Map) { 13 | this.updatedStacks = updatedStacks 14 | } 15 | 16 | // Receiver's constructor 17 | constructor(buf: PacketByteBuf) { 18 | val size = buf.readInt() 19 | val updatedStacks = mutableMapOf() 20 | for (i in 0 until size) 21 | updatedStacks[buf.readInt()] = buf.readItemStack() 22 | this.updatedStacks = updatedStacks 23 | } 24 | 25 | // Sender's writer 26 | fun write(buf: PacketByteBuf) { 27 | buf.writeInt(updatedStacks.size) 28 | for ((index, stack) in updatedStacks) { 29 | buf.writeInt(index) 30 | buf.writeItemStack(stack) 31 | } 32 | } 33 | 34 | // Receiver's consumer 35 | fun consume(context: NetworkEvent.Context) { 36 | context.enqueueWork { 37 | PlayerInventoryAddon.Client.local?.receiveStacksUpdateS2C(updatedStacks) 38 | } 39 | context.packetHandled = true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/UseBoostRocketC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.neoforged.neoforge.network.NetworkEvent 5 | 6 | class UseBoostRocketC2SPacket { 7 | fun consume(context: NetworkEvent.Context) { 8 | val sender = context.sender ?: return 9 | context.enqueueWork { 10 | sender.inventoryAddon?.fireRocketFromInventory() 11 | } 12 | context.packetHandled = true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "kotlinforforge" 2 | loaderVersion = "[${forge_kotlin_version},)" 3 | issueTrackerURL = "${issues_url}" 4 | license = "${license}" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${version}" 9 | displayName = "${mod_name}" 10 | displayURL = "${homepage_url}" 11 | logoFile = "icon.png" 12 | authors = "${authors}" 13 | description = "${description}" 14 | 15 | [[mixins]] 16 | config = "${mod_id}.mixins.json" 17 | [[mixins]] 18 | config = "${mod_id}-neoforge.mixins.json" 19 | [[mixins]] 20 | config = "${mod_id}-neoforge-12002.mixins.json" 21 | 22 | [[dependencies.${mod_id}]] 23 | modId = "minecraft" 24 | mandatory = true 25 | versionRange = "${minecraft_version_range_forge}" 26 | ordering = "NONE" 27 | side = "BOTH" 28 | 29 | [[dependencies.${mod_id}]] 30 | modId = "neoforge" 31 | mandatory = true 32 | versionRange = "${neoforge_version_range}" 33 | ordering = "NONE" 34 | side = "BOTH" 35 | 36 | [[dependencies.${mod_id}]] 37 | modId = "cloth_config" 38 | mandatory = true 39 | versionRange = "[10,)" 40 | ordering = "NONE" 41 | side = "CLIENT" 42 | -------------------------------------------------------------------------------- /versions/1.20.2-neoforge/src/main/resources/inventorio-neoforge-12002.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "de.rubixdev.inventorio.mixin.neoforge", 4 | "compatibilityLevel": "JAVA_17", 5 | "minVersion": "0.8", 6 | "plugin": "de.rubixdev.inventorio.InventorioMixinPlugin", 7 | "mixins": [ 8 | "curios.CPacketScrollMixin" 9 | ], 10 | "client": [ 11 | "curios.SPacketScrollMixin", 12 | "curios.SPacketSyncCuriosMixin", 13 | "curios.SPacketSyncModifiersMixin" 14 | ], 15 | "injectors": { 16 | "defaultRequire": 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /versions/1.20.4-common/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | minecraft_version=1.20.4 3 | yarn_mappings=1.20.4+build.3 4 | game_versions=1.20.3\n1.20.4 5 | 6 | # (Neo)Forge and dependency version ranges 7 | minecraft_version_range_fabric= 8 | minecraft_version_range_forge= 9 | forge_version= 10 | forge_version_range= 11 | neoforge_version= 12 | neoforge_version_range= 13 | 14 | # Common Dependencies 15 | cloth_version=13.0.121 16 | # https://modrinth.com/mod/clumps/versions 17 | clumps_version=15.0.0.2-fabric,1.20.4 18 | 19 | # Fabric Dependencies 20 | # https://modrinth.com/mod/early-loading-screen/versions 21 | early_loading_screen_version= 22 | fabric_api_version= 23 | modmenu_version= 24 | # https://modrinth.com/mod/trinkets/versions?l=fabric 25 | trinkets_version= 26 | cca_version= 27 | 28 | # (Neo)Forge Dependencies 29 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 30 | curios_version= 31 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=fabric 3 | minecraft_version=1.20.4 4 | yarn_mappings=1.20.4+build.3 5 | game_versions=1.20.3\n1.20.4 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric=>=1.20.3 9 | minecraft_version_range_forge= 10 | forge_version= 11 | forge_version_range= 12 | neoforge_version= 13 | neoforge_version_range= 14 | 15 | # Common Dependencies 16 | cloth_version=13.0.121 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=15.0.0.2-fabric,1.20.4 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version=0.1.5+1.20.4 23 | fabric_api_version=0.95.4+1.20.4 24 | modmenu_version=9.0.0 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version=3.8.1 27 | cca_version= 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version= 32 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/java/de/rubixdev/inventorio/mixin/fabric/trinkets/SlotGroupMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.fabric.trinkets; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 4 | import de.rubixdev.inventorio.client.ui.InventorioScreen; 5 | import de.rubixdev.inventorio.player.InventorioScreenHandler; 6 | import de.rubixdev.inventorio.util.TrinketsTester; 7 | import dev.emi.trinkets.api.SlotGroup; 8 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 9 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 10 | import net.fabricmc.api.EnvType; 11 | import net.fabricmc.loader.api.FabricLoader; 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.screen.PlayerScreenHandler; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | 17 | @Restriction( 18 | require = { @Condition("trinkets"), @Condition(type = Condition.Type.TESTER, tester = TrinketsTester.class) } 19 | ) 20 | @Mixin(SlotGroup.class) 21 | public class SlotGroupMixin { 22 | @ModifyReturnValue(method = "getSlotId", at = @At("RETURN"), remap = false) 23 | private int overwriteOffhandId(int original) { 24 | // when injecting Trinkets in the Inventorio screen we change groups 25 | // associated with the offhand slot to the first utility belt slot 26 | // instead 27 | if ( 28 | original == PlayerScreenHandler.OFFHAND_ID 29 | && FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT 30 | && MinecraftClient.getInstance().currentScreen instanceof InventorioScreen 31 | ) { 32 | return InventorioScreenHandler.utilityBeltRange.getFirst(); 33 | } 34 | return original; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/ScreenTypeProviderFabric.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.client.ui.InventorioScreen 4 | import de.rubixdev.inventorio.player.InventorioScreenHandler 5 | import net.minecraft.client.gui.screen.ingame.HandledScreens 6 | import net.minecraft.registry.Registries 7 | import net.minecraft.registry.Registry 8 | import net.minecraft.resource.featuretoggle.FeatureFlags 9 | import net.minecraft.screen.ScreenHandlerType 10 | import net.minecraft.util.Identifier 11 | 12 | object ScreenTypeProviderFabric : ScreenTypeProvider { 13 | private val handlerProvider = Registry.register( 14 | Registries.SCREEN_HANDLER, 15 | Identifier("inventorio", "player_screen"), 16 | ScreenHandlerType({ syncId, inv -> InventorioScreenHandler(syncId, inv) }, FeatureFlags.VANILLA_FEATURES), 17 | ) 18 | 19 | override fun getScreenHandlerType(): ScreenHandlerType { 20 | return handlerProvider 21 | } 22 | 23 | fun registerScreen() { 24 | HandledScreens.register(getScreenHandlerType()) { handler, inventory, _ -> InventorioScreen(handler, inventory) } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/integration/ClumpsIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | import com.blamejared.clumps.api.events.ClumpsEvents 4 | import de.rubixdev.inventorio.api.InventorioAPI 5 | import net.fabricmc.loader.api.FabricLoader 6 | 7 | object ClumpsIntegration : ModIntegration() { 8 | override val name = "clumps" 9 | override val displayName = "Clumps" 10 | 11 | override fun shouldApply() = FabricLoader.getInstance().isModLoaded("clumps") 12 | 13 | override fun apply() { 14 | ClumpsEvents.REPAIR_EVENT.register { event -> 15 | event.value = InventorioAPI.getInventoryAddon(event.player)!!.mendToolBeltItems(event.value) 16 | null 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/integration/ModMenuIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | import com.terraformersmc.modmenu.api.ConfigScreenFactory 4 | import com.terraformersmc.modmenu.api.ModMenuApi 5 | import de.rubixdev.inventorio.client.configscreen.PlayerSettingsScreen 6 | import net.fabricmc.api.EnvType 7 | import net.fabricmc.api.Environment 8 | 9 | @Environment(EnvType.CLIENT) 10 | class ModMenuIntegration : ModMenuApi { 11 | @Environment(EnvType.CLIENT) 12 | override fun getModConfigScreenFactory(): ConfigScreenFactory<*> { 13 | return ConfigScreenFactory { parent -> PlayerSettingsScreen.get(parent) } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/GlobalSettingsS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import de.rubixdev.inventorio.config.GlobalSettings 6 | import net.fabricmc.fabric.api.networking.v1.PacketSender 7 | import net.minecraft.client.MinecraftClient 8 | import net.minecraft.client.network.ClientPlayNetworkHandler 9 | import net.minecraft.network.PacketByteBuf 10 | import net.minecraft.util.Identifier 11 | 12 | @Suppress("UNUSED_PARAMETER") 13 | object GlobalSettingsS2CPacket { 14 | val identifier = Identifier("inventorio", "global_settings") 15 | 16 | fun consume(client: MinecraftClient, handler: ClientPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 17 | val jsonString = buf.readString() 18 | val settingsJson = Gson().fromJson(jsonString, JsonObject::class.java) 19 | client.execute { 20 | GlobalSettings.syncFromServer(settingsJson) 21 | } 22 | } 23 | 24 | fun write(buf: PacketByteBuf) { 25 | buf.writeString(GlobalSettings.asJson().toString()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/MoveItemToUtilityBeltC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler.Companion.inventorioScreenHandler 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.server.network.ServerPlayNetworkHandler 8 | import net.minecraft.server.network.ServerPlayerEntity 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object MoveItemToUtilityBeltC2SPacket { 13 | val identifier = Identifier("inventorio", "move_to_utility_c2s") 14 | 15 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | val sourceSlot = buf.readByte().toInt() 17 | server.execute { 18 | val screenHandler = player.inventorioScreenHandler ?: return@execute 19 | screenHandler.tryTransferToUtilityBeltSlot(screenHandler.getSlot(sourceSlot)) 20 | } 21 | } 22 | 23 | fun write(buf: PacketByteBuf, sourceSlot: Int = 0) { 24 | buf.writeByte(sourceSlot) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/OpenInventorioScreenC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.server.network.ServerPlayNetworkHandler 8 | import net.minecraft.server.network.ServerPlayerEntity 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object OpenInventorioScreenC2SPacket { 13 | val identifier = Identifier("inventorio", "open_screen") 14 | 15 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | server.execute { 17 | InventorioScreenHandler.open(player) 18 | } 19 | } 20 | 21 | fun write(buf: PacketByteBuf) { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/SelectUtilitySlotPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.mojang.datafixers.util.Pair 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 6 | import net.fabricmc.fabric.api.networking.v1.PacketSender 7 | import net.minecraft.client.MinecraftClient 8 | import net.minecraft.client.network.ClientPlayNetworkHandler 9 | import net.minecraft.entity.EquipmentSlot 10 | import net.minecraft.network.PacketByteBuf 11 | import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket 12 | import net.minecraft.server.MinecraftServer 13 | import net.minecraft.server.network.ServerPlayNetworkHandler 14 | import net.minecraft.server.network.ServerPlayerEntity 15 | import net.minecraft.server.world.ServerWorld 16 | import net.minecraft.util.Identifier 17 | 18 | @Suppress("UNUSED_PARAMETER") 19 | object SelectUtilitySlotPacket { 20 | val identifier = Identifier("inventorio", "select_utility") 21 | 22 | // Server's receiving consumer 23 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 24 | val utilitySlot = buf.readByte().toInt() 25 | server.execute { 26 | player.inventoryAddon?.selectedUtility = utilitySlot 27 | 28 | // Resending the current offhand item (aka a selected utility belt item) of this player to other players 29 | val broadcastPacket = EntityEquipmentUpdateS2CPacket(player.id, listOf(Pair(EquipmentSlot.OFFHAND, player.offHandStack))) 30 | (player.world as ServerWorld).chunkManager.sendToOtherNearbyPlayers(player, broadcastPacket) 31 | } 32 | } 33 | 34 | // Client's receiving consumer 35 | fun consume(client: MinecraftClient, handler: ClientPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 36 | val utilitySlot = buf.readByte().toInt() 37 | client.execute { 38 | PlayerInventoryAddon.Client.local?.selectedUtility = utilitySlot 39 | } 40 | } 41 | 42 | fun write(buf: PacketByteBuf, slot: Int = 0) { 43 | buf.writeByte(slot) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/SwapItemsInHandsKeyC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.server.network.ServerPlayNetworkHandler 8 | import net.minecraft.server.network.ServerPlayerEntity 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object SwapItemsInHandsKeyC2SPacket { 13 | val identifier = Identifier("inventorio", "swap_items_in_hands") 14 | 15 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | server.execute { 17 | player.inventoryAddon?.swapItemsInHands() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/SwappedHandsModeC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.server.network.ServerPlayNetworkHandler 8 | import net.minecraft.server.network.ServerPlayerEntity 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object SwappedHandsModeC2SPacket { 13 | val identifier = Identifier("inventorio", "swapped_hands") 14 | 15 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | val swappedHands = buf.readBoolean() 17 | server.execute { 18 | player.inventoryAddon?.swappedHands = swappedHands 19 | } 20 | } 21 | 22 | fun write(buf: PacketByteBuf, swappedHands: Boolean = false) { 23 | buf.writeBoolean(swappedHands) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/UpdateAddonStacksS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.client.MinecraftClient 6 | import net.minecraft.client.network.ClientPlayNetworkHandler 7 | import net.minecraft.item.ItemStack 8 | import net.minecraft.network.PacketByteBuf 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object UpdateAddonStacksS2CPacket { 13 | val identifier = Identifier("inventorio", "update_addon_stacks") 14 | 15 | fun consume(client: MinecraftClient, handler: ClientPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | val size = buf.readInt() 17 | val updatedStacks = mutableMapOf() 18 | for (i in 0 until size) 19 | updatedStacks[buf.readInt()] = buf.readItemStack() 20 | client.execute { 21 | PlayerInventoryAddon.Client.local?.receiveStacksUpdateS2C(updatedStacks) 22 | } 23 | } 24 | 25 | fun write(buf: PacketByteBuf, updatedStacks: Map) { 26 | buf.writeInt(updatedStacks.size) 27 | for ((index, stack) in updatedStacks) { 28 | buf.writeInt(index) 29 | buf.writeItemStack(stack) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/packet/UseBoostRocketC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import net.fabricmc.fabric.api.networking.v1.PacketSender 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.server.MinecraftServer 7 | import net.minecraft.server.network.ServerPlayNetworkHandler 8 | import net.minecraft.server.network.ServerPlayerEntity 9 | import net.minecraft.util.Identifier 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | object UseBoostRocketC2SPacket { 13 | val identifier = Identifier("inventorio", "fire_boost_rocket_c2s") 14 | 15 | fun consume(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) { 16 | server.execute { 17 | player.inventoryAddon?.fireRocketFromInventory() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/kotlin/de/rubixdev/inventorio/util/PlatformApi.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | import net.fabricmc.loader.api.FabricLoader 4 | 5 | object PlatformApi { 6 | fun isModLoaded(modId: String): Boolean = FabricLoader.getInstance().isModLoaded(modId) 7 | } 8 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${version}", 5 | "name": "${mod_name}", 6 | "description": "${description}", 7 | "authors": ["${authors}"], 8 | "contact": { 9 | "homepage": "${homepage_url}", 10 | "sources": "${sources_url}", 11 | "issues": "${issues_url}" 12 | }, 13 | "license": "${license}", 14 | "icon": "icon.png", 15 | "entrypoints": { 16 | "main": [{ 17 | "value": "de.rubixdev.inventorio.InventorioFabric", 18 | "adapter": "kotlin" 19 | }], 20 | "modmenu": [{ 21 | "value": "de.rubixdev.inventorio.integration.ModMenuIntegration", 22 | "adapter": "kotlin" 23 | }] 24 | }, 25 | "mixins": [ 26 | "${mod_id}.mixins.json", 27 | "${mod_id}-fabric.mixins.json" 28 | ], 29 | "depends": { 30 | "minecraft": "${minecraft_version_range_fabric}", 31 | "fabricloader": ">=${fabric_loader_version}", 32 | "fabric-api": "*", 33 | "fabric-language-kotlin": ">=${fabric_kotlin_version}", 34 | "cloth-config": "*" 35 | }, 36 | "suggests": { 37 | "modmenu": "*" 38 | }, 39 | "custom": { 40 | "modmenu": { 41 | "links": { 42 | "modmenu.discord": "https://discord.gg/Etq9EBYU7Q" 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /versions/1.20.4-fabric/src/main/resources/inventorio-fabric.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "de.rubixdev.inventorio.mixin.fabric", 4 | "compatibilityLevel": "JAVA_17", 5 | "minVersion": "0.8", 6 | "plugin": "de.rubixdev.inventorio.InventorioMixinPlugin", 7 | "mixins": [ 8 | "trinkets.InventorioScreenHandlerMixin" 9 | ], 10 | "client": [ 11 | "trinkets.InventorioScreenMixin", 12 | "trinkets.SlotGroupMixin" 13 | ], 14 | "injectors": { 15 | "defaultRequire": 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | # General Properties 2 | loom.platform=neoforge 3 | minecraft_version=1.20.4 4 | yarn_mappings=1.20.4+build.3 5 | game_versions=1.20.3\n1.20.4 6 | 7 | # (Neo)Forge and dependency version ranges 8 | minecraft_version_range_fabric= 9 | minecraft_version_range_forge=[1.20.3,) 10 | forge_version= 11 | forge_version_range= 12 | neoforge_version=20.4.169 13 | neoforge_version_range=[20.4,) 14 | 15 | # Common Dependencies 16 | cloth_version=13.0.121 17 | # https://modrinth.com/mod/clumps/versions 18 | clumps_version=15.0.0.2-neoforge,1.20.4 19 | 20 | # Fabric Dependencies 21 | # https://modrinth.com/mod/early-loading-screen/versions 22 | early_loading_screen_version= 23 | fabric_api_version= 24 | modmenu_version= 25 | # https://modrinth.com/mod/trinkets/versions?l=fabric 26 | trinkets_version= 27 | cca_version= 28 | 29 | # (Neo)Forge Dependencies 30 | # https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/ 31 | curios_version=7.3.4+1.20.4 32 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CurioStacksHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import org.objectweb.asm.Opcodes; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.Slice; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 17 | import top.theillusivec4.curios.common.inventory.CurioStacksHandler; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(CurioStacksHandler.class) 21 | public class CurioStacksHandlerMixin { 22 | @Shadow 23 | @Final 24 | private ICuriosItemHandler itemHandler; 25 | 26 | @Inject( 27 | method = "update", 28 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 29 | slice = @Slice( 30 | from = @At( 31 | value = "INVOKE", 32 | target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;" 33 | ) 34 | ) 35 | ) 36 | private void inventorioResetSlots(CallbackInfo ci) { 37 | if ( 38 | itemHandler.getWearer() instanceof PlayerEntity player 39 | && player.currentScreenHandler instanceof ICuriosContainer curiosContainer 40 | ) { 41 | curiosContainer.inventorio$resetSlots(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CuriosEventHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 4 | import de.rubixdev.inventorio.util.CuriosTester; 5 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import org.objectweb.asm.Opcodes; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.Slice; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 14 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; 15 | import top.theillusivec4.curios.common.event.CuriosEventHandler; 16 | 17 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 18 | @Mixin(CuriosEventHandler.class) 19 | public class CuriosEventHandlerMixin { 20 | //#if MC >= 12004 21 | @Inject( 22 | method = "lambda$onDatapackSync$4", 23 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 24 | slice = @Slice( 25 | from = @At( 26 | value = "FIELD", 27 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 28 | ) 29 | ) 30 | ) 31 | private static void inventorioResetSlots(ServerPlayerEntity mp, ICuriosItemHandler handler, CallbackInfo ci) { 32 | if (mp.currentScreenHandler instanceof ICuriosContainer curiosContainer) { 33 | curiosContainer.inventorio$resetSlots(); 34 | } 35 | } 36 | //#endif 37 | 38 | @Inject( 39 | //#if MC >= 12004 40 | method = "lambda$onDatapackSync$2", 41 | //#else 42 | //$$ method = "lambda$onDatapackSync$5", 43 | //#endif 44 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 45 | slice = @Slice( 46 | from = @At( 47 | value = "FIELD", 48 | target = "Lnet/minecraft/server/network/ServerPlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 49 | ) 50 | ) 51 | ) 52 | private static void inventorioResetSlots2(ServerPlayerEntity player, ICuriosItemHandler handler, CallbackInfo ci) { 53 | if (player.currentScreenHandler instanceof ICuriosContainer curiosContainer) { 54 | curiosContainer.inventorio$resetSlots(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/CuriosServerPayloadHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import com.llamalad7.mixinextras.sugar.Local; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosContainer; 5 | import de.rubixdev.inventorio.util.CuriosTester; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import net.minecraft.screen.ScreenHandler; 10 | import org.objectweb.asm.Opcodes; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.Slice; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import top.theillusivec4.curios.common.network.client.CPacketScroll; 17 | import top.theillusivec4.curios.common.network.server.CuriosServerPayloadHandler; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(CuriosServerPayloadHandler.class) 21 | public class CuriosServerPayloadHandlerMixin { 22 | @Inject( 23 | method = "lambda$handleScroll$5", 24 | at = @At(value = "JUMP", opcode = Opcodes.IFEQ, shift = At.Shift.BEFORE, ordinal = 0), 25 | slice = @Slice( 26 | from = @At( 27 | value = "FIELD", 28 | target = "Lnet/minecraft/entity/player/PlayerEntity;currentScreenHandler:Lnet/minecraft/screen/ScreenHandler;" 29 | ) 30 | ) 31 | ) 32 | private static void inventorioScrollToIndex( 33 | CPacketScroll data, 34 | PlayerEntity player, 35 | CallbackInfo ci, 36 | @Local ScreenHandler container 37 | ) { 38 | if (container instanceof ICuriosContainer curiosContainer && container.syncId == data.windowId()) { 39 | curiosContainer.inventorio$scrollToIndex(data.index()); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/java/de/rubixdev/inventorio/mixin/neoforge/curios/HandledScreenMixin.java: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.mixin.neoforge.curios; 2 | 3 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 4 | import de.rubixdev.inventorio.integration.curios.ICuriosScreen; 5 | import de.rubixdev.inventorio.util.CuriosTester; 6 | import me.fallenbreath.conditionalmixin.api.annotation.Condition; 7 | import me.fallenbreath.conditionalmixin.api.annotation.Restriction; 8 | import net.minecraft.client.gui.DrawContext; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 11 | import net.minecraft.screen.slot.Slot; 12 | import net.minecraft.text.Text; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | import top.theillusivec4.curios.common.inventory.CurioSlot; 18 | 19 | @Restriction(require = { @Condition("curios"), @Condition(type = Condition.Type.TESTER, tester = CuriosTester.class) }) 20 | @Mixin(HandledScreen.class) 21 | public class HandledScreenMixin extends Screen { 22 | protected HandledScreenMixin(Text title) { 23 | super(title); 24 | } 25 | 26 | @ModifyReturnValue(method = "isPointOverSlot", at = @At("RETURN")) 27 | private boolean dontRenderCuriosWhenClosed(boolean original, Slot slot) { 28 | if ( 29 | this instanceof ICuriosScreen curiosScreen 30 | && slot instanceof CurioSlot 31 | && !curiosScreen.getInventorio$isCuriosOpen() 32 | ) { 33 | return false; 34 | } 35 | return original; 36 | } 37 | 38 | @Inject(method = "drawSlot", at = @At("HEAD"), cancellable = true) 39 | private void dontRenderCuriosWhenClosed(DrawContext context, Slot slot, CallbackInfo ci) { 40 | if ( 41 | this instanceof ICuriosScreen curiosScreen 42 | && slot instanceof CurioSlot 43 | && !curiosScreen.getInventorio$isCuriosOpen() 44 | ) { 45 | ci.cancel(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/NeoForgeEvents.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.client.control.InventorioKeyHandler 4 | import de.rubixdev.inventorio.client.ui.HotbarHUDRenderer.renderHotbarAddons 5 | import net.minecraft.util.Identifier 6 | import net.neoforged.api.distmarker.Dist 7 | import net.neoforged.api.distmarker.OnlyIn 8 | import net.neoforged.bus.api.SubscribeEvent 9 | import net.neoforged.neoforge.client.event.RegisterGuiOverlaysEvent 10 | import net.neoforged.neoforge.event.TickEvent 11 | 12 | @OnlyIn(Dist.CLIENT) 13 | object NeoForgeEvents { 14 | @SubscribeEvent 15 | fun onClientTick(event: TickEvent.ClientTickEvent) { 16 | InventorioKeyHandler.tick() 17 | } 18 | } 19 | 20 | @OnlyIn(Dist.CLIENT) 21 | object NeoForgeModEvents { 22 | @SubscribeEvent 23 | fun preGuiRender(event: RegisterGuiOverlaysEvent) { 24 | event.registerBelowAll(Identifier("inventorio", "hotbar_addons")) { _, guiGraphics, _, _, _ -> 25 | renderHotbarAddons(guiGraphics) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/ScreenTypeProviderNeoForge.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio 2 | 3 | import de.rubixdev.inventorio.client.ui.InventorioScreen 4 | import de.rubixdev.inventorio.player.InventorioScreenHandler 5 | import net.minecraft.registry.Registries 6 | import net.minecraft.screen.ScreenHandlerType 7 | import net.neoforged.neoforge.common.extensions.IMenuTypeExtension 8 | import net.neoforged.neoforge.registries.DeferredRegister 9 | import thedarkcolour.kotlinforforge.neoforge.KotlinModLoadingContext 10 | 11 | //#if MC >= 12004 12 | import net.neoforged.bus.api.SubscribeEvent 13 | import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent 14 | //#else 15 | //$$ import net.minecraft.client.gui.screen.ingame.HandledScreens 16 | //#endif 17 | 18 | object ScreenTypeProviderNeoForge : ScreenTypeProvider { 19 | private val handlerProvider = IMenuTypeExtension.create { syncId, inv, _ -> 20 | InventorioScreenHandler(syncId, inv) 21 | } 22 | 23 | init { 24 | val registry = DeferredRegister.create(Registries.SCREEN_HANDLER, "inventorio") 25 | registry.register(KotlinModLoadingContext.get().getKEventBus()) 26 | registry.register("player_screen") { -> handlerProvider } 27 | } 28 | 29 | override fun getScreenHandlerType(): ScreenHandlerType { 30 | return handlerProvider 31 | } 32 | 33 | //#if MC >= 12004 34 | @SubscribeEvent 35 | fun registerScreen(event: RegisterMenuScreensEvent) { 36 | event.register(handlerProvider) { handler, inventory, _ -> InventorioScreen(handler, inventory) } 37 | } 38 | //#else 39 | //$$ fun registerScreen() { 40 | //$$ HandledScreens.register(handlerProvider) { handler, inventory, _ -> InventorioScreen(handler, inventory) } 41 | //$$ } 42 | //#endif 43 | } 44 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/integration/ClumpsIntegration.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration 2 | 3 | import com.blamejared.clumps.api.events.RepairEvent 4 | import de.rubixdev.inventorio.api.InventorioAPI 5 | import net.neoforged.fml.ModList 6 | import net.neoforged.neoforge.common.NeoForge 7 | 8 | object ClumpsIntegration : ModIntegration() { 9 | override val name = "clumps" 10 | override val displayName = "Clumps" 11 | 12 | override fun shouldApply() = ModList.get().isLoaded("clumps") 13 | 14 | override fun apply() { 15 | NeoForge.EVENT_BUS.addListener { event: RepairEvent -> 16 | event.value = InventorioAPI.getInventoryAddon(event.player)!!.mendToolBeltItems(event.value) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/CustomCuriosButton.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import net.minecraft.client.gui.DrawContext 5 | import net.minecraft.client.gui.screen.ButtonTextures 6 | import net.minecraft.client.gui.screen.ingame.HandledScreen 7 | import net.minecraft.client.gui.widget.TexturedButtonWidget 8 | import top.theillusivec4.curios.client.gui.CuriosScreen 9 | 10 | class CustomCuriosButton( 11 | private val parentGui: HandledScreen<*>, 12 | x: Int, 13 | y: Int, 14 | width: Int, 15 | height: Int, 16 | textures: ButtonTextures?, 17 | pressAction: PressAction?, 18 | ) : TexturedButtonWidget(x, y, width, height, textures, pressAction) { 19 | override fun renderWidget(context: DrawContext?, mouseX: Int, mouseY: Int, delta: Float) { 20 | val offsets = CuriosScreen.getButtonOffset(false) 21 | x = parentGui.guiLeft + offsets.left + 2 22 | y = parentGui.height / 2 + offsets.right + 2 - 9 * (PlayerInventoryAddon.Client.local?.getDeepPocketsRowCount() ?: 0) 23 | super.renderWidget(context, mouseX, mouseY, delta) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/ICuriosContainer.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler 4 | 5 | @Suppress("FunctionName", "PropertyName") 6 | interface ICuriosContainer { 7 | fun `inventorio$resetSlots`() 8 | fun `inventorio$scrollTo`(pos: Float) 9 | fun `inventorio$scrollToIndex`(indexIn: Int) 10 | val `inventorio$hasCosmeticColumn`: Boolean 11 | val `inventorio$canScroll`: Boolean 12 | val `inventorio$curiosHandler`: ICuriosItemHandler? 13 | } 14 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/integration/curios/ICuriosScreen.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.integration.curios 2 | 3 | @Suppress("FunctionName", "PropertyName") 4 | interface ICuriosScreen { 5 | fun `inventorio$updateRenderButtons`() 6 | val `inventorio$isCuriosOpen`: Boolean 7 | } 8 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/GlobalSettingsS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import de.rubixdev.inventorio.config.GlobalSettings 6 | import net.minecraft.network.PacketByteBuf 7 | import net.minecraft.network.packet.CustomPayload 8 | import net.minecraft.util.Identifier 9 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 10 | 11 | class GlobalSettingsS2CPacket : CustomPayload { 12 | companion object { 13 | val identifier = Identifier("inventorio", "global_settings") 14 | } 15 | 16 | private var settingsJson: JsonObject 17 | 18 | // Sender's constructor 19 | constructor() { 20 | this.settingsJson = GlobalSettings.asJson() 21 | } 22 | 23 | // Receiver's constructor 24 | constructor(buf: PacketByteBuf) { 25 | this.settingsJson = Gson().fromJson(buf.readString(), JsonObject::class.java) 26 | } 27 | 28 | override fun id(): Identifier = identifier 29 | 30 | // Sender's writer 31 | override fun write(buf: PacketByteBuf) { 32 | buf.writeString(settingsJson.toString()) 33 | } 34 | 35 | // Receiver's consumer 36 | fun consume(context: PlayPayloadContext) { 37 | context.workHandler.execute { 38 | GlobalSettings.syncFromServer(settingsJson) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/MoveItemToUtilityBeltC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler.Companion.inventorioScreenHandler 4 | import kotlin.jvm.optionals.getOrNull 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class MoveItemToUtilityBeltC2SPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "move_to_utility_c2s") 13 | } 14 | private var sourceSlot = 0 15 | 16 | // Sender's constructor 17 | constructor(sourceSlot: Int) { 18 | this.sourceSlot = sourceSlot 19 | } 20 | 21 | // Receiver's constructor 22 | constructor(buf: PacketByteBuf) { 23 | sourceSlot = buf.readByte().toInt() 24 | } 25 | 26 | override fun id(): Identifier = identifier 27 | 28 | // Sender's writer 29 | override fun write(buf: PacketByteBuf) { 30 | buf.writeByte(sourceSlot) 31 | } 32 | 33 | // Receiver's consumer 34 | fun consume(context: PlayPayloadContext) { 35 | val player = context.player.getOrNull() ?: return 36 | context.workHandler.execute { 37 | val screenHandler = player.inventorioScreenHandler ?: return@execute 38 | screenHandler.tryTransferToUtilityBeltSlot(screenHandler.getSlot(sourceSlot)) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/OpenInventorioScreenC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.InventorioScreenHandler 4 | import kotlin.jvm.optionals.getOrNull 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class OpenInventorioScreenC2SPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "open_screen") 13 | } 14 | 15 | override fun id(): Identifier = identifier 16 | 17 | override fun write(buf: PacketByteBuf?) {} 18 | 19 | fun consume(context: PlayPayloadContext) { 20 | val sender = context.player.getOrNull() ?: return 21 | context.workHandler.execute { 22 | InventorioScreenHandler.open(sender) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SelectUtilitySlotPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import com.mojang.datafixers.util.Pair 4 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 5 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 6 | import kotlin.jvm.optionals.getOrNull 7 | import net.minecraft.entity.EquipmentSlot 8 | import net.minecraft.network.PacketByteBuf 9 | import net.minecraft.network.packet.CustomPayload 10 | import net.minecraft.network.packet.s2c.play.EntityEquipmentUpdateS2CPacket 11 | import net.minecraft.server.world.ServerWorld 12 | import net.minecraft.util.Identifier 13 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 14 | 15 | class SelectUtilitySlotPacket : CustomPayload { 16 | companion object { 17 | val identifier = Identifier("inventorio", "select_utility") 18 | } 19 | private var utilitySlot = 0 20 | 21 | // Sender's constructor 22 | constructor(utilitySlot: Int) { 23 | this.utilitySlot = utilitySlot 24 | } 25 | 26 | // Receiver's constructor 27 | constructor(buf: PacketByteBuf) { 28 | this.utilitySlot = buf.readByte().toInt() 29 | } 30 | 31 | override fun id(): Identifier = identifier 32 | 33 | // Sender's writer 34 | override fun write(buf: PacketByteBuf) { 35 | buf.writeByte(utilitySlot) 36 | } 37 | 38 | // Client's receiving consumer 39 | fun consumeClient(context: PlayPayloadContext) { 40 | context.workHandler.execute { 41 | PlayerInventoryAddon.Client.local?.selectedUtility = utilitySlot 42 | } 43 | } 44 | 45 | // Server's receiving consumer 46 | fun consumeServer(context: PlayPayloadContext) { 47 | val player = context.player.getOrNull() ?: return 48 | context.workHandler.execute { 49 | player.inventoryAddon?.selectedUtility = utilitySlot 50 | 51 | val broadcastPacket = EntityEquipmentUpdateS2CPacket(player.id, listOf(Pair(EquipmentSlot.OFFHAND, player.offHandStack))) 52 | (player.world as ServerWorld).chunkManager.sendToOtherNearbyPlayers(player, broadcastPacket) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SwapItemsInHandsKeyC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import kotlin.jvm.optionals.getOrNull 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class SwapItemsInHandsKeyC2SPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "swap_items_in_hands") 13 | } 14 | 15 | override fun id(): Identifier = identifier 16 | 17 | override fun write(buf: PacketByteBuf?) {} 18 | 19 | // Receiver's consumer 20 | fun consume(context: PlayPayloadContext) { 21 | val sender = context.player.getOrNull() ?: return 22 | context.workHandler.execute { 23 | sender.inventoryAddon?.swapItemsInHands() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/SwappedHandsModeC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import kotlin.jvm.optionals.getOrNull 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class SwappedHandsModeC2SPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "swapped_hands") 13 | } 14 | private var swappedHands = false 15 | 16 | // Sender's constructor 17 | constructor(swappedHands: Boolean) { 18 | this.swappedHands = swappedHands 19 | } 20 | 21 | // Receiver's constructor 22 | constructor(buf: PacketByteBuf) { 23 | swappedHands = buf.readBoolean() 24 | } 25 | 26 | override fun id(): Identifier = identifier 27 | 28 | // Sender's writer 29 | override fun write(buf: PacketByteBuf) { 30 | buf.writeBoolean(swappedHands) 31 | } 32 | 33 | // Receiver's consumer 34 | fun consume(context: PlayPayloadContext) { 35 | val sender = context.player.getOrNull() ?: return 36 | context.workHandler.execute { 37 | sender.inventoryAddon?.swappedHands = swappedHands 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/UpdateAddonStacksS2CPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon 4 | import net.minecraft.item.ItemStack 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class UpdateAddonStacksS2CPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "update_addon_stacks") 13 | } 14 | private var updatedStacks: Map 15 | 16 | // Sender's constructor 17 | constructor(updatedStacks: Map) { 18 | this.updatedStacks = updatedStacks 19 | } 20 | 21 | // Receiver's constructor 22 | constructor(buf: PacketByteBuf) { 23 | val size = buf.readInt() 24 | val updatedStacks = mutableMapOf() 25 | for (i in 0 until size) 26 | updatedStacks[buf.readInt()] = buf.readItemStack() 27 | this.updatedStacks = updatedStacks 28 | } 29 | 30 | override fun id(): Identifier = identifier 31 | 32 | // Sender's writer 33 | override fun write(buf: PacketByteBuf) { 34 | buf.writeInt(updatedStacks.size) 35 | for ((index, stack) in updatedStacks) { 36 | buf.writeInt(index) 37 | buf.writeItemStack(stack) 38 | } 39 | } 40 | 41 | // Receiver's consumer 42 | fun consume(context: PlayPayloadContext) { 43 | context.workHandler.execute { 44 | PlayerInventoryAddon.Client.local?.receiveStacksUpdateS2C(updatedStacks) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/packet/UseBoostRocketC2SPacket.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.packet 2 | 3 | import de.rubixdev.inventorio.player.PlayerInventoryAddon.Companion.inventoryAddon 4 | import kotlin.jvm.optionals.getOrNull 5 | import net.minecraft.network.PacketByteBuf 6 | import net.minecraft.network.packet.CustomPayload 7 | import net.minecraft.util.Identifier 8 | import net.neoforged.neoforge.network.handling.PlayPayloadContext 9 | 10 | class UseBoostRocketC2SPacket : CustomPayload { 11 | companion object { 12 | val identifier = Identifier("inventorio", "fire_boost_rocket_c2s") 13 | } 14 | 15 | override fun id(): Identifier = identifier 16 | 17 | override fun write(buf: PacketByteBuf?) {} 18 | 19 | fun consume(context: PlayPayloadContext) { 20 | val sender = context.player.getOrNull() ?: return 21 | context.workHandler.execute { 22 | sender.inventoryAddon?.fireRocketFromInventory() 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/kotlin/de/rubixdev/inventorio/util/PlatformApi.kt: -------------------------------------------------------------------------------- 1 | package de.rubixdev.inventorio.util 2 | 3 | import net.neoforged.fml.ModList 4 | 5 | object PlatformApi { 6 | fun isModLoaded(modId: String): Boolean = ModList.get().isLoaded(modId) 7 | } 8 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "kotlinforforge" 2 | loaderVersion = "[${forge_kotlin_version},)" 3 | issueTrackerURL = "${issues_url}" 4 | license = "${license}" 5 | 6 | [[mods]] 7 | modId = "${mod_id}" 8 | version = "${version}" 9 | displayName = "${mod_name}" 10 | displayURL = "${homepage_url}" 11 | logoFile = "icon.png" 12 | authors = "${authors}" 13 | description = "${description}" 14 | 15 | [[mixins]] 16 | config = "${mod_id}.mixins.json" 17 | [[mixins]] 18 | config = "${mod_id}-neoforge.mixins.json" 19 | 20 | [[dependencies.${mod_id}]] 21 | modId = "minecraft" 22 | type = "required" 23 | versionRange = "${minecraft_version_range_forge}" 24 | ordering = "NONE" 25 | side = "BOTH" 26 | 27 | [[dependencies.${mod_id}]] 28 | modId = "neoforge" 29 | type = "required" 30 | versionRange = "${neoforge_version_range}" 31 | ordering = "NONE" 32 | side = "BOTH" 33 | 34 | [[dependencies.${mod_id}]] 35 | modId = "cloth_config" 36 | type = "required" 37 | versionRange = "[10,)" 38 | ordering = "NONE" 39 | side = "CLIENT" 40 | -------------------------------------------------------------------------------- /versions/1.20.4-neoforge/src/main/resources/inventorio-neoforge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "de.rubixdev.inventorio.mixin.neoforge", 4 | "compatibilityLevel": "JAVA_17", 5 | "minVersion": "0.8", 6 | "plugin": "de.rubixdev.inventorio.InventorioMixinPlugin", 7 | "mixins": [ 8 | "curios.CuriosEventHandlerMixin", 9 | "curios.CuriosServerPayloadHandlerMixin", 10 | "curios.CurioStacksHandlerMixin", 11 | "curios.InventorioScreenHandlerMixin" 12 | ], 13 | "client": [ 14 | "curios.CuriosClientPayloadHandlerMixin", 15 | "curios.HandledScreenMixin", 16 | "curios.InventorioScreenMixin", 17 | "curios.InventorioScreenMixin_alternative" 18 | ], 19 | "injectors": { 20 | "defaultRequire": 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /versions/mainProject: -------------------------------------------------------------------------------- 1 | 1.20.4-common -------------------------------------------------------------------------------- /versions/mappings-common-forge.txt: -------------------------------------------------------------------------------- 1 | net.fabricmc.api.Environment net.minecraftforge.api.distmarker.OnlyIn 2 | net.fabricmc.api.EnvType net.minecraftforge.api.distmarker.Dist 3 | net.fabricmc.api.EnvType SERVER net.minecraftforge.api.distmarker.Dist DEDICATED_SERVER 4 | -------------------------------------------------------------------------------- /versions/mappings-common-neoforge.txt: -------------------------------------------------------------------------------- 1 | net.fabricmc.api.Environment net.neoforged.api.distmarker.OnlyIn 2 | net.fabricmc.api.EnvType net.neoforged.api.distmarker.Dist 3 | net.fabricmc.api.EnvType SERVER net.neoforged.api.distmarker.Dist DEDICATED_SERVER 4 | --------------------------------------------------------------------------------