Compare commits
28 Commits
v0.4.1
...
MultiLoade
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fb2c614db | |||
| c05c0bdfc4 | |||
| 5a1c2fdbc5 | |||
| c9b9e0eefe | |||
| f589cf27a2 | |||
| 35ceb69f0b | |||
| dbae05691d | |||
| a435c3b272 | |||
| 04640d2b12 | |||
| 9dbeb0732f | |||
| 408482759a | |||
| e4fe0f17f2 | |||
|
|
4cdbefc9c3 | ||
|
|
c653832a9c | ||
| 85c4c47a72 | |||
| 80872ebbaa | |||
| a5d00dad96 | |||
| 9eec9972f4 | |||
| 6c6883b767 | |||
| 0c2a589a0c | |||
| 50856266d8 | |||
| 418e85394c | |||
| af3e313fde | |||
| 099f29e76f | |||
| 0c62d360d9 | |||
| 5a6729aa31 | |||
| eac118e9a4 | |||
| b616b4535e |
207
.github/workflows/build.yml
vendored
207
.github/workflows/build.yml
vendored
|
|
@ -1,207 +0,0 @@
|
||||||
name: Build and Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup JDK 21
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '21'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Make gradlew executable
|
|
||||||
run: chmod +x ./gradlew
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew build
|
|
||||||
|
|
||||||
- name: Prepare release files
|
|
||||||
run: |
|
|
||||||
mkdir -p release-files
|
|
||||||
cp build/libs/*.jar release-files/ 2>/dev/null || true
|
|
||||||
echo "准备发布的文件:"
|
|
||||||
ls -la release-files/
|
|
||||||
|
|
||||||
- name: Upload release artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: release-files
|
|
||||||
path: release-files/
|
|
||||||
retention-days: 7
|
|
||||||
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout with full history
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: release-files
|
|
||||||
path: ./dist
|
|
||||||
|
|
||||||
- name: Generate CZ-compliant changelog
|
|
||||||
id: generate_changelog
|
|
||||||
run: |
|
|
||||||
CURRENT_TAG="${{ github.ref_name }}"
|
|
||||||
PREV_TAG=$(git describe --tags --abbrev=0 $(git rev-list --tags --skip=1 --max-count=1) 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
# 创建临时文件
|
|
||||||
TEMP_FILE=$(mktemp)
|
|
||||||
|
|
||||||
echo "# 🚀 版本 $CURRENT_TAG 发布" > $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "## 📋 变更摘要" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
|
|
||||||
if [ -z "$PREV_TAG" ]; then
|
|
||||||
echo "### 初始版本发布" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "这是项目的第一个正式版本。" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
# 获取所有提交并按类型分组
|
|
||||||
git log --pretty=format:"%s" --reverse | while read -r line; do
|
|
||||||
echo "- $line" >> $TEMP_FILE
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "### 从 $PREV_TAG 到 $CURRENT_TAG 的变更" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
|
|
||||||
# 定义符合CZ规范的提交类型映射
|
|
||||||
declare -A commit_types
|
|
||||||
commit_types=(
|
|
||||||
["✨ 新功能"]="^(feat|feature)(\(.*\))?:"
|
|
||||||
["🐛 修复"]="^(fix|bugfix)(\(.*\))?:"
|
|
||||||
["📝 文档"]="^(docs|documentation)(\(.*\))?:"
|
|
||||||
["🎨 样式"]="^(style)(\(.*\))?:"
|
|
||||||
["🔨 重构"]="^(refactor)(\(.*\))?:"
|
|
||||||
["⚡️ 性能"]="^(perf|performance)(\(.*\))?:"
|
|
||||||
["✅ 测试"]="^(test)(\(.*\))?:"
|
|
||||||
["🔧 构建"]="^(build)(\(.*\))?:"
|
|
||||||
["👷 CI"]="^(ci)(\(.*\))?:"
|
|
||||||
["📦 依赖"]="^(chore|deps)(\(.*\))?:"
|
|
||||||
["⏪ 回退"]="^(revert)(\(.*\))?:"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 获取所有提交
|
|
||||||
COMMITS=$(git log --pretty=format:"%s" $PREV_TAG..HEAD)
|
|
||||||
|
|
||||||
# 处理每种类型的提交
|
|
||||||
for type_name in "${!commit_types[@]}"; do
|
|
||||||
pattern="${commit_types[$type_name]}"
|
|
||||||
|
|
||||||
# 提取匹配的提交
|
|
||||||
matched_commits=$(echo "$COMMITS" | grep -E "$pattern" || true)
|
|
||||||
|
|
||||||
if [ -n "$matched_commits" ]; then
|
|
||||||
echo "#### $type_name" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
|
|
||||||
# 处理每条提交,提取scope和subject
|
|
||||||
echo "$matched_commits" | while read -r commit; do
|
|
||||||
# 解析scope和subject
|
|
||||||
if [[ $commit =~ ^[a-z]+\((.*)\):\ (.*) ]]; then
|
|
||||||
scope="${BASH_REMATCH[1]}"
|
|
||||||
subject="${BASH_REMATCH[2]}"
|
|
||||||
echo "- **$scope**: $subject" >> $TEMP_FILE
|
|
||||||
elif [[ $commit =~ ^[a-z]+:\ (.*) ]]; then
|
|
||||||
subject="${BASH_REMATCH[1]}"
|
|
||||||
echo "- $subject" >> $TEMP_FILE
|
|
||||||
else
|
|
||||||
echo "- $commit" >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 处理破坏性变更(BREAKING CHANGE)
|
|
||||||
breaking_changes=$(git log --pretty=format:"%b" $PREV_TAG..HEAD | grep -i "BREAKING CHANGE" || true)
|
|
||||||
if [ -n "$breaking_changes" ]; then
|
|
||||||
echo "#### ⚠️ 破坏性变更" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "$breaking_changes" | while read -r line; do
|
|
||||||
echo "- $line" >> $TEMP_FILE
|
|
||||||
done
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 处理未分类的提交
|
|
||||||
uncategorized="$COMMITS"
|
|
||||||
for pattern in "${commit_types[@]}"; do
|
|
||||||
uncategorized=$(echo "$uncategorized" | grep -v -E "$pattern" || true)
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$uncategorized" ]; then
|
|
||||||
echo "#### 📝 其他更改" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "$uncategorized" | while read -r commit; do
|
|
||||||
echo "- $commit" >> $TEMP_FILE
|
|
||||||
done
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "## 📊 统计信息" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
|
|
||||||
if [ -z "$PREV_TAG" ]; then
|
|
||||||
TOTAL_COMMITS=$(git rev-list --count HEAD)
|
|
||||||
echo "- 总提交数: $TOTAL_COMMITS" >> $TEMP_FILE
|
|
||||||
echo "- 首次发布" >> $TEMP_FILE
|
|
||||||
else
|
|
||||||
COMMITS=$(git rev-list --count $PREV_TAG..HEAD)
|
|
||||||
echo "- 本次发布提交数: $COMMITS" >> $TEMP_FILE
|
|
||||||
echo "- 上一个版本: $PREV_TAG" >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "- 发布日期: $(date '+%Y年%m月%d日')" >> $TEMP_FILE
|
|
||||||
echo "- 当前版本: $CURRENT_TAG" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "---" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
echo "### 📜 详细提交历史" >> $TEMP_FILE
|
|
||||||
echo "" >> $TEMP_FILE
|
|
||||||
|
|
||||||
# 显示所有提交的详细列表,包含scope信息
|
|
||||||
if [ -z "$PREV_TAG" ]; then
|
|
||||||
git log --pretty=format:"- **%h** %s - %an (%ad)" --date=short --reverse | head -100 >> $TEMP_FILE
|
|
||||||
else
|
|
||||||
git log --pretty=format:"- **%h** %s - %an (%ad)" --date=short $PREV_TAG..HEAD | head -100 >> $TEMP_FILE
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 将文件内容输出到变量
|
|
||||||
CHANGELOG_CONTENT=$(cat $TEMP_FILE)
|
|
||||||
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Create Release
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
with:
|
|
||||||
artifacts: "dist/*.jar"
|
|
||||||
tag: ${{ github.ref_name }}
|
|
||||||
name: "版本 ${{ github.ref_name }}"
|
|
||||||
body: ${{ steps.generate_changelog.outputs.changelog }}
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
454
.github/workflows/buildAndRelease.yml
vendored
Normal file
454
.github/workflows/buildAndRelease.yml
vendored
Normal file
|
|
@ -0,0 +1,454 @@
|
||||||
|
name: Build and Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup JDK 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '21'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Make gradlew executable
|
||||||
|
run: chmod +x ./gradlew
|
||||||
|
|
||||||
|
- name: Run Forge data generation
|
||||||
|
run: |
|
||||||
|
echo "=== 运行 Forge 数据生成 ==="
|
||||||
|
./gradlew runData --no-daemon
|
||||||
|
|
||||||
|
continue-on-error: false
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew build --no-daemon
|
||||||
|
|
||||||
|
- name: Prepare release files
|
||||||
|
run: |
|
||||||
|
mkdir -p release-files
|
||||||
|
|
||||||
|
# 收集所有模块的构建产物
|
||||||
|
echo "=== 收集 common 模块构建产物 ==="
|
||||||
|
if [ -d "common/build/libs" ]; then
|
||||||
|
cp common/build/libs/*.jar release-files/ 2>/dev/null || echo "common 模块没有 jar 文件"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== 收集 fabric 模块构建产物 ==="
|
||||||
|
if [ -d "fabric/build/libs" ]; then
|
||||||
|
cp fabric/build/libs/*-dev.jar release-files/ 2>/dev/null || true # 排除dev jar
|
||||||
|
cp fabric/build/libs/*-sources.jar release-files/ 2>/dev/null || true
|
||||||
|
cp fabric/build/libs/*-javadoc.jar release-files/ 2>/dev/null || true
|
||||||
|
# 只复制主jar(没有sources/javadoc/dev classifier的jar)
|
||||||
|
find fabric/build/libs -name "*.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" ! -name "*-dev.jar" -exec cp {} release-files/ \;
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== 收集 forge 模块构建产物 ==="
|
||||||
|
if [ -d "forge/build/libs" ]; then
|
||||||
|
cp forge/build/libs/*-sources.jar release-files/ 2>/dev/null || true
|
||||||
|
cp forge/build/libs/*-javadoc.jar release-files/ 2>/dev/null || true
|
||||||
|
# 只复制主jar(没有sources/javadoc classifier的jar)
|
||||||
|
find forge/build/libs -name "*.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" -exec cp {} release-files/ \;
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== 准备发布的文件 ==="
|
||||||
|
ls -la release-files/
|
||||||
|
|
||||||
|
- name: Upload release artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-files
|
||||||
|
path: release-files/
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout with full history
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Determine version type
|
||||||
|
id: version_type
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref_name }}" == *"alpha"* ]]; then
|
||||||
|
echo "type=alpha" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.ref_name }}" == *"beta"* ]]; then
|
||||||
|
echo "type=beta" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ github.ref_name }}" == *"rc"* ]]; then
|
||||||
|
echo "type=beta" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "type=release" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-files
|
||||||
|
path: ./dist
|
||||||
|
|
||||||
|
- name: Extract version info
|
||||||
|
id: version_info
|
||||||
|
run: |
|
||||||
|
# 从tag中提取版本号(去掉v前缀)
|
||||||
|
VERSION="${GITHUB_REF_NAME#v}"
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "minecraft_version=$(grep "^minecraft_version=" gradle.properties | cut -d'=' -f2)" >> $GITHUB_OUTPUT
|
||||||
|
# 从 gradle.properties 提取 mod_id,如果没有则尝试从文件名推断
|
||||||
|
MOD_ID=$(grep "^mod_id=" gradle.properties | cut -d'=' -f2 || echo "")
|
||||||
|
if [ -z "$MOD_ID" ]; then
|
||||||
|
# 尝试从现有的 jar 文件名提取 mod_id
|
||||||
|
SAMPLE_JAR=$(ls dist/ | grep -m 1 -E ".*-(fabric|forge)-.*\.jar" || echo "")
|
||||||
|
if [ -n "$SAMPLE_JAR" ]; then
|
||||||
|
MOD_ID=$(echo "$SAMPLE_JAR" | sed -E 's/-(fabric|forge)-.*//')
|
||||||
|
else
|
||||||
|
MOD_ID="mymod" # 默认值,请根据实际情况修改
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "mod_id=$MOD_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# 从 gradle.properties 提取 mod_name(用于显示)
|
||||||
|
MOD_NAME=$(grep "^mod_name=" gradle.properties | cut -d'=' -f2 || echo "My Mod")
|
||||||
|
echo "mod_name=$MOD_NAME" >> $GITHUB_OUTPUT
|
||||||
|
# 从 gradle.properties 提取 modrinth_id
|
||||||
|
MODRINTH_ID=$(grep "^modrinth_id=" gradle.properties | cut -d'=' -f2 || echo "")
|
||||||
|
echo "modrinth_id=$MODRINTH_ID" >> $GITHUB_OUTPUT
|
||||||
|
# 从 gradle.properties 提取 curseforge_id
|
||||||
|
CURSEFORGE_ID=$(grep "^curseforge_id=" gradle.properties | cut -d'=' -f2 || echo "")
|
||||||
|
echo "curseforge_id=$CURSEFORGE_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Java版本 - 使用简单格式,不用JSON
|
||||||
|
JAVA_VERSIONS=$(grep "^java_versions=" gradle.properties | cut -d'=' -f2- || echo "21,17")
|
||||||
|
# 清理格式,移除无效字符
|
||||||
|
JAVA_VERSIONS=$(echo "$JAVA_VERSIONS" | sed 's/\[//g; s/\]//g; s/"//g; s/ //g; s/21a/21/g' | tr -d '\r')
|
||||||
|
echo "java_versions=$JAVA_VERSIONS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# 读取发布控制布尔值(默认都为 true)
|
||||||
|
PUBLISH_GITHUB=$(grep "^publish_github=" gradle.properties | cut -d'=' -f2 | tr '[:upper:]' '[:lower:]' | tr -d ' ' || echo "true")
|
||||||
|
if [ "$PUBLISH_GITHUB" = "true" ] || [ "$PUBLISH_GITHUB" = "1" ] || [ "$PUBLISH_GITHUB" = "yes" ]; then
|
||||||
|
echo "publish_github=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "publish_github=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
PUBLISH_MODRINTH=$(grep "^publish_modrinth=" gradle.properties | cut -d'=' -f2 | tr '[:upper:]' '[:lower:]' | tr -d ' ' || echo "true")
|
||||||
|
if [ "$PUBLISH_MODRINTH" = "true" ] || [ "$PUBLISH_MODRINTH" = "1" ] || [ "$PUBLISH_MODRINTH" = "yes" ]; then
|
||||||
|
echo "publish_modrinth=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "publish_modrinth=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
PUBLISH_CURSEFORGE=$(grep "^publish_curseforge=" gradle.properties | cut -d'=' -f2 | tr '[:upper:]' '[:lower:]' | tr -d ' ' || echo "true")
|
||||||
|
if [ "$PUBLISH_CURSEFORGE" = "true" ] || [ "$PUBLISH_CURSEFORGE" = "1" ] || [ "$PUBLISH_CURSEFORGE" = "yes" ]; then
|
||||||
|
echo "publish_curseforge=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "publish_curseforge=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 读取依赖配置 - 使用简单字符串,不用JSON
|
||||||
|
FABRIC_MODRINTH_DEPS=$(grep "^fabric_modrinth_dependencies=" gradle.properties | cut -d'=' -f2- || echo "")
|
||||||
|
echo "fabric_modrinth_dependencies=$FABRIC_MODRINTH_DEPS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
FORGE_MODRINTH_DEPS=$(grep "^forge_modrinth_dependencies=" gradle.properties | cut -d'=' -f2- || echo "")
|
||||||
|
echo "forge_modrinth_dependencies=$FORGE_MODRINTH_DEPS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
FABRIC_CURSEFORGE_DEPS=$(grep "^fabric_curseforge_dependencies=" gradle.properties | cut -d'=' -f2- || echo "")
|
||||||
|
echo "fabric_curseforge_dependencies=$FABRIC_CURSEFORGE_DEPS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
FORGE_CURSEFORGE_DEPS=$(grep "^forge_curseforge_dependencies=" gradle.properties | cut -d'=' -f2- || echo "")
|
||||||
|
echo "forge_curseforge_dependencies=$FORGE_CURSEFORGE_DEPS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Generate CZ-compliant changelog
|
||||||
|
id: generate_changelog
|
||||||
|
run: |
|
||||||
|
CURRENT_TAG="${{ github.ref_name }}"
|
||||||
|
PREV_TAG=$(git describe --tags --abbrev=0 $(git rev-list --tags --skip=1 --max-count=1) 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# 创建临时文件
|
||||||
|
TEMP_FILE=$(mktemp)
|
||||||
|
|
||||||
|
echo "# 🚀 版本 $CURRENT_TAG 发布" > $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "## 📋 变更摘要" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
|
||||||
|
if [ -z "$PREV_TAG" ]; then
|
||||||
|
echo "### 初始版本发布" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "这是项目的第一个正式版本。" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
# 获取所有提交并按类型分组
|
||||||
|
git log --pretty=format:"%s" --reverse | while read -r line; do
|
||||||
|
echo "- $line" >> $TEMP_FILE
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "### 从 $PREV_TAG 到 $CURRENT_TAG 的变更" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
|
||||||
|
# 定义符合CZ规范的提交类型映射
|
||||||
|
declare -A commit_types
|
||||||
|
commit_types=(
|
||||||
|
["✨ 新功能"]="^(feat|feature)(\(.*\))?:"
|
||||||
|
["🐛 修复"]="^(fix|bugfix)(\(.*\))?:"
|
||||||
|
["📝 文档"]="^(docs|documentation)(\(.*\))?:"
|
||||||
|
["🎨 样式"]="^(style)(\(.*\))?:"
|
||||||
|
["🔨 重构"]="^(refactor)(\(.*\))?:"
|
||||||
|
["⚡️ 性能"]="^(perf|performance)(\(.*\))?:"
|
||||||
|
["✅ 测试"]="^(test)(\(.*\))?:"
|
||||||
|
["🔧 构建"]="^(build)(\(.*\))?:"
|
||||||
|
["👷 CI"]="^(ci)(\(.*\))?:"
|
||||||
|
["📦 依赖"]="^(chore|deps)(\(.*\))?:"
|
||||||
|
["⏪ 回退"]="^(revert)(\(.*\))?:"
|
||||||
|
["🛠 合并"]="^Merge "
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取所有提交
|
||||||
|
COMMITS=$(git log --pretty=format:"%s" $PREV_TAG..HEAD)
|
||||||
|
|
||||||
|
# 处理每种类型的提交
|
||||||
|
for type_name in "${!commit_types[@]}"; do
|
||||||
|
pattern="${commit_types[$type_name]}"
|
||||||
|
|
||||||
|
# 提取匹配的提交
|
||||||
|
matched_commits=$(echo "$COMMITS" | grep -E "$pattern" || true)
|
||||||
|
|
||||||
|
if [ -n "$matched_commits" ]; then
|
||||||
|
echo "#### $type_name" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
|
||||||
|
# 处理每条提交,提取scope和subject
|
||||||
|
echo "$matched_commits" | while read -r commit; do
|
||||||
|
# 解析scope和subject
|
||||||
|
if [[ $commit =~ ^[a-z]+\((.*)\):\ (.*) ]]; then
|
||||||
|
scope="${BASH_REMATCH[1]}"
|
||||||
|
subject="${BASH_REMATCH[2]}"
|
||||||
|
echo "- **$scope**: $subject" >> $TEMP_FILE
|
||||||
|
elif [[ $commit =~ ^[a-z]+:\ (.*) ]]; then
|
||||||
|
subject="${BASH_REMATCH[1]}"
|
||||||
|
echo "- $subject" >> $TEMP_FILE
|
||||||
|
else
|
||||||
|
echo "- $commit" >> $TEMP_FILE
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 处理破坏性变更(BREAKING CHANGE)
|
||||||
|
breaking_changes=$(git log --pretty=format:"%b" $PREV_TAG..HEAD | grep -i "BREAKING CHANGE" || true)
|
||||||
|
if [ -n "$breaking_changes" ]; then
|
||||||
|
echo "#### ⚠️ 破坏性变更" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "$breaking_changes" | while read -r line; do
|
||||||
|
echo "- $line" >> $TEMP_FILE
|
||||||
|
done
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 处理未分类的提交
|
||||||
|
uncategorized="$COMMITS"
|
||||||
|
for pattern in "${commit_types[@]}"; do
|
||||||
|
uncategorized=$(echo "$uncategorized" | grep -v -E "$pattern" || true)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$uncategorized" ]; then
|
||||||
|
echo "#### 📝 其他更改" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "$uncategorized" | while read -r commit; do
|
||||||
|
echo "- $commit" >> $TEMP_FILE
|
||||||
|
done
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "## 📊 统计信息" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
|
||||||
|
if [ -z "$PREV_TAG" ]; then
|
||||||
|
TOTAL_COMMITS=$(git rev-list --count HEAD)
|
||||||
|
echo "- 总提交数: $TOTAL_COMMITS" >> $TEMP_FILE
|
||||||
|
echo "- 首次发布" >> $TEMP_FILE
|
||||||
|
else
|
||||||
|
COMMITS=$(git rev-list --count $PREV_TAG..HEAD)
|
||||||
|
echo "- 本次发布提交数: $COMMITS" >> $TEMP_FILE
|
||||||
|
echo "- 上一个版本: $PREV_TAG" >> $TEMP_FILE
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "- 发布日期: $(date '+%Y年%m月%d日')" >> $TEMP_FILE
|
||||||
|
echo "- 当前版本: $CURRENT_TAG" >> $TEMP_FILE
|
||||||
|
echo "- Minecraft版本: ${{ steps.version_info.outputs.minecraft_version }}" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "---" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
|
||||||
|
echo "### 📜 详细提交历史" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "<details>" >> $TEMP_FILE
|
||||||
|
echo "<summary>点击展开查看完整提交历史</summary>" >> $TEMP_FILE
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "\`\`\`" >> $TEMP_FILE
|
||||||
|
|
||||||
|
if [ -z "$PREV_TAG" ]; then
|
||||||
|
# 使用 while 循环确保每条提交独立一行
|
||||||
|
git log --pretty=format:"%h %s - %an (%ad)" --date=short --reverse | while IFS= read -r line; do
|
||||||
|
echo "$line" >> $TEMP_FILE
|
||||||
|
done
|
||||||
|
else
|
||||||
|
git log --pretty=format:"%h %s - %an (%ad)" --date=short $PREV_TAG..HEAD | while IFS= read -r line; do
|
||||||
|
echo "$line" >> $TEMP_FILE
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 确保文件末尾有换行
|
||||||
|
echo "" >> $TEMP_FILE
|
||||||
|
echo "\`\`\`" >> $TEMP_FILE
|
||||||
|
echo "</details>" >> $TEMP_FILE
|
||||||
|
|
||||||
|
# 将文件内容输出到变量
|
||||||
|
CHANGELOG_CONTENT=$(cat $TEMP_FILE)
|
||||||
|
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
if: steps.version_info.outputs.publish_github == 'true'
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
artifacts: |
|
||||||
|
dist/*.jar
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
|
name: "${{ steps.version_info.outputs.minecraft_version }} - ${{ github.ref_name }}"
|
||||||
|
body: ${{ steps.generate_changelog.outputs.changelog }}
|
||||||
|
draft: false
|
||||||
|
prerelease: ${{ contains(github.ref_name, 'rc') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
allowUpdates: true
|
||||||
|
removeArtifacts: true
|
||||||
|
# Fabric 发布到 Modrinth 和 CurseForge
|
||||||
|
- name: Publish Fabric to Modrinth & CurseForge
|
||||||
|
uses: Kir-Antipov/mc-publish@v3.3
|
||||||
|
if: success() && (steps.version_info.outputs.publish_modrinth == 'true' || steps.version_info.outputs.publish_curseforge == 'true')
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
# 文件匹配规则 - 只匹配 fabric 的文件
|
||||||
|
files: |
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-fabric-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}.jar
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-fabric-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}-javadoc.jar
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-fabric-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}-sources.jar
|
||||||
|
|
||||||
|
# 版本信息
|
||||||
|
name: ${{ steps.version_info.outputs.mod_name }} ${{ steps.version_info.outputs.version }} (Fabric/${{ steps.version_info.outputs.minecraft_version }})
|
||||||
|
version: "${{ steps.version_info.outputs.minecraft_version }}-fabric-${{ steps.version_info.outputs.version }}"
|
||||||
|
|
||||||
|
# 更新日志
|
||||||
|
changelog: ${{ steps.generate_changelog.outputs.changelog }}
|
||||||
|
|
||||||
|
# 版本类型
|
||||||
|
version-type: ${{ steps.version_type.outputs.type }}
|
||||||
|
|
||||||
|
# 只指定 Fabric 加载器
|
||||||
|
loaders: fabric
|
||||||
|
|
||||||
|
# 游戏版本
|
||||||
|
game-versions: |
|
||||||
|
${{ steps.version_info.outputs.minecraft_version }}
|
||||||
|
|
||||||
|
# Java版本
|
||||||
|
java: |
|
||||||
|
${{ steps.version_info.outputs.java_versions }}
|
||||||
|
|
||||||
|
# Modrinth 配置
|
||||||
|
modrinth-id: ${{ steps.version_info.outputs.modrinth_id }}
|
||||||
|
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
|
modrinth-featured: true
|
||||||
|
modrinth-unfeature-mode: any
|
||||||
|
modrinth-dependencies: ${{ steps.version_info.outputs.fabric_modrinth_dependencies }}
|
||||||
|
# CurseForge 配置
|
||||||
|
curseforge-id: ${{ steps.version_info.outputs.curseforge_id }}
|
||||||
|
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||||
|
curseforge-dependencies: ${{ steps.version_info.outputs.fabric_curseforge_dependencies }}
|
||||||
|
|
||||||
|
# 失败处理
|
||||||
|
fail-mode: skip
|
||||||
|
|
||||||
|
# Forge 发布到 Modrinth 和 CurseForge
|
||||||
|
- name: Publish Forge to Modrinth & CurseForge
|
||||||
|
uses: Kir-Antipov/mc-publish@v3.3
|
||||||
|
if: success() && (steps.version_info.outputs.publish_modrinth == 'true' || steps.version_info.outputs.publish_curseforge == 'true')
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
# 文件匹配规则 - 只匹配 forge 的文件
|
||||||
|
files: |
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-forge-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}.jar
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-forge-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}-javadoc.jar
|
||||||
|
dist/${{ steps.version_info.outputs.mod_id }}-forge-${{ steps.version_info.outputs.minecraft_version }}-${{ steps.version_info.outputs.version }}-sources.jar
|
||||||
|
|
||||||
|
# 版本信息
|
||||||
|
name: ${{ steps.version_info.outputs.mod_name }} ${{ steps.version_info.outputs.version }} (Forge/${{ steps.version_info.outputs.minecraft_version }})
|
||||||
|
version: "${{ steps.version_info.outputs.minecraft_version }}-forge-${{ steps.version_info.outputs.version }}"
|
||||||
|
|
||||||
|
# 更新日志
|
||||||
|
changelog: ${{ steps.generate_changelog.outputs.changelog }}
|
||||||
|
|
||||||
|
# 版本类型
|
||||||
|
version-type: ${{ steps.version_type.outputs.type }}
|
||||||
|
|
||||||
|
# 只指定 Forge 加载器
|
||||||
|
loaders: forge
|
||||||
|
|
||||||
|
# 游戏版本
|
||||||
|
game-versions: |
|
||||||
|
${{ steps.version_info.outputs.minecraft_version }}
|
||||||
|
|
||||||
|
# Java版本
|
||||||
|
java: |
|
||||||
|
${{ steps.version_info.outputs.java_versions }}
|
||||||
|
|
||||||
|
# Modrinth 配置
|
||||||
|
modrinth-id: ${{ steps.version_info.outputs.modrinth_id }}
|
||||||
|
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
|
modrinth-featured: true
|
||||||
|
modrinth-unfeature-mode: any
|
||||||
|
modrinth-dependencies: ${{ steps.version_info.outputs.forge_modrinth_dependencies }}
|
||||||
|
|
||||||
|
# CurseForge 配置
|
||||||
|
curseforge-id: ${{ steps.version_info.outputs.curseforge_id }}
|
||||||
|
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||||
|
curseforge-dependencies: ${{ steps.version_info.outputs.forge_curseforge_dependencies }}
|
||||||
|
|
||||||
|
# 失败处理
|
||||||
|
fail-mode: skip
|
||||||
|
|
||||||
|
# 发布完成后列出结果
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "## 发布结果摘要" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### GitHub Release" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- 标签: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- URL: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Modrinth" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- 项目ID: ${{ steps.version_info.outputs.modrinth_id }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Fabric版本: ${{ steps.version_info.outputs.version }}-fabric" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Forge版本: ${{ steps.version_info.outputs.version }}-forge" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### CurseForge" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- 项目ID: ${{ steps.version_info.outputs.curseforge_id }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Fabric版本: ${{ steps.version_info.outputs.version }}-fabric" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Forge版本: ${{ steps.version_info.outputs.version }}-forge" >> $GITHUB_STEP_SUMMARY
|
||||||
30
.github/workflows/styleCheck.yml
vendored
Normal file
30
.github/workflows/styleCheck.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
name: Check Style in Pull Request
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checkstyle:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
checks: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: refs/pull/${{ github.event.number }}/merge
|
||||||
|
- name: Setup Java 17
|
||||||
|
uses: actions/setup-java@v3.6.0
|
||||||
|
with:
|
||||||
|
distribution: zulu
|
||||||
|
java-version: 17
|
||||||
|
- uses: reviewdog/action-setup@v1
|
||||||
|
with:
|
||||||
|
reviewdog_version: latest
|
||||||
|
- name: download checkstyle
|
||||||
|
run: curl -o checkstyle.jar -L https://github.com/checkstyle/checkstyle/releases/download/checkstyle-12.1.2/checkstyle-12.1.2-all.jar
|
||||||
|
- name: checkstyle
|
||||||
|
env:
|
||||||
|
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: java -jar checkstyle.jar -c style.xml -f xml */src | reviewdog -f=checkstyle -name="Checkstyle" -reporter=github-pr-review -fail-level=any
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -21,6 +21,7 @@ build
|
||||||
# other
|
# other
|
||||||
eclipse
|
eclipse
|
||||||
run
|
run
|
||||||
|
generated
|
||||||
runs
|
runs
|
||||||
run-data
|
run-data
|
||||||
|
|
||||||
|
|
|
||||||
45
README.md
45
README.md
|
|
@ -1,10 +1,14 @@
|
||||||
# Lib39
|
# Lib39
|
||||||
|
 []()
|
||||||
|
|
||||||
|
[](https://www.curseforge.com/minecraft/mc-mods/lib-39)
|
||||||
|
[](https://modrinth.com/mod/lib-39)
|
||||||
|
|
||||||
**Lib39** is a general-purpose dependency library for Minecraft mods.
|
**Lib39** is a general-purpose dependency library for Minecraft mods.
|
||||||
It provides utility methods and core functionality that other mods can build upon.
|
It provides utility methods and core functionality that other mods can build upon.
|
||||||
### How to implementation?
|
### How to implementation? ( Only for Version 0.5.0+ )
|
||||||
|
|
||||||
**In repositories:**
|
#### **In repositories:**
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
maven {
|
maven {
|
||||||
|
|
@ -13,10 +17,41 @@ It provides utility methods and core functionality that other mods can build upo
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**In dependencies:**
|
#### **In dependencies:**
|
||||||
|
##### General
|
||||||
|
**gradle.properties**
|
||||||
|
```properties
|
||||||
|
lib39_version=0.5.1
|
||||||
|
````
|
||||||
|
##### For Loom
|
||||||
|
**build.gradle**
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("top.r3944realms.lib39:lib39:1.20.1-0.4.1")
|
modImplementation("top.r3944realms.lib39:lib39-fabric-1.20.1:${lib39_version}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### For ForgeGradle
|
||||||
|
**build.gradle**
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
implementation fg.deof("top.r3944realms.lib39:lib39-forge-1.20.1:${lib39_version}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### For NeoForgeGradle / ModDevGradle
|
||||||
|
**build.gradle**
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
modImplementation("top.r3944realms.lib39:lib39-forge-1.20.1:${lib39_version}")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### For MultiLoader Project
|
||||||
|
Add this in your common subproject.
|
||||||
|
**build.gradle**
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
implementation("top.r3944realms.lib39:lib39-common-1.20.1:${lib39_version}")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 NeoForged project
|
|
||||||
|
|
||||||
This license applies to the template files as supplied by github.com/NeoForged/MDK
|
|
||||||
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
535
build.gradle
535
build.gradle
|
|
@ -1,535 +1,4 @@
|
||||||
//file:noinspection GroovyAssignabilityCheck
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'fabric-loom' version '1.9-SNAPSHOT' apply(false)
|
||||||
id 'idea'
|
id 'net.neoforged.moddev.legacyforge' version '2.0.103' apply(false)
|
||||||
id 'java-library'
|
|
||||||
id 'maven-publish'
|
|
||||||
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
|
||||||
id 'net.neoforged.moddev.legacyforge' version '2.0.103'
|
|
||||||
id 'com.dorongold.task-tree' version '2.1.1'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: 'gradle/jni-heads.gradle'
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain.languageVersion = JavaLanguageVersion.of(17)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('wrapper', Wrapper).configure {
|
|
||||||
distributionType = Wrapper.DistributionType.BIN
|
|
||||||
}
|
|
||||||
|
|
||||||
version = "${minecraft_version}-${mod_version}"
|
|
||||||
group = mod_group_id
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
maven { url = "https://libraries.minecraft.net/" }
|
|
||||||
maven { url = "https://neoforged.forgecdn.net/releases" }
|
|
||||||
maven { url = "https://neoforged.forgecdn.net/mojang-meta" }
|
|
||||||
maven { url = "https://maven.neoforged.net/releases" }
|
|
||||||
maven {
|
|
||||||
name = "LTD Maven"
|
|
||||||
url = "https://nexus.bot.leisuretimedock.top/repository/maven-public/"
|
|
||||||
}
|
|
||||||
flatDir {
|
|
||||||
dir "libs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base {
|
|
||||||
archivesName = mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mojang ships Java 17 to end users in 1.20.1, so mods should target Java 17.
|
|
||||||
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
|
|
||||||
|
|
||||||
legacyForge {
|
|
||||||
// Specify the version of MinecraftForge to use.
|
|
||||||
version = project.minecraft_version + '-' + project.forge_version
|
|
||||||
|
|
||||||
parchment {
|
|
||||||
mappingsVersion = project.parchment_mappings_version
|
|
||||||
minecraftVersion = project.parchment_minecraft_version
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default run configurations.
|
|
||||||
runs {
|
|
||||||
client {
|
|
||||||
client()
|
|
||||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
clientAuth{
|
|
||||||
devLogin = true
|
|
||||||
client()
|
|
||||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
server()
|
|
||||||
programArgument '--nogui'
|
|
||||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
gameTestServer {
|
|
||||||
type = "gameTestServer"
|
|
||||||
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
data {
|
|
||||||
data()
|
|
||||||
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
configureEach {
|
|
||||||
systemProperty 'forge.logging.markers', 'REGISTRIES'
|
|
||||||
logLevel = org.slf4j.event.Level.DEBUG
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mods {
|
|
||||||
"${mod_id}" {
|
|
||||||
sourceSet(sourceSets.main)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include resources generated by data generators.
|
|
||||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
runtimeClasspath.extendsFrom localRuntime
|
|
||||||
}
|
|
||||||
obfuscation {
|
|
||||||
createRemappingConfiguration(configurations.localRuntime)
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(jarJar("io.github.llamalad7:mixinextras-forge:[0.4.1,)"))
|
|
||||||
|
|
||||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1"))
|
|
||||||
modImplementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1"))
|
|
||||||
modImplementation("blank:carryon-1.20.1:2.1.2.7")
|
|
||||||
|
|
||||||
implementation 'org.joml:joml:1.10.5'
|
|
||||||
// 单元测试依赖
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3'
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.3'
|
|
||||||
|
|
||||||
// 断言库
|
|
||||||
testImplementation 'org.assertj:assertj-core:3.24.2'
|
|
||||||
|
|
||||||
// Mock库(可选)
|
|
||||||
testImplementation 'org.mockito:mockito-core:5.3.1'
|
|
||||||
testImplementation 'org.mockito:mockito-junit-jupiter:5.3.1'
|
|
||||||
|
|
||||||
// 测试工具
|
|
||||||
testImplementation 'org.hamcrest:hamcrest:2.2'
|
|
||||||
}
|
|
||||||
mixin {
|
|
||||||
add sourceSets.main, "${mod_id}.refmap.json"
|
|
||||||
config "${mod_id}.mixins.json"
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
manifest.attributes([
|
|
||||||
"MixinConfigs": "${mod_id}.mixins.json"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
|
|
||||||
// 显示测试输出
|
|
||||||
testLogging {
|
|
||||||
events "passed", "skipped", "failed"
|
|
||||||
showStandardStreams = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置类路径
|
|
||||||
classpath = sourceSets.test.runtimeClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
// This block of code expands all declared replace properties in the specified resource targets.
|
|
||||||
var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) {
|
|
||||||
var replaceProperties = [
|
|
||||||
minecraft_version : minecraft_version,
|
|
||||||
minecraft_version_range : minecraft_version_range,
|
|
||||||
forge_version : forge_version,
|
|
||||||
forge_version_range : forge_version_range,
|
|
||||||
loader_version_range : loader_version_range,
|
|
||||||
mod_id : mod_id,
|
|
||||||
mod_name : mod_name,
|
|
||||||
mod_license : mod_license,
|
|
||||||
mod_version : mod_version,
|
|
||||||
mod_authors : mod_authors,
|
|
||||||
mod_description : mod_description,
|
|
||||||
mod_credits : mod_credits
|
|
||||||
]
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
inputs.properties replaceProperties
|
|
||||||
expand replaceProperties
|
|
||||||
from "src/main/templates"
|
|
||||||
into "build/generated/sources/modMetadata"
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets.main.resources.srcDir generateModMetadata
|
|
||||||
legacyForge.ideSyncTask generateModMetadata
|
|
||||||
|
|
||||||
// ==================== Javadoc 配置 ====================
|
|
||||||
javadoc {
|
|
||||||
options {
|
|
||||||
encoding = 'UTF-8'
|
|
||||||
charSet = 'UTF-8'
|
|
||||||
author = true
|
|
||||||
version = true
|
|
||||||
windowTitle = "Lib39 ${project.mod_version} API"
|
|
||||||
docTitle = "Lib39 ${project.mod_version} API"
|
|
||||||
memberLevel = JavadocMemberLevel.PROTECTED
|
|
||||||
links = [
|
|
||||||
'https://docs.oracle.com/javase/8/docs/api/'
|
|
||||||
]
|
|
||||||
addBooleanOption('Xdoclint:none', true)
|
|
||||||
addBooleanOption('html5', true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保有源代码可供生成文档
|
|
||||||
if (sourceSets.main.allJava.files.any { it.exists() }) {
|
|
||||||
source = sourceSets.main.allJava
|
|
||||||
}
|
|
||||||
classpath = configurations.compileClasspath
|
|
||||||
exclude '**/test/**'
|
|
||||||
exclude '**/internal/**'
|
|
||||||
|
|
||||||
// 确保输出目录存在
|
|
||||||
doFirst {
|
|
||||||
destinationDir.mkdirs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('javadocJar', Jar) {
|
|
||||||
archiveFileName = "${mod_id}-${minecraft_version}-${mod_version}-javadoc.jar"
|
|
||||||
archiveClassifier.set("javadoc")
|
|
||||||
from tasks.javadoc
|
|
||||||
dependsOn tasks.javadoc
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('sourceJar', Jar) {
|
|
||||||
from(sourceSets.main.allSource) // java
|
|
||||||
archiveFileName = "${mod_id}-${minecraft_version}-${mod_version}-sources.jar"
|
|
||||||
archiveClassifier.set("sources")
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
manifest {
|
|
||||||
attributes([
|
|
||||||
'Specification-Title' : mod_id,
|
|
||||||
'Specification-Vendor' : mod_authors,
|
|
||||||
'Specification-Version' : '1',
|
|
||||||
'Implementation-Title' : project.name,
|
|
||||||
'Implementation-Version' : archiveVersion,
|
|
||||||
'Implementation-Vendor' : mod_authors,
|
|
||||||
'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
|
||||||
'MixinConfigs' : "${mod_id}.mixins.json"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
dependsOn classes
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tasks.named('publish') {
|
|
||||||
dependsOn build
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ==================== 发布配置 ====================
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
mavenJava(MavenPublication) {
|
|
||||||
artifactId = mod_id
|
|
||||||
artifact reobfJar
|
|
||||||
artifact sourceJar
|
|
||||||
artifact javadocJar
|
|
||||||
|
|
||||||
pom {
|
|
||||||
name = 'Lib39'
|
|
||||||
description = 'Lib39 is a general-purpose dependency library for Minecraft mods.'
|
|
||||||
url = 'https://github.com/3944Realms/lib39'
|
|
||||||
|
|
||||||
properties = [
|
|
||||||
'minecraft.version': project.minecraft_version,
|
|
||||||
'mod.version': project.mod_version,
|
|
||||||
'forge.version': project.forge_version,
|
|
||||||
'java.version': '17'
|
|
||||||
]
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name = 'MIT'
|
|
||||||
url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE'
|
|
||||||
distribution = 'repo'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id = 'R3944Realms'
|
|
||||||
name = "${mod_authors}"
|
|
||||||
email = 'f256198830@hotmail.com'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scm {
|
|
||||||
connection = 'scm:git:https://github.com/3944Realms/lib39.git'
|
|
||||||
developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git'
|
|
||||||
url = 'https://github.com/3944Realms/lib39'
|
|
||||||
tag = 'main'
|
|
||||||
}
|
|
||||||
|
|
||||||
issueManagement {
|
|
||||||
system = 'GitHub'
|
|
||||||
url = 'https://github.com/3944Realms/lib39/issues'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
// 本地仓库
|
|
||||||
maven {
|
|
||||||
name = 'local'
|
|
||||||
url = layout.buildDirectory.dir("repo")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nexus 远程仓库
|
|
||||||
maven {
|
|
||||||
name = 'LTDNexus'
|
|
||||||
url = 'https://nexus.bot.leisuretimedock.top/repository/maven-releases/'
|
|
||||||
credentials {
|
|
||||||
username = System.getenv('LTDNexusUsername') ?: ''
|
|
||||||
password = System.getenv('LTDNexusPassword') ?: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 任务配置 ====================
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
options.encoding = 'UTF-8'
|
|
||||||
options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation']
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置 Javadoc JAR - 使用标准 javadoc 任务输出
|
|
||||||
tasks.named('javadocJar') {
|
|
||||||
from javadoc.destinationDir
|
|
||||||
}
|
|
||||||
// ==================== 验证任务 ====================
|
|
||||||
tasks.register('verifyNexusCredentials') {
|
|
||||||
doLast {
|
|
||||||
def username = System.getenv('LTDNexusUsername')
|
|
||||||
def password = System.getenv('LTDNexusPassword')
|
|
||||||
|
|
||||||
// 安全地显示用户名和密码(只显示最后两位)
|
|
||||||
def displayUsername = username ? "***${username.length() > 2 ? username.substring(username.length() - 2) : '**'}" : 'NOT SET'
|
|
||||||
def displayPassword = password ? "***${password.length() > 2 ? password.substring(password.length() - 2) : '**'}" : 'NOT SET'
|
|
||||||
|
|
||||||
println "Nexus Username: ${displayUsername}"
|
|
||||||
println "Nexus Password: ${displayPassword}"
|
|
||||||
|
|
||||||
if (!username || !password) {
|
|
||||||
throw new GradleException('LTDNexusUsername or LTDNexusPassword environment variables are not set')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('checkPublicationContents') {
|
|
||||||
doLast {
|
|
||||||
def publication = publishing.publications.mavenJava
|
|
||||||
println "=== Publication Details ==="
|
|
||||||
println "Group: ${publication.groupId}"
|
|
||||||
println "Artifact: ${publication.artifactId}"
|
|
||||||
println "Version: ${publication.version}"
|
|
||||||
println "Artifacts:"
|
|
||||||
publication.artifacts.each { artifact ->
|
|
||||||
def file = artifact.file
|
|
||||||
def exists = file.exists()
|
|
||||||
println " - ${file.name} (${artifact.classifier ?: 'main'}) - Exists: ${exists}"
|
|
||||||
|
|
||||||
if (!exists) {
|
|
||||||
throw new GradleException("Publication artifact missing: ${file.absolutePath}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 任务依赖 ====================
|
|
||||||
tasks.named('publishMavenJavaPublicationToLTDNexusRepository') {
|
|
||||||
dependsOn verifyNexusCredentials
|
|
||||||
dependsOn checkPublicationContents
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(PublishToMavenRepository) {
|
|
||||||
dependsOn assemble
|
|
||||||
dependsOn javadocJar
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 便捷任务 ====================
|
|
||||||
tasks.register('publishToNexus') {
|
|
||||||
group = 'publishing'
|
|
||||||
description = 'Publishes all publications to LTD Nexus'
|
|
||||||
dependsOn 'publishMavenJavaPublicationToLTDNexusRepository'
|
|
||||||
}
|
|
||||||
tasks.named('build') {
|
|
||||||
dependsOn javadocJar, sourceJar
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tasks.register('publishLocal') {
|
|
||||||
group = 'publishing'
|
|
||||||
description = 'Publishes all publications to the local Maven repository'
|
|
||||||
dependsOn 'publishToMavenLocal'
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('cleanRepo', Delete) {
|
|
||||||
delete layout.buildDirectory.dir("repo")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('clean') {
|
|
||||||
dependsOn cleanRepo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== IDEA 配置 ====================
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
downloadSources = true
|
|
||||||
downloadJavadoc = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 禁用模块元数据生成
|
|
||||||
tasks.withType(GenerateModuleMetadata) {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
tasks.register('showTaskTree') {
|
|
||||||
doLast {
|
|
||||||
def showTaskDeps
|
|
||||||
showTaskDeps = { task, prefix = '' ->
|
|
||||||
println "${prefix}${task.name}"
|
|
||||||
task.getTaskDependencies().getDependencies(task).each { dep ->
|
|
||||||
showTaskDeps(dep, prefix + ' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def targetTask = tasks.findByName('build')
|
|
||||||
if (targetTask) {
|
|
||||||
println "构建任务依赖树:"
|
|
||||||
showTaskDeps(targetTask)
|
|
||||||
} else {
|
|
||||||
println "未找到 build 任务"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**<pre>
|
|
||||||
build
|
|
||||||
├── check
|
|
||||||
│ └── test
|
|
||||||
│ ├── compileTestJava
|
|
||||||
│ │ ├── classes
|
|
||||||
│ │ │ ├── compileJava
|
|
||||||
│ │ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ │ └── extractSrg
|
|
||||||
│ │ │ │ └── downloadMcpConfig
|
|
||||||
│ │ │ └── processResources
|
|
||||||
│ │ └── compileJava
|
|
||||||
│ │ └── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ ├── testClasses
|
|
||||||
│ │ ├── processTestResources
|
|
||||||
│ │ └── compileTestJava
|
|
||||||
│ │ ├── classes
|
|
||||||
│ │ │ ├── compileJava
|
|
||||||
│ │ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ │ └── extractSrg
|
|
||||||
│ │ │ │ └── downloadMcpConfig
|
|
||||||
│ │ │ └── processResources
|
|
||||||
│ │ └── compileJava
|
|
||||||
│ │ └── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ ├── classes
|
|
||||||
│ │ ├── compileJava
|
|
||||||
│ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ └── extractSrg
|
|
||||||
│ │ │ └── downloadMcpConfig
|
|
||||||
│ │ └── processResources
|
|
||||||
│ └── compileJava
|
|
||||||
│ └── createMcpToSrg
|
|
||||||
│ └── extractSrg
|
|
||||||
│ └── downloadMcpConfig
|
|
||||||
└── assemble
|
|
||||||
├── reobfJarJar
|
|
||||||
│ ├── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ ├── configureReobfTaskForReobfJarJar
|
|
||||||
│ └── proguard
|
|
||||||
│ └── jarJar
|
|
||||||
│ ├── classes
|
|
||||||
│ │ ├── compileJava
|
|
||||||
│ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ └── extractSrg
|
|
||||||
│ │ │ └── downloadMcpConfig
|
|
||||||
│ │ └── processResources
|
|
||||||
│ ├── compileJava
|
|
||||||
│ │ └── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ └── addMixinsToJarJar
|
|
||||||
│ └── compileJava
|
|
||||||
│ └── createMcpToSrg
|
|
||||||
│ └── extractSrg
|
|
||||||
│ └── downloadMcpConfig
|
|
||||||
├── reobfJar
|
|
||||||
│ ├── jar
|
|
||||||
│ │ ├── classes
|
|
||||||
│ │ │ ├── compileJava
|
|
||||||
│ │ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ │ └── extractSrg
|
|
||||||
│ │ │ │ └── downloadMcpConfig
|
|
||||||
│ │ │ └── processResources
|
|
||||||
│ │ ├── compileJava
|
|
||||||
│ │ │ └── createMcpToSrg
|
|
||||||
│ │ │ └── extractSrg
|
|
||||||
│ │ │ └── downloadMcpConfig
|
|
||||||
│ │ └── addMixinsToJar
|
|
||||||
│ │ └── compileJava
|
|
||||||
│ │ └── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ ├── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ └── configureReobfTaskForReobfJar
|
|
||||||
└── jar
|
|
||||||
├── classes
|
|
||||||
│ ├── compileJava
|
|
||||||
│ │ └── createMcpToSrg
|
|
||||||
│ │ └── extractSrg
|
|
||||||
│ │ └── downloadMcpConfig
|
|
||||||
│ └── processResources
|
|
||||||
├── compileJava
|
|
||||||
│ └── createMcpToSrg
|
|
||||||
│ └── extractSrg
|
|
||||||
│ └── downloadMcpConfig
|
|
||||||
└── addMixinsToJar
|
|
||||||
└── compileJava
|
|
||||||
└── createMcpToSrg
|
|
||||||
└── extractSrg
|
|
||||||
└── downloadMcpConfig
|
|
||||||
</pre>
|
|
||||||
*/
|
|
||||||
3
buildSrc/build.gradle
Normal file
3
buildSrc/build.gradle
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
plugins {
|
||||||
|
id 'groovy-gradle-plugin'
|
||||||
|
}
|
||||||
207
buildSrc/src/main/groovy/multiloader-common.gradle
Normal file
207
buildSrc/src/main/groovy/multiloader-common.gradle
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = "${mod_id}-${project.name}-${minecraft_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(java_version)
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
|
||||||
|
// https://docs.gradle.org/current/userguide/declaring_repositories.html#declaring_content_exclusively_found_in_one_repository
|
||||||
|
exclusiveContent {
|
||||||
|
forRepository {
|
||||||
|
maven {
|
||||||
|
name = 'Sponge'
|
||||||
|
url = 'https://repo.spongepowered.org/repository/maven-public'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter { includeGroupAndSubgroups('org.spongepowered') }
|
||||||
|
}
|
||||||
|
exclusiveContent {
|
||||||
|
forRepositories(
|
||||||
|
maven {
|
||||||
|
name = 'ParchmentMC'
|
||||||
|
url = 'https://maven.parchmentmc.org/'
|
||||||
|
},
|
||||||
|
maven { url = "https://neoforged.forgecdn.net/releases" },
|
||||||
|
maven { url = "https://neoforged.forgecdn.net/mojang-meta" }
|
||||||
|
)
|
||||||
|
filter { includeGroup('org.parchmentmc.data') }
|
||||||
|
}
|
||||||
|
maven { url = "https://libraries.minecraft.net/" }
|
||||||
|
|
||||||
|
|
||||||
|
maven {
|
||||||
|
url "https://cursemaven.com"
|
||||||
|
content { includeGroup "curse.maven" }
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'BlameJared'
|
||||||
|
url = 'https://maven.blamejared.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare capabilities on the outgoing configurations.
|
||||||
|
// Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component
|
||||||
|
['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant ->
|
||||||
|
configurations."$variant".outgoing {
|
||||||
|
capability("$group:${project.name}:$version")
|
||||||
|
capability("$group:${base.archivesName.get()}:$version")
|
||||||
|
capability("$group:$mod_id-${project.name}-${minecraft_version}:$version")
|
||||||
|
capability("$group:$mod_id:$version")
|
||||||
|
}
|
||||||
|
publishing.publications.configureEach {
|
||||||
|
suppressPomMetadataWarningsFor(variant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJar {
|
||||||
|
from(rootProject.file('LICENSE')) {
|
||||||
|
rename { "${it}_${mod_name}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from(rootProject.file('LICENSE')) {
|
||||||
|
rename { "${it}_${mod_name}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes([
|
||||||
|
'Specification-Title' : mod_name,
|
||||||
|
'Specification-Vendor' : mod_author,
|
||||||
|
'Specification-Version' : project.jar.archiveVersion,
|
||||||
|
'Implementation-Title' : project.name,
|
||||||
|
'Implementation-Version': project.jar.archiveVersion,
|
||||||
|
'Implementation-Vendor' : mod_author,
|
||||||
|
'Built-On-Minecraft' : minecraft_version
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
var expandProps = [
|
||||||
|
'version' : version,
|
||||||
|
'group' : project.group, //Else we target the task's group.
|
||||||
|
'minecraft_version' : minecraft_version,
|
||||||
|
'minecraft_version_range' : minecraft_version_range,
|
||||||
|
'fabric_version' : fabric_version,
|
||||||
|
'fabric_loader_version' : fabric_loader_version,
|
||||||
|
'mod_name' : mod_name,
|
||||||
|
'mod_author' : mod_author,
|
||||||
|
'mod_id' : mod_id,
|
||||||
|
'license' : license,
|
||||||
|
'description' : project.description,
|
||||||
|
"forge_version" : forge_version,
|
||||||
|
"forge_loader_version_range" : forge_loader_version_range,
|
||||||
|
'credits' : credits,
|
||||||
|
'java_version' : java_version
|
||||||
|
]
|
||||||
|
|
||||||
|
var jsonExpandProps = expandProps.collectEntries {
|
||||||
|
key, value -> [(key): value instanceof String ? value.replace("\n", "\\\\n") : value]
|
||||||
|
}
|
||||||
|
|
||||||
|
filesMatching(['META-INF/mods.toml']) {
|
||||||
|
expand expandProps
|
||||||
|
}
|
||||||
|
|
||||||
|
filesMatching(['pack.mcmeta', 'fabric.mod.json', '*.mixins.json']) {
|
||||||
|
expand jsonExpandProps
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.properties(expandProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
register('mavenJava', MavenPublication) {
|
||||||
|
artifactId base.archivesName.get()
|
||||||
|
from components.java
|
||||||
|
pom {
|
||||||
|
name = 'Lib39'
|
||||||
|
description = 'Lib39 is a general-purpose dependency library for Minecraft mods.'
|
||||||
|
url = 'https://github.com/3944Realms/lib39'
|
||||||
|
|
||||||
|
properties = [
|
||||||
|
'minecraft.version': project.minecraft_version,
|
||||||
|
'mod.version': project.version,
|
||||||
|
'forge.version': project.forge_version,
|
||||||
|
'java.version': '17'
|
||||||
|
]
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'MIT'
|
||||||
|
url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE'
|
||||||
|
distribution = 'repo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = 'R3944Realms'
|
||||||
|
name = "${mod_author}"
|
||||||
|
email = 'f256198830@hotmail.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scm {
|
||||||
|
connection = 'scm:git:https://github.com/3944Realms/lib39.git'
|
||||||
|
developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git'
|
||||||
|
url = 'https://github.com/3944Realms/lib39'
|
||||||
|
tag = 'main'
|
||||||
|
}
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system = 'GitHub'
|
||||||
|
url = 'https://github.com/3944Realms/lib39/issues'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
// 本地仓库
|
||||||
|
maven {
|
||||||
|
name = 'local'
|
||||||
|
url = layout.buildDirectory.dir("repo")
|
||||||
|
}
|
||||||
|
// Nexus 远程仓库
|
||||||
|
maven {
|
||||||
|
name = 'LTDNexus'
|
||||||
|
url = 'https://nexus.bot.leisuretimedock.top/repository/maven-releases/'
|
||||||
|
credentials {
|
||||||
|
username = System.getenv('LTDNexusUsername') ?: ''
|
||||||
|
password = System.getenv('LTDNexusPassword') ?: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 任务依赖 ====================
|
||||||
|
|
||||||
|
tasks.withType(PublishToMavenRepository) {
|
||||||
|
dependsOn assemble
|
||||||
|
dependsOn javadoc
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('build') {
|
||||||
|
dependsOn javadoc, sourcesJar
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('cleanRepo', Delete) {
|
||||||
|
delete layout.buildDirectory.dir("repo")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('clean') {
|
||||||
|
dependsOn cleanRepo
|
||||||
|
}
|
||||||
50
buildSrc/src/main/groovy/multiloader-loader.gradle
Normal file
50
buildSrc/src/main/groovy/multiloader-loader.gradle
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
plugins {
|
||||||
|
id 'multiloader-common'
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
commonJava{
|
||||||
|
canBeResolved = true
|
||||||
|
}
|
||||||
|
commonResources{
|
||||||
|
canBeResolved = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(':common')) {
|
||||||
|
capabilities {
|
||||||
|
requireCapability "$group:$mod_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commonJava project(path: ':common', configuration: 'commonJava')
|
||||||
|
commonResources project(path: ':common', configuration: 'commonResources')
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('compileJava', JavaCompile) {
|
||||||
|
dependsOn(configurations.commonJava)
|
||||||
|
source(configurations.commonJava)
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
dependsOn(configurations.commonResources)
|
||||||
|
from(configurations.commonResources)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('javadoc', Javadoc).configure {
|
||||||
|
dependsOn(configurations.commonJava)
|
||||||
|
source(configurations.commonJava)
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
options.charSet = 'UTF-8'
|
||||||
|
options.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
|
||||||
|
options.memberLevel = JavadocMemberLevel.PUBLIC
|
||||||
|
options.addBooleanOption('Xdoclint:none', true)
|
||||||
|
options.addStringOption('doctitle', "${mod_id} ${minecraft_version} ${version} Javadoc")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('sourcesJar', Jar) {
|
||||||
|
dependsOn(configurations.commonJava)
|
||||||
|
from(configurations.commonJava)
|
||||||
|
dependsOn(configurations.commonResources)
|
||||||
|
from(configurations.commonResources)
|
||||||
|
}
|
||||||
43
common/build.gradle
Normal file
43
common/build.gradle
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
plugins {
|
||||||
|
id 'multiloader-common'
|
||||||
|
id 'net.neoforged.moddev.legacyforge'
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyForge {
|
||||||
|
mcpVersion = minecraft_version
|
||||||
|
if (file("src/main/resources/META-INF/accesstransformer.cfg").exists()) {
|
||||||
|
accessTransformers = ["src/main/resources/META-INF/accesstransformer.cfg"]
|
||||||
|
}
|
||||||
|
parchment {
|
||||||
|
minecraftVersion = parchment_minecraft
|
||||||
|
mappingsVersion = parchment_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(group: 'org.spongepowered', name: 'mixin', version: '0.8.5')
|
||||||
|
implementation(group: 'tschipp.carryon', name: 'carryon-common-1.20.1', version: '2.1.2') {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
|
||||||
|
implementation(group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1')
|
||||||
|
}
|
||||||
|
configurations {
|
||||||
|
commonJava {
|
||||||
|
canBeResolved = false
|
||||||
|
canBeConsumed = true
|
||||||
|
}
|
||||||
|
commonResources {
|
||||||
|
canBeResolved = false
|
||||||
|
canBeConsumed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
commonJava sourceSets.main.java.sourceDirectories.singleFile
|
||||||
|
commonResources sourceSets.main.resources.sourceDirectories.singleFile, file('src/generated/resources')
|
||||||
|
}
|
||||||
|
|
||||||
|
clean {
|
||||||
|
delete 'generated'
|
||||||
|
}
|
||||||
125
common/src/main/java/top/r3944realms/lib39/Lib39.java
Normal file
125
common/src/main/java/top/r3944realms/lib39/Lib39.java
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
package top.r3944realms.lib39;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import top.r3944realms.lib39.example.Lib39Example;
|
||||||
|
import top.r3944realms.lib39.platform.Services;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39.
|
||||||
|
*/
|
||||||
|
public class Lib39 {
|
||||||
|
/**
|
||||||
|
* The constant MOD_ID.
|
||||||
|
*/
|
||||||
|
public static final String MOD_ID = "lib39";
|
||||||
|
/**
|
||||||
|
* The constant MOD_NAME.
|
||||||
|
*/
|
||||||
|
public static final String MOD_NAME = "3944Realms 's Lib Mod";
|
||||||
|
/**
|
||||||
|
* The constant LOGGER.
|
||||||
|
*/
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME);
|
||||||
|
/**
|
||||||
|
* The constant ENABLE_EXAMPLES_PROPERTY_KEY.
|
||||||
|
*/
|
||||||
|
public static final String ENABLE_EXAMPLES_PROPERTY_KEY = "lib39.enable_examples";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize.
|
||||||
|
*/
|
||||||
|
public static void initialize() {
|
||||||
|
Lib39.LOGGER.info("[Lib39-Common] Lib39-Common start initialization.");
|
||||||
|
if (shouldRegisterExamples()) {
|
||||||
|
LOGGER.info("[Lib39-Common] Registering Examples");
|
||||||
|
registerExamples();
|
||||||
|
}
|
||||||
|
Lib39.LOGGER.info("[Lib39-Common] Finished Lib39-Common!.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rl resource location.
|
||||||
|
*
|
||||||
|
* @param path the path
|
||||||
|
* @return the resource location
|
||||||
|
*/
|
||||||
|
@Contract("_ -> new")
|
||||||
|
public static @NotNull ResourceLocation rl(String path) {
|
||||||
|
return new ResourceLocation(Lib39.MOD_ID, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rl resource location.
|
||||||
|
*
|
||||||
|
* @param modId the mod id
|
||||||
|
* @param path the path
|
||||||
|
* @return the resource location
|
||||||
|
*/
|
||||||
|
@Contract("_, _ -> new")
|
||||||
|
public static @NotNull ResourceLocation rl(String modId, String path) {
|
||||||
|
return new ResourceLocation(modId, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mrl resource location.
|
||||||
|
*
|
||||||
|
* @param path the path
|
||||||
|
* @return the resource location
|
||||||
|
*/
|
||||||
|
@Contract("_ -> new")
|
||||||
|
public static @NotNull ResourceLocation mrl(String path) {
|
||||||
|
return new ResourceLocation(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is client environment boolean.
|
||||||
|
*
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
|
public static boolean isClientEnvironment() {
|
||||||
|
return Services.PLATFORM.isClientEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should register examples boolean.
|
||||||
|
*
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
|
public static boolean shouldRegisterExamples() {
|
||||||
|
return Services.PLATFORM.isDevelopmentEnvironment() || Boolean.getBoolean(ENABLE_EXAMPLES_PROPERTY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register examples.
|
||||||
|
*/
|
||||||
|
static void registerExamples() {
|
||||||
|
LOGGER.info("[Lib39-Common] Starting example demonstrations");
|
||||||
|
try {
|
||||||
|
// 创建示例实例并演示功能
|
||||||
|
Lib39Example example = new Lib39Example();
|
||||||
|
example.demonstrateFeature();
|
||||||
|
|
||||||
|
LOGGER.info("[Lib39-Common] Example demonstrations completed successfully");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("[Lib39-Common] Failed to demonstrate examples", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Mod info.
|
||||||
|
*/
|
||||||
|
public static class ModInfo {
|
||||||
|
/**
|
||||||
|
* The constant VERSION.
|
||||||
|
*/
|
||||||
|
public static final String VERSION;
|
||||||
|
static {
|
||||||
|
VERSION = Services.PLATFORM.getModVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,20 +5,26 @@ import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.core.command.SimpleCommandHelpManager;
|
import top.r3944realms.lib39.core.command.SimpleCommandHelpManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Lib 39 command help manager.
|
* <pre>
|
||||||
|
* 命令帮助注册管理类
|
||||||
|
* 这是一个模组内置的示例
|
||||||
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class Lib39CommandHelpManager extends SimpleCommandHelpManager {
|
public class Lib39CommandHelpManager extends SimpleCommandHelpManager {
|
||||||
/**
|
/**
|
||||||
* The constant INSTANCE.
|
* 单例模式
|
||||||
*/
|
*/
|
||||||
public static volatile Lib39CommandHelpManager INSTANCE = new Lib39CommandHelpManager();
|
public static volatile Lib39CommandHelpManager INSTANCE = new Lib39CommandHelpManager();
|
||||||
/**
|
/**
|
||||||
* The Id.
|
* 作为唯一标识符
|
||||||
*/
|
*/
|
||||||
ResourceLocation ID = Lib39.rl("command_helper");
|
ResourceLocation ID = Lib39.rl("command_helper");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 一定要在构造器方法里调用 {@link #initialize 初始化方法}
|
||||||
* Instantiates a new Lib 39 command help manager.
|
* Instantiates a new Lib 39 command help manager.
|
||||||
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Lib39CommandHelpManager() {
|
public Lib39CommandHelpManager() {
|
||||||
initialize();
|
initialize();
|
||||||
|
|
@ -6,13 +6,13 @@ import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import net.minecraft.commands.CommandBuildContext;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.commands.arguments.EntityArgument;
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.core.command.ICommandHelpManager;
|
import top.r3944realms.lib39.core.command.ICommandHelpManager;
|
||||||
|
|
@ -21,20 +21,27 @@ import top.r3944realms.lib39.core.command.SimpleHelpCommand;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Lib 39 help command.
|
* <pre>
|
||||||
|
* 指令注册以及帮助编写类
|
||||||
|
* 这是一个模组内置的示例
|
||||||
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class Lib39HelpCommand extends SimpleHelpCommand {
|
public class Lib39HelpCommand extends SimpleHelpCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 需要{@link CommandDispatcher<CommandSourceStack> 指令注册调度器} 和 {@link CommandBuildContext 指令上下文}
|
||||||
|
* </pre>
|
||||||
* Instantiates a new Lib 39 help command.
|
* Instantiates a new Lib 39 help command.
|
||||||
*
|
*
|
||||||
* @param event the event
|
* @param dispatcher the dispatcher
|
||||||
|
* @param context the context
|
||||||
*/
|
*/
|
||||||
public Lib39HelpCommand(@NotNull RegisterCommandsEvent event) {
|
public Lib39HelpCommand(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) {
|
||||||
super(event);
|
super(dispatcher, context);
|
||||||
if(Lib39.shouldRegisterExamples()) {
|
if(Lib39.shouldRegisterExamples()) {
|
||||||
// 在這裡註冊測試命令
|
// 在這裡註冊測試命令
|
||||||
registerTestCommands(event.getDispatcher());
|
registerTestCommands(dispatcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ import net.minecraft.data.recipes.ShapelessRecipeBuilder;
|
||||||
import net.minecraft.tags.ItemTags;
|
import net.minecraft.tags.ItemTags;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class Lib39RecipeProvider extends RecipeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {
|
public void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {
|
||||||
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Lib39Items.DOLL.get())
|
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Lib39Items.DOLL.get())
|
||||||
.requires(ItemTags.WOOL)
|
.requires(ItemTags.WOOL)
|
||||||
.requires(Items.ARMOR_STAND)
|
.requires(Items.ARMOR_STAND)
|
||||||
|
|
@ -3,9 +3,9 @@ package top.r3944realms.lib39.base.datagen.value;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.content.register.Lib39Blocks;
|
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
||||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||||
import top.r3944realms.lib39.content.register.Lib39SoundEvents;
|
import top.r3944realms.lib39.core.register.Lib39SoundEvents;
|
||||||
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
||||||
import top.r3944realms.lib39.datagen.value.LangKeyValue;
|
import top.r3944realms.lib39.datagen.value.LangKeyValue;
|
||||||
import top.r3944realms.lib39.datagen.value.ModPartEnum;
|
import top.r3944realms.lib39.datagen.value.ModPartEnum;
|
||||||
|
|
@ -15,6 +15,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The enum Lib 39 lang key.
|
* The enum Lib 39 lang key.
|
||||||
|
|
@ -248,6 +249,13 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
addLang(LangKeyValue.copyOf(
|
addLang(LangKeyValue.copyOf(
|
||||||
Lib39Blocks.DOLL, ModPartEnum.BLOCK, dollName
|
Lib39Blocks.DOLL, ModPartEnum.BLOCK, dollName
|
||||||
));
|
));
|
||||||
|
addLang(LangKeyValue.copyOf(
|
||||||
|
Lib39Blocks.WALL_DOLL, ModPartEnum.BLOCK, dollName
|
||||||
|
));
|
||||||
|
addLang(
|
||||||
|
LangKeyValue.ofKey("config.jade.plugin_lib39.lib39", ModPartEnum.DEFAULT,
|
||||||
|
"Lib 39", "叁玖库", "叁玖庫", "叁玖庫"
|
||||||
|
));
|
||||||
addLang(LangKeyValue.ofKey(
|
addLang(LangKeyValue.ofKey(
|
||||||
"tooltip.lib39.content.doll.hover.1", ModPartEnum.DESCRIPTION,
|
"tooltip.lib39.content.doll.hover.1", ModPartEnum.DESCRIPTION,
|
||||||
"§eSkinOwner §7:§a %s ", "§e皮肤所有者§7:§a%s", "§e皮膚所有者§7:§a%s", "§e膚主§7:§a%s"
|
"§eSkinOwner §7:§a %s ", "§e皮肤所有者§7:§a%s", "§e皮膚所有者§7:§a%s", "§e膚主§7:§a%s"
|
||||||
|
|
@ -315,7 +323,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_ROOT.
|
* The constant LIB39_ROOT.
|
||||||
*/
|
*/
|
||||||
// 根命令
|
|
||||||
public static final LangKeyValue LIB39_ROOT = addAndRet(
|
public static final LangKeyValue LIB39_ROOT = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.root", ModPartEnum.MESSAGE,
|
"commands.lib39.root", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -330,7 +337,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_TEST.
|
* The constant LIB39_TEST.
|
||||||
*/
|
*/
|
||||||
// 測試命令
|
|
||||||
public static final LangKeyValue LIB39_TEST = addAndRet(
|
public static final LangKeyValue LIB39_TEST = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.test", ModPartEnum.MESSAGE,
|
"commands.lib39.test", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -401,7 +407,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_GREET_BASIC.
|
* The constant LIB39_GREET_BASIC.
|
||||||
*/
|
*/
|
||||||
// 問候命令
|
|
||||||
public static final LangKeyValue LIB39_GREET_BASIC = addAndRet(
|
public static final LangKeyValue LIB39_GREET_BASIC = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.greet.basic", ModPartEnum.MESSAGE,
|
"commands.lib39.greet.basic", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -458,7 +463,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_CALCULATE.
|
* The constant LIB39_CALCULATE.
|
||||||
*/
|
*/
|
||||||
// 計算命令
|
|
||||||
public static final LangKeyValue LIB39_CALCULATE = addAndRet(
|
public static final LangKeyValue LIB39_CALCULATE = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.calculate", ModPartEnum.MESSAGE,
|
"commands.lib39.calculate", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -487,7 +491,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_TELEPORT.
|
* The constant LIB39_TELEPORT.
|
||||||
*/
|
*/
|
||||||
// 傳送命令
|
|
||||||
public static final LangKeyValue LIB39_TELEPORT = addAndRet(
|
public static final LangKeyValue LIB39_TELEPORT = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.teleport", ModPartEnum.MESSAGE,
|
"commands.lib39.teleport", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -516,7 +519,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_INFO.
|
* The constant LIB39_INFO.
|
||||||
*/
|
*/
|
||||||
// 信息命令
|
|
||||||
public static final LangKeyValue LIB39_INFO = addAndRet(
|
public static final LangKeyValue LIB39_INFO = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.info", ModPartEnum.MESSAGE,
|
"commands.lib39.info", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -573,7 +575,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_TEAM.
|
* The constant LIB39_TEAM.
|
||||||
*/
|
*/
|
||||||
// 隊伍系統
|
|
||||||
public static final LangKeyValue LIB39_TEAM = addAndRet(
|
public static final LangKeyValue LIB39_TEAM = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.team", ModPartEnum.MESSAGE,
|
"commands.lib39.team", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -672,7 +673,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_GAME.
|
* The constant LIB39_GAME.
|
||||||
*/
|
*/
|
||||||
// 遊戲系統
|
|
||||||
public static final LangKeyValue LIB39_GAME = addAndRet(
|
public static final LangKeyValue LIB39_GAME = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.game", ModPartEnum.MESSAGE,
|
"commands.lib39.game", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -799,7 +799,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
/**
|
/**
|
||||||
* The constant LIB39_SETTINGS.
|
* The constant LIB39_SETTINGS.
|
||||||
*/
|
*/
|
||||||
// 設置命令
|
|
||||||
public static final LangKeyValue LIB39_SETTINGS = addAndRet(
|
public static final LangKeyValue LIB39_SETTINGS = addAndRet(
|
||||||
LangKeyValue.ofKey(
|
LangKeyValue.ofKey(
|
||||||
"commands.lib39.settings", ModPartEnum.MESSAGE,
|
"commands.lib39.settings", ModPartEnum.MESSAGE,
|
||||||
|
|
@ -854,7 +853,7 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
||||||
);
|
);
|
||||||
|
|
||||||
// ===== 添加缺失的導入 =====
|
// ===== 添加缺失的導入 =====
|
||||||
private static final java.util.function.Consumer<LangKeyValue> addConsumer = items::add;
|
private static final Consumer<LangKeyValue> addConsumer = items::add;
|
||||||
|
|
||||||
private static LangKeyValue addAndRet(LangKeyValue item) {
|
private static LangKeyValue addAndRet(LangKeyValue item) {
|
||||||
items.add(item);
|
items.add(item);
|
||||||
|
|
@ -353,8 +353,8 @@ public class WheelWidget extends AbstractWidget {
|
||||||
*
|
*
|
||||||
* @return the section circle diameter
|
* @return the section circle diameter
|
||||||
*/
|
*/
|
||||||
// 滚轮选择器中每个扇形的圆形直径
|
|
||||||
public float getSectionCircleDiameter() {
|
public float getSectionCircleDiameter() {
|
||||||
|
// 滚轮选择器中每个扇形的圆形直径
|
||||||
return this.ringOuterRadius + this.ringInnerRadius;
|
return this.ringOuterRadius + this.ringInnerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -635,8 +635,10 @@ public class WheelWidget extends AbstractWidget {
|
||||||
float pixelOuterRadius = outerRadius * guiScale;
|
float pixelOuterRadius = outerRadius * guiScale;
|
||||||
float pixelAntiAliasing = 2.0f * guiScale; // 抗锯齿范围
|
float pixelAntiAliasing = 2.0f * guiScale; // 抗锯齿范围
|
||||||
|
|
||||||
System.out.println("Shader Params - Center: (" + pixelCenterX + ", " + pixelCenterY +
|
// if (Services.PLATFORM.isDevelopmentEnvironment()) {
|
||||||
"), InnerRadius: " + pixelInnerRadius + ", OuterRadius: " + pixelOuterRadius);
|
// System.out.println("Shader Params - Center: (" + pixelCenterX + ", " + pixelCenterY +
|
||||||
|
// "), InnerRadius: " + pixelInnerRadius + ", OuterRadius: " + pixelOuterRadius);
|
||||||
|
// }
|
||||||
|
|
||||||
ShaderInstance shader = Lib39Shaders.getRingShader();
|
ShaderInstance shader = Lib39Shaders.getRingShader();
|
||||||
shader.safeGetUniform("Center").set(pixelCenterX, pixelCenterY);
|
shader.safeGetUniform("Center").set(pixelCenterX, pixelCenterY);
|
||||||
|
|
@ -11,11 +11,15 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.level.block.SkullBlock;
|
||||||
|
import net.minecraft.world.level.block.WallSkullBlock;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.RotationSegment;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.client.model.DollModel;
|
import top.r3944realms.lib39.client.model.DollModel;
|
||||||
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
|
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
|
||||||
import top.r3944realms.lib39.content.block.DollBlock;
|
import top.r3944realms.lib39.content.block.AbstractDollBlock;
|
||||||
|
import top.r3944realms.lib39.content.block.WallDollBlock;
|
||||||
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
||||||
import top.r3944realms.lib39.util.lang.Pair;
|
import top.r3944realms.lib39.util.lang.Pair;
|
||||||
|
|
||||||
|
|
@ -37,14 +41,15 @@ public class DollBlockEntityRenderer implements BlockEntityRenderer<DollBlockEnt
|
||||||
@Override
|
@Override
|
||||||
public void render(@NotNull DollBlockEntity dollBlockEntity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) {
|
public void render(@NotNull DollBlockEntity dollBlockEntity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) {
|
||||||
BlockState blockState = dollBlockEntity.getBlockState();
|
BlockState blockState = dollBlockEntity.getBlockState();
|
||||||
if (blockState.getBlock() instanceof DollBlock) {
|
if (blockState.getBlock() instanceof AbstractDollBlock dollBlock) {
|
||||||
Direction facing = blockState.getValue(DollBlock.FACING);
|
boolean isWall = dollBlock instanceof WallDollBlock;
|
||||||
|
Direction direction = isWall ? blockState.getValue(WallSkullBlock.FACING) : null;
|
||||||
|
float rotation = isWall ? direction.toYRot() : RotationSegment.convertToDegrees(blockState.getValue(SkullBlock.ROTATION));
|
||||||
GameProfile profile = dollBlockEntity.getOwnerProfile();
|
GameProfile profile = dollBlockEntity.getOwnerProfile();
|
||||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
|
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(0.5, 1.5, 0.5);
|
poseStack.translate(0.5, 1.5, 0.5);
|
||||||
poseStack.scale(1.0F, -1.0F, -1.0F);
|
poseStack.scale(1.0F, -1.0F, -1.0F);
|
||||||
float rotation = facing.toYRot();
|
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(rotation));
|
poseStack.mulPose(Axis.YP.rotationDegrees(rotation));
|
||||||
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(resourceLocationBooleanPair.first));
|
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(resourceLocationBooleanPair.first));
|
||||||
this.dollModel.slim = resourceLocationBooleanPair.second;
|
this.dollModel.slim = resourceLocationBooleanPair.second;
|
||||||
|
|
@ -14,6 +14,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.client.model.DollModel;
|
import top.r3944realms.lib39.client.model.DollModel;
|
||||||
import top.r3944realms.lib39.content.item.DollItem;
|
import top.r3944realms.lib39.content.item.DollItem;
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||||
|
|
@ -24,15 +25,29 @@ import top.r3944realms.lib39.util.lang.Pair;
|
||||||
*/
|
*/
|
||||||
public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
|
public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
|
||||||
private static DollItemRenderer instance;
|
private static DollItemRenderer instance;
|
||||||
private final DollModel dollModel;
|
private DollModel dollModel;
|
||||||
|
private boolean initialized = false;
|
||||||
private DollItemRenderer() {
|
private DollItemRenderer() {
|
||||||
super(
|
super(
|
||||||
Minecraft.getInstance().getBlockEntityRenderDispatcher(),
|
Minecraft.getInstance().getBlockEntityRenderDispatcher(),
|
||||||
Minecraft.getInstance().getEntityModels()
|
Minecraft.getInstance().getEntityModels()
|
||||||
);
|
);
|
||||||
this.dollModel = new DollModel(
|
}
|
||||||
Minecraft.getInstance().getEntityModels().bakeLayer(DollModel.LAYER_LOCATION)
|
private void lazyInit() {
|
||||||
);
|
if (!initialized) {
|
||||||
|
try {
|
||||||
|
// 确保 Minecraft 实例已初始化
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
mc.getEntityModels();
|
||||||
|
this.dollModel = new DollModel(
|
||||||
|
mc.getEntityModels().bakeLayer(DollModel.LAYER_LOCATION)
|
||||||
|
);
|
||||||
|
initialized = true;
|
||||||
|
Lib39.LOGGER.info("Doll model initialized successfully");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Lib39.LOGGER.error("Failed to initialize doll model", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,6 +67,7 @@ public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
|
||||||
if (!(stack.getItem() instanceof DollItem)) {
|
if (!(stack.getItem() instanceof DollItem)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
lazyInit();
|
||||||
GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
|
GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
|
||||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
|
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
|
||||||
ResourceLocation playerSkin = resourceLocationBooleanPair.first;
|
ResourceLocation playerSkin = resourceLocationBooleanPair.first;
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package top.r3944realms.lib39.client.shader;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.ShaderInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39 shaders.
|
||||||
|
*/
|
||||||
|
public class Lib39Shaders {
|
||||||
|
/**
|
||||||
|
* Gets ring shader.
|
||||||
|
*
|
||||||
|
* @return the ring shader
|
||||||
|
*/
|
||||||
|
public static ShaderInstance getRingShader() {
|
||||||
|
return ringShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Ring shader.
|
||||||
|
*/
|
||||||
|
static ShaderInstance ringShader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets selection shader.
|
||||||
|
*
|
||||||
|
* @return the selection shader
|
||||||
|
*/
|
||||||
|
public static ShaderInstance getSelectionShader() {
|
||||||
|
return selectionShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets ring shader.
|
||||||
|
*
|
||||||
|
* @param ringShader the ring shader
|
||||||
|
*/
|
||||||
|
public static void setRingShader(ShaderInstance ringShader) {
|
||||||
|
Lib39Shaders.ringShader = ringShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets selection shader.
|
||||||
|
*
|
||||||
|
* @param selectionShader the selection shader
|
||||||
|
*/
|
||||||
|
public static void setSelectionShader(ShaderInstance selectionShader) {
|
||||||
|
Lib39Shaders.selectionShader = selectionShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Selection shader.
|
||||||
|
*/
|
||||||
|
static ShaderInstance selectionShader;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
|
||||||
import net.minecraft.sounds.SoundSource;
|
import net.minecraft.sounds.SoundSource;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
|
|
@ -17,7 +16,6 @@ import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.*;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
|
@ -30,39 +28,36 @@ import net.minecraft.world.level.material.PushReaction;
|
||||||
import net.minecraft.world.level.storage.loot.LootParams;
|
import net.minecraft.world.level.storage.loot.LootParams;
|
||||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
||||||
import top.r3944realms.lib39.content.block.property.DollPose;
|
import top.r3944realms.lib39.content.block.property.DollPose;
|
||||||
import top.r3944realms.lib39.content.register.Lib39BlockEntities;
|
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
|
||||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||||
import top.r3944realms.lib39.content.register.Lib39SoundEvents;
|
import top.r3944realms.lib39.core.register.Lib39SoundEvents;
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Doll block.
|
* The type Abstract doll block.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class DollBlock extends HorizontalDirectionalBlock implements SimpleWaterloggedBlock, EntityBlock {
|
public abstract class AbstractDollBlock extends BaseEntityBlock implements SimpleWaterloggedBlock {
|
||||||
private static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
|
||||||
/**
|
/**
|
||||||
* The constant POSE.
|
* The constant WATERLOGGED.
|
||||||
*/
|
*/
|
||||||
public static final EnumProperty<DollPose> POSE = EnumProperty.create("pose", DollPose.class);
|
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||||
|
|
||||||
private static final VoxelShape DOLL_SHAPE = Block.box(2.0d, 0.0d, 2.0d, 14.0d, 12.0d, 14.0d);
|
|
||||||
private static final Properties properties = Properties.of()
|
private static final Properties properties = Properties.of()
|
||||||
.instrument(NoteBlockInstrument.BASEDRUM)
|
.instrument(NoteBlockInstrument.BASEDRUM)
|
||||||
.sound(SoundType.WOOL)
|
.sound(SoundType.WOOL)
|
||||||
|
.pushReaction(PushReaction.DESTROY)
|
||||||
.strength(0f, 10f)
|
.strength(0f, 10f)
|
||||||
.noOcclusion();
|
.noOcclusion();
|
||||||
|
|
||||||
private static final double PARTICLE_OFFSET_RANGE = 0.25;
|
private static final double PARTICLE_OFFSET_RANGE = 0.25;
|
||||||
private static final double PARTICLE_HEIGHT_OFFSET = 1.0;
|
private static final double PARTICLE_HEIGHT_OFFSET = 1.0;
|
||||||
private static final double PARTICLE_HEIGHT_VARIANCE = 0.2;
|
private static final double PARTICLE_HEIGHT_VARIANCE = 0.2;
|
||||||
|
|
@ -73,26 +68,23 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
||||||
private static final float PITCH_VARIANCE = 0.5f;
|
private static final float PITCH_VARIANCE = 0.5f;
|
||||||
private static final float BASE_PITCH = 0.75f;
|
private static final float BASE_PITCH = 0.75f;
|
||||||
|
|
||||||
|
private static final VoxelShape DOLL_SHAPE = Block.box(2.0d, 0.0d, 2.0d, 14.0d, 12.0d, 14.0d);
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Doll block.
|
* The constant POSE.
|
||||||
*/
|
*/
|
||||||
public DollBlock() {
|
public static final EnumProperty<DollPose> POSE = EnumProperty.create("pose", DollPose.class);
|
||||||
super(properties);
|
|
||||||
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.SOUTH)
|
|
||||||
.setValue(POSE, DollPose.DEFAULT)
|
|
||||||
.setValue(WATERLOGGED, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Abstract doll block.
|
||||||
|
*/
|
||||||
|
public AbstractDollBlock() {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean canBeReplaced(@NotNull BlockState state, @NotNull BlockPlaceContext useContext) {
|
public boolean canBeReplaced(@NotNull BlockState state, @NotNull BlockPlaceContext useContext) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable PushReaction getPistonPushReaction(BlockState state) {
|
|
||||||
return PushReaction.DESTROY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull BlockState updateShape(@NotNull BlockState currentState, @NotNull Direction direction, @NotNull BlockState neighborState,
|
public @NotNull BlockState updateShape(@NotNull BlockState currentState, @NotNull Direction direction, @NotNull BlockState neighborState,
|
||||||
@NotNull LevelAccessor level, @NotNull BlockPos currentPos, @NotNull BlockPos neighborPos) {
|
@NotNull LevelAccessor level, @NotNull BlockPos currentPos, @NotNull BlockPos neighborPos) {
|
||||||
|
|
@ -118,7 +110,6 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
||||||
}
|
}
|
||||||
return InteractionResult.SUCCESS;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在玩偶位置生成音符粒子效果
|
* 在玩偶位置生成音符粒子效果
|
||||||
*/
|
*/
|
||||||
|
|
@ -158,26 +149,13 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
||||||
SoundSource.BLOCKS, BASE_VOLUME, pitch);
|
SoundSource.BLOCKS, BASE_VOLUME, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
|
|
||||||
FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos());
|
|
||||||
boolean isWaterlogged = fluidState.getType() == Fluids.WATER;
|
|
||||||
|
|
||||||
return this.defaultBlockState()
|
|
||||||
.setValue(FACING, context.getHorizontalDirection().getOpposite())
|
|
||||||
.setValue(WATERLOGGED, isWaterlogged)
|
|
||||||
.setValue(POSE, DollPose.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull VoxelShape getShape(@NotNull BlockState blockState, @NotNull BlockGetter level, @NotNull BlockPos blockPos, @NotNull CollisionContext context) {
|
public @NotNull VoxelShape getShape(@NotNull BlockState blockState, @NotNull BlockGetter level, @NotNull BlockPos blockPos, @NotNull CollisionContext context) {
|
||||||
return DOLL_SHAPE;
|
return DOLL_SHAPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public @NotNull VoxelShape getOcclusionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) {
|
||||||
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
return Shapes.empty();
|
||||||
super.createBlockStateDefinition(builder);
|
|
||||||
builder.add(FACING, WATERLOGGED, POSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -193,9 +171,8 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, Player player) {
|
public @NotNull ItemStack getCloneItemStack(@NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state) {
|
||||||
ItemStack stack = super.getCloneItemStack(state, target, level, pos, player);
|
ItemStack stack = super.getCloneItemStack(level, pos, state);
|
||||||
|
|
||||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||||
if (blockEntity instanceof DollBlockEntity doll) {
|
if (blockEntity instanceof DollBlockEntity doll) {
|
||||||
GameProfile profile = doll.getOwnerProfile();
|
GameProfile profile = doll.getOwnerProfile();
|
||||||
|
|
@ -222,6 +199,12 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
||||||
return super.getDrops(state, params);
|
return super.getDrops(state, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
||||||
|
super.createBlockStateDefinition(builder);
|
||||||
|
builder.add(WATERLOGGED, POSE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成自定义掉落物
|
* 生成自定义掉落物
|
||||||
*/
|
*/
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package top.r3944realms.lib39.content.block;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.block.state.properties.RotationSegment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import top.r3944realms.lib39.content.block.property.DollPose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Doll block.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class DollBlock extends AbstractDollBlock{
|
||||||
|
/**
|
||||||
|
* The constant MAX.
|
||||||
|
*/
|
||||||
|
public static final int MAX = RotationSegment.getMaxSegmentIndex();
|
||||||
|
|
||||||
|
private static final int ROTATIONS = MAX + 1;
|
||||||
|
/**
|
||||||
|
* The constant ROTATION.
|
||||||
|
*/
|
||||||
|
public static final IntegerProperty ROTATION = BlockStateProperties.ROTATION_16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Doll block.
|
||||||
|
*/
|
||||||
|
public DollBlock() {
|
||||||
|
super();
|
||||||
|
this.registerDefaultState(
|
||||||
|
this.stateDefinition.any()
|
||||||
|
.setValue(POSE, DollPose.DEFAULT)
|
||||||
|
.setValue(WATERLOGGED, false)
|
||||||
|
.setValue(ROTATION, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
|
||||||
|
BlockState stateForPlacement = super.getStateForPlacement(context);
|
||||||
|
return stateForPlacement != null ? stateForPlacement.setValue(ROTATION, RotationSegment.convertToSegment((context.getRotation()+180) % 360)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) {
|
||||||
|
return state.setValue(ROTATION, rotation.rotate(state.getValue(ROTATION), ROTATIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BlockState mirror(@NotNull BlockState state, @NotNull Mirror mirror) {
|
||||||
|
return state.setValue(ROTATION, mirror.mirror(state.getValue(ROTATION), ROTATIONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
||||||
|
super.createBlockStateDefinition(builder);
|
||||||
|
builder.add(ROTATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package top.r3944realms.lib39.content.block;
|
||||||
|
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import top.r3944realms.lib39.content.block.property.DollPose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Wall doll block.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"deprecation"})
|
||||||
|
public class WallDollBlock extends AbstractDollBlock {
|
||||||
|
/**
|
||||||
|
* The constant FACING.
|
||||||
|
*/
|
||||||
|
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Wall doll block.
|
||||||
|
*/
|
||||||
|
public WallDollBlock() {
|
||||||
|
super();
|
||||||
|
this.registerDefaultState(
|
||||||
|
this.stateDefinition.any()
|
||||||
|
.setValue(POSE, DollPose.DEFAULT)
|
||||||
|
.setValue(WATERLOGGED, false)
|
||||||
|
.setValue(FACING, Direction.NORTH)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) {
|
||||||
|
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull BlockState mirror(@NotNull BlockState state, @NotNull Mirror mirror) {
|
||||||
|
return state.rotate(mirror.getRotation(state.getValue(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
|
||||||
|
BlockState stateForPlacement = super.getStateForPlacement(context);
|
||||||
|
return stateForPlacement != null ? stateForPlacement.setValue(FACING, context.getHorizontalDirection().getOpposite()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
||||||
|
super.createBlockStateDefinition(builder);
|
||||||
|
builder.add(FACING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.content.register.Lib39BlockEntities;
|
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTReader;
|
import top.r3944realms.lib39.util.nbt.NBTReader;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
||||||
|
|
@ -1,51 +1,34 @@
|
||||||
package top.r3944realms.lib39.content.item;
|
package top.r3944realms.lib39.content.item;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.Equipable;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.StandingAndWallBlockItem;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
|
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
||||||
import top.r3944realms.lib39.content.register.Lib39Blocks;
|
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Doll item.
|
* The type Doll item.
|
||||||
*/
|
*/
|
||||||
public class DollItem extends BlockItem {
|
public class DollItem extends StandingAndWallBlockItem implements Equipable {
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Doll item.
|
* Instantiates a new Doll item.
|
||||||
*
|
*
|
||||||
* @param properties the properties
|
* @param properties the properties
|
||||||
*/
|
*/
|
||||||
public DollItem(Properties properties) {
|
public DollItem(Properties properties) {
|
||||||
super(Lib39Blocks.DOLL.get(), properties);
|
super(Lib39Blocks.DOLL.get(), Lib39Blocks.WALL_DOLL.get(), properties, Direction.DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeClient(@NotNull Consumer<IClientItemExtensions> consumer) {
|
|
||||||
consumer.accept(new IClientItemExtensions() {
|
|
||||||
@Override
|
|
||||||
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
|
|
||||||
return DollItemRenderer.getInstance();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canEquip(ItemStack stack, EquipmentSlot armorType, Entity entity) {
|
|
||||||
return armorType == EquipmentSlot.HEAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, @NotNull List<Component> tooltip, @NotNull TooltipFlag flag) {
|
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, @NotNull List<Component> tooltip, @NotNull TooltipFlag flag) {
|
||||||
|
|
@ -55,4 +38,9 @@ public class DollItem extends BlockItem {
|
||||||
}
|
}
|
||||||
tooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
|
tooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull EquipmentSlot getEquipmentSlot() {
|
||||||
|
return EquipmentSlot.HEAD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -483,6 +483,7 @@ public interface ICommandHelpManager {
|
||||||
/**
|
/**
|
||||||
* 获取命令树的字符串表示
|
* 获取命令树的字符串表示
|
||||||
*
|
*
|
||||||
|
* @param commandSourceStack the command source stack
|
||||||
* @return 命令树列表 command tree
|
* @return 命令树列表 command tree
|
||||||
*/
|
*/
|
||||||
default List<MutableComponent> getCommandTree(CommandSourceStack commandSourceStack) {
|
default List<MutableComponent> getCommandTree(CommandSourceStack commandSourceStack) {
|
||||||
|
|
@ -537,6 +538,7 @@ public interface ICommandHelpManager {
|
||||||
/**
|
/**
|
||||||
* Build command tree help mutable component.
|
* Build command tree help mutable component.
|
||||||
*
|
*
|
||||||
|
* @param commandSourceStack the command source stack
|
||||||
* @return the mutable component
|
* @return the mutable component
|
||||||
*/
|
*/
|
||||||
default MutableComponent buildCommandTreeHelp(CommandSourceStack commandSourceStack) {
|
default MutableComponent buildCommandTreeHelp(CommandSourceStack commandSourceStack) {
|
||||||
|
|
@ -9,10 +9,9 @@ import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.api.event.RegisterCommandHelpEvent;
|
|
||||||
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
|
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
|
||||||
|
import top.r3944realms.lib39.platform.Services;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
@ -63,8 +62,7 @@ public interface IHelpCommand {
|
||||||
.then(Commands.literal("toggle")
|
.then(Commands.literal("toggle")
|
||||||
.then(Commands.argument("hash", IntegerArgumentType.integer()).executes(this::handleHelpToggle))
|
.then(Commands.argument("hash", IntegerArgumentType.integer()).executes(this::handleHelpToggle))
|
||||||
));
|
));
|
||||||
RegisterCommandHelpEvent registerHelpCommandEvent = new RegisterCommandHelpEvent(tree, getCommandHelpManager(), context);
|
Services.PLATFORM.getHelpCommandHook().onRegister(tree, getCommandHelpManager(), context);
|
||||||
MinecraftForge.EVENT_BUS.post(registerHelpCommandEvent);
|
|
||||||
dispatcher.register(head);
|
dispatcher.register(head);
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,6 @@ import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.minecraft.commands.CommandBuildContext;
|
import net.minecraft.commands.CommandBuildContext;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Simple help command.
|
* The type Simple help command.
|
||||||
|
|
@ -17,15 +15,9 @@ public abstract class SimpleHelpCommand implements IHelpCommand {
|
||||||
protected final LiteralArgumentBuilder<CommandSourceStack> root;
|
protected final LiteralArgumentBuilder<CommandSourceStack> root;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Simple help command.
|
* <pre>
|
||||||
*
|
* 需要{@link CommandDispatcher<CommandSourceStack> 指令注册调度器} 和 {@link CommandBuildContext 指令上下文}
|
||||||
* @param event the event
|
* </pre>
|
||||||
*/
|
|
||||||
public SimpleHelpCommand(@NotNull RegisterCommandsEvent event) {
|
|
||||||
root = buildCommand(event.getDispatcher(), event.getBuildContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new Simple help command.
|
* Instantiates a new Simple help command.
|
||||||
*
|
*
|
||||||
* @param dispatcher the dispatcher
|
* @param dispatcher the dispatcher
|
||||||
|
|
@ -35,9 +35,16 @@ public class CommandNode {
|
||||||
// 展开/闭合状态
|
// 展开/闭合状态
|
||||||
private boolean expanded = true;
|
private boolean expanded = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test permission boolean.
|
||||||
|
*
|
||||||
|
* @param source the source
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
public boolean testPermission(CommandSourceStack source) {
|
public boolean testPermission(CommandSourceStack source) {
|
||||||
return testPermission.test(source);
|
return testPermission.test(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Command node.
|
* Instantiates a new Command node.
|
||||||
*
|
*
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
package top.r3944realms.lib39.core.compat;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Compat manager.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public abstract class CompatManager {
|
||||||
|
/**
|
||||||
|
* Gets id.
|
||||||
|
*
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public ResourceLocation getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Logger.
|
||||||
|
*/
|
||||||
|
protected final Logger logger;
|
||||||
|
/**
|
||||||
|
* The Id.
|
||||||
|
*/
|
||||||
|
protected final ResourceLocation id;
|
||||||
|
/**
|
||||||
|
* The Compats.
|
||||||
|
*/
|
||||||
|
protected final Map<ResourceLocation, ICompat> compats = new HashMap<>();
|
||||||
|
/**
|
||||||
|
* The Initialized.
|
||||||
|
*/
|
||||||
|
protected boolean initialized = false;
|
||||||
|
/**
|
||||||
|
* The Pending tasks.
|
||||||
|
*/
|
||||||
|
protected final List<Runnable> pendingTasks = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize.
|
||||||
|
*/
|
||||||
|
public void initialize() {
|
||||||
|
initializeAllCompat();
|
||||||
|
onLoadComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Compat manager.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
*/
|
||||||
|
public CompatManager(@NotNull ResourceLocation id) {
|
||||||
|
this.id = id;
|
||||||
|
this.logger = LoggerFactory.getLogger(id.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register compat.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
* @param compat the compat
|
||||||
|
*/
|
||||||
|
public void registerCompat(ResourceLocation id, ICompat compat) {
|
||||||
|
if (initialized) {
|
||||||
|
// 已初始化,直接注册
|
||||||
|
doRegisterCompat(id, compat);
|
||||||
|
} else {
|
||||||
|
// 未初始化,缓存起来
|
||||||
|
pendingTasks.add(() -> doRegisterCompat(id, compat));
|
||||||
|
logger.debug("Cached compat registration for: {}", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do register compat.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
* @param compat the compat
|
||||||
|
*/
|
||||||
|
protected void doRegisterCompat(ResourceLocation id, ICompat compat) {
|
||||||
|
if (compats.containsKey(id)) {
|
||||||
|
logger.warn("Compat with id {} is already registered!", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compats.put(id, compat);
|
||||||
|
logger.debug("Registered compat: {}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register compat.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace
|
||||||
|
* @param path the path
|
||||||
|
* @param compat the compat
|
||||||
|
*/
|
||||||
|
public void registerCompat(String namespace, String path, ICompat compat) {
|
||||||
|
registerCompat(Lib39.rl(namespace, path), compat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ===================== 初始化和管理 =====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化所有兼容模块并应用事件监听器
|
||||||
|
*/
|
||||||
|
protected synchronized void initializeAllCompat() {
|
||||||
|
logger.info("Initializing {} compatibility modules", compats.size());
|
||||||
|
|
||||||
|
// 先处理所有缓存的注册
|
||||||
|
pendingTasks.forEach(Runnable::run);
|
||||||
|
pendingTasks.clear();
|
||||||
|
|
||||||
|
// 初始化所有兼容模块
|
||||||
|
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
|
||||||
|
if (!entry.getValue().isInitialized() && entry.getValue().isModLoaded()) {
|
||||||
|
try {
|
||||||
|
entry.getValue().initialize();
|
||||||
|
entry.getValue().setInitialize(true);
|
||||||
|
logger.info("Initialized compat: {}", entry.getKey());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to initialize compat: {}", entry.getKey(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets compat.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
* @return the compat
|
||||||
|
*/
|
||||||
|
public Optional<ICompat> getCompat(ResourceLocation id) {
|
||||||
|
return Optional.ofNullable(compats.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has compat boolean.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
|
public boolean hasCompat(ResourceLocation id) {
|
||||||
|
return compats.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister compat.
|
||||||
|
*
|
||||||
|
* @param id the id
|
||||||
|
*/
|
||||||
|
public void unregisterCompat(ResourceLocation id) {
|
||||||
|
ICompat removed = compats.remove(id);
|
||||||
|
if (removed != null) {
|
||||||
|
logger.debug("Unregistered compat: {}", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets loaded compats.
|
||||||
|
*
|
||||||
|
* @return the loaded compats
|
||||||
|
*/
|
||||||
|
public List<ICompat> getLoadedCompats() {
|
||||||
|
return compats.values().stream()
|
||||||
|
.filter(ICompat::isModLoaded)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On load complete.
|
||||||
|
*/
|
||||||
|
public void onLoadComplete() {
|
||||||
|
logger.info("Calling onLoadComplete for {} compatibility modules", compats.size());
|
||||||
|
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
|
||||||
|
try {
|
||||||
|
entry.getValue().onLoadComplete();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Error in onLoadComplete for compat: {}", entry.getKey(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package top.r3944realms.lib39.core.compat;
|
package top.r3944realms.lib39.core.compat;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
|
@ -9,8 +8,20 @@ import java.util.concurrent.Callable;
|
||||||
* The interface Compat.
|
* The interface Compat.
|
||||||
*/
|
*/
|
||||||
public interface ICompat {
|
public interface ICompat {
|
||||||
|
/**
|
||||||
|
* Sets initialize.
|
||||||
|
*
|
||||||
|
* @param initialize the initialize
|
||||||
|
*/
|
||||||
void setInitialize(boolean initialize);
|
void setInitialize(boolean initialize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is initialized boolean.
|
||||||
|
*
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
boolean isInitialized();
|
boolean isInitialized();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Id resource location.
|
* Id resource location.
|
||||||
*
|
*
|
||||||
|
|
@ -75,58 +86,4 @@ public interface ICompat {
|
||||||
if (isModLoaded()) runnable.run(); else return false;
|
if (isModLoaded()) runnable.run(); else return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add common game listener.
|
|
||||||
*
|
|
||||||
* @param gameBus the game bus
|
|
||||||
*/
|
|
||||||
default void addCommonGameListener(IEventBus gameBus) {
|
|
||||||
// 实现通用游戏事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add common mod listener.
|
|
||||||
*
|
|
||||||
* @param modBus the mod bus
|
|
||||||
*/
|
|
||||||
default void addCommonModListener(IEventBus modBus) {
|
|
||||||
// 实现通用模组事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add client game listener.
|
|
||||||
*
|
|
||||||
* @param gameBus the game bus
|
|
||||||
*/
|
|
||||||
default void addClientGameListener(IEventBus gameBus) {
|
|
||||||
// 实现客户端游戏事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add client mod listener.
|
|
||||||
*
|
|
||||||
* @param modBus the mod bus
|
|
||||||
*/
|
|
||||||
default void addClientModListener(IEventBus modBus) {
|
|
||||||
// 实现客户端模组事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add server game listener.
|
|
||||||
*
|
|
||||||
* @param gameBus the game bus
|
|
||||||
*/
|
|
||||||
default void addServerGameListener(IEventBus gameBus) {
|
|
||||||
// 实现服务端游戏事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add server mod listener.
|
|
||||||
*
|
|
||||||
* @param modBus the mod bus
|
|
||||||
*/
|
|
||||||
default void addServerModListener(IEventBus modBus) {
|
|
||||||
// 实现服务端模组事件监听器添加逻辑
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import java.util.stream.Stream;
|
||||||
*/
|
*/
|
||||||
public class ClassEncryptor {
|
public class ClassEncryptor {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("ClassEncrypt");
|
// System.loadLibrary("ClassEncrypt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -13,7 +13,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class EncryptedClassLoader extends ClassLoader {
|
public class EncryptedClassLoader extends ClassLoader {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("ClassEncrypt");
|
// System.loadLibrary("ClassEncrypt");
|
||||||
}
|
}
|
||||||
|
|
||||||
private native byte[] decryptClass(byte[] encryptedData, String key);
|
private native byte[] decryptClass(byte[] encryptedData, String key);
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package top.r3944realms.lib39.core.register;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39 block entities.
|
||||||
|
*/
|
||||||
|
public class Lib39BlockEntities {
|
||||||
|
/**
|
||||||
|
* The constant DOLL_BLOCK_ENTITY.
|
||||||
|
*/
|
||||||
|
public static Supplier<BlockEntityType<DollBlockEntity>> DOLL_BLOCK_ENTITY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package top.r3944realms.lib39.core.register;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39 blocks.
|
||||||
|
*/
|
||||||
|
public class Lib39Blocks {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constant DOLL.
|
||||||
|
*/
|
||||||
|
public static Supplier<Block> DOLL;
|
||||||
|
/**
|
||||||
|
* The Wall doll.
|
||||||
|
*/
|
||||||
|
public static Supplier<Block> WALL_DOLL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package top.r3944realms.lib39.core.register;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Ex lib 39 items.
|
||||||
|
*/
|
||||||
|
public class Lib39Items {
|
||||||
|
/**
|
||||||
|
* The constant DOLL.
|
||||||
|
*/
|
||||||
|
public static Supplier<Item> DOLL;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package top.r3944realms.lib39.core.register;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39 sound events.
|
||||||
|
*/
|
||||||
|
public class Lib39SoundEvents {
|
||||||
|
/**
|
||||||
|
* The constant RL_DUCK_TOY.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation RL_DUCK_TOY = Lib39.rl("duck_toy");
|
||||||
|
/**
|
||||||
|
* The constant DUCK_TOY.
|
||||||
|
*/
|
||||||
|
public static Supplier<SoundEvent> DUCK_TOY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets sub title translate key.
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @return the sub title translate key
|
||||||
|
*/
|
||||||
|
public static String getSubTitleTranslateKey(String name) {
|
||||||
|
return "sound." + Lib39.MOD_ID + ".subtitle." + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package top.r3944realms.lib39.core.sync;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Inbt serializable.
|
||||||
|
*
|
||||||
|
* @param <T> the type parameter
|
||||||
|
*/
|
||||||
|
public interface INBTSerializable <T extends Tag>{
|
||||||
|
/**
|
||||||
|
* Serialize nbt t.
|
||||||
|
*
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
T serializeNBT();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize nbt.
|
||||||
|
*
|
||||||
|
* @param var1 the var 1
|
||||||
|
*/
|
||||||
|
void deserializeNBT(T var1);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package top.r3944realms.lib39.core.sync;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Update.
|
||||||
|
*/
|
||||||
|
public interface IUpdate {
|
||||||
|
/**
|
||||||
|
* Update.
|
||||||
|
*/
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets sync data.
|
||||||
|
*
|
||||||
|
* @return the sync data
|
||||||
|
*/
|
||||||
|
NBTEntitySyncData getSyncData();
|
||||||
|
}
|
||||||
|
|
@ -2,15 +2,12 @@ package top.r3944realms.lib39.core.sync;
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraftforge.common.util.INBTSerializable;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.core.network.NetworkHandler;
|
|
||||||
import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPack;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Nbt sync data.
|
* The type Nbt entity sync data.
|
||||||
*/
|
*/
|
||||||
public abstract class NBTEntitySyncData implements IEntity, ISyncData<NBTEntitySyncData>, INBTSerializable<CompoundTag> {
|
public abstract class NBTEntitySyncData implements IEntity, ISyncData<NBTEntitySyncData>, INBTSerializable<CompoundTag>, IUpdate {
|
||||||
/**
|
/**
|
||||||
* The Dirty.
|
* The Dirty.
|
||||||
*/
|
*/
|
||||||
|
|
@ -52,8 +49,13 @@ public abstract class NBTEntitySyncData implements IEntity, ISyncData<NBTEntityS
|
||||||
@Override
|
@Override
|
||||||
public void checkIfDirtyThenUpdate() {
|
public void checkIfDirtyThenUpdate() {
|
||||||
if (isDirty()) {
|
if (isDirty()) {
|
||||||
NetworkHandler.sendToAllPlayer(new SyncNBTCapDataEntityS2CPack(entityId(), id(), serializeNBT()));
|
update();
|
||||||
}
|
}
|
||||||
dirty = false;
|
dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NBTEntitySyncData getSyncData() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package top.r3944realms.lib39.core.sync;
|
package top.r3944realms.lib39.core.sync;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
@ -13,10 +12,17 @@ import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Sync data 2 manager.
|
* The type Sync data 2 manager.
|
||||||
|
*
|
||||||
|
* @param <V> the type parameter
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unused", "DuplicatedCode"})
|
@SuppressWarnings({"unused", "DuplicatedCode"})
|
||||||
public class SyncData2Manager {
|
public abstract class SyncData2Manager<V extends SyncData2Manager.TypedSyncEntry<?, ?>> {
|
||||||
private final Map<ResourceLocation, TypedSyncEntry<?, ?>> typedEntries = Maps.newConcurrentMap();
|
/**
|
||||||
|
* Gets typed entries.
|
||||||
|
*
|
||||||
|
* @return the typed entries
|
||||||
|
*/
|
||||||
|
protected abstract Map<ResourceLocation, V> getTypedEntries();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据提供者接口 - 用于通过键获取数据
|
* 数据提供者接口 - 用于通过键获取数据
|
||||||
|
|
@ -35,7 +41,13 @@ public class SyncData2Manager {
|
||||||
Optional<T> getData(K key);
|
Optional<T> getData(K key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TypedSyncEntry<K, T extends ISyncData<?>> {
|
/**
|
||||||
|
* The type Typed sync entry.
|
||||||
|
*
|
||||||
|
* @param <K> the type parameter
|
||||||
|
* @param <T> the type parameter
|
||||||
|
*/
|
||||||
|
protected static class TypedSyncEntry<K, T extends ISyncData<?>> {
|
||||||
/**
|
/**
|
||||||
* The Manager.
|
* The Manager.
|
||||||
*/
|
*/
|
||||||
|
|
@ -56,7 +68,7 @@ public class SyncData2Manager {
|
||||||
* @param manager the manager
|
* @param manager the manager
|
||||||
* @param dataProvider the data provider
|
* @param dataProvider the data provider
|
||||||
*/
|
*/
|
||||||
TypedSyncEntry(ISyncManager<K, T> manager, @Nullable DataProvider<Entity, T> dataProvider) {
|
public TypedSyncEntry(ISyncManager<K, T> manager, @Nullable DataProvider<Entity, T> dataProvider) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.dataProvider = dataProvider;
|
this.dataProvider = dataProvider;
|
||||||
this.allowedClasses = Sets.newConcurrentHashSet();
|
this.allowedClasses = Sets.newConcurrentHashSet();
|
||||||
|
|
@ -72,6 +84,7 @@ public class SyncData2Manager {
|
||||||
* @param manager the manager
|
* @param manager the manager
|
||||||
* @param dataProvider the data provider
|
* @param dataProvider the data provider
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <K, T extends ISyncData<?>> void registerManagerWithProvider(
|
public <K, T extends ISyncData<?>> void registerManagerWithProvider(
|
||||||
ResourceLocation key,
|
ResourceLocation key,
|
||||||
ISyncManager<K, T> manager,
|
ISyncManager<K, T> manager,
|
||||||
|
|
@ -81,7 +94,7 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||||
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
||||||
|
|
||||||
typedEntries.put(key, new TypedSyncEntry<>(manager, dataProvider));
|
getTypedEntries().put(key, (V) new TypedSyncEntry<>(manager, dataProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -93,6 +106,7 @@ public class SyncData2Manager {
|
||||||
* @param manager the manager
|
* @param manager the manager
|
||||||
* @param getter the data getter function
|
* @param getter the data getter function
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <K, T extends ISyncData<?>> void registerManager(
|
public <K, T extends ISyncData<?>> void registerManager(
|
||||||
ResourceLocation key,
|
ResourceLocation key,
|
||||||
ISyncManager<K, T> manager,
|
ISyncManager<K, T> manager,
|
||||||
|
|
@ -102,7 +116,7 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||||
Objects.requireNonNull(getter, "Data getter function cannot be null");
|
Objects.requireNonNull(getter, "Data getter function cannot be null");
|
||||||
|
|
||||||
typedEntries.put(key, new TypedSyncEntry<>(manager, getter::apply));
|
getTypedEntries().put(key, (V) new TypedSyncEntry<>(manager, getter::apply));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -117,7 +131,7 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
Objects.requireNonNull(manager, "Sync manager cannot be null");
|
||||||
|
|
||||||
// 创建一个没有数据提供者的 TypedSyncEntry
|
// 创建一个没有数据提供者的 TypedSyncEntry
|
||||||
typedEntries.put(key, new TypedSyncEntry<>(
|
getTypedEntries().put(key, (V) new TypedSyncEntry<>(
|
||||||
(ISyncManager<?, ISyncData<?>>) manager,
|
(ISyncManager<?, ISyncData<?>>) manager,
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
|
|
@ -133,7 +147,7 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <K, T extends ISyncData<?>> Optional<ISyncManager<K, T>> getManager(ResourceLocation key) {
|
public <K, T extends ISyncData<?>> Optional<ISyncManager<K, T>> getManager(ResourceLocation key) {
|
||||||
TypedSyncEntry<?,?> entry = typedEntries.get(key);
|
TypedSyncEntry<?,?> entry = getTypedEntries().get(key);
|
||||||
return entry != null ? Optional.of((ISyncManager<K,T>) entry.manager) : Optional.empty();
|
return entry != null ? Optional.of((ISyncManager<K,T>) entry.manager) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +160,7 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends ISyncData<?>> Optional<DataProvider<Entity, T>> getDataProvider(ResourceLocation key) {
|
public <T extends ISyncData<?>> Optional<DataProvider<Entity, T>> getDataProvider(ResourceLocation key) {
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null && entry.dataProvider != null) {
|
if (entry != null && entry.dataProvider != null) {
|
||||||
return Optional.of((DataProvider<Entity, T>) entry.dataProvider);
|
return Optional.of((DataProvider<Entity, T>) entry.dataProvider);
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +198,7 @@ public class SyncData2Manager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entry.allowedClasses.addAll(Arrays.asList(classes));
|
entry.allowedClasses.addAll(Arrays.asList(classes));
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +214,7 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
Objects.requireNonNull(classes, "Classes array cannot be null");
|
Objects.requireNonNull(classes, "Classes array cannot be null");
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null && classes.length > 0) {
|
if (entry != null && classes.length > 0) {
|
||||||
Arrays.asList(classes).forEach(entry.allowedClasses::remove);
|
Arrays.asList(classes).forEach(entry.allowedClasses::remove);
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +231,7 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
// 更新现有条目的数据提供者
|
// 更新现有条目的数据提供者
|
||||||
updateDataProviderInEntry(key, entry, dataProvider);
|
updateDataProviderInEntry(key, entry, dataProvider);
|
||||||
|
|
@ -233,7 +247,7 @@ public class SyncData2Manager {
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param getter the data getter function
|
* @param getter the data getter function
|
||||||
*/
|
*/
|
||||||
public <T extends ISyncData<?>> void bindDataGetter(ResourceLocation key, Function<Entity, Optional<T>> getter) {
|
public <T extends ISyncData<?>> void bindDataGetter(ResourceLocation key, @NotNull Function<Entity, Optional<T>> getter) {
|
||||||
bindDataProvider(key, getter::apply);
|
bindDataProvider(key, getter::apply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +259,7 @@ public class SyncData2Manager {
|
||||||
public void unbindDataProvider(ResourceLocation key) {
|
public void unbindDataProvider(ResourceLocation key) {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
// 将数据提供者设置为null,但保留管理器和其他配置
|
// 将数据提供者设置为null,但保留管理器和其他配置
|
||||||
updateDataProviderInEntry(key, entry, null);
|
updateDataProviderInEntry(key, entry, null);
|
||||||
|
|
@ -260,7 +274,7 @@ public class SyncData2Manager {
|
||||||
public void clearAllowedEntityClasses(ResourceLocation key) {
|
public void clearAllowedEntityClasses(ResourceLocation key) {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entry.allowedClasses.clear();
|
entry.allowedClasses.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -277,19 +291,17 @@ public class SyncData2Manager {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
Objects.requireNonNull(entityClass, "Entity class cannot be null");
|
Objects.requireNonNull(entityClass, "Entity class cannot be null");
|
||||||
|
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||||
if (entry == null) {
|
boolean isAllowed = false;
|
||||||
return false;
|
if (entry != null) {
|
||||||
|
for (Class<?> allowedClass : entry.allowedClasses) {
|
||||||
|
if (allowedClass.isAssignableFrom(entityClass)) {
|
||||||
|
isAllowed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return entry != null && isAllowed ;
|
||||||
// 如果没有设置允许的类,则默认允许所有类
|
|
||||||
if (entry.allowedClasses.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查实体类是否在允许的类中
|
|
||||||
return entry.allowedClasses.stream()
|
|
||||||
.anyMatch(allowedClass -> allowedClass.isAssignableFrom(entityClass));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -300,7 +312,7 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void trackEntityForManager(Entity entity, ResourceLocation managerId) {
|
public void trackEntityForManager(Entity entity, ResourceLocation managerId) {
|
||||||
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) getTypedEntries().get(managerId);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
trackEntityWithTypedEntry(entity, entry);
|
trackEntityWithTypedEntry(entity, entry);
|
||||||
}
|
}
|
||||||
|
|
@ -321,7 +333,7 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void untrackEntityForManager(Entity entity, ResourceLocation managerId) {
|
public void untrackEntityForManager(Entity entity, ResourceLocation managerId) {
|
||||||
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) typedEntries.get(managerId);
|
TypedSyncEntry<UUID, ?> entry = (TypedSyncEntry<UUID, ?>) getTypedEntries().get(managerId);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
untrackEntityWithTypedEntry(entity, entry);
|
untrackEntityWithTypedEntry(entity, entry);
|
||||||
}
|
}
|
||||||
|
|
@ -376,7 +388,7 @@ public class SyncData2Manager {
|
||||||
* @param managerId the manager id
|
* @param managerId the manager id
|
||||||
*/
|
*/
|
||||||
public void clearAllTrackedData(ResourceLocation managerId) {
|
public void clearAllTrackedData(ResourceLocation managerId) {
|
||||||
TypedSyncEntry<?, ?> entry = typedEntries.get(managerId);
|
TypedSyncEntry<?, ?> entry = getTypedEntries().get(managerId);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
clearTrackedDataForEntry(entry);
|
clearTrackedDataForEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
@ -398,9 +410,18 @@ public class SyncData2Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助方法:更新条目的数据提供者
|
/**
|
||||||
|
* Update data provider in entry.
|
||||||
|
*
|
||||||
|
* @param <K> the type parameter
|
||||||
|
* @param <T> the type parameter
|
||||||
|
* @param id the id
|
||||||
|
* @param entry the entry
|
||||||
|
* @param newDataProvider the new data provider
|
||||||
|
*/
|
||||||
|
// 辅助方法:更新条目的数据提供者
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <K, T extends ISyncData<?>> void updateDataProviderInEntry(
|
protected <K, T extends ISyncData<?>> void updateDataProviderInEntry(
|
||||||
ResourceLocation id,
|
ResourceLocation id,
|
||||||
TypedSyncEntry<?,?> entry,
|
TypedSyncEntry<?,?> entry,
|
||||||
DataProvider<Entity, T> newDataProvider
|
DataProvider<Entity, T> newDataProvider
|
||||||
|
|
@ -412,7 +433,7 @@ public class SyncData2Manager {
|
||||||
);
|
);
|
||||||
newEntry.allowedClasses.addAll(entry.allowedClasses);
|
newEntry.allowedClasses.addAll(entry.allowedClasses);
|
||||||
|
|
||||||
typedEntries.put(id, newEntry);
|
getTypedEntries().put(id, (V) newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -421,7 +442,7 @@ public class SyncData2Manager {
|
||||||
* @return the registered keys
|
* @return the registered keys
|
||||||
*/
|
*/
|
||||||
public Set<ResourceLocation> getRegisteredKeys() {
|
public Set<ResourceLocation> getRegisteredKeys() {
|
||||||
return Collections.unmodifiableSet(typedEntries.keySet());
|
return Collections.unmodifiableSet(getTypedEntries().keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -431,7 +452,7 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
public void forEach(BiConsumer<ResourceLocation, ISyncManager<?,?>> consumer) {
|
public void forEach(BiConsumer<ResourceLocation, ISyncManager<?,?>> consumer) {
|
||||||
Objects.requireNonNull(consumer, "Consumer cannot be null");
|
Objects.requireNonNull(consumer, "Consumer cannot be null");
|
||||||
typedEntries.forEach((key, entry) -> consumer.accept(key, entry.manager));
|
getTypedEntries().forEach((key, entry) -> consumer.accept(key, entry.manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -440,14 +461,14 @@ public class SyncData2Manager {
|
||||||
* @return the manager count
|
* @return the manager count
|
||||||
*/
|
*/
|
||||||
public int getManagerCount() {
|
public int getManagerCount() {
|
||||||
return typedEntries.size();
|
return getTypedEntries().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all.
|
* Clear all.
|
||||||
*/
|
*/
|
||||||
public void clearAll() {
|
public void clearAll() {
|
||||||
typedEntries.clear();
|
getTypedEntries().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -457,6 +478,6 @@ public class SyncData2Manager {
|
||||||
*/
|
*/
|
||||||
public void removeManager(ResourceLocation key) {
|
public void removeManager(ResourceLocation key) {
|
||||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||||
typedEntries.remove(key);
|
getTypedEntries().remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
package top.r3944realms.lib39.datagen.provider;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import net.minecraft.data.CachedOutput;
|
||||||
|
import net.minecraft.data.DataProvider;
|
||||||
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.data.PackOutput.Target;
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.enchantment.Enchantment;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Language provider.
|
||||||
|
*/
|
||||||
|
public abstract class LanguageProvider implements DataProvider {
|
||||||
|
private final Map<String, String> data = new TreeMap<>();
|
||||||
|
private final PackOutput output;
|
||||||
|
private final String modid;
|
||||||
|
private final String locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Language provider.
|
||||||
|
*
|
||||||
|
* @param output the output
|
||||||
|
* @param modid the modid
|
||||||
|
* @param locale the locale
|
||||||
|
*/
|
||||||
|
public LanguageProvider(PackOutput output, String modid, String locale) {
|
||||||
|
this.output = output;
|
||||||
|
this.modid = modid;
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add translations.
|
||||||
|
*/
|
||||||
|
protected abstract void addTranslations();
|
||||||
|
|
||||||
|
public @NotNull CompletableFuture<?> run(@NotNull CachedOutput cache) {
|
||||||
|
this.addTranslations();
|
||||||
|
return !this.data.isEmpty() ? this.save(cache, this.output.getOutputFolder(Target.RESOURCE_PACK).resolve(this.modid).resolve("lang").resolve(this.locale + ".json")) : CompletableFuture.allOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull String getName() {
|
||||||
|
return "Languages: " + this.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull CompletableFuture<?> save(CachedOutput cache, Path target) {
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
Objects.requireNonNull(json);
|
||||||
|
this.data.forEach(json::addProperty);
|
||||||
|
return DataProvider.saveStable(cache, json, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add block.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addBlock(@NotNull Supplier<? extends Block> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull Block key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add item.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addItem(@NotNull Supplier<? extends Item> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull Item key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add item stack.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addItemStack(@NotNull Supplier<ItemStack> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull ItemStack key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add enchantment.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addEnchantment(@NotNull Supplier<? extends Enchantment> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull Enchantment key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add effect.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addEffect(@NotNull Supplier<? extends MobEffect> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull MobEffect key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add entity type.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void addEntityType(@NotNull Supplier<? extends EntityType<?>> key, String name) {
|
||||||
|
this.add(key.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
|
public void add(@NotNull EntityType<?> key, String name) {
|
||||||
|
this.add(key.getDescriptionId(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param value the value
|
||||||
|
*/
|
||||||
|
public void add(String key, String value) {
|
||||||
|
if (this.data.put(key, value) != null) {
|
||||||
|
throw new IllegalStateException("Duplicate translation key " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package top.r3944realms.lib39.datagen.provider;
|
package top.r3944realms.lib39.datagen.provider;
|
||||||
|
|
||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraftforge.common.data.LanguageProvider;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.datagen.value.ILangKeyValue;
|
import top.r3944realms.lib39.datagen.value.ILangKeyValue;
|
||||||
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
||||||
import top.r3944realms.lib39.datagen.value.McLocale;
|
import top.r3944realms.lib39.datagen.value.McLocale;
|
||||||
|
|
@ -98,7 +98,7 @@ public class SimpleLanguageProvider extends LanguageProvider {
|
||||||
.filter(translationMap::containsKey)
|
.filter(translationMap::containsKey)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
LOGGER.info("Added {}/{} translations for {}",
|
Lib39.LOGGER.info("Added {}/{} translations for {}",
|
||||||
addedCount, orderedKeys.size(), language.mcCode());
|
addedCount, orderedKeys.size(), language.mcCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package top.r3944realms.lib39.example;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Lib 39 example.
|
||||||
|
*/
|
||||||
|
public class Lib39Example {
|
||||||
|
private static boolean registered = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Lib 39 example.
|
||||||
|
*/
|
||||||
|
public Lib39Example() {
|
||||||
|
if (!registered) {
|
||||||
|
init();
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init.
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrate feature.
|
||||||
|
*/
|
||||||
|
public void demonstrateFeature() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import top.r3944realms.lib39.client.gui.component.WheelWidget;
|
import top.r3944realms.lib39.client.gui.component.WheelWidget;
|
||||||
|
import top.r3944realms.lib39.mixin.minecraft.ScreenAccessor;
|
||||||
import top.r3944realms.lib39.util.lang.FourConsumer;
|
import top.r3944realms.lib39.util.lang.FourConsumer;
|
||||||
import top.r3944realms.lib39.util.lang.Pair;
|
import top.r3944realms.lib39.util.lang.Pair;
|
||||||
|
|
||||||
|
|
@ -114,7 +115,7 @@ public class ForgeScreen extends Screen {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(@NotNull GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
public void render(@NotNull GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
|
||||||
for (Renderable renderable : this.renderables) {
|
for (Renderable renderable : ((ScreenAccessor) this).getrRenderables()) {
|
||||||
renderable.render(guiGraphics, mouseX, mouseY, partialTick);
|
renderable.render(guiGraphics, mouseX, mouseY, partialTick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package top.r3944realms.lib39.example.content.capability;
|
package top.r3944realms.lib39.example.content.data;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
|
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -8,6 +10,27 @@ import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public abstract class AbstractedTestSyncData extends NBTEntitySyncData {
|
public abstract class AbstractedTestSyncData extends NBTEntitySyncData {
|
||||||
|
/**
|
||||||
|
* The constant DEFAULT_TEST_STRING.
|
||||||
|
*/
|
||||||
|
public final static String DEFAULT_TEST_STRING = "default_value";
|
||||||
|
/**
|
||||||
|
* The constant DEFAULT_TEST_INT.
|
||||||
|
*/
|
||||||
|
public final static int DEFAULT_TEST_INT = 42;
|
||||||
|
/**
|
||||||
|
* The constant DEFAULT_TEST_BOOLEAN.
|
||||||
|
*/
|
||||||
|
public final static boolean DEFAULT_TEST_BOOLEAN = true;
|
||||||
|
/**
|
||||||
|
* The constant DEFAULT_TEST_DOUBLE.
|
||||||
|
*/
|
||||||
|
public final static double DEFAULT_TEST_DOUBLE = 3.14159;
|
||||||
|
/**
|
||||||
|
* The constant DEFAULT_TEST_DATA.
|
||||||
|
*/
|
||||||
|
public final static TestData DEFAULT_TEST_DATA = new TestData("default", 100, false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Nbt sync data.
|
* Instantiates a new Nbt sync data.
|
||||||
*
|
*
|
||||||
|
|
@ -22,105 +45,157 @@ public abstract class AbstractedTestSyncData extends NBTEntitySyncData {
|
||||||
*
|
*
|
||||||
* @return the test string
|
* @return the test string
|
||||||
*/
|
*/
|
||||||
abstract String getTestString();
|
public abstract String getTestString();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets test string.
|
* Sets test string.
|
||||||
*
|
*
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
abstract void setTestString(String value);
|
public abstract void setTestString(String value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets test int.
|
* Gets test int.
|
||||||
*
|
*
|
||||||
* @return the test int
|
* @return the test int
|
||||||
*/
|
*/
|
||||||
abstract int getTestInt();
|
public abstract int getTestInt();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets test int.
|
* Sets test int.
|
||||||
*
|
*
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
abstract void setTestInt(int value);
|
public abstract void setTestInt(int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is test boolean boolean.
|
* Is test boolean boolean.
|
||||||
*
|
*
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
abstract boolean isTestBoolean();
|
public abstract boolean isTestBoolean();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets test boolean.
|
* Sets test boolean.
|
||||||
*
|
*
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
abstract void setTestBoolean(boolean value);
|
public abstract void setTestBoolean(boolean value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets test double.
|
* Gets test double.
|
||||||
*
|
*
|
||||||
* @return the test double
|
* @return the test double
|
||||||
*/
|
*/
|
||||||
abstract double getTestDouble();
|
public abstract double getTestDouble();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets test double.
|
* Sets test double.
|
||||||
*
|
*
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
abstract void setTestDouble(double value);
|
public abstract void setTestDouble(double value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets counter.
|
* Gets counter.
|
||||||
*
|
*
|
||||||
* @return the counter
|
* @return the counter
|
||||||
*/
|
*/
|
||||||
// 计数器,用于测试数据变化
|
public abstract int getCounter();
|
||||||
abstract int getCounter();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment counter.
|
* Increment counter.
|
||||||
*/
|
*/
|
||||||
abstract void incrementCounter();
|
public abstract void incrementCounter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear counter.
|
||||||
|
*/
|
||||||
|
public abstract void clearCounter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets last sync time.
|
* Gets last sync time.
|
||||||
*
|
*
|
||||||
* @return the last sync time
|
* @return the last sync time
|
||||||
*/
|
*/
|
||||||
// 时间戳,用于测试同步时机
|
public abstract long getLastSyncTime();
|
||||||
abstract long getLastSyncTime();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update sync time.
|
* Update sync time.
|
||||||
*/
|
*/
|
||||||
abstract void updateSyncTime();
|
public abstract void updateSyncTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear sync time.
|
||||||
|
*/
|
||||||
|
public abstract void clearSyncTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets custom data.
|
* Gets custom data.
|
||||||
*
|
*
|
||||||
* @return the custom data
|
* @return the custom data
|
||||||
*/
|
*/
|
||||||
// 自定义对象测试
|
public abstract TestData getCustomData();
|
||||||
abstract TestData getCustomData();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets custom data.
|
* Sets custom data.
|
||||||
*
|
*
|
||||||
* @param data the data
|
* @param data the data
|
||||||
*/
|
*/
|
||||||
abstract void setCustomData(TestData data);
|
public abstract void setCustomData(TestData data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate data boolean.
|
* Validate data boolean.
|
||||||
*
|
*
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
// 验证数据完整性
|
public abstract boolean validateData();
|
||||||
abstract boolean validateData();
|
|
||||||
|
/**
|
||||||
|
* Reset to defaults.
|
||||||
|
*/
|
||||||
|
public void resetToDefaults() {
|
||||||
|
setTestString(DEFAULT_TEST_STRING);
|
||||||
|
setTestInt(DEFAULT_TEST_INT);
|
||||||
|
setTestBoolean(DEFAULT_TEST_BOOLEAN);
|
||||||
|
setTestDouble(DEFAULT_TEST_DOUBLE);
|
||||||
|
setCustomData(DEFAULT_TEST_DATA);
|
||||||
|
clearCounter();
|
||||||
|
clearSyncTime();
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate random data.
|
||||||
|
*/
|
||||||
|
public void generateRandomData() {
|
||||||
|
setTestString("random_" + System.currentTimeMillis());
|
||||||
|
setTestInt((int) (Math.random() * 1000));
|
||||||
|
setTestBoolean(Math.random() > 0.5);
|
||||||
|
setTestDouble(Math.random() * 100.0);
|
||||||
|
setCustomData(new TestData(
|
||||||
|
"custom_" + getCounter(),
|
||||||
|
(int) (Math.random() * 500),
|
||||||
|
Math.random() > 0.5
|
||||||
|
));
|
||||||
|
updateSyncTime();
|
||||||
|
incrementCounter();
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To bytes.
|
||||||
|
*
|
||||||
|
* @param buf the buf
|
||||||
|
*/
|
||||||
|
public abstract void toBytes(FriendlyByteBuf buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From bytes.
|
||||||
|
*
|
||||||
|
* @param buf the buf
|
||||||
|
*/
|
||||||
|
public abstract void fromBytes(@NotNull FriendlyByteBuf buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试数据对象
|
* 测试数据对象
|
||||||
|
|
@ -153,7 +228,6 @@ public abstract class AbstractedTestSyncData extends NBTEntitySyncData {
|
||||||
*
|
*
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
// getters and setters
|
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,11 +17,7 @@ import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData;
|
import top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
|
||||||
import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler;
|
|
||||||
import top.r3944realms.lib39.example.content.capability.TestSyncData;
|
|
||||||
import top.r3944realms.lib39.example.core.network.ClientDataPacket;
|
|
||||||
import top.r3944realms.lib39.example.core.network.ExNetworkHandler;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
@ -31,14 +27,14 @@ import java.util.concurrent.CompletableFuture;
|
||||||
* Shift + 右键:客户端与服务器双端同时查询检查同步
|
* Shift + 右键:客户端与服务器双端同时查询检查同步
|
||||||
* 普通右键:单端查询目标生物数据
|
* 普通右键:单端查询目标生物数据
|
||||||
*/
|
*/
|
||||||
public class FabricItem extends Item {
|
public abstract class AbstractFabricItem extends Item {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Fabric item.
|
* Instantiates a new Fabric item.
|
||||||
*
|
*
|
||||||
* @param properties the properties
|
* @param properties the properties
|
||||||
*/
|
*/
|
||||||
public FabricItem(Properties properties) {
|
public AbstractFabricItem(Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +78,7 @@ public class FabricItem extends Item {
|
||||||
|
|
||||||
if (targetEntity instanceof LivingEntity livingTarget) {
|
if (targetEntity instanceof LivingEntity livingTarget) {
|
||||||
// 在客户端获取本地数据
|
// 在客户端获取本地数据
|
||||||
TestSyncData clientData = getLocalClientData(livingTarget);
|
AbstractedTestSyncData clientData = getLocalClientData(livingTarget);
|
||||||
|
|
||||||
if (clientData != null) {
|
if (clientData != null) {
|
||||||
// 发送客户端数据到服务器
|
// 发送客户端数据到服务器
|
||||||
|
|
@ -107,7 +103,7 @@ public class FabricItem extends Item {
|
||||||
*/
|
*/
|
||||||
private void handlePlayerSelfData(Player player) {
|
private void handlePlayerSelfData(Player player) {
|
||||||
// 获取玩家自身的客户端数据
|
// 获取玩家自身的客户端数据
|
||||||
TestSyncData clientData = getLocalClientData(player);
|
AbstractedTestSyncData clientData = getLocalClientData(player);
|
||||||
|
|
||||||
if (clientData != null) {
|
if (clientData != null) {
|
||||||
// 发送玩家自身数据到服务器
|
// 发送玩家自身数据到服务器
|
||||||
|
|
@ -126,7 +122,7 @@ public class FabricItem extends Item {
|
||||||
Entity targetEntity = getClientTargetedEntity(player);
|
Entity targetEntity = getClientTargetedEntity(player);
|
||||||
|
|
||||||
if (targetEntity instanceof LivingEntity livingTarget) {
|
if (targetEntity instanceof LivingEntity livingTarget) {
|
||||||
TestSyncData clientData = getLocalClientData(livingTarget);
|
AbstractedTestSyncData clientData = getLocalClientData(livingTarget);
|
||||||
|
|
||||||
if (clientData != null) {
|
if (clientData != null) {
|
||||||
displayClientSideResults(player, livingTarget, clientData);
|
displayClientSideResults(player, livingTarget, clientData);
|
||||||
|
|
@ -157,14 +153,22 @@ public class FabricItem extends Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在客户端获取本地数据
|
* Gets data.
|
||||||
|
*
|
||||||
|
* @param target the target
|
||||||
|
* @return the data
|
||||||
*/
|
*/
|
||||||
private TestSyncData getLocalClientData(LivingEntity target) {
|
protected abstract AbstractedTestSyncData getData(Entity target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在客户端获取本地数据
|
||||||
|
*
|
||||||
|
* @param target the target
|
||||||
|
* @return the local client data
|
||||||
|
*/
|
||||||
|
protected AbstractedTestSyncData getLocalClientData(LivingEntity target) {
|
||||||
try {
|
try {
|
||||||
AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null);
|
return getData(target);
|
||||||
if (abstractData instanceof TestSyncData) {
|
|
||||||
return (TestSyncData) abstractData;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Lib39.LOGGER.error("[FabricItem] 获取客户端数据失败", e);
|
Lib39.LOGGER.error("[FabricItem] 获取客户端数据失败", e);
|
||||||
}
|
}
|
||||||
|
|
@ -173,51 +177,11 @@ public class FabricItem extends Item {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送客户端数据到服务器
|
* 发送客户端数据到服务器
|
||||||
*/
|
|
||||||
private void sendClientDataToServer(TestSyncData clientData, int targetEntityId) {
|
|
||||||
// 使用网络系统发送数据包
|
|
||||||
ExNetworkHandler.INSTANCE.sendToServer(new ClientDataPacket(clientData, targetEntityId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务器端处理客户端发送的数据(从数据包调用)
|
|
||||||
*
|
*
|
||||||
* @param player the player
|
|
||||||
* @param clientData the client data
|
* @param clientData the client data
|
||||||
* @param targetEntityId the target entity id
|
* @param targetEntityId the target entity id
|
||||||
*/
|
*/
|
||||||
public static void handleClientDataFromPacket(@NotNull ServerPlayer player, TestSyncData clientData, int targetEntityId) {
|
protected abstract void sendClientDataToServer(AbstractedTestSyncData clientData, int targetEntityId);
|
||||||
Entity target = player.level().getEntity(targetEntityId);
|
|
||||||
|
|
||||||
if (target instanceof LivingEntity livingTarget) {
|
|
||||||
// 获取服务器端数据
|
|
||||||
TestSyncData serverData = getServerSideData(livingTarget);
|
|
||||||
|
|
||||||
if (serverData != null) {
|
|
||||||
// 显示双端对比结果
|
|
||||||
displayDualEndComparison(player, livingTarget, serverData, clientData);
|
|
||||||
} else {
|
|
||||||
player.sendSystemMessage(Component.literal("§c无法获取服务器端数据"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
player.sendSystemMessage(Component.literal("§c目标生物不存在或已消失"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取服务器端数据
|
|
||||||
*/
|
|
||||||
private static @Nullable TestSyncData getServerSideData(LivingEntity target) {
|
|
||||||
try {
|
|
||||||
AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null);
|
|
||||||
if (abstractData instanceof TestSyncData) {
|
|
||||||
return (TestSyncData) abstractData;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Lib39.LOGGER.error("[FabricItem] 获取服务器端数据失败", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动服务器单端查询
|
* 启动服务器单端查询
|
||||||
|
|
@ -255,9 +219,9 @@ public class FabricItem extends Item {
|
||||||
// 获取目标生物的数据
|
// 获取目标生物的数据
|
||||||
AbstractedTestSyncData abstractData = getTestSyncData(target);
|
AbstractedTestSyncData abstractData = getTestSyncData(target);
|
||||||
|
|
||||||
if (abstractData instanceof TestSyncData testData) {
|
if (abstractData != null) {
|
||||||
// 显示详细数据
|
// 显示详细数据
|
||||||
displayServerDetailedData(player, target, testData);
|
displayServerDetailedData(player, target, abstractData);
|
||||||
} else {
|
} else {
|
||||||
player.sendSystemMessage(Component.literal(
|
player.sendSystemMessage(Component.literal(
|
||||||
String.format("§c生物 §e%s§c 没有测试数据或数据无效", target.getName().getString())
|
String.format("§c生物 §e%s§c 没有测试数据或数据无效", target.getName().getString())
|
||||||
|
|
@ -268,7 +232,7 @@ public class FabricItem extends Item {
|
||||||
/**
|
/**
|
||||||
* 显示客户端查询结果
|
* 显示客户端查询结果
|
||||||
*/
|
*/
|
||||||
private void displayClientSideResults(Player player, LivingEntity target, TestSyncData clientData) {
|
private void displayClientSideResults(Player player, LivingEntity target, AbstractedTestSyncData clientData) {
|
||||||
player.sendSystemMessage(Component.literal("§6=== 客户端数据查询结果 ==="));
|
player.sendSystemMessage(Component.literal("§6=== 客户端数据查询结果 ==="));
|
||||||
player.sendSystemMessage(Component.literal("§7目标生物: §e" + target.getName().getString()));
|
player.sendSystemMessage(Component.literal("§7目标生物: §e" + target.getName().getString()));
|
||||||
player.sendSystemMessage(Component.literal("§7数据来源: §9客户端本地"));
|
player.sendSystemMessage(Component.literal("§7数据来源: §9客户端本地"));
|
||||||
|
|
@ -291,7 +255,7 @@ public class FabricItem extends Item {
|
||||||
/**
|
/**
|
||||||
* 显示服务器详细数据(单端查询)
|
* 显示服务器详细数据(单端查询)
|
||||||
*/
|
*/
|
||||||
private void displayServerDetailedData(ServerPlayer player, LivingEntity target, TestSyncData testData) {
|
private void displayServerDetailedData(ServerPlayer player, LivingEntity target, AbstractedTestSyncData testData) {
|
||||||
player.sendSystemMessage(Component.literal("§6=== 数据查询结果 ==="));
|
player.sendSystemMessage(Component.literal("§6=== 数据查询结果 ==="));
|
||||||
player.sendSystemMessage(Component.literal(
|
player.sendSystemMessage(Component.literal(
|
||||||
String.format("§7目标生物: §e%s", target.getName().getString())
|
String.format("§7目标生物: §e%s", target.getName().getString())
|
||||||
|
|
@ -324,7 +288,7 @@ public class FabricItem extends Item {
|
||||||
player.sendSystemMessage(Component.literal(""));
|
player.sendSystemMessage(Component.literal(""));
|
||||||
|
|
||||||
// 显示自定义数据
|
// 显示自定义数据
|
||||||
TestSyncData.TestData customData = testData.getCustomData();
|
AbstractedTestSyncData.TestData customData = testData.getCustomData();
|
||||||
player.sendSystemMessage(Component.literal("§a自定义数据:"));
|
player.sendSystemMessage(Component.literal("§a自定义数据:"));
|
||||||
player.sendSystemMessage(Component.literal(
|
player.sendSystemMessage(Component.literal(
|
||||||
String.format("§7名称: §f%s", customData.getName())
|
String.format("§7名称: §f%s", customData.getName())
|
||||||
|
|
@ -349,8 +313,13 @@ public class FabricItem extends Item {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示双端比较结果
|
* 显示双端比较结果
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @param target the target
|
||||||
|
* @param serverData the server data
|
||||||
|
* @param clientData the client data
|
||||||
*/
|
*/
|
||||||
private static void displayDualEndComparison(ServerPlayer player, LivingEntity target, TestSyncData serverData, TestSyncData clientData) {
|
protected static void displayDualEndComparison(ServerPlayer player, LivingEntity target, AbstractedTestSyncData serverData, AbstractedTestSyncData clientData) {
|
||||||
player.sendSystemMessage(Component.literal("§6=== 客户端-服务器双端同步检查结果 ==="));
|
player.sendSystemMessage(Component.literal("§6=== 客户端-服务器双端同步检查结果 ==="));
|
||||||
player.sendSystemMessage(Component.literal(
|
player.sendSystemMessage(Component.literal(
|
||||||
String.format("§7目标生物: §e%s", target.getName().getString())
|
String.format("§7目标生物: §e%s", target.getName().getString())
|
||||||
|
|
@ -462,7 +431,7 @@ public class FabricItem extends Item {
|
||||||
/**
|
/**
|
||||||
* 比较自定义数据
|
* 比较自定义数据
|
||||||
*/
|
*/
|
||||||
private static boolean compareCustomData(TestSyncData.TestData first, TestSyncData.TestData second) {
|
private static boolean compareCustomData(AbstractedTestSyncData.TestData first, AbstractedTestSyncData.TestData second) {
|
||||||
return first.getName().equals(second.getName()) &&
|
return first.getName().equals(second.getName()) &&
|
||||||
first.getValue() == second.getValue() &&
|
first.getValue() == second.getValue() &&
|
||||||
first.isFlag() == second.isFlag();
|
first.isFlag() == second.isFlag();
|
||||||
|
|
@ -552,7 +521,7 @@ public class FabricItem extends Item {
|
||||||
*/
|
*/
|
||||||
private AbstractedTestSyncData getTestSyncData(Entity entity) {
|
private AbstractedTestSyncData getTestSyncData(Entity entity) {
|
||||||
try {
|
try {
|
||||||
return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null);
|
return getData(entity);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Lib39.LOGGER.debug("[FabricItem] 获取生物 {} 的 TestSyncData 失败: {}",
|
Lib39.LOGGER.debug("[FabricItem] 获取生物 {} 的 TestSyncData 失败: {}",
|
||||||
entity.getName().getString(), e.getMessage());
|
entity.getName().getString(), e.getMessage());
|
||||||
|
|
@ -17,9 +17,7 @@ import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData;
|
import top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
|
||||||
import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler;
|
|
||||||
import top.r3944realms.lib39.example.content.capability.TestSyncData;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
@ -29,7 +27,7 @@ import java.util.Random;
|
||||||
* Shift + 右键:操作自己的数据
|
* Shift + 右键:操作自己的数据
|
||||||
* 普通右键:操作瞄准生物的数据
|
* 普通右键:操作瞄准生物的数据
|
||||||
*/
|
*/
|
||||||
public class NeoForgeItem extends Item {
|
public abstract class AbstractNeoForgeItem extends Item {
|
||||||
private static final Random RANDOM = new Random();
|
private static final Random RANDOM = new Random();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,7 +35,7 @@ public class NeoForgeItem extends Item {
|
||||||
*
|
*
|
||||||
* @param properties the properties
|
* @param properties the properties
|
||||||
*/
|
*/
|
||||||
public NeoForgeItem(Properties properties) {
|
public AbstractNeoForgeItem(Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,10 +137,8 @@ public class NeoForgeItem extends Item {
|
||||||
*/
|
*/
|
||||||
private boolean triggerRandomTransformation(LivingEntity entity) {
|
private boolean triggerRandomTransformation(LivingEntity entity) {
|
||||||
try {
|
try {
|
||||||
AbstractedTestSyncData abstractData = getOrCreateTestSyncData(entity);
|
AbstractedTestSyncData testData = getOrCreateTestSyncData(entity);
|
||||||
if (!(abstractData instanceof TestSyncData testData)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 随机选择一种变换方式
|
// 随机选择一种变换方式
|
||||||
int transformationType = RANDOM.nextInt(6); // 增加更多变换类型
|
int transformationType = RANDOM.nextInt(6); // 增加更多变换类型
|
||||||
|
|
@ -170,7 +166,7 @@ public class NeoForgeItem extends Item {
|
||||||
}
|
}
|
||||||
case 3 -> {
|
case 3 -> {
|
||||||
// 修改自定义数据
|
// 修改自定义数据
|
||||||
TestSyncData.TestData newCustomData = new TestSyncData.TestData(
|
AbstractedTestSyncData.TestData newCustomData = new AbstractedTestSyncData.TestData(
|
||||||
"custom_" + RANDOM.nextInt(100),
|
"custom_" + RANDOM.nextInt(100),
|
||||||
RANDOM.nextInt(500),
|
RANDOM.nextInt(500),
|
||||||
RANDOM.nextBoolean()
|
RANDOM.nextBoolean()
|
||||||
|
|
@ -223,7 +219,7 @@ public class NeoForgeItem extends Item {
|
||||||
/**
|
/**
|
||||||
* 显示数据预览给玩家
|
* 显示数据预览给玩家
|
||||||
*/
|
*/
|
||||||
private void displayDataPreview(Player player, TestSyncData testData) {
|
private void displayDataPreview(Player player, AbstractedTestSyncData testData) {
|
||||||
player.sendSystemMessage(Component.literal("§6数据预览:"));
|
player.sendSystemMessage(Component.literal("§6数据预览:"));
|
||||||
player.sendSystemMessage(Component.literal(
|
player.sendSystemMessage(Component.literal(
|
||||||
String.format("§7字符串: §f%s", testData.getTestString())
|
String.format("§7字符串: §f%s", testData.getTestString())
|
||||||
|
|
@ -247,9 +243,23 @@ public class NeoForgeItem extends Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractedTestSyncData getOrCreateTestSyncData(Entity entity) {
|
/**
|
||||||
|
* Gets data.
|
||||||
|
*
|
||||||
|
* @param entity the entity
|
||||||
|
* @return the data
|
||||||
|
*/
|
||||||
|
protected abstract AbstractedTestSyncData getData(Entity entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets or create test sync data.
|
||||||
|
*
|
||||||
|
* @param entity the entity
|
||||||
|
* @return the or create test sync data
|
||||||
|
*/
|
||||||
|
protected AbstractedTestSyncData getOrCreateTestSyncData(Entity entity) {
|
||||||
try {
|
try {
|
||||||
return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElseThrow();
|
return getData(entity);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Lib39.LOGGER.error("[NeoForgeItem] 获取 {} 的 TestSyncData 失败: {}",
|
Lib39.LOGGER.error("[NeoForgeItem] 获取 {} 的 TestSyncData 失败: {}",
|
||||||
getEntityName((LivingEntity) entity), e.getMessage());
|
getEntityName((LivingEntity) entity), e.getMessage());
|
||||||
|
|
@ -7,10 +7,9 @@ import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.example.client.screen.ForgeScreen;
|
import top.r3944realms.lib39.example.client.screen.ForgeScreen;
|
||||||
|
import top.r3944realms.lib39.util.IClientOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Forge item.
|
* The type Forge item.
|
||||||
|
|
@ -28,13 +27,17 @@ public class ForgeItem extends Item {
|
||||||
@Override
|
@Override
|
||||||
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand usedHand) {
|
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand usedHand) {
|
||||||
if (level.isClientSide() && usedHand == InteractionHand.MAIN_HAND) {
|
if (level.isClientSide() && usedHand == InteractionHand.MAIN_HAND) {
|
||||||
clientUse(usedHand);
|
ClientOpt.clientUse(usedHand);
|
||||||
}
|
}
|
||||||
return super.use(level, player, usedHand);
|
return super.use(level, player, usedHand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
/**
|
||||||
private static void clientUse(@NotNull InteractionHand usedHand) {
|
* The type Client opt.
|
||||||
Minecraft.getInstance().setScreen(new ForgeScreen(usedHand, 0));
|
*/
|
||||||
}
|
static class ClientOpt implements IClientOnly {
|
||||||
|
private static void clientUse(@NotNull InteractionHand usedHand) {
|
||||||
|
IClientOnly.check(() -> Minecraft.getInstance().setScreen(new ForgeScreen(usedHand, 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package top.r3944realms.lib39.example.core.register;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Ex lib 39 items.
|
||||||
|
*/
|
||||||
|
public class ExLib39Items {
|
||||||
|
/**
|
||||||
|
* The constant SUPER_LEAD_ROPE.
|
||||||
|
*/
|
||||||
|
public static Supplier<Item> FABRIC;
|
||||||
|
/**
|
||||||
|
* The constant ETERNAL_POTATO.
|
||||||
|
*/
|
||||||
|
public static Supplier<Item> NEOFORGE;
|
||||||
|
/**
|
||||||
|
* The constant FORGE.
|
||||||
|
*/
|
||||||
|
public static Supplier<Item> FORGE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.spongepowered.asm.mixin.Debug;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Pseudo;
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
package top.r3944realms.lib39.mixin.minecraft;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
|
import net.minecraft.world.item.CreativeModeTabs;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Creative mode tabs accessor.
|
||||||
|
*/
|
||||||
|
@Mixin(CreativeModeTabs.class)
|
||||||
|
public interface CreativeModeTabsAccessor {
|
||||||
|
/**
|
||||||
|
* Gets building blocks.
|
||||||
|
*
|
||||||
|
* @return the building blocks
|
||||||
|
*/
|
||||||
|
@Accessor("BUILDING_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getBuildingBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets colored blocks.
|
||||||
|
*
|
||||||
|
* @return the colored blocks
|
||||||
|
*/
|
||||||
|
@Accessor("COLORED_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getColoredBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets natural blocks.
|
||||||
|
*
|
||||||
|
* @return the natural blocks
|
||||||
|
*/
|
||||||
|
@Accessor("NATURAL_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getNaturalBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets functional blocks.
|
||||||
|
*
|
||||||
|
* @return the functional blocks
|
||||||
|
*/
|
||||||
|
@Accessor("FUNCTIONAL_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getFunctionalBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets redstone blocks.
|
||||||
|
*
|
||||||
|
* @return the redstone blocks
|
||||||
|
*/
|
||||||
|
@Accessor("REDSTONE_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getRedstoneBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets hotbar.
|
||||||
|
*
|
||||||
|
* @return the hotbar
|
||||||
|
*/
|
||||||
|
@Accessor("HOTBAR")
|
||||||
|
static ResourceKey<CreativeModeTab> getHotbar() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets search.
|
||||||
|
*
|
||||||
|
* @return the search
|
||||||
|
*/
|
||||||
|
@Accessor("SEARCH")
|
||||||
|
static ResourceKey<CreativeModeTab> getSearch() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets tools and utilities.
|
||||||
|
*
|
||||||
|
* @return the tools and utilities
|
||||||
|
*/
|
||||||
|
@Accessor("TOOLS_AND_UTILITIES")
|
||||||
|
static ResourceKey<CreativeModeTab> getToolsAndUtilities() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets combat.
|
||||||
|
*
|
||||||
|
* @return the combat
|
||||||
|
*/
|
||||||
|
@Accessor("COMBAT")
|
||||||
|
static ResourceKey<CreativeModeTab> getCombat() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets food and drinks.
|
||||||
|
*
|
||||||
|
* @return the food and drinks
|
||||||
|
*/
|
||||||
|
@Accessor("FOOD_AND_DRINKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getFoodAndDrinks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets ingredients.
|
||||||
|
*
|
||||||
|
* @return the ingredients
|
||||||
|
*/
|
||||||
|
@Accessor("INGREDIENTS")
|
||||||
|
static ResourceKey<CreativeModeTab> getIngredients() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets spawn eggs.
|
||||||
|
*
|
||||||
|
* @return the spawn eggs
|
||||||
|
*/
|
||||||
|
@Accessor("SPAWN_EGGS")
|
||||||
|
static ResourceKey<CreativeModeTab> getSpawnEggs() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets op blocks.
|
||||||
|
*
|
||||||
|
* @return the op blocks
|
||||||
|
*/
|
||||||
|
@Accessor("OP_BLOCKS")
|
||||||
|
static ResourceKey<CreativeModeTab> getOpBlocks() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets inventory.
|
||||||
|
*
|
||||||
|
* @return the inventory
|
||||||
|
*/
|
||||||
|
@Accessor("INVENTORY")
|
||||||
|
static ResourceKey<CreativeModeTab> getInventory() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets cached parameters.
|
||||||
|
*
|
||||||
|
* @return the cached parameters
|
||||||
|
*/
|
||||||
|
@Accessor("CACHED_PARAMETERS")
|
||||||
|
static CreativeModeTab.ItemDisplayParameters getCachedParameters() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets painting comparator.
|
||||||
|
*
|
||||||
|
* @return the painting comparator
|
||||||
|
*/
|
||||||
|
@Accessor("PAINTING_COMPARATOR")
|
||||||
|
static Comparator<net.minecraft.world.item.CreativeModeTab> getPaintingComparator() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package top.r3944realms.lib39.mixin.minecraft;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.components.Renderable;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Screen accessor.
|
||||||
|
*/
|
||||||
|
@Mixin(Screen.class)
|
||||||
|
public interface ScreenAccessor {
|
||||||
|
/**
|
||||||
|
* Gets renderables.
|
||||||
|
*
|
||||||
|
* @return the renderables
|
||||||
|
*/
|
||||||
|
@Accessor("renderables")
|
||||||
|
List<Renderable> getrRenderables();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package top.r3944realms.lib39.platform;
|
||||||
|
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
import top.r3944realms.lib39.platform.services.IPlatformHelper;
|
||||||
|
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type Services.
|
||||||
|
*/
|
||||||
|
// Service loaders are a built-in Java feature that allow us to locate implementations of an interface that vary from one
|
||||||
|
// environment to another. In the context of MultiLoader we use this feature to access a mock API in the common code that
|
||||||
|
// is swapped out for the platform specific implementation at runtime.
|
||||||
|
public class Services {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constant PLATFORM.
|
||||||
|
*/
|
||||||
|
// In this example we provide a platform helper which provides information about what platform the mod is running on.
|
||||||
|
// For example this can be used to check if the code is running on Forge vs Fabric, or to ask the modloader if another
|
||||||
|
// mod is loaded.
|
||||||
|
public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load t.
|
||||||
|
*
|
||||||
|
* @param <T> the type parameter
|
||||||
|
* @param clazz the clazz
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
// This code is used to load a service for the current environment. Your implementation of the service must be defined
|
||||||
|
// manually by including a text file in META-INF/services named with the fully qualified class name of the service.
|
||||||
|
// Inside the file you should write the fully qualified class name of the implementation to load for the platform. For
|
||||||
|
// example our file on Forge points to ForgePlatformHelper while Fabric points to FabricPlatformHelper.
|
||||||
|
public static <T> T load(Class<T> clazz) {
|
||||||
|
|
||||||
|
final T loadedService = ServiceLoader.load(clazz)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
|
||||||
|
Lib39.LOGGER.debug("Loaded {} for service {}", loadedService, clazz);
|
||||||
|
return loadedService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package top.r3944realms.lib39.platform.services;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import net.minecraft.commands.CommandBuildContext;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import top.r3944realms.lib39.core.command.ICommandHelpManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Help command hook.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IHelpCommandHook {
|
||||||
|
/**
|
||||||
|
* On register.
|
||||||
|
*
|
||||||
|
* @param tree the tree
|
||||||
|
* @param manager the manager
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
void onRegister(LiteralArgumentBuilder<CommandSourceStack> tree, ICommandHelpManager manager, CommandBuildContext context);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package top.r3944realms.lib39.platform.services;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Platform helper.
|
||||||
|
*/
|
||||||
|
public interface IPlatformHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the current platform
|
||||||
|
*
|
||||||
|
* @return The name of the current platform.
|
||||||
|
*/
|
||||||
|
String getPlatformName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a mod with the given id is loaded.
|
||||||
|
*
|
||||||
|
* @param modId The mod to check if it is loaded.
|
||||||
|
* @return True if the mod is loaded, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isModLoaded(String modId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the game is currently in a development environment.
|
||||||
|
*
|
||||||
|
* @return True if in a development environment, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isDevelopmentEnvironment();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the environment type as a string.
|
||||||
|
*
|
||||||
|
* @return The name of the environment type.
|
||||||
|
*/
|
||||||
|
default String getEnvironmentName() {
|
||||||
|
return isDevelopmentEnvironment() ? "development" : "production";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is client environment boolean.
|
||||||
|
*
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
|
boolean isClientEnvironment();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets mod version.
|
||||||
|
*
|
||||||
|
* @return the mod version
|
||||||
|
*/
|
||||||
|
String getModVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets util helper.
|
||||||
|
*
|
||||||
|
* @return the util helper
|
||||||
|
*/
|
||||||
|
IUtilHelper getUtilHelper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets help command hook.
|
||||||
|
*
|
||||||
|
* @return the help command hook
|
||||||
|
*/
|
||||||
|
IHelpCommandHook getHelpCommandHook();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package top.r3944realms.lib39.platform.services;
|
||||||
|
|
||||||
|
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Util helper.
|
||||||
|
*/
|
||||||
|
public interface IUtilHelper {
|
||||||
|
/**
|
||||||
|
* Gets block registry builder.
|
||||||
|
*
|
||||||
|
* @return the block registry builder
|
||||||
|
*/
|
||||||
|
BlockRegistryBuilder getBlockRegistryBuilder();
|
||||||
|
}
|
||||||
|
|
@ -13,8 +13,6 @@ import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTReader;
|
import top.r3944realms.lib39.util.nbt.NBTReader;
|
||||||
|
|
@ -30,6 +28,74 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
* The type GameProfile helper.
|
* The type GameProfile helper.
|
||||||
*/
|
*/
|
||||||
public class GameProfileHelper {
|
public class GameProfileHelper {
|
||||||
|
/**
|
||||||
|
* Client Only Class
|
||||||
|
*/
|
||||||
|
public static class ClientOpt implements IClientOnly {
|
||||||
|
/**
|
||||||
|
* Resolve skin texture resource location.
|
||||||
|
*
|
||||||
|
* @param gameProfile the game profile
|
||||||
|
* @return the resource location
|
||||||
|
*/
|
||||||
|
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
|
||||||
|
return IClientOnly.check(() ->
|
||||||
|
Minecraft.getInstance().getSkinManager()
|
||||||
|
.getInsecureSkinLocation(gameProfile));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets skin texture.
|
||||||
|
*
|
||||||
|
* @param gameProfile the game profile
|
||||||
|
* @return the skin texture
|
||||||
|
*/
|
||||||
|
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
|
||||||
|
return IClientOnly.check(() -> {
|
||||||
|
if (gameProfile == null) {
|
||||||
|
return DefaultPlayerSkin.getDefaultSkin();
|
||||||
|
}
|
||||||
|
return resolveSkinTexture(gameProfile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has slim arms client boolean.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the boolean
|
||||||
|
*/
|
||||||
|
public static boolean hasSlimArmsClient(Player player) {
|
||||||
|
return IClientOnly.check(() -> {
|
||||||
|
if (player instanceof AbstractClientPlayer clientPlayer) {
|
||||||
|
PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
|
||||||
|
.getConnection())
|
||||||
|
.getPlayerInfo(clientPlayer.getUUID());
|
||||||
|
return playerInfo != null && "slim".equals(playerInfo.getModelName());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets skin model name.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @return the skin model name
|
||||||
|
*/
|
||||||
|
public static @NotNull String getSkinModelName(@NotNull Player player) {
|
||||||
|
return IClientOnly.check(() -> {
|
||||||
|
if (player.level().isClientSide && player instanceof AbstractClientPlayer) {
|
||||||
|
PlayerInfo info = Objects.requireNonNull(Minecraft.getInstance().getConnection())
|
||||||
|
.getPlayerInfo(player.getUUID());
|
||||||
|
return info != null ? info.getModelName() : "default";
|
||||||
|
}
|
||||||
|
return "default";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constant TAG_BE.
|
* The constant TAG_BE.
|
||||||
*/
|
*/
|
||||||
|
|
@ -39,32 +105,25 @@ public class GameProfileHelper {
|
||||||
*/
|
*/
|
||||||
public static final String TAG_OWN_PROFILE = "OwnerProfile";
|
public static final String TAG_OWN_PROFILE = "OwnerProfile";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets skin texture.
|
* Gets skin texture.
|
||||||
*
|
*
|
||||||
* @param gameProfile the game profile
|
* @param gameProfile the game profile
|
||||||
* @return the skin texture
|
* @return the skin texture
|
||||||
*/
|
*/
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
|
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
|
||||||
if (gameProfile == null) {
|
return ClientOpt.getSkinTexture(gameProfile);
|
||||||
return DefaultPlayerSkin.getDefaultSkin();
|
|
||||||
}
|
|
||||||
return resolveSkinTexture(gameProfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve skin texture resource location.
|
* Resolve skin texture resource location.
|
||||||
*
|
*
|
||||||
* @param gameProfile the game profile
|
* @param gameProfile the game profile
|
||||||
* @return the resource location
|
* @return the resource location
|
||||||
*/
|
*/
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
|
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
|
||||||
Minecraft minecraft = Minecraft.getInstance();
|
return ClientOpt.resolveSkinTexture(gameProfile);
|
||||||
return minecraft.getSkinManager()
|
|
||||||
.getInsecureSkinLocation(gameProfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,7 +132,6 @@ public class GameProfileHelper {
|
||||||
* @param player the player
|
* @param player the player
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
// 判断玩家是否使用纤细手臂
|
|
||||||
public static boolean hasSlimArms(@NotNull Player player) {
|
public static boolean hasSlimArms(@NotNull Player player) {
|
||||||
if (player.level().isClientSide) {
|
if (player.level().isClientSide) {
|
||||||
return hasSlimArmsClient(player);
|
return hasSlimArmsClient(player);
|
||||||
|
|
@ -82,16 +140,9 @@ public class GameProfileHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 客户端判断
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private static boolean hasSlimArmsClient(Player player) {
|
private static boolean hasSlimArmsClient(Player player) {
|
||||||
if (player instanceof AbstractClientPlayer clientPlayer) {
|
return ClientOpt.hasSlimArmsClient(player);
|
||||||
PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
|
|
||||||
.getConnection())
|
|
||||||
.getPlayerInfo(clientPlayer.getUUID());
|
|
||||||
return playerInfo != null && "slim".equals(playerInfo.getModelName());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 服务器端判断
|
// 服务器端判断
|
||||||
|
|
@ -123,15 +174,8 @@ public class GameProfileHelper {
|
||||||
* @param player the player
|
* @param player the player
|
||||||
* @return the skin model name
|
* @return the skin model name
|
||||||
*/
|
*/
|
||||||
// 获取皮肤模型名称
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static @NotNull String getSkinModelName(@NotNull Player player) {
|
public static @NotNull String getSkinModelName(@NotNull Player player) {
|
||||||
if (player.level().isClientSide && player instanceof AbstractClientPlayer) {
|
return ClientOpt.getSkinModelName(player);
|
||||||
PlayerInfo info = Objects.requireNonNull(Minecraft.getInstance().getConnection())
|
|
||||||
.getPlayerInfo(player.getUUID());
|
|
||||||
return info != null ? info.getModelName() : "default";
|
|
||||||
}
|
|
||||||
return "default";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package top.r3944realms.lib39.util;
|
||||||
|
|
||||||
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface Client only.
|
||||||
|
*/
|
||||||
|
public interface IClientOnly {
|
||||||
|
/**
|
||||||
|
* Check.
|
||||||
|
*
|
||||||
|
* @param runnable the runnable
|
||||||
|
*/
|
||||||
|
static void check(Runnable runnable) {
|
||||||
|
if (Lib39.isClientEnvironment()) {
|
||||||
|
runnable.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("This method should be called in ClientEnvironment");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check.
|
||||||
|
*
|
||||||
|
* @param runnable the runnable
|
||||||
|
* @param fallback the fallback
|
||||||
|
*/
|
||||||
|
static void check(Runnable runnable, Runnable fallback) {
|
||||||
|
if (Lib39.isClientEnvironment()) {
|
||||||
|
runnable.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fallback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check t.
|
||||||
|
*
|
||||||
|
* @param <T> the type parameter
|
||||||
|
* @param supplier the supplier
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
static <T> T check(Supplier<T> supplier) {
|
||||||
|
if (Lib39.isClientEnvironment()) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
throw new RuntimeException("This method should be called in ClientEnvironment");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check t.
|
||||||
|
*
|
||||||
|
* @param <T> the type parameter
|
||||||
|
* @param supplier the supplier
|
||||||
|
* @param fallback the fallback
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
static <T> T check(Supplier<T> supplier, Supplier<T> fallback) {
|
||||||
|
if (Lib39.isClientEnvironment()) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
return fallback.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package top.r3944realms.lib39.util;
|
package top.r3944realms.lib39.util;
|
||||||
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
|
@ -66,7 +64,6 @@ public interface ILevelHelper {
|
||||||
* @return the client level
|
* @return the client level
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
static Level getClientLevel() {
|
static Level getClientLevel() {
|
||||||
return LevelHelper.CLIENT.getLevel();
|
return LevelHelper.CLIENT.getLevel();
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
* <p><b>重要:</b>由于使用了 weakValues(),实现类必须被其他对象强引用,
|
* <p><b>重要:</b>由于使用了 weakValues(),实现类必须被其他对象强引用,
|
||||||
* 否则会被 GC 清理导致锁自动释放。通常这意味着将实现类实例存储在
|
* 否则会被 GC 清理导致锁自动释放。通常这意味着将实现类实例存储在
|
||||||
* 适当的管理器或容器中。
|
* 适当的管理器或容器中。
|
||||||
|
*
|
||||||
* @author sch246
|
* @author sch246
|
||||||
*/
|
*/
|
||||||
public interface IUniPosOwner {
|
public interface IUniPosOwner {
|
||||||
|
|
@ -67,8 +68,7 @@ public interface IUniPosOwner {
|
||||||
*
|
*
|
||||||
* @param level 维度 The level (dimension) of the position.
|
* @param level 维度 The level (dimension) of the position.
|
||||||
* @param pos 坐标 The position to lock.
|
* @param pos 坐标 The position to lock.
|
||||||
* @return true if ownership was successfully claimed or was already held by this object,
|
* @return true if ownership was successfully claimed or was already held by this object, false if the position is owned by another object.
|
||||||
* false if the position is owned by another object.
|
|
||||||
*/
|
*/
|
||||||
default boolean tryLock(Level level, BlockPos pos) {
|
default boolean tryLock(Level level, BlockPos pos) {
|
||||||
return UniPosManager.INSTANCE.tryLock(level, pos, this);
|
return UniPosManager.INSTANCE.tryLock(level, pos, this);
|
||||||
|
|
@ -88,6 +88,7 @@ public interface IUniPosOwner {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 续租,继续持有锁
|
* 续租,继续持有锁
|
||||||
|
*
|
||||||
* @param level 维度
|
* @param level 维度
|
||||||
* @param pos 位置
|
* @param pos 位置
|
||||||
*/
|
*/
|
||||||
|
|
@ -97,16 +98,19 @@ public interface IUniPosOwner {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
管理 IUniPosOwner 系统的单例存储。
|
* 管理 IUniPosOwner 系统的单例存储。
|
||||||
该类是后台实现,大多数类不应直接使用。
|
* 该类是后台实现,大多数类不应直接使用。
|
||||||
在同一维度键(ResourceKey<Level)范围内,确保任意时刻一个 BlockPos 只能被一个对象“拥有”。
|
* 在同一维度键(ResourceKey<Level)范围内,确保任意时刻一个 BlockPos 只能被一个对象“拥有”。
|
||||||
注意:锁的作用域是维度键级别,因此在服务端同一维度的不同 Level 实例之间共享。
|
* 注意:锁的作用域是维度键级别,因此在服务端同一维度的不同 Level 实例之间共享。
|
||||||
缓存以 BlockPos 的 long 值为键,以 IUniPosOwner 的弱值(weak values)为值;
|
* 缓存以 BlockPos 的 long 值为键,以 IUniPosOwner 的弱值(weak values)为值;
|
||||||
当所有者不再被强引用时,条目会自动移除,从而释放锁。
|
* 当所有者不再被强引用时,条目会自动移除,从而释放锁。
|
||||||
该实现面向服务端使用。
|
* 该实现面向服务端使用。
|
||||||
*/
|
*/
|
||||||
final class UniPosManager {
|
final class UniPosManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constant INSTANCE.
|
||||||
|
*/
|
||||||
public static final UniPosManager INSTANCE = new UniPosManager();
|
public static final UniPosManager INSTANCE = new UniPosManager();
|
||||||
|
|
||||||
// 顶层映射:维度键(ResourceKey<Level>) -> 每维度的坐标缓存。
|
// 顶层映射:维度键(ResourceKey<Level>) -> 每维度的坐标缓存。
|
||||||
|
|
@ -139,7 +143,7 @@ final class UniPosManager {
|
||||||
*
|
*
|
||||||
* @param level 维度
|
* @param level 维度
|
||||||
* @param pos 坐标
|
* @param pos 坐标
|
||||||
* @return 如果存在所有者,则返回所有者对象;否则返回 null。
|
* @return 如果存在所有者 ,则返回所有者对象;否则返回 null。
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public IUniPosOwner getOwner(Level level, BlockPos pos) {
|
public IUniPosOwner getOwner(Level level, BlockPos pos) {
|
||||||
|
|
@ -182,6 +186,7 @@ final class UniPosManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 续租,继续持有锁
|
* 续租,继续持有锁
|
||||||
|
*
|
||||||
* @param level 维度
|
* @param level 维度
|
||||||
* @param pos 位置
|
* @param pos 位置
|
||||||
* @param owner 对象
|
* @param owner 对象
|
||||||
|
|
@ -1,39 +1,35 @@
|
||||||
package top.r3944realms.lib39.util.block;
|
package top.r3944realms.lib39.util.block;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.item.ItemProperties;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraftforge.registries.DeferredRegister;
|
|
||||||
import net.minecraftforge.registries.RegistryObject;
|
|
||||||
import org.jetbrains.annotations.Contract;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.core.event.CommonEventHandler;
|
import top.r3944realms.lib39.mixin.minecraft.CreativeModeTabsAccessor;
|
||||||
|
import top.r3944realms.lib39.platform.Services;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Block registry builder.
|
* The type Block registry builder.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||||
public class BlockRegistryBuilder {
|
public abstract class BlockRegistryBuilder {
|
||||||
private String registryName;
|
private String registryName;
|
||||||
private RegistryObject<Block> blockObject;
|
private Supplier<Block> blockObject;
|
||||||
private DeferredRegister<Item> items;
|
private BiFunction<String, Supplier<Item>, Supplier<Item>> blockItemRegister;
|
||||||
private boolean needBuildItem;
|
private boolean needBuildItem;
|
||||||
private Item.Properties properties;
|
private Item.Properties properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建新的构建器实例
|
* Create block registry builder.
|
||||||
*
|
*
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
@Contract(value = " -> new", pure = true)
|
public static BlockRegistryBuilder create() {
|
||||||
public static @NotNull BlockRegistryBuilder create() {
|
return Services.PLATFORM.getUtilHelper().getBlockRegistryBuilder();
|
||||||
return new BlockRegistryBuilder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,8 +50,8 @@ public class BlockRegistryBuilder {
|
||||||
* @param blockSupplier the block supplier
|
* @param blockSupplier the block supplier
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
public BlockRegistryBuilder registerBlock(@NotNull DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
public BlockRegistryBuilder registerBlock(@NotNull BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
|
||||||
this.blockObject = blockRegister.register(this.registryName, blockSupplier);
|
this.blockObject = blockRegister.apply(this.registryName, blockSupplier);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,8 +61,8 @@ public class BlockRegistryBuilder {
|
||||||
* @param itemRegister the item deferred register
|
* @param itemRegister the item deferred register
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
public BlockRegistryBuilder registerItem(DeferredRegister<Item> itemRegister) {
|
public BlockRegistryBuilder registerItem(BiFunction<String, Supplier<Item>,Supplier<Item>> itemRegister) {
|
||||||
this.items = itemRegister;
|
this.blockItemRegister = itemRegister;
|
||||||
needBuildItem = true;
|
needBuildItem = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -78,8 +74,8 @@ public class BlockRegistryBuilder {
|
||||||
* @param properties the item properties
|
* @param properties the item properties
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
public BlockRegistryBuilder registerItemWithProperties(DeferredRegister<Item> itemRegister, Item.Properties properties) {
|
public BlockRegistryBuilder registerItemWithProperties(BiFunction<String, Supplier<Item>,Supplier<Item>> itemRegister, Item.Properties properties) {
|
||||||
this.items = itemRegister;
|
this.blockItemRegister = itemRegister;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
needBuildItem = true;
|
needBuildItem = true;
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -98,11 +94,11 @@ public class BlockRegistryBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内部方法:注册对应的方块物品
|
* 内部方法:注册对应的方块物品
|
||||||
|
*
|
||||||
|
* @param blockObject the block object
|
||||||
|
* @param creativeTabs the creative tabs
|
||||||
*/
|
*/
|
||||||
@SafeVarargs
|
protected abstract void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs);
|
||||||
private void registerBlockItem(RegistryObject<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
|
|
||||||
CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册方块和物品到建筑标签页
|
* 注册方块和物品到建筑标签页
|
||||||
|
|
@ -111,9 +107,9 @@ public class BlockRegistryBuilder {
|
||||||
* @param blockSupplier the block supplier
|
* @param blockSupplier the block supplier
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
public BlockRegistryBuilder registerWithBuildingTab(DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
public BlockRegistryBuilder registerWithBuildingTab(BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
|
||||||
registerBlock(blockRegister, blockSupplier);
|
registerBlock(blockRegister, blockSupplier);
|
||||||
registerBlockItem(this.blockObject, CreativeModeTabs.BUILDING_BLOCKS);
|
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getBuildingBlocks());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,9 +120,9 @@ public class BlockRegistryBuilder {
|
||||||
* @param blockSupplier the block supplier
|
* @param blockSupplier the block supplier
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
public BlockRegistryBuilder registerWithFunctionalTab(DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
public BlockRegistryBuilder registerWithFunctionalTab(BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
|
||||||
registerBlock(blockRegister, blockSupplier);
|
registerBlock(blockRegister, blockSupplier);
|
||||||
registerBlockItem(this.blockObject, CreativeModeTabs.FUNCTIONAL_BLOCKS);
|
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getFunctionalBlocks());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,9 +131,9 @@ public class BlockRegistryBuilder {
|
||||||
*
|
*
|
||||||
* @return the registry object
|
* @return the registry object
|
||||||
*/
|
*/
|
||||||
public RegistryObject<Block> build() {
|
public Supplier<Block> build() {
|
||||||
if (needBuildItem) {
|
if (needBuildItem) {
|
||||||
items.register(this.registryName, () -> new BlockItem(this.blockObject.get(), properties == null ? new Item.Properties() : properties));
|
blockItemRegister.apply(this.registryName, () -> new BlockItem(this.blockObject.get(), properties == null ? new Item.Properties() : properties));
|
||||||
}
|
}
|
||||||
return this.blockObject;
|
return this.blockObject;
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ public abstract class EntityListResolve {
|
||||||
/**
|
/**
|
||||||
* The Result.
|
* The Result.
|
||||||
*/
|
*/
|
||||||
protected EntityListResolve.EntityResolveResult result;
|
protected EntityResolveResult result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Entity resolve result.
|
* The type Entity resolve result.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user