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
|
||||
eclipse
|
||||
run
|
||||
generated
|
||||
runs
|
||||
run-data
|
||||
|
||||
|
|
|
|||
47
README.md
47
README.md
|
|
@ -1,10 +1,14 @@
|
|||
# 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.
|
||||
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
|
||||
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
|
||||
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.
|
||||
537
build.gradle
537
build.gradle
|
|
@ -1,535 +1,4 @@
|
|||
//file:noinspection GroovyAssignabilityCheck
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'idea'
|
||||
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>
|
||||
*/
|
||||
id 'fabric-loom' version '1.9-SNAPSHOT' apply(false)
|
||||
id 'net.neoforged.moddev.legacyforge' version '2.0.103' apply(false)
|
||||
}
|
||||
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;
|
||||
|
||||
/**
|
||||
* The type Lib 39 command help manager.
|
||||
* <pre>
|
||||
* 命令帮助注册管理类
|
||||
* 这是一个模组内置的示例
|
||||
* </pre>
|
||||
*/
|
||||
public class Lib39CommandHelpManager extends SimpleCommandHelpManager {
|
||||
/**
|
||||
* The constant INSTANCE.
|
||||
* 单例模式
|
||||
*/
|
||||
public static volatile Lib39CommandHelpManager INSTANCE = new Lib39CommandHelpManager();
|
||||
/**
|
||||
* The Id.
|
||||
* 作为唯一标识符
|
||||
*/
|
||||
ResourceLocation ID = Lib39.rl("command_helper");
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 一定要在构造器方法里调用 {@link #initialize 初始化方法}
|
||||
* Instantiates a new Lib 39 command help manager.
|
||||
* </pre>
|
||||
*/
|
||||
public Lib39CommandHelpManager() {
|
||||
initialize();
|
||||
|
|
@ -6,13 +6,13 @@ import com.mojang.brigadier.arguments.IntegerArgumentType;
|
|||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.core.command.ICommandHelpManager;
|
||||
|
|
@ -21,20 +21,27 @@ import top.r3944realms.lib39.core.command.SimpleHelpCommand;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The type Lib 39 help command.
|
||||
* <pre>
|
||||
* 指令注册以及帮助编写类
|
||||
* 这是一个模组内置的示例
|
||||
* </pre>
|
||||
*/
|
||||
public class Lib39HelpCommand extends SimpleHelpCommand {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 需要{@link CommandDispatcher<CommandSourceStack> 指令注册调度器} 和 {@link CommandBuildContext 指令上下文}
|
||||
* </pre>
|
||||
* Instantiates a new Lib 39 help command.
|
||||
*
|
||||
* @param event the event
|
||||
* @param dispatcher the dispatcher
|
||||
* @param context the context
|
||||
*/
|
||||
public Lib39HelpCommand(@NotNull RegisterCommandsEvent event) {
|
||||
super(event);
|
||||
public Lib39HelpCommand(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) {
|
||||
super(dispatcher, context);
|
||||
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.world.item.Items;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
||||
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ public class Lib39RecipeProvider extends RecipeProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {
|
||||
public void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {
|
||||
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Lib39Items.DOLL.get())
|
||||
.requires(ItemTags.WOOL)
|
||||
.requires(Items.ARMOR_STAND)
|
||||
|
|
@ -3,9 +3,9 @@ package top.r3944realms.lib39.base.datagen.value;
|
|||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.content.register.Lib39Blocks;
|
||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
||||
import top.r3944realms.lib39.content.register.Lib39SoundEvents;
|
||||
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
||||
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||
import top.r3944realms.lib39.core.register.Lib39SoundEvents;
|
||||
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
||||
import top.r3944realms.lib39.datagen.value.LangKeyValue;
|
||||
import top.r3944realms.lib39.datagen.value.ModPartEnum;
|
||||
|
|
@ -15,6 +15,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The enum Lib 39 lang key.
|
||||
|
|
@ -248,6 +249,13 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
addLang(LangKeyValue.copyOf(
|
||||
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(
|
||||
"tooltip.lib39.content.doll.hover.1", ModPartEnum.DESCRIPTION,
|
||||
"§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.
|
||||
*/
|
||||
// 根命令
|
||||
public static final LangKeyValue LIB39_ROOT = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.root", ModPartEnum.MESSAGE,
|
||||
|
|
@ -330,7 +337,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_TEST.
|
||||
*/
|
||||
// 測試命令
|
||||
public static final LangKeyValue LIB39_TEST = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.test", ModPartEnum.MESSAGE,
|
||||
|
|
@ -401,7 +407,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_GREET_BASIC.
|
||||
*/
|
||||
// 問候命令
|
||||
public static final LangKeyValue LIB39_GREET_BASIC = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.greet.basic", ModPartEnum.MESSAGE,
|
||||
|
|
@ -458,7 +463,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_CALCULATE.
|
||||
*/
|
||||
// 計算命令
|
||||
public static final LangKeyValue LIB39_CALCULATE = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.calculate", ModPartEnum.MESSAGE,
|
||||
|
|
@ -487,7 +491,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_TELEPORT.
|
||||
*/
|
||||
// 傳送命令
|
||||
public static final LangKeyValue LIB39_TELEPORT = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.teleport", ModPartEnum.MESSAGE,
|
||||
|
|
@ -516,7 +519,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_INFO.
|
||||
*/
|
||||
// 信息命令
|
||||
public static final LangKeyValue LIB39_INFO = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.info", ModPartEnum.MESSAGE,
|
||||
|
|
@ -573,7 +575,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_TEAM.
|
||||
*/
|
||||
// 隊伍系統
|
||||
public static final LangKeyValue LIB39_TEAM = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.team", ModPartEnum.MESSAGE,
|
||||
|
|
@ -672,7 +673,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_GAME.
|
||||
*/
|
||||
// 遊戲系統
|
||||
public static final LangKeyValue LIB39_GAME = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"commands.lib39.game", ModPartEnum.MESSAGE,
|
||||
|
|
@ -799,7 +799,6 @@ public enum Lib39LangKey implements ILangKeyValueCollection {
|
|||
/**
|
||||
* The constant LIB39_SETTINGS.
|
||||
*/
|
||||
// 設置命令
|
||||
public static final LangKeyValue LIB39_SETTINGS = addAndRet(
|
||||
LangKeyValue.ofKey(
|
||||
"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) {
|
||||
items.add(item);
|
||||
|
|
@ -353,8 +353,8 @@ public class WheelWidget extends AbstractWidget {
|
|||
*
|
||||
* @return the section circle diameter
|
||||
*/
|
||||
// 滚轮选择器中每个扇形的圆形直径
|
||||
public float getSectionCircleDiameter() {
|
||||
// 滚轮选择器中每个扇形的圆形直径
|
||||
return this.ringOuterRadius + this.ringInnerRadius;
|
||||
}
|
||||
|
||||
|
|
@ -635,8 +635,10 @@ public class WheelWidget extends AbstractWidget {
|
|||
float pixelOuterRadius = outerRadius * guiScale;
|
||||
float pixelAntiAliasing = 2.0f * guiScale; // 抗锯齿范围
|
||||
|
||||
System.out.println("Shader Params - Center: (" + pixelCenterX + ", " + pixelCenterY +
|
||||
"), InnerRadius: " + pixelInnerRadius + ", OuterRadius: " + pixelOuterRadius);
|
||||
// if (Services.PLATFORM.isDevelopmentEnvironment()) {
|
||||
// System.out.println("Shader Params - Center: (" + pixelCenterX + ", " + pixelCenterY +
|
||||
// "), InnerRadius: " + pixelInnerRadius + ", OuterRadius: " + pixelOuterRadius);
|
||||
// }
|
||||
|
||||
ShaderInstance shader = Lib39Shaders.getRingShader();
|
||||
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.core.Direction;
|
||||
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.properties.RotationSegment;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.client.model.DollModel;
|
||||
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.util.lang.Pair;
|
||||
|
||||
|
|
@ -37,14 +41,15 @@ public class DollBlockEntityRenderer implements BlockEntityRenderer<DollBlockEnt
|
|||
@Override
|
||||
public void render(@NotNull DollBlockEntity dollBlockEntity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) {
|
||||
BlockState blockState = dollBlockEntity.getBlockState();
|
||||
if (blockState.getBlock() instanceof DollBlock) {
|
||||
Direction facing = blockState.getValue(DollBlock.FACING);
|
||||
if (blockState.getBlock() instanceof AbstractDollBlock dollBlock) {
|
||||
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();
|
||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(0.5, 1.5, 0.5);
|
||||
poseStack.scale(1.0F, -1.0F, -1.0F);
|
||||
float rotation = facing.toYRot();
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(rotation));
|
||||
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(resourceLocationBooleanPair.first));
|
||||
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.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.client.model.DollModel;
|
||||
import top.r3944realms.lib39.content.item.DollItem;
|
||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||
|
|
@ -24,15 +25,29 @@ import top.r3944realms.lib39.util.lang.Pair;
|
|||
*/
|
||||
public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
|
||||
private static DollItemRenderer instance;
|
||||
private final DollModel dollModel;
|
||||
private DollModel dollModel;
|
||||
private boolean initialized = false;
|
||||
private DollItemRenderer() {
|
||||
super(
|
||||
Minecraft.getInstance().getBlockEntityRenderDispatcher(),
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
lazyInit();
|
||||
GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
|
||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
|
||||
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.particles.ParticleTypes;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
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.block.*;
|
||||
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.StateDefinition;
|
||||
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.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
||||
import top.r3944realms.lib39.content.block.property.DollPose;
|
||||
import top.r3944realms.lib39.content.register.Lib39BlockEntities;
|
||||
import top.r3944realms.lib39.content.register.Lib39Items;
|
||||
import top.r3944realms.lib39.content.register.Lib39SoundEvents;
|
||||
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
|
||||
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||
import top.r3944realms.lib39.core.register.Lib39SoundEvents;
|
||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The type Doll block.
|
||||
* The type Abstract doll block.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class DollBlock extends HorizontalDirectionalBlock implements SimpleWaterloggedBlock, EntityBlock {
|
||||
private static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
public abstract class AbstractDollBlock extends BaseEntityBlock implements SimpleWaterloggedBlock {
|
||||
/**
|
||||
* The constant POSE.
|
||||
* The constant WATERLOGGED.
|
||||
*/
|
||||
public static final EnumProperty<DollPose> POSE = EnumProperty.create("pose", DollPose.class);
|
||||
|
||||
private static final VoxelShape DOLL_SHAPE = Block.box(2.0d, 0.0d, 2.0d, 14.0d, 12.0d, 14.0d);
|
||||
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
private static final Properties properties = Properties.of()
|
||||
.instrument(NoteBlockInstrument.BASEDRUM)
|
||||
.sound(SoundType.WOOL)
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
.strength(0f, 10f)
|
||||
.noOcclusion();
|
||||
|
||||
private static final double PARTICLE_OFFSET_RANGE = 0.25;
|
||||
private static final double PARTICLE_HEIGHT_OFFSET = 1.0;
|
||||
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 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() {
|
||||
super(properties);
|
||||
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.SOUTH)
|
||||
.setValue(POSE, DollPose.DEFAULT)
|
||||
.setValue(WATERLOGGED, false));
|
||||
}
|
||||
public static final EnumProperty<DollPose> POSE = EnumProperty.create("pose", DollPose.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract doll block.
|
||||
*/
|
||||
public AbstractDollBlock() {
|
||||
super(properties);
|
||||
}
|
||||
@Override
|
||||
public boolean canBeReplaced(@NotNull BlockState state, @NotNull BlockPlaceContext useContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PushReaction getPistonPushReaction(BlockState state) {
|
||||
return PushReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState updateShape(@NotNull BlockState currentState, @NotNull Direction direction, @NotNull BlockState neighborState,
|
||||
@NotNull LevelAccessor level, @NotNull BlockPos currentPos, @NotNull BlockPos neighborPos) {
|
||||
|
|
@ -118,7 +110,6 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
|||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在玩偶位置生成音符粒子效果
|
||||
*/
|
||||
|
|
@ -158,26 +149,13 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
|||
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
|
||||
public @NotNull VoxelShape getShape(@NotNull BlockState blockState, @NotNull BlockGetter level, @NotNull BlockPos blockPos, @NotNull CollisionContext context) {
|
||||
return DOLL_SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.@NotNull Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(FACING, WATERLOGGED, POSE);
|
||||
public @NotNull VoxelShape getOcclusionShape(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos) {
|
||||
return Shapes.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -193,9 +171,8 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
|||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos, Player player) {
|
||||
ItemStack stack = super.getCloneItemStack(state, target, level, pos, player);
|
||||
|
||||
public @NotNull ItemStack getCloneItemStack(@NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state) {
|
||||
ItemStack stack = super.getCloneItemStack(level, pos, state);
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (blockEntity instanceof DollBlockEntity doll) {
|
||||
GameProfile profile = doll.getOwnerProfile();
|
||||
|
|
@ -222,6 +199,12 @@ public class DollBlock extends HorizontalDirectionalBlock implements SimpleWater
|
|||
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.state.BlockState;
|
||||
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.nbt.NBTReader;
|
||||
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
||||
|
|
@ -1,51 +1,34 @@
|
|||
package top.r3944realms.lib39.content.item;
|
||||
|
||||
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.world.entity.Entity;
|
||||
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.StandingAndWallBlockItem;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
|
||||
import top.r3944realms.lib39.content.register.Lib39Blocks;
|
||||
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The type Doll item.
|
||||
*/
|
||||
public class DollItem extends BlockItem {
|
||||
public class DollItem extends StandingAndWallBlockItem implements Equipable {
|
||||
/**
|
||||
* Instantiates a new Doll item.
|
||||
*
|
||||
* @param properties the 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
|
||||
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"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull EquipmentSlot getEquipmentSlot() {
|
||||
return EquipmentSlot.HEAD;
|
||||
}
|
||||
}
|
||||
|
|
@ -483,6 +483,7 @@ public interface ICommandHelpManager {
|
|||
/**
|
||||
* 获取命令树的字符串表示
|
||||
*
|
||||
* @param commandSourceStack the command source stack
|
||||
* @return 命令树列表 command tree
|
||||
*/
|
||||
default List<MutableComponent> getCommandTree(CommandSourceStack commandSourceStack) {
|
||||
|
|
@ -537,6 +538,7 @@ public interface ICommandHelpManager {
|
|||
/**
|
||||
* Build command tree help mutable component.
|
||||
*
|
||||
* @param commandSourceStack the command source stack
|
||||
* @return the mutable component
|
||||
*/
|
||||
default MutableComponent buildCommandTreeHelp(CommandSourceStack commandSourceStack) {
|
||||
|
|
@ -9,10 +9,9 @@ import net.minecraft.commands.CommandSourceStack;
|
|||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.api.event.RegisterCommandHelpEvent;
|
||||
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
|
||||
import top.r3944realms.lib39.platform.Services;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
|
@ -63,8 +62,7 @@ public interface IHelpCommand {
|
|||
.then(Commands.literal("toggle")
|
||||
.then(Commands.argument("hash", IntegerArgumentType.integer()).executes(this::handleHelpToggle))
|
||||
));
|
||||
RegisterCommandHelpEvent registerHelpCommandEvent = new RegisterCommandHelpEvent(tree, getCommandHelpManager(), context);
|
||||
MinecraftForge.EVENT_BUS.post(registerHelpCommandEvent);
|
||||
Services.PLATFORM.getHelpCommandHook().onRegister(tree, getCommandHelpManager(), context);
|
||||
dispatcher.register(head);
|
||||
return head;
|
||||
}
|
||||
|
|
@ -4,8 +4,6 @@ import com.mojang.brigadier.CommandDispatcher;
|
|||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The type Simple help command.
|
||||
|
|
@ -17,15 +15,9 @@ public abstract class SimpleHelpCommand implements IHelpCommand {
|
|||
protected final LiteralArgumentBuilder<CommandSourceStack> root;
|
||||
|
||||
/**
|
||||
* Instantiates a new Simple help command.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
public SimpleHelpCommand(@NotNull RegisterCommandsEvent event) {
|
||||
root = buildCommand(event.getDispatcher(), event.getBuildContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 需要{@link CommandDispatcher<CommandSourceStack> 指令注册调度器} 和 {@link CommandBuildContext 指令上下文}
|
||||
* </pre>
|
||||
* Instantiates a new Simple help command.
|
||||
*
|
||||
* @param dispatcher the dispatcher
|
||||
|
|
@ -35,9 +35,16 @@ public class CommandNode {
|
|||
// 展开/闭合状态
|
||||
private boolean expanded = true;
|
||||
|
||||
/**
|
||||
* Test permission boolean.
|
||||
*
|
||||
* @param source the source
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean testPermission(CommandSourceStack source) {
|
||||
return testPermission.test(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
|
@ -9,8 +8,20 @@ import java.util.concurrent.Callable;
|
|||
* The interface Compat.
|
||||
*/
|
||||
public interface ICompat {
|
||||
/**
|
||||
* Sets initialize.
|
||||
*
|
||||
* @param initialize the initialize
|
||||
*/
|
||||
void setInitialize(boolean initialize);
|
||||
|
||||
/**
|
||||
* Is initialized boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Id resource location.
|
||||
*
|
||||
|
|
@ -75,58 +86,4 @@ public interface ICompat {
|
|||
if (isModLoaded()) runnable.run(); else return false;
|
||||
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 {
|
||||
static {
|
||||
System.loadLibrary("ClassEncrypt");
|
||||
// System.loadLibrary("ClassEncrypt");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -13,7 +13,7 @@ import java.util.Map;
|
|||
*/
|
||||
public class EncryptedClassLoader extends ClassLoader {
|
||||
static {
|
||||
System.loadLibrary("ClassEncrypt");
|
||||
// System.loadLibrary("ClassEncrypt");
|
||||
}
|
||||
|
||||
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.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
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.
|
||||
*/
|
||||
|
|
@ -52,8 +49,13 @@ public abstract class NBTEntitySyncData implements IEntity, ISyncData<NBTEntityS
|
|||
@Override
|
||||
public void checkIfDirtyThenUpdate() {
|
||||
if (isDirty()) {
|
||||
NetworkHandler.sendToAllPlayer(new SyncNBTCapDataEntityS2CPack(entityId(), id(), serializeNBT()));
|
||||
update();
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTEntitySyncData getSyncData() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package top.r3944realms.lib39.core.sync;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
|
@ -13,10 +12,17 @@ import java.util.function.Function;
|
|||
|
||||
/**
|
||||
* The type Sync data 2 manager.
|
||||
*
|
||||
* @param <V> the type parameter
|
||||
*/
|
||||
@SuppressWarnings({"unused", "DuplicatedCode"})
|
||||
public class SyncData2Manager {
|
||||
private final Map<ResourceLocation, TypedSyncEntry<?, ?>> typedEntries = Maps.newConcurrentMap();
|
||||
public abstract class SyncData2Manager<V extends SyncData2Manager.TypedSyncEntry<?, ?>> {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
@ -56,7 +68,7 @@ public class SyncData2Manager {
|
|||
* @param manager the manager
|
||||
* @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.dataProvider = dataProvider;
|
||||
this.allowedClasses = Sets.newConcurrentHashSet();
|
||||
|
|
@ -72,6 +84,7 @@ public class SyncData2Manager {
|
|||
* @param manager the manager
|
||||
* @param dataProvider the data provider
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K, T extends ISyncData<?>> void registerManagerWithProvider(
|
||||
ResourceLocation key,
|
||||
ISyncManager<K, T> manager,
|
||||
|
|
@ -81,7 +94,7 @@ public class SyncData2Manager {
|
|||
Objects.requireNonNull(manager, "Sync manager 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 getter the data getter function
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K, T extends ISyncData<?>> void registerManager(
|
||||
ResourceLocation key,
|
||||
ISyncManager<K, T> manager,
|
||||
|
|
@ -102,7 +116,7 @@ public class SyncData2Manager {
|
|||
Objects.requireNonNull(manager, "Sync manager 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");
|
||||
|
||||
// 创建一个没有数据提供者的 TypedSyncEntry
|
||||
typedEntries.put(key, new TypedSyncEntry<>(
|
||||
getTypedEntries().put(key, (V) new TypedSyncEntry<>(
|
||||
(ISyncManager<?, ISyncData<?>>) manager,
|
||||
null
|
||||
));
|
||||
|
|
@ -133,7 +147,7 @@ public class SyncData2Manager {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +160,7 @@ public class SyncData2Manager {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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) {
|
||||
return Optional.of((DataProvider<Entity, T>) entry.dataProvider);
|
||||
}
|
||||
|
|
@ -184,7 +198,7 @@ public class SyncData2Manager {
|
|||
return;
|
||||
}
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||
if (entry != null) {
|
||||
entry.allowedClasses.addAll(Arrays.asList(classes));
|
||||
}
|
||||
|
|
@ -200,7 +214,7 @@ public class SyncData2Manager {
|
|||
Objects.requireNonNull(key, "ResourceLocation key 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) {
|
||||
Arrays.asList(classes).forEach(entry.allowedClasses::remove);
|
||||
}
|
||||
|
|
@ -217,7 +231,7 @@ public class SyncData2Manager {
|
|||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(dataProvider, "Data provider cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||
if (entry != null) {
|
||||
// 更新现有条目的数据提供者
|
||||
updateDataProviderInEntry(key, entry, dataProvider);
|
||||
|
|
@ -233,7 +247,7 @@ public class SyncData2Manager {
|
|||
* @param key the key
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +259,7 @@ public class SyncData2Manager {
|
|||
public void unbindDataProvider(ResourceLocation key) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||
if (entry != null) {
|
||||
// 将数据提供者设置为null,但保留管理器和其他配置
|
||||
updateDataProviderInEntry(key, entry, null);
|
||||
|
|
@ -260,7 +274,7 @@ public class SyncData2Manager {
|
|||
public void clearAllowedEntityClasses(ResourceLocation key) {
|
||||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||
if (entry != null) {
|
||||
entry.allowedClasses.clear();
|
||||
}
|
||||
|
|
@ -277,19 +291,17 @@ public class SyncData2Manager {
|
|||
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
|
||||
Objects.requireNonNull(entityClass, "Entity class cannot be null");
|
||||
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(key);
|
||||
if (entry == null) {
|
||||
return false;
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(key);
|
||||
boolean isAllowed = false;
|
||||
if (entry != null) {
|
||||
for (Class<?> allowedClass : entry.allowedClasses) {
|
||||
if (allowedClass.isAssignableFrom(entityClass)) {
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有设置允许的类,则默认允许所有类
|
||||
if (entry.allowedClasses.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查实体类是否在允许的类中
|
||||
return entry.allowedClasses.stream()
|
||||
.anyMatch(allowedClass -> allowedClass.isAssignableFrom(entityClass));
|
||||
return entry != null && isAllowed ;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -300,7 +312,7 @@ public class SyncData2Manager {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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) {
|
||||
trackEntityWithTypedEntry(entity, entry);
|
||||
}
|
||||
|
|
@ -321,7 +333,7 @@ public class SyncData2Manager {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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) {
|
||||
untrackEntityWithTypedEntry(entity, entry);
|
||||
}
|
||||
|
|
@ -376,7 +388,7 @@ public class SyncData2Manager {
|
|||
* @param managerId the manager id
|
||||
*/
|
||||
public void clearAllTrackedData(ResourceLocation managerId) {
|
||||
TypedSyncEntry<?, ?> entry = typedEntries.get(managerId);
|
||||
TypedSyncEntry<?, ?> entry = getTypedEntries().get(managerId);
|
||||
if (entry != null) {
|
||||
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")
|
||||
private <K, T extends ISyncData<?>> void updateDataProviderInEntry(
|
||||
protected <K, T extends ISyncData<?>> void updateDataProviderInEntry(
|
||||
ResourceLocation id,
|
||||
TypedSyncEntry<?,?> entry,
|
||||
DataProvider<Entity, T> newDataProvider
|
||||
|
|
@ -412,7 +433,7 @@ public class SyncData2Manager {
|
|||
);
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
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
|
||||
*/
|
||||
public int getManagerCount() {
|
||||
return typedEntries.size();
|
||||
return getTypedEntries().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all.
|
||||
*/
|
||||
public void clearAll() {
|
||||
typedEntries.clear();
|
||||
getTypedEntries().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -457,6 +478,6 @@ public class SyncData2Manager {
|
|||
*/
|
||||
public void removeManager(ResourceLocation key) {
|
||||
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;
|
||||
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraftforge.common.data.LanguageProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.datagen.value.ILangKeyValue;
|
||||
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
||||
import top.r3944realms.lib39.datagen.value.McLocale;
|
||||
|
|
@ -98,7 +98,7 @@ public class SimpleLanguageProvider extends LanguageProvider {
|
|||
.filter(translationMap::containsKey)
|
||||
.count();
|
||||
|
||||
LOGGER.info("Added {}/{} translations for {}",
|
||||
Lib39.LOGGER.info("Added {}/{} translations for {}",
|
||||
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.joml.Vector2f;
|
||||
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.Pair;
|
||||
|
||||
|
|
@ -114,7 +115,7 @@ public class ForgeScreen extends Screen {
|
|||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
|
||||
|
||||
/**
|
||||
|
|
@ -8,6 +10,27 @@ import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
|
|||
*/
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
*
|
||||
|
|
@ -22,105 +45,157 @@ public abstract class AbstractedTestSyncData extends NBTEntitySyncData {
|
|||
*
|
||||
* @return the test string
|
||||
*/
|
||||
abstract String getTestString();
|
||||
public abstract String getTestString();
|
||||
|
||||
/**
|
||||
* Sets test string.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
abstract void setTestString(String value);
|
||||
public abstract void setTestString(String value);
|
||||
|
||||
/**
|
||||
* Gets test int.
|
||||
*
|
||||
* @return the test int
|
||||
*/
|
||||
abstract int getTestInt();
|
||||
public abstract int getTestInt();
|
||||
|
||||
/**
|
||||
* Sets test int.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
abstract void setTestInt(int value);
|
||||
public abstract void setTestInt(int value);
|
||||
|
||||
/**
|
||||
* Is test boolean boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
abstract boolean isTestBoolean();
|
||||
public abstract boolean isTestBoolean();
|
||||
|
||||
/**
|
||||
* Sets test boolean.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
abstract void setTestBoolean(boolean value);
|
||||
public abstract void setTestBoolean(boolean value);
|
||||
|
||||
/**
|
||||
* Gets test double.
|
||||
*
|
||||
* @return the test double
|
||||
*/
|
||||
abstract double getTestDouble();
|
||||
public abstract double getTestDouble();
|
||||
|
||||
/**
|
||||
* Sets test double.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
abstract void setTestDouble(double value);
|
||||
public abstract void setTestDouble(double value);
|
||||
|
||||
/**
|
||||
* Gets counter.
|
||||
*
|
||||
* @return the counter
|
||||
*/
|
||||
// 计数器,用于测试数据变化
|
||||
abstract int getCounter();
|
||||
public abstract int getCounter();
|
||||
|
||||
/**
|
||||
* Increment counter.
|
||||
*/
|
||||
abstract void incrementCounter();
|
||||
public abstract void incrementCounter();
|
||||
|
||||
/**
|
||||
* Clear counter.
|
||||
*/
|
||||
public abstract void clearCounter();
|
||||
|
||||
/**
|
||||
* Gets last sync time.
|
||||
*
|
||||
* @return the last sync time
|
||||
*/
|
||||
// 时间戳,用于测试同步时机
|
||||
abstract long getLastSyncTime();
|
||||
public abstract long getLastSyncTime();
|
||||
|
||||
/**
|
||||
* Update sync time.
|
||||
*/
|
||||
abstract void updateSyncTime();
|
||||
public abstract void updateSyncTime();
|
||||
|
||||
/**
|
||||
* Clear sync time.
|
||||
*/
|
||||
public abstract void clearSyncTime();
|
||||
|
||||
/**
|
||||
* Gets custom data.
|
||||
*
|
||||
* @return the custom data
|
||||
*/
|
||||
// 自定义对象测试
|
||||
abstract TestData getCustomData();
|
||||
public abstract TestData getCustomData();
|
||||
|
||||
/**
|
||||
* Sets custom data.
|
||||
*
|
||||
* @param data the data
|
||||
*/
|
||||
abstract void setCustomData(TestData data);
|
||||
public abstract void setCustomData(TestData data);
|
||||
|
||||
/**
|
||||
* Validate data boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
// 验证数据完整性
|
||||
abstract boolean validateData();
|
||||
public 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
|
||||
*/
|
||||
// getters and setters
|
||||
public String getName() { return name; }
|
||||
|
||||
/**
|
||||
|
|
@ -17,11 +17,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.example.content.capability.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 top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
|
@ -31,14 +27,14 @@ import java.util.concurrent.CompletableFuture;
|
|||
* Shift + 右键:客户端与服务器双端同时查询检查同步
|
||||
* 普通右键:单端查询目标生物数据
|
||||
*/
|
||||
public class FabricItem extends Item {
|
||||
public abstract class AbstractFabricItem extends Item {
|
||||
|
||||
/**
|
||||
* Instantiates a new Fabric item.
|
||||
*
|
||||
* @param properties the properties
|
||||
*/
|
||||
public FabricItem(Properties properties) {
|
||||
public AbstractFabricItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +78,7 @@ public class FabricItem extends Item {
|
|||
|
||||
if (targetEntity instanceof LivingEntity livingTarget) {
|
||||
// 在客户端获取本地数据
|
||||
TestSyncData clientData = getLocalClientData(livingTarget);
|
||||
AbstractedTestSyncData clientData = getLocalClientData(livingTarget);
|
||||
|
||||
if (clientData != null) {
|
||||
// 发送客户端数据到服务器
|
||||
|
|
@ -107,7 +103,7 @@ public class FabricItem extends Item {
|
|||
*/
|
||||
private void handlePlayerSelfData(Player player) {
|
||||
// 获取玩家自身的客户端数据
|
||||
TestSyncData clientData = getLocalClientData(player);
|
||||
AbstractedTestSyncData clientData = getLocalClientData(player);
|
||||
|
||||
if (clientData != null) {
|
||||
// 发送玩家自身数据到服务器
|
||||
|
|
@ -126,7 +122,7 @@ public class FabricItem extends Item {
|
|||
Entity targetEntity = getClientTargetedEntity(player);
|
||||
|
||||
if (targetEntity instanceof LivingEntity livingTarget) {
|
||||
TestSyncData clientData = getLocalClientData(livingTarget);
|
||||
AbstractedTestSyncData clientData = getLocalClientData(livingTarget);
|
||||
|
||||
if (clientData != null) {
|
||||
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 {
|
||||
AbstractedTestSyncData abstractData = target.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null);
|
||||
if (abstractData instanceof TestSyncData) {
|
||||
return (TestSyncData) abstractData;
|
||||
}
|
||||
return getData(target);
|
||||
} catch (Exception 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 targetEntityId the target entity id
|
||||
*/
|
||||
public static void handleClientDataFromPacket(@NotNull ServerPlayer player, TestSyncData 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;
|
||||
}
|
||||
protected abstract void sendClientDataToServer(AbstractedTestSyncData clientData, int targetEntityId);
|
||||
|
||||
/**
|
||||
* 启动服务器单端查询
|
||||
|
|
@ -255,9 +219,9 @@ public class FabricItem extends Item {
|
|||
// 获取目标生物的数据
|
||||
AbstractedTestSyncData abstractData = getTestSyncData(target);
|
||||
|
||||
if (abstractData instanceof TestSyncData testData) {
|
||||
if (abstractData != null) {
|
||||
// 显示详细数据
|
||||
displayServerDetailedData(player, target, testData);
|
||||
displayServerDetailedData(player, target, abstractData);
|
||||
} else {
|
||||
player.sendSystemMessage(Component.literal(
|
||||
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("§7目标生物: §e" + target.getName().getString()));
|
||||
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(
|
||||
String.format("§7目标生物: §e%s", target.getName().getString())
|
||||
|
|
@ -324,7 +288,7 @@ public class FabricItem extends Item {
|
|||
player.sendSystemMessage(Component.literal(""));
|
||||
|
||||
// 显示自定义数据
|
||||
TestSyncData.TestData customData = testData.getCustomData();
|
||||
AbstractedTestSyncData.TestData customData = testData.getCustomData();
|
||||
player.sendSystemMessage(Component.literal("§a自定义数据:"));
|
||||
player.sendSystemMessage(Component.literal(
|
||||
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(
|
||||
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()) &&
|
||||
first.getValue() == second.getValue() &&
|
||||
first.isFlag() == second.isFlag();
|
||||
|
|
@ -552,7 +521,7 @@ public class FabricItem extends Item {
|
|||
*/
|
||||
private AbstractedTestSyncData getTestSyncData(Entity entity) {
|
||||
try {
|
||||
return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElse(null);
|
||||
return getData(entity);
|
||||
} catch (Exception e) {
|
||||
Lib39.LOGGER.debug("[FabricItem] 获取生物 {} 的 TestSyncData 失败: {}",
|
||||
entity.getName().getString(), e.getMessage());
|
||||
|
|
@ -17,9 +17,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.lib39.Lib39;
|
||||
import top.r3944realms.lib39.example.content.capability.AbstractedTestSyncData;
|
||||
import top.r3944realms.lib39.example.content.capability.ExCapabilityHandler;
|
||||
import top.r3944realms.lib39.example.content.capability.TestSyncData;
|
||||
import top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
|
@ -29,7 +27,7 @@ import java.util.Random;
|
|||
* Shift + 右键:操作自己的数据
|
||||
* 普通右键:操作瞄准生物的数据
|
||||
*/
|
||||
public class NeoForgeItem extends Item {
|
||||
public abstract class AbstractNeoForgeItem extends Item {
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
/**
|
||||
|
|
@ -37,7 +35,7 @@ public class NeoForgeItem extends Item {
|
|||
*
|
||||
* @param properties the properties
|
||||
*/
|
||||
public NeoForgeItem(Properties properties) {
|
||||
public AbstractNeoForgeItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
|
|
@ -139,10 +137,8 @@ public class NeoForgeItem extends Item {
|
|||
*/
|
||||
private boolean triggerRandomTransformation(LivingEntity entity) {
|
||||
try {
|
||||
AbstractedTestSyncData abstractData = getOrCreateTestSyncData(entity);
|
||||
if (!(abstractData instanceof TestSyncData testData)) {
|
||||
return false;
|
||||
}
|
||||
AbstractedTestSyncData testData = getOrCreateTestSyncData(entity);
|
||||
|
||||
|
||||
// 随机选择一种变换方式
|
||||
int transformationType = RANDOM.nextInt(6); // 增加更多变换类型
|
||||
|
|
@ -170,7 +166,7 @@ public class NeoForgeItem extends Item {
|
|||
}
|
||||
case 3 -> {
|
||||
// 修改自定义数据
|
||||
TestSyncData.TestData newCustomData = new TestSyncData.TestData(
|
||||
AbstractedTestSyncData.TestData newCustomData = new AbstractedTestSyncData.TestData(
|
||||
"custom_" + RANDOM.nextInt(100),
|
||||
RANDOM.nextInt(500),
|
||||
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(
|
||||
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 {
|
||||
return entity.getCapability(ExCapabilityHandler.TEST_CAP).resolve().orElseThrow();
|
||||
return getData(entity);
|
||||
} catch (Exception e) {
|
||||
Lib39.LOGGER.error("[NeoForgeItem] 获取 {} 的 TestSyncData 失败: {}",
|
||||
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.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.lib39.example.client.screen.ForgeScreen;
|
||||
import top.r3944realms.lib39.util.IClientOnly;
|
||||
|
||||
/**
|
||||
* The type Forge item.
|
||||
|
|
@ -28,13 +27,17 @@ public class ForgeItem extends Item {
|
|||
@Override
|
||||
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level level, @NotNull Player player, @NotNull InteractionHand usedHand) {
|
||||
if (level.isClientSide() && usedHand == InteractionHand.MAIN_HAND) {
|
||||
clientUse(usedHand);
|
||||
ClientOpt.clientUse(usedHand);
|
||||
}
|
||||
return super.use(level, player, usedHand);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static void clientUse(@NotNull InteractionHand usedHand) {
|
||||
Minecraft.getInstance().setScreen(new ForgeScreen(usedHand, 0));
|
||||
}
|
||||
/**
|
||||
* The type Client opt.
|
||||
*/
|
||||
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.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Debug;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Pseudo;
|
||||
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.world.entity.player.Player;
|
||||
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.Nullable;
|
||||
import top.r3944realms.lib39.util.nbt.NBTReader;
|
||||
|
|
@ -30,6 +28,74 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
* The type GameProfile helper.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
@ -39,32 +105,25 @@ public class GameProfileHelper {
|
|||
*/
|
||||
public static final String TAG_OWN_PROFILE = "OwnerProfile";
|
||||
|
||||
|
||||
/**
|
||||
* Gets skin texture.
|
||||
*
|
||||
* @param gameProfile the game profile
|
||||
* @return the skin texture
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
|
||||
if (gameProfile == null) {
|
||||
return DefaultPlayerSkin.getDefaultSkin();
|
||||
}
|
||||
return resolveSkinTexture(gameProfile);
|
||||
return ClientOpt.getSkinTexture(gameProfile);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve skin texture resource location.
|
||||
*
|
||||
* @param gameProfile the game profile
|
||||
* @return the resource location
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
return minecraft.getSkinManager()
|
||||
.getInsecureSkinLocation(gameProfile);
|
||||
return ClientOpt.resolveSkinTexture(gameProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,7 +132,6 @@ public class GameProfileHelper {
|
|||
* @param player the player
|
||||
* @return the boolean
|
||||
*/
|
||||
// 判断玩家是否使用纤细手臂
|
||||
public static boolean hasSlimArms(@NotNull Player player) {
|
||||
if (player.level().isClientSide) {
|
||||
return hasSlimArmsClient(player);
|
||||
|
|
@ -82,16 +140,9 @@ public class GameProfileHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// 客户端判断
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
||||
private static boolean hasSlimArmsClient(Player player) {
|
||||
if (player instanceof AbstractClientPlayer clientPlayer) {
|
||||
PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
|
||||
.getConnection())
|
||||
.getPlayerInfo(clientPlayer.getUUID());
|
||||
return playerInfo != null && "slim".equals(playerInfo.getModelName());
|
||||
}
|
||||
return false;
|
||||
return ClientOpt.hasSlimArmsClient(player);
|
||||
}
|
||||
|
||||
// 服务器端判断
|
||||
|
|
@ -123,15 +174,8 @@ public class GameProfileHelper {
|
|||
* @param player the player
|
||||
* @return the skin model name
|
||||
*/
|
||||
// 获取皮肤模型名称
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static @NotNull String getSkinModelName(@NotNull Player player) {
|
||||
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";
|
||||
return ClientOpt.getSkinModelName(player);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -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;
|
||||
|
||||
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.Nullable;
|
||||
|
||||
|
|
@ -66,7 +64,6 @@ public interface ILevelHelper {
|
|||
* @return the client level
|
||||
*/
|
||||
@Nullable
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static Level getClientLevel() {
|
||||
return LevelHelper.CLIENT.getLevel();
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
|||
* <p><b>重要:</b>由于使用了 weakValues(),实现类必须被其他对象强引用,
|
||||
* 否则会被 GC 清理导致锁自动释放。通常这意味着将实现类实例存储在
|
||||
* 适当的管理器或容器中。
|
||||
*
|
||||
* @author sch246
|
||||
*/
|
||||
public interface IUniPosOwner {
|
||||
|
|
@ -67,8 +68,7 @@ public interface IUniPosOwner {
|
|||
*
|
||||
* @param level 维度 The level (dimension) of the position.
|
||||
* @param pos 坐标 The position to lock.
|
||||
* @return true if ownership was successfully claimed or was already held by this object,
|
||||
* false if the position is owned by another object.
|
||||
* @return true if ownership was successfully claimed or was already held by this object, false if the position is owned by another object.
|
||||
*/
|
||||
default boolean tryLock(Level level, BlockPos pos) {
|
||||
return UniPosManager.INSTANCE.tryLock(level, pos, this);
|
||||
|
|
@ -88,6 +88,7 @@ public interface IUniPosOwner {
|
|||
|
||||
/**
|
||||
* 续租,继续持有锁
|
||||
*
|
||||
* @param level 维度
|
||||
* @param pos 位置
|
||||
*/
|
||||
|
|
@ -97,16 +98,19 @@ public interface IUniPosOwner {
|
|||
}
|
||||
|
||||
/**
|
||||
管理 IUniPosOwner 系统的单例存储。
|
||||
该类是后台实现,大多数类不应直接使用。
|
||||
在同一维度键(ResourceKey<Level)范围内,确保任意时刻一个 BlockPos 只能被一个对象“拥有”。
|
||||
注意:锁的作用域是维度键级别,因此在服务端同一维度的不同 Level 实例之间共享。
|
||||
缓存以 BlockPos 的 long 值为键,以 IUniPosOwner 的弱值(weak values)为值;
|
||||
当所有者不再被强引用时,条目会自动移除,从而释放锁。
|
||||
该实现面向服务端使用。
|
||||
* 管理 IUniPosOwner 系统的单例存储。
|
||||
* 该类是后台实现,大多数类不应直接使用。
|
||||
* 在同一维度键(ResourceKey<Level)范围内,确保任意时刻一个 BlockPos 只能被一个对象“拥有”。
|
||||
* 注意:锁的作用域是维度键级别,因此在服务端同一维度的不同 Level 实例之间共享。
|
||||
* 缓存以 BlockPos 的 long 值为键,以 IUniPosOwner 的弱值(weak values)为值;
|
||||
* 当所有者不再被强引用时,条目会自动移除,从而释放锁。
|
||||
* 该实现面向服务端使用。
|
||||
*/
|
||||
final class UniPosManager {
|
||||
|
||||
/**
|
||||
* The constant INSTANCE.
|
||||
*/
|
||||
public static final UniPosManager INSTANCE = new UniPosManager();
|
||||
|
||||
// 顶层映射:维度键(ResourceKey<Level>) -> 每维度的坐标缓存。
|
||||
|
|
@ -139,7 +143,7 @@ final class UniPosManager {
|
|||
*
|
||||
* @param level 维度
|
||||
* @param pos 坐标
|
||||
* @return 如果存在所有者,则返回所有者对象;否则返回 null。
|
||||
* @return 如果存在所有者 ,则返回所有者对象;否则返回 null。
|
||||
*/
|
||||
@Nullable
|
||||
public IUniPosOwner getOwner(Level level, BlockPos pos) {
|
||||
|
|
@ -182,6 +186,7 @@ final class UniPosManager {
|
|||
|
||||
/**
|
||||
* 续租,继续持有锁
|
||||
*
|
||||
* @param level 维度
|
||||
* @param pos 位置
|
||||
* @param owner 对象
|
||||
|
|
@ -1,39 +1,35 @@
|
|||
package top.r3944realms.lib39.util.block;
|
||||
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.CreativeModeTabs;
|
||||
import net.minecraft.world.item.Item;
|
||||
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 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;
|
||||
|
||||
/**
|
||||
* The type Block registry builder.
|
||||
*/
|
||||
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||
public class BlockRegistryBuilder {
|
||||
public abstract class BlockRegistryBuilder {
|
||||
private String registryName;
|
||||
private RegistryObject<Block> blockObject;
|
||||
private DeferredRegister<Item> items;
|
||||
private Supplier<Block> blockObject;
|
||||
private BiFunction<String, Supplier<Item>, Supplier<Item>> blockItemRegister;
|
||||
private boolean needBuildItem;
|
||||
private Item.Properties properties;
|
||||
|
||||
/**
|
||||
* 创建新的构建器实例
|
||||
* Create block registry builder.
|
||||
*
|
||||
* @return the block registry builder
|
||||
*/
|
||||
@Contract(value = " -> new", pure = true)
|
||||
public static @NotNull BlockRegistryBuilder create() {
|
||||
return new BlockRegistryBuilder();
|
||||
public static BlockRegistryBuilder create() {
|
||||
return Services.PLATFORM.getUtilHelper().getBlockRegistryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -54,8 +50,8 @@ public class BlockRegistryBuilder {
|
|||
* @param blockSupplier the block supplier
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerBlock(@NotNull DeferredRegister<Block> blockRegister, Supplier<? extends Block> blockSupplier) {
|
||||
this.blockObject = blockRegister.register(this.registryName, blockSupplier);
|
||||
public BlockRegistryBuilder registerBlock(@NotNull BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
|
||||
this.blockObject = blockRegister.apply(this.registryName, blockSupplier);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -65,8 +61,8 @@ public class BlockRegistryBuilder {
|
|||
* @param itemRegister the item deferred register
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerItem(DeferredRegister<Item> itemRegister) {
|
||||
this.items = itemRegister;
|
||||
public BlockRegistryBuilder registerItem(BiFunction<String, Supplier<Item>,Supplier<Item>> itemRegister) {
|
||||
this.blockItemRegister = itemRegister;
|
||||
needBuildItem = true;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -78,8 +74,8 @@ public class BlockRegistryBuilder {
|
|||
* @param properties the item properties
|
||||
* @return the block registry builder
|
||||
*/
|
||||
public BlockRegistryBuilder registerItemWithProperties(DeferredRegister<Item> itemRegister, Item.Properties properties) {
|
||||
this.items = itemRegister;
|
||||
public BlockRegistryBuilder registerItemWithProperties(BiFunction<String, Supplier<Item>,Supplier<Item>> itemRegister, Item.Properties properties) {
|
||||
this.blockItemRegister = itemRegister;
|
||||
this.properties = properties;
|
||||
needBuildItem = true;
|
||||
return this;
|
||||
|
|
@ -98,11 +94,11 @@ public class BlockRegistryBuilder {
|
|||
|
||||
/**
|
||||
* 内部方法:注册对应的方块物品
|
||||
*
|
||||
* @param blockObject the block object
|
||||
* @param creativeTabs the creative tabs
|
||||
*/
|
||||
@SafeVarargs
|
||||
private void registerBlockItem(RegistryObject<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
|
||||
CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs);
|
||||
}
|
||||
protected abstract void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs);
|
||||
|
||||
/**
|
||||
* 注册方块和物品到建筑标签页
|
||||
|
|
@ -111,9 +107,9 @@ public class BlockRegistryBuilder {
|
|||
* @param blockSupplier the block supplier
|
||||
* @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);
|
||||
registerBlockItem(this.blockObject, CreativeModeTabs.BUILDING_BLOCKS);
|
||||
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getBuildingBlocks());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -124,9 +120,9 @@ public class BlockRegistryBuilder {
|
|||
* @param blockSupplier the block supplier
|
||||
* @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);
|
||||
registerBlockItem(this.blockObject, CreativeModeTabs.FUNCTIONAL_BLOCKS);
|
||||
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getFunctionalBlocks());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -135,9 +131,9 @@ public class BlockRegistryBuilder {
|
|||
*
|
||||
* @return the registry object
|
||||
*/
|
||||
public RegistryObject<Block> build() {
|
||||
public Supplier<Block> build() {
|
||||
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;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public abstract class EntityListResolve {
|
|||
/**
|
||||
* The Result.
|
||||
*/
|
||||
protected EntityListResolve.EntityResolveResult result;
|
||||
protected EntityResolveResult 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