From da21f8f956a131f5aae9a16a8e8bbc0ec89bc95e Mon Sep 17 00:00:00 2001 From: 1024_byteeeee <2270484921@qq.com> Date: Sat, 30 Mar 2024 15:39:03 +0800 Subject: [PATCH] :white_check_mark: Kaleidoscope v0.1.0 --- .github/ISSUE_TEMPLATE/bug_report.yml | 79 ++ .github/ISSUE_TEMPLATE/feature_request.yml | 25 + .github/workflows/build.yml | 79 ++ .github/workflows/gradle.yml | 16 + .github/workflows/matrix_includes.json | 29 + .github/workflows/matrix_prep.yml | 39 + .github/workflows/release.yml | 130 ++++ .github/workflows/scripts/summary.py | 40 ++ .gitignore | 34 + HEADER.txt | 17 + LICENSE | 674 ++++++++++++++++++ README.md | 25 + README_en.md | 26 + build.gradle | 50 ++ common.gradle | 167 +++++ gradle.properties | 15 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 249 +++++++ gradlew.bat | 92 +++ run/options.txt | 139 ++++ settings.gradle | 44 ++ .../kaleidoscope/KaleidoscopeClientMod.java | 40 ++ .../KaleidoscopeCommand.java | 98 +++ .../commands/RegisterCommands.java | 39 + .../config/KaleidoscopeConfig.java | 89 +++ .../blockOutlineColor/BlockOutlineConfig.java | 47 ++ .../config/fogColor/FogConfig.java | 38 + .../config/skyColor/SkyConfig.java | 38 + .../kaleidoscope/event/ClientStartEvent.java | 30 + .../mixin/biomeColor/BiomeEffectsMixin.java | 51 ++ .../blockOutlineColor/WorldRenderMixin.java | 74 ++ .../resources/assets/kaledoscope/icon.png | Bin 0 -> 33990 bytes src/main/resources/fabric.mod.json | 26 + src/main/resources/kaleidoscope.mixins.json | 13 + versions/1.16.5/gradle.properties | 12 + versions/1.17.1/gradle.properties | 12 + versions/1.18.2/gradle.properties | 12 + versions/1.19.4/gradle.properties | 12 + versions/1.20.1/gradle.properties | 12 + versions/1.20.2/gradle.properties | 12 + versions/1.20.3/gradle.properties | 12 + versions/1.20.4/gradle.properties | 12 + versions/1.20/gradle.properties | 12 + versions/mainProject | 1 + versions/mapping-1.16-1.17.txt | 0 versions/mapping-1.17-1.18.txt | 0 versions/mapping-1.18-1.19.txt | 2 + versions/mapping-1.19-1.20.txt | 0 versions/mapping-1.20-1.20.1.txt | 0 versions/mapping-1.20.1-1.20.2.txt | 0 versions/mapping-1.20.2-1.20.3.txt | 0 versions/mapping-1.20.3-1.20.4.txt | 0 53 files changed, 2670 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/gradle.yml create mode 100644 .github/workflows/matrix_includes.json create mode 100644 .github/workflows/matrix_prep.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/scripts/summary.py create mode 100644 .gitignore create mode 100644 HEADER.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_en.md create mode 100644 build.gradle create mode 100644 common.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 run/options.txt create mode 100644 settings.gradle create mode 100644 src/main/java/top/byteeeee/kaleidoscope/KaleidoscopeClientMod.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/commands/KaleidoscopeCommand/KaleidoscopeCommand.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/commands/RegisterCommands.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/config/KaleidoscopeConfig.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/config/blockOutlineColor/BlockOutlineConfig.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/config/fogColor/FogConfig.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/config/skyColor/SkyConfig.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/event/ClientStartEvent.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/mixin/biomeColor/BiomeEffectsMixin.java create mode 100644 src/main/java/top/byteeeee/kaleidoscope/mixin/blockOutlineColor/WorldRenderMixin.java create mode 100644 src/main/resources/assets/kaledoscope/icon.png create mode 100644 src/main/resources/fabric.mod.json create mode 100644 src/main/resources/kaleidoscope.mixins.json create mode 100644 versions/1.16.5/gradle.properties create mode 100644 versions/1.17.1/gradle.properties create mode 100644 versions/1.18.2/gradle.properties create mode 100644 versions/1.19.4/gradle.properties create mode 100644 versions/1.20.1/gradle.properties create mode 100644 versions/1.20.2/gradle.properties create mode 100644 versions/1.20.3/gradle.properties create mode 100644 versions/1.20.4/gradle.properties create mode 100644 versions/1.20/gradle.properties create mode 100644 versions/mainProject create mode 100644 versions/mapping-1.16-1.17.txt create mode 100644 versions/mapping-1.17-1.18.txt create mode 100644 versions/mapping-1.18-1.19.txt create mode 100644 versions/mapping-1.19-1.20.txt create mode 100644 versions/mapping-1.20-1.20.1.txt create mode 100644 versions/mapping-1.20.1-1.20.2.txt create mode 100644 versions/mapping-1.20.2-1.20.3.txt create mode 100644 versions/mapping-1.20.3-1.20.4.txt diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..9f8dcb9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,79 @@ +name: Bug Report +description: Something doesn't seem correct and it might be a bug +labels: [] +body: + - type: textarea + id: description + attributes: + label: Bug description + description: | + A clear and concise description of what the bug is. + Is it a game crash, an unexpected behavior, or has something gone wrong? + If applicable, add screenshots to help explain the bug. + placeholder: Tell us what you see! + validations: + required: true + - type: textarea + id: to-reproduce + attributes: + label: Steps to reproduce + description: Steps to reproduce the bug + placeholder: | + 1. Create a world + 2. Wait until midnight + 3. Hug a creeper + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: What did you expect to happen? + placeholder: The creeper explodes + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: What actually happened? + placeholder: The creeper launches itself into the sky + - type: textarea + id: logs + attributes: + label: Relevant logs + description: |- + If it's a crash, send the corresponding Minecraft log in the `logs` folder, or crash report in the `crash-reports` folder, here. + Please upload the log file as an attachment, or upload the log to [pastebin](https://pastebin.com/) / [mclo.gs](https://mclo.gs/) and paste the url here. + Please refrain from pasting the entire log file directly. + Leave empty if there is none. + placeholder: https://pastebin.com/J6b7lKxR + - type: input + id: minecraft-version + attributes: + label: Minecraft version + description: The Minecraft version(s) where this bug occurs in. + placeholder: 1.15.2 + validations: + required: true + - type: input + id: mod-version + attributes: + label: TemplateMod version + description: The TemplateMod version(s) where this bug occurs in. + placeholder: 1.2.3 + validations: + required: true + - type: textarea + id: other-information + attributes: + label: Other information + description: Other useful information to this bug report, e.g. other related mod version(s). Leave empty if there is none. + placeholder: The issue only occurs if the player is in survival mode + - type: checkboxes + id: check-list + attributes: + label: Check list + options: + - label: I have verified that the issue persists in the latest version of the mod. + required: true + - label: I have searched the existing issues and confirmed that this is not a duplicate. + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..75d7db3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,25 @@ +name: Feature Request +description: Suggest an idea for this project +labels: [] +body: + - type: textarea + id: motivation + attributes: + label: Motivation + description: Why do you want this feature? What problem do you want to solve? How can the suggested feature help with that? + placeholder: Tell us what you want! + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: Describe the feature you want, as detailed as possible + placeholder: I want to see a fancy starry sky when I look up at midnight. + validations: + required: true + - type: textarea + id: other-information + attributes: + label: Other information + description: Other useful information to this feature request. Leave empty if there is none. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..aa94190 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,79 @@ +name: step.build + +on: + workflow_call: + inputs: + release: + type: boolean + required: false + default: false + target_subproject: + description: The subproject name of the specified Minecraft version to be built. Leave it empty to build all + type: string + required: false + default: '' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: 17 + + - name: Cache gradle files + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + ./.gradle/loom-cache + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle', '**/gradle.properties', '**/*.accesswidener') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Get subproject name to build + id: subproject_info + run: | + if [ "${{ inputs.target_subproject }}" != "" ] + then + echo "prefix=${{ inputs.target_subproject }}:" >> $GITHUB_OUTPUT + else + echo "prefix=" >> $GITHUB_OUTPUT + fi + + - name: Build with Gradle + run: | + chmod +x gradlew + ./gradlew ${{ steps.subproject_info.outputs.prefix }}build --no-daemon + env: + BUILD_ID: ${{ github.run_number }} + BUILD_RELEASE: ${{ inputs.release }} + + - uses: actions/upload-artifact@v3 + with: + name: build-artifacts + path: versions/*/build/libs/ + + summary: + runs-on: ubuntu-22.04 + needs: + - build + + steps: + - uses: actions/checkout@v3 + + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifacts + path: build-artifacts + + - name: Make build summary + run: python3 .github/workflows/scripts/summary.py # Python 3.10.6 + env: + TARGET_SUBPROJECT: ${{ inputs.target_subproject }} diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..ceae381 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,16 @@ +name: Dev Builds + +on: + push: + paths: + - "*.gradle" + - "gradle.properties" + - "src/**" + - "versions/**" + - ".github/**" + pull_request: + + +jobs: + build: + uses: ./.github/workflows/build.yml diff --git a/.github/workflows/matrix_includes.json b/.github/workflows/matrix_includes.json new file mode 100644 index 0000000..7bbf74f --- /dev/null +++ b/.github/workflows/matrix_includes.json @@ -0,0 +1,29 @@ +[ + { + "subproject_dir": "1.16.5" + }, + { + "subproject_dir": "1.17.1" + }, + { + "subproject_dir": "1.18.2" + }, + { + "subproject_dir": "1.19.4" + }, + { + "subproject_dir": "1.20" + }, + { + "subproject_dir": "1.20.1" + }, + { + "subproject_dir": "1.20.2" + }, + { + "subproject_dir": "1.20.3" + }, + { + "subproject_dir": "1.20.4" + } +] \ No newline at end of file diff --git a/.github/workflows/matrix_prep.yml b/.github/workflows/matrix_prep.yml new file mode 100644 index 0000000..da80ebe --- /dev/null +++ b/.github/workflows/matrix_prep.yml @@ -0,0 +1,39 @@ +name: step.matrix_prepare + +on: + workflow_call: + inputs: + target_subproject: + description: The subproject name of the specified Minecraft version for generating matrix entry + type: string + required: false + default: '' + outputs: + matrix: + description: The generated run matrix + value: ${{ jobs.matrix_prep.outputs.matrix }} + + +jobs: + matrix_prep: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Display context + run: | + echo ref_name = ${{ github.ref_name }} + echo target_subproject = ${{ github.event.inputs.target_subproject }} + echo target_release_tag = ${{ github.event.inputs.target_release_tag }} + + - id: setmatrix + uses: JoshuaTheMiller/conditional-build-matrix@v1.0.1 + with: + # inputFile: '.github/workflows/matrix_includes.json' # Default input file path + filter: '[? `${{ github.event_name }}` == `release` || `${{ github.event.inputs.target_subproject }}` == `` || `"${{ github.event.inputs.target_subproject }}"` == subproject_dir ]' + + - name: Print matrix + run: echo ${{ steps.setmatrix.outputs.matrix }} + + outputs: + matrix: ${{ steps.setmatrix.outputs.matrix }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b44692e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,130 @@ +name: Release + +on: + release: + types: + - published + workflow_dispatch: + inputs: + target_subproject: + description: The subproject name of the specified Minecraft version to be released. + type: string + required: false + default: '' + target_release_tag: + description: The tag of the release you want to append the artifact to + type: string + required: true + + +jobs: + show_action_parameters: + runs-on: ubuntu-latest + steps: + - name: Show action parameters + run: | + cat < $GITHUB_STEP_SUMMARY + ## Action Parameters + - target_subproject: `${{ github.event.inputs.target_subproject }}` + - target_release_tag: `${{ github.event.inputs.target_release_tag }}` + EOF + + matrix_prep: + uses: ./.github/workflows/matrix_prep.yml + with: + target_subproject: ${{ github.event.inputs.target_subproject }} + + build: + uses: ./.github/workflows/build.yml + with: + target_subproject: ${{ github.event.inputs.target_subproject }} + release: true + + release: + needs: + - matrix_prep + - build + runs-on: ubuntu-latest + + strategy: + matrix: ${{ fromJson(needs.matrix_prep.outputs.matrix) }} + + steps: + - uses: actions/checkout@v3 + + - name: Download build artifacts + uses: actions/download-artifact@v3 + with: + name: build-artifacts + path: build-artifacts + + - name: Get github release information + if: ${{ github.event_name == 'workflow_dispatch' }} + id: get_release + uses: cardinalby/git-get-release-action@1.2.4 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tag: ${{ github.event.inputs.target_release_tag }} + + - name: Generate publish related information + id: release_info + run: | + if [ $GITHUB_EVENT_NAME == 'release' ] + then + echo "tag_name=" >> $GITHUB_OUTPUT # leave an empty value here so softprops/action-gh-release will use the default value + elif [ $GITHUB_EVENT_NAME == 'workflow_dispatch' ] + then + echo "tag_name=${{ github.event.inputs.target_release_tag }}" >> $GITHUB_OUTPUT + else + echo Unknown github event name $GITHUB_EVENT_NAME + exit 1 + fi + + - name: Read common properties + id: properties_g + uses: christian-draeger/read-properties@1.1.1 + with: + path: gradle.properties + properties: 'mod_name mod_version' + + - name: Read version-specific properties + id: properties_v + uses: christian-draeger/read-properties@1.1.1 + with: + path: ${{ format('versions/{0}/gradle.properties', matrix.subproject_dir) }} + properties: 'minecraft_version game_versions' + + - name: Fix game version + id: game_versions + run: | + # Fixed \n in game_versions isn't parsed by christian-draeger/read-properties as a line separator + echo 'value<> $GITHUB_OUTPUT + echo -e "${{ steps.properties_v.outputs.game_versions }}" >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + + - name: Publish Minecraft Mods + uses: Kir-Antipov/mc-publish@v3.3.0 + with: + modrinth-id: vBxRFGLR + modrinth-token: ${{ secrets.MODRINTH_API_TOKEN }} + + # curseforge-id: _INSERT_CURSEFORGE_MOD_ID_HERE_ + # curseforge-token: ${{ secrets.CF_API_TOKEN }} + + github-tag: ${{ steps.release_info.outputs.tag_name }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + files: ${{ format('build-artifacts/{0}/build/libs/!(*-@(dev|sources)).jar', matrix.subproject_dir) }} + + name: ${{ format('{0} v{1} for mc{2}', steps.properties_g.outputs.mod_name, steps.properties_g.outputs.mod_version, steps.properties_v.outputs.minecraft_version) }} + version: ${{ format('mc{0}-v{1}', steps.properties_v.outputs.minecraft_version, steps.properties_g.outputs.mod_version) }} + version-type: release + changelog: ${{ format('{0}{1}', github.event.release.body, steps.get_release.outputs.body) }} # one of them should be an empty string (null) + + loaders: fabric + game-versions: ${{ steps.game_versions.outputs.value }} + game-version-filter: any + + retry-attempts: 3 + retry-delay: 10000 diff --git a/.github/workflows/scripts/summary.py b/.github/workflows/scripts/summary.py new file mode 100644 index 0000000..60dce13 --- /dev/null +++ b/.github/workflows/scripts/summary.py @@ -0,0 +1,40 @@ +""" +A script to scan through all valid mod jars in build-artifacts.zip/$version/build/libs, +and generate an artifact summary table for that to GitHub action step summary +""" +__author__ = 'Fallen_Breath' + +import glob +import json +import os + + +def read_prop(file_name: str, key: str) -> str: + with open(file_name) as prop: + return next(filter( + lambda l: l.split('=', 1)[0].strip() == key, + prop.readlines() + )).split('=', 1)[1].lstrip() + + +target_subproject = os.environ.get('TARGET_SUBPROJECT', '') +with open('.github/workflows/matrix_includes.json') as f: + matrix: list[dict] = json.load(f) + +with open(os.environ['GITHUB_STEP_SUMMARY'], 'w') as f: + f.write('## Build Artifacts Summary\n\n') + f.write('| Subproject | for Minecraft | Files |\n') + f.write('| --- | --- | --- |\n') + + for m in matrix: + subproject = m['subproject_dir'] + if target_subproject != '' and subproject != target_subproject: + continue + game_versions = read_prop('versions/{}/gradle.properties'.format(subproject), 'game_versions') + game_versions = game_versions.strip().replace('\\n', ', ') + file_names = glob.glob('build-artifacts/{}/build/libs/*.jar'.format(subproject)) + file_names = ', '.join(map( + lambda fn: '`{}`'.format(os.path.basename(fn)), + filter(lambda fn: not fn.endswith('-sources.jar') and not fn.endswith('-dev.jar'), file_names) + )) + f.write('| {} | {} | {} |\n'.format(subproject, game_versions, file_names)) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1166ec9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/* +!run/options.txt \ No newline at end of file diff --git a/HEADER.txt b/HEADER.txt new file mode 100644 index 0000000..6c57ca6 --- /dev/null +++ b/HEADER.txt @@ -0,0 +1,17 @@ +This file is part of the ${name} project, licensed under the +GNU Lesser General Public License v3.0 + +Copyright (C) ${year} ${author} and contributors + +${name} is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +${name} is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with ${name}. If not, see . diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0da45b --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# kaleidoscope - 万花筒 +**中文** **|** [**English**](README_en.md) + +这是一个可以修改方块轮廓线颜色、迷雾颜色、天空颜色的模组,未来将会添加更多可修改的颜色。 + + + +--- + + + +# 指令 + +- /kaleidoscope sky [value] + - 用于修改天空颜色,支持16位RGB代码。 +- /kaleidoscope sky [true/false] + - 用于开启/关闭修改天空颜色。 +- /kaleidoscope fog [value] + - 用于修改迷雾颜色,支持16位RGB代码。 +- /kaleidoscope fog [true/false] + - 用于开启/关闭修改迷雾颜色。 +- /kaleidoscope blockOutline [red] [green] [blue] [alpha] + - 用于修改方块轮廓的RGB颜色以及其透明度。 +- /kaleidoscope blockOutline [true/false] + - 用于开启/关闭修改方块轮廓颜色。 diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000..34d3e41 --- /dev/null +++ b/README_en.md @@ -0,0 +1,26 @@ +# kaleidoscope - 万花筒 + +[**中文**](README.md) **|** [**English**] + +This is a mod that allows you to modify the colors of block outlines, fog, and sky. More customizable colors will be added in the future. + + + +--- + + + +# Commands + +- /kaleidoscope sky [value] + - Used to modify the sky color, supporting 16-bit RGB codes. +- /kaleidoscope sky [true/false] + - Used to enable/disable the modification of sky color. +- /kaleidoscope fog [value] + - Used to modify the fog color, supporting 16-bit RGB codes. +- /kaleidoscope fog [true/false] + - Used to enable/disable the modification of fog color. +- /kaleidoscope blockOutline [red] [green] [blue] [alpha] + - Used to modify the RGB color and transparency of block outlines. +- /kaleidoscope blockOutline [true/false] + - Used to enable/disable the modification of block outline color. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..bc9ee99 --- /dev/null +++ b/build.gradle @@ -0,0 +1,50 @@ +plugins { + id 'maven-publish' + id 'com.github.hierynomus.license' version '0.16.1' apply false + id 'fabric-loom' version '1.5-SNAPSHOT' apply false + id 'com.replaymod.preprocess' version '7fa8d51' +} + +preprocess { + def mc116 = createNode('1.16.5', 1_16_05, 'yarn') + def mc117 = createNode('1.17.1', 1_17_01, 'yarn') + def mc118 = createNode('1.18.2', 1_18_02, 'yarn') + def mc119 = createNode('1.19.4', 1_19_04, 'yarn') + def mc1200 = createNode('1.20', 1_20_00, 'yarn') + def mc1201 = createNode('1.20.1', 1_20_01, 'yarn') + def mc1202 = createNode('1.20.2', 1_20_02, 'yarn') + def mc1203 = createNode('1.20.3', 1_20_03, 'yarn') + def mc1204 = createNode('1.20.4', 1_20_04, 'yarn') + + mc116.link(mc117, file('versions/mapping-1.16-1.17.txt')) + mc117.link(mc118, file('versions/mapping-1.17-1.18.txt')) + mc118.link(mc119, file('versions/mapping-1.18-1.19.txt')) + mc119.link(mc1200, file('versions/mapping-1.19-1.20.txt')) + mc1200.link(mc1201, file('versions/mapping-1.20-1.20.1.txt')) + mc1201.link(mc1202, file('versions/mapping-1.20.1-1.20.2.txt')) + mc1202.link(mc1203, file('versions/mapping-1.20.2-1.20.3.txt')) + mc1203.link(mc1204, file('versions/mapping-1.20.3-1.20.4.txt')) +} + +tasks.register('buildAndGather') { + subprojects { + dependsOn project.name + ':build' + } + doFirst { + println 'Gathering builds' + delete fileTree(project.projectDir.toPath().resolve('build/libs')) { + include '*' + } + copy { + subprojects { + def libDir = project.projectDir.toPath().resolve('build/libs') + from(libDir) { + include '*.jar' + exclude '*-dev.jar', '*-sources.jar' + } + into 'build/libs/' + duplicatesStrategy DuplicatesStrategy.INCLUDE + } + } + } +} diff --git a/common.gradle b/common.gradle new file mode 100644 index 0000000..596d135 --- /dev/null +++ b/common.gradle @@ -0,0 +1,167 @@ +apply plugin: 'maven-publish' +apply plugin: 'com.github.hierynomus.license' +apply plugin: 'fabric-loom' +apply plugin: 'com.replaymod.preprocess' + +int mcVersion = 1 + +preprocess { + mcVersion = vars.get()["MC"] as int +} + +repositories { + maven { + url = 'https://api.modrinth.com/maven' + } + maven { + url = 'https://www.cursemaven.com' + } + maven { + url = 'https://jitpack.io' + } +} + +// https://github.com/FabricMC/fabric-loader/issues/783 +configurations { + modRuntimeOnly.exclude group: 'net.fabricmc', module: 'fabric-loader' +} + +dependencies { + // loom + minecraft "com.mojang:minecraft:${project.minecraft_version}" + + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" +} + +loom { + runConfigs.configureEach { + // to make sure it generates all "Minecraft Client (:subproject_name)" applications + ideConfigGenerated = true + runDir '../../run' + vmArgs '-Dmixin.debug.export=true' + } + + runs { + mixinAudit { + server() + vmArgs '-Dcarpetamsaddition.mixin_audit=true' + ideConfigGenerated false + } + mixinAuditClient { + client() + vmArgs '-Dcarpetamsaddition.mixin_audit=true' + ideConfigGenerated false + } + } +} + +remapJar { + remapperIsolation = true +} + +if (mcVersion >= 11800) { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} +else if (mcVersion >= 11700) { + sourceCompatibility = JavaVersion.VERSION_16 + targetCompatibility = JavaVersion.VERSION_16 +} +else { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +String versionSuffix = '' +// detect github action environment variables +// https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables +if (System.getenv("BUILD_RELEASE") != "true") { + String buildNumber = System.getenv("BUILD_ID") + versionSuffix += buildNumber != null ? ('+build.' + buildNumber) : '-SNAPSHOT' +} +String fullModVersion = project.mod_version + versionSuffix + +version = 'v' + fullModVersion +group = project.maven_group +archivesBaseName = project.archives_base_name + '-mc' + project.minecraft_version + +processResources { + inputs.property "version", fullModVersion + + filesMatching("fabric.mod.json") { + def valueMap = [ + "id": project.mod_id, + "name": project.mod_name, + "version": fullModVersion, + "minecraft_dependency": project.minecraft_dependency, + ] + expand valueMap + } +} + +java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() +} + +jar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${project.archivesBaseName}"} + } +} + +// https://github.com/hierynomus/license-gradle-plugin +license { + // use "gradle licenseFormat" to apply license headers + header = rootProject.file('HEADER.txt') + include '**/*.java' + skipExistingHeaders = true + + headerDefinitions { + // ref: https://github.com/mathieucarbou/license-maven-plugin/blob/4c42374bb737378f5022a3a36849d5e23ac326ea/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/header/HeaderType.java#L48 + // modification: add a newline at the end + SLASHSTAR_STYLE_NEWLINE { + firstLine = "/*" + beforeEachLine = " * " + endLine = " */" + System.lineSeparator() + afterEachLine = "" + skipLinePattern = null + firstLineDetectionPattern = "(\\s|\\t)*/\\*.*\$" + lastLineDetectionPattern = ".*\\*/(\\s|\\t)*\$" + allowBlankLines = false + isMultiline = true + padLines = false + } + } + mapping { + java = 'SLASHSTAR_STYLE_NEWLINE' + } + ext { + name = project.mod_name + author = '1024_byteeeee' + year = Calendar.getInstance().get(Calendar.YEAR).toString() + } +} +classes.dependsOn licenseFormatMain +testClasses.dependsOn licenseFormatTest + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + artifactId archivesBaseName + from components.java + } + } + + // select the repositories you want to publish to + repositories { + // uncomment to publish to the local maven + // mavenLocal() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..2149e6f --- /dev/null +++ b/gradle.properties @@ -0,0 +1,15 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs = -Xmx4G + +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version = 1.16.5 +yarn_mappings = 1.16.5+build.10 +loader_version = 0.15.7 + +# Mod Properties +mod_id = kaleidoscope +mod_name = Kaleidoscope +mod_version = 0.1.0 +maven_group = Kaleidoscope +archives_base_name = Kaleidoscope diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d64cd4917707c1f8861d8cb53dd15194d4248596 GIT binary patch literal 43462 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a80b22c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1aa94a4 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..25da30d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/run/options.txt b/run/options.txt new file mode 100644 index 0000000..3f742f6 --- /dev/null +++ b/run/options.txt @@ -0,0 +1,139 @@ +version:3700 +autoJump:false +operatorItemsTab:false +autoSuggestions:true +chatColors:true +chatLinks:true +chatLinksPrompt:true +enableVsync:false +entityShadows:true +forceUnicodeFont:false +discrete_mouse_scroll:false +invertYMouse:false +realmsNotifications:true +reducedDebugInfo:false +showSubtitles:false +directionalAudio:false +touchscreen:false +fullscreen:false +bobView:true +toggleCrouch:false +toggleSprint:false +darkMojangStudiosBackground:false +hideLightningFlashes:false +hideSplashTexts:false +mouseSensitivity:0.5 +fov:0.0 +screenEffectScale:1.0 +fovEffectScale:1.0 +darknessEffectScale:1.0 +glintSpeed:0.5 +glintStrength:0.75 +damageTiltStrength:1.0 +highContrast:false +narratorHotkey:true +gamma:0.5 +renderDistance:12 +simulationDistance:12 +entityDistanceScaling:1.0 +guiScale:0 +particles:0 +maxFps:260 +graphicsMode:1 +ao:true +prioritizeChunkUpdates:0 +biomeBlendRadius:2 +renderClouds:"false" +resourcePacks:["fabric"] +incompatibleResourcePacks:[] +lastServer: +lang:zh_cn +soundDevice:"" +chatVisibility:0 +chatOpacity:1.0 +chatLineSpacing:0.0 +textBackgroundOpacity:0.5 +backgroundForChatOnly:true +hideServerAddress:false +advancedItemTooltips:false +pauseOnLostFocus:true +overrideWidth:0 +overrideHeight:0 +chatHeightFocused:1.0 +chatDelay:0.0 +chatHeightUnfocused:0.4375 +chatScale:0.5017605633802817 +chatWidth:1.0 +notificationDisplayTime:1.0 +mipmapLevels:4 +useNativeTransport:true +mainHand:"right" +attackIndicator:1 +narrator:0 +tutorialStep:none +mouseWheelSensitivity:1.0 +rawMouseInput:true +glDebugVerbosity:1 +skipMultiplayerWarning:true +skipRealms32bitWarning:false +hideMatchedNames:true +joinedFirstServer:false +hideBundleTutorial:false +syncChunkWrites:true +showAutosaveIndicator:true +allowServerListing:true +onlyShowSecureChat:false +panoramaScrollSpeed:1.0 +telemetryOptInExtra:false +onboardAccessibility:false +key_key.attack:key.mouse.left +key_key.use:key.mouse.right +key_key.forward:key.keyboard.w +key_key.left:key.keyboard.a +key_key.back:key.keyboard.s +key_key.right:key.keyboard.d +key_key.jump:key.keyboard.space +key_key.sneak:key.keyboard.left.shift +key_key.sprint:key.keyboard.left.control +key_key.drop:key.keyboard.q +key_key.inventory:key.keyboard.e +key_key.chat:key.keyboard.t +key_key.playerlist:key.keyboard.tab +key_key.pickItem:key.mouse.middle +key_key.command:key.keyboard.slash +key_key.socialInteractions:key.keyboard.p +key_key.screenshot:key.keyboard.f2 +key_key.togglePerspective:key.keyboard.f5 +key_key.smoothCamera:key.keyboard.unknown +key_key.fullscreen:key.keyboard.f11 +key_key.spectatorOutlines:key.keyboard.unknown +key_key.swapOffhand:key.keyboard.f +key_key.saveToolbarActivator:key.keyboard.c +key_key.loadToolbarActivator:key.keyboard.x +key_key.advancements:key.keyboard.l +key_key.hotbar.1:key.keyboard.1 +key_key.hotbar.2:key.keyboard.2 +key_key.hotbar.3:key.keyboard.3 +key_key.hotbar.4:key.keyboard.4 +key_key.hotbar.5:key.keyboard.5 +key_key.hotbar.6:key.keyboard.6 +key_key.hotbar.7:key.keyboard.7 +key_key.hotbar.8:key.keyboard.8 +key_key.hotbar.9:key.keyboard.9 +soundCategory_master:0.29304636 +soundCategory_music:0.0 +soundCategory_record:1.0 +soundCategory_weather:1.0 +soundCategory_block:1.0 +soundCategory_hostile:1.0 +soundCategory_neutral:1.0 +soundCategory_player:1.0 +soundCategory_ambient:1.0 +soundCategory_voice:1.0 +modelPart_cape:true +modelPart_jacket:true +modelPart_left_sleeve:true +modelPart_right_sleeve:true +modelPart_left_pants_leg:true +modelPart_right_pants_leg:true +modelPart_hat:true diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..51aa1dd --- /dev/null +++ b/settings.gradle @@ -0,0 +1,44 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'Jitpack' + url = "https://jitpack.io" + } + mavenCentral() + gradlePluginPortal() + } + resolutionStrategy { + eachPlugin { + switch (requested.id.id) { + case "com.replaymod.preprocess": { + useModule("com.github.1024-byteeeee:preprocessor:${requested.version}") + break + } + } + } + } +} + +def versions = Arrays.asList( + "1.16.5", + "1.17.1", + "1.18.2", + "1.19.4", + "1.20", + "1.20.1", + "1.20.2", + "1.20.3", + "1.20.4" +) + +for (String version : versions) { + include(":$version") + + def proj = project(":$version") + proj.projectDir = file("versions/$version") + proj.buildFileName = "../../common.gradle" +} diff --git a/src/main/java/top/byteeeee/kaleidoscope/KaleidoscopeClientMod.java b/src/main/java/top/byteeeee/kaleidoscope/KaleidoscopeClientMod.java new file mode 100644 index 0000000..50bae23 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/KaleidoscopeClientMod.java @@ -0,0 +1,40 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope; + +import net.fabricmc.api.ClientModInitializer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import top.byteeeee.kaleidoscope.commands.RegisterCommands; +import top.byteeeee.kaleidoscope.event.ClientStartEvent; + +public class KaleidoscopeClientMod implements ClientModInitializer { + public static final String MOD_NAME = "Kaleidoscope"; + public static final Logger LOGGER = LogManager.getLogger(MOD_NAME); + + @Override + public void onInitializeClient() { + ClientStartEvent.event(); + RegisterCommands.register(); + } +} \ No newline at end of file diff --git a/src/main/java/top/byteeeee/kaleidoscope/commands/KaleidoscopeCommand/KaleidoscopeCommand.java b/src/main/java/top/byteeeee/kaleidoscope/commands/KaleidoscopeCommand/KaleidoscopeCommand.java new file mode 100644 index 0000000..a0bbed0 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/commands/KaleidoscopeCommand/KaleidoscopeCommand.java @@ -0,0 +1,98 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.commands.KaleidoscopeCommand; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; + +import com.mojang.brigadier.arguments.StringArgumentType; +import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +public class KaleidoscopeCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + ClientCommandManager.literal("kaleidoscope") + + // Set sky color + .then(ClientCommandManager.literal("sky") + .then(ClientCommandManager.argument("switch", BoolArgumentType.bool()) + .executes( + context -> { + KaleidoscopeConfig.skyConfig.displaySwitch = context.getArgument("switch", Boolean.class); + KaleidoscopeConfig.saveToConfig(); + return 1; + } + )) + .then(ClientCommandManager.argument("value", StringArgumentType.string()) + .executes(context -> { + String value = context.getArgument("value", String.class); + KaleidoscopeConfig.skyConfig.color = Integer.parseInt(value, 16); + KaleidoscopeConfig.saveToConfig(); + return 1; + }))) + + // Set fog color + .then(ClientCommandManager.literal("fog") + .then(ClientCommandManager.argument("switch", BoolArgumentType.bool()) + .executes( + context -> { + KaleidoscopeConfig.fogConfig.displaySwitch = context.getArgument("switch", Boolean.class); + KaleidoscopeConfig.saveToConfig(); + return 1; + } + )) + .then(ClientCommandManager.argument("value", StringArgumentType.string()) + .executes(context -> { + String value = context.getArgument("value", String.class); + KaleidoscopeConfig.fogConfig.color = Integer.parseInt(value, 16); + KaleidoscopeConfig.saveToConfig(); + return 1; + }))) + + // Set block outline color + .then(ClientCommandManager.literal("blockOutline") + .then(ClientCommandManager.argument("switch", BoolArgumentType.bool()) + .executes( + context -> { + KaleidoscopeConfig.blockOutlineConfig.displaySwitch = context.getArgument("switch", Boolean.class); + KaleidoscopeConfig.saveToConfig(); + return 1; + } + )) + .then(ClientCommandManager.argument("red", IntegerArgumentType.integer()) + .then(ClientCommandManager.argument("green", IntegerArgumentType.integer()) + .then(ClientCommandManager.argument("blue", IntegerArgumentType.integer()) + .then(ClientCommandManager.argument("alpha", IntegerArgumentType.integer()) + .executes(context -> { + KaleidoscopeConfig.blockOutlineConfig.red = context.getArgument("red", Integer.class); + KaleidoscopeConfig.blockOutlineConfig.green = context.getArgument("green", Integer.class); + KaleidoscopeConfig.blockOutlineConfig.blue = context.getArgument("blue", Integer.class); + KaleidoscopeConfig.blockOutlineConfig.alpha = context.getArgument("alpha", Integer.class); + KaleidoscopeConfig.saveToConfig(); + return 1; + })))))) + ); + } +} diff --git a/src/main/java/top/byteeeee/kaleidoscope/commands/RegisterCommands.java b/src/main/java/top/byteeeee/kaleidoscope/commands/RegisterCommands.java new file mode 100644 index 0000000..f57d526 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/commands/RegisterCommands.java @@ -0,0 +1,39 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.commands; + +//#if MC<11900 +import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager; +//#else +//$$ import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +//#endif + +import top.byteeeee.kaleidoscope.commands.KaleidoscopeCommand.KaleidoscopeCommand; + +public class RegisterCommands { + public static void register() { + //#if MC<11900 + KaleidoscopeCommand.register(ClientCommandManager.DISPATCHER); + //#else + //$$ ClientCommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess) -> KaleidoscopeCommand.register(dispatcher))); + //#endif + } +} diff --git a/src/main/java/top/byteeeee/kaleidoscope/config/KaleidoscopeConfig.java b/src/main/java/top/byteeeee/kaleidoscope/config/KaleidoscopeConfig.java new file mode 100644 index 0000000..8cab124 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/config/KaleidoscopeConfig.java @@ -0,0 +1,89 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import net.fabricmc.loader.api.FabricLoader; + +import top.byteeeee.kaleidoscope.KaleidoscopeClientMod; +import top.byteeeee.kaleidoscope.config.skyColor.SkyConfig; +import top.byteeeee.kaleidoscope.config.fogColor.FogConfig; +import top.byteeeee.kaleidoscope.config.blockOutlineColor.BlockOutlineConfig; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; + +public class KaleidoscopeConfig { + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("kaleidoscope"); + private static final String CONFIG_FILE = CONFIG_PATH.resolve("colors.json").toString(); + + public static SkyConfig skyConfig = new SkyConfig(); + public static FogConfig fogConfig = new FogConfig(); + public static BlockOutlineConfig blockOutlineConfig = new BlockOutlineConfig(); + + public static void loadFromConfig() { + createConfigPath(); + try (Reader reader = new FileReader(CONFIG_FILE)) { + ConfigData config = gson.fromJson(reader, ConfigData.class); + if (config != null) { + skyConfig.loadFromConfig(config); + fogConfig.loadFromConfig(config); + blockOutlineConfig.loadFromConfig(config); + } + } catch (IOException e) { + KaleidoscopeClientMod.LOGGER.warn("Failed to load configuration" + e); + } + } + + public static void saveToConfig() { + createConfigPath(); + ConfigData config = new ConfigData(); + skyConfig.saveToConfig(config); + fogConfig.saveToConfig(config); + blockOutlineConfig.saveToConfig(config); + try (Writer writer = new FileWriter(CONFIG_FILE)) { + gson.toJson(config, writer); + } catch (IOException e) { + KaleidoscopeClientMod.LOGGER.warn("Failed to save configuration" + e); + } + } + + private static void createConfigPath() { + try { + if (!Files.exists(CONFIG_PATH)) { + Files.createDirectories(CONFIG_PATH); + Files.createFile(CONFIG_PATH.resolve("config.json")); + } + } catch (IOException e) { + KaleidoscopeClientMod.LOGGER.warn("Failed to creat configuration" + e); + } + } + + public static class ConfigData { + public SkyConfig skyConfig = new SkyConfig(); + public FogConfig fogConfig = new FogConfig(); + public BlockOutlineConfig blockOutlineConfig = new BlockOutlineConfig(); + } +} \ No newline at end of file diff --git a/src/main/java/top/byteeeee/kaleidoscope/config/blockOutlineColor/BlockOutlineConfig.java b/src/main/java/top/byteeeee/kaleidoscope/config/blockOutlineColor/BlockOutlineConfig.java new file mode 100644 index 0000000..b5a9e00 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/config/blockOutlineColor/BlockOutlineConfig.java @@ -0,0 +1,47 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.config.blockOutlineColor; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +public class BlockOutlineConfig { + public int red = 0; + public int green = 0; + public int blue = 0; + public int alpha = 102; + public boolean displaySwitch = false; + + public void loadFromConfig(KaleidoscopeConfig.ConfigData config) { + red = config.blockOutlineConfig.red; + green = config.blockOutlineConfig.green; + blue = config.blockOutlineConfig.blue; + alpha = config.blockOutlineConfig.alpha; + displaySwitch = config.blockOutlineConfig.displaySwitch; + } + + public void saveToConfig(KaleidoscopeConfig.ConfigData config) { + config.blockOutlineConfig.red = red; + config.blockOutlineConfig.green = green; + config.blockOutlineConfig.blue = blue; + config.blockOutlineConfig.alpha = alpha; + config.blockOutlineConfig.displaySwitch = displaySwitch; + } +} \ No newline at end of file diff --git a/src/main/java/top/byteeeee/kaleidoscope/config/fogColor/FogConfig.java b/src/main/java/top/byteeeee/kaleidoscope/config/fogColor/FogConfig.java new file mode 100644 index 0000000..5177614 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/config/fogColor/FogConfig.java @@ -0,0 +1,38 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.config.fogColor; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +public class FogConfig { + public Integer color = 12638463; + public boolean displaySwitch = false; + + public void loadFromConfig(KaleidoscopeConfig.ConfigData config) { + color = config.fogConfig.color; + displaySwitch = config.fogConfig.displaySwitch; + } + + public void saveToConfig(KaleidoscopeConfig.ConfigData config) { + config.fogConfig.color = color; + config.fogConfig.displaySwitch = displaySwitch; + } +} \ No newline at end of file diff --git a/src/main/java/top/byteeeee/kaleidoscope/config/skyColor/SkyConfig.java b/src/main/java/top/byteeeee/kaleidoscope/config/skyColor/SkyConfig.java new file mode 100644 index 0000000..d19b1fa --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/config/skyColor/SkyConfig.java @@ -0,0 +1,38 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.config.skyColor; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +public class SkyConfig { + public Integer color = 7907327; + public boolean displaySwitch = false; + + public void loadFromConfig(KaleidoscopeConfig.ConfigData config) { + color = config.skyConfig.color; + displaySwitch = config.skyConfig.displaySwitch; + } + + public void saveToConfig(KaleidoscopeConfig.ConfigData config) { + config.skyConfig.color = color; + config.skyConfig.displaySwitch = displaySwitch; + } +} \ No newline at end of file diff --git a/src/main/java/top/byteeeee/kaleidoscope/event/ClientStartEvent.java b/src/main/java/top/byteeeee/kaleidoscope/event/ClientStartEvent.java new file mode 100644 index 0000000..843072a --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/event/ClientStartEvent.java @@ -0,0 +1,30 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.event; + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +public class ClientStartEvent { + public static void event() { + ClientLifecycleEvents.CLIENT_STARTED.register(client -> KaleidoscopeConfig.loadFromConfig()); + } +} diff --git a/src/main/java/top/byteeeee/kaleidoscope/mixin/biomeColor/BiomeEffectsMixin.java b/src/main/java/top/byteeeee/kaleidoscope/mixin/biomeColor/BiomeEffectsMixin.java new file mode 100644 index 0000000..04031fe --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/mixin/biomeColor/BiomeEffectsMixin.java @@ -0,0 +1,51 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.mixin.biomeColor; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +import net.minecraft.world.biome.BiomeEffects; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +@Environment(EnvType.CLIENT) +@Mixin(BiomeEffects.class) +public abstract class BiomeEffectsMixin { + @Inject(method = "getSkyColor", at = @At("HEAD"), cancellable = true) + private void getSkyColor(CallbackInfoReturnable cir) { + if (KaleidoscopeConfig.skyConfig.displaySwitch) { + cir.setReturnValue(KaleidoscopeConfig.skyConfig.color); + } + } + + @Inject(method = "getFogColor", at = @At("HEAD"), cancellable = true) + private void getFogColor(CallbackInfoReturnable cir) { + if (KaleidoscopeConfig.fogConfig.displaySwitch) { + cir.setReturnValue(KaleidoscopeConfig.fogConfig.color); + } + } +} diff --git a/src/main/java/top/byteeeee/kaleidoscope/mixin/blockOutlineColor/WorldRenderMixin.java b/src/main/java/top/byteeeee/kaleidoscope/mixin/blockOutlineColor/WorldRenderMixin.java new file mode 100644 index 0000000..45548e1 --- /dev/null +++ b/src/main/java/top/byteeeee/kaleidoscope/mixin/blockOutlineColor/WorldRenderMixin.java @@ -0,0 +1,74 @@ +/* + * This file is part of the Kaleidoscope project, licensed under the + * GNU Lesser General Public License v3.0 + * + * Copyright (C) 2024 1024_byteeeee and contributors + * + * Kaleidoscope is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Kaleidoscope is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Kaleidoscope. If not, see . + */ + +package top.byteeeee.kaleidoscope.mixin.blockOutlineColor; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; + +import org.jetbrains.annotations.Nullable; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import top.byteeeee.kaleidoscope.config.KaleidoscopeConfig; + +@Environment(EnvType.CLIENT) +@Mixin(WorldRenderer.class) +public abstract class WorldRenderMixin { + + @Shadow + @Nullable + private ClientWorld world; + + @Shadow + private static void drawShapeOutline(MatrixStack matrices, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j) {} + + @Inject(method = "drawBlockOutline", at = @At("HEAD"), cancellable = true) + private void drawBlockOutline (MatrixStack matrices, VertexConsumer vertexConsumer, Entity entity, double cameraX, double cameraY, double cameraZ, BlockPos pos, BlockState state, CallbackInfo ci) { + if (KaleidoscopeConfig.blockOutlineConfig.displaySwitch) { + float R = KaleidoscopeConfig.blockOutlineConfig.red / 255.0F; + float G = KaleidoscopeConfig.blockOutlineConfig.green / 255.0F; + float B = KaleidoscopeConfig.blockOutlineConfig.blue / 255.0F; + float alpha = KaleidoscopeConfig.blockOutlineConfig.alpha / 255.0F; + drawShapeOutline( + matrices, vertexConsumer, state.getOutlineShape(this.world, pos, ShapeContext.of(entity)), + (double)pos.getX() - cameraX, + (double)pos.getY() - cameraY, + (double)pos.getZ() - cameraZ, + R, G, B, alpha + ); + ci.cancel(); + } + } +} diff --git a/src/main/resources/assets/kaledoscope/icon.png b/src/main/resources/assets/kaledoscope/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8b1b140e9ad07ac6bcf93b13daa0336414ebf203 GIT binary patch literal 33990 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