mirror of
https://github.com/CPTProgrammer/ChatPlus.git
synced 2026-09-22 00:23:36 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6f91ae87f | ||
|
|
1ae838b4e9 | ||
|
|
43e582fbe6 | ||
|
|
edaf3115bb | ||
|
|
11e09bf0fb | ||
|
|
aaf4b64e6e | ||
|
|
1494ae1e2e | ||
|
|
74b909fe84 | ||
|
|
36a7c48531 | ||
|
|
a9e4fb14b8 | ||
|
|
3b9e607f24 | ||
|
|
09dcc04430 | ||
|
|
888b801ac7 | ||
|
|
84b925d05c | ||
|
|
f02b2acde5 | ||
|
|
e43426128a | ||
|
|
bcd52a866f | ||
|
|
be8e0d1cab | ||
|
|
2c6471a8c0 | ||
|
|
8bf4a7bb7a | ||
|
|
bfe8ae0328 | ||
|
|
d5f37d5e07 | ||
|
|
7ccb661fbd | ||
|
|
f76b670fdc | ||
|
|
1cd925f192 | ||
|
|
6a84f79d69 | ||
|
|
a94415e427 | ||
|
|
ed5e4a7ea7 | ||
|
|
642c890c58 | ||
|
|
7ac3c4a802 | ||
|
|
ef99035b2d | ||
|
|
a924921a77 | ||
|
|
886761f03e | ||
|
|
7b88d13069 | ||
|
|
3e3e5f9797 | ||
|
|
68d4e2e250 | ||
|
|
0f398308dd | ||
|
|
c7728cdc78 |
@@ -0,0 +1,11 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[{*.gradle,*.properties,*.java,*.json,*.accesswidener}]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = tab
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 120
|
||||||
|
|
||||||
|
[*.properties]
|
||||||
|
ij_properties_keep_blank_lines = true
|
||||||
+10
-2
@@ -1,2 +1,10 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
#
|
||||||
* text=auto
|
# https://help.github.com/articles/dealing-with-line-endings/
|
||||||
|
#
|
||||||
|
# Linux start script should use lf
|
||||||
|
/gradlew text eol=lf
|
||||||
|
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
# These are Windows script files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
@@ -8,33 +8,23 @@ on: [pull_request, push]
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
runs-on: ubuntu-24.04
|
||||||
matrix:
|
|
||||||
# Use these Java versions
|
|
||||||
java: [
|
|
||||||
17, # Current Java LTS & minimum supported by Minecraft
|
|
||||||
]
|
|
||||||
# and run on both Linux and Windows
|
|
||||||
os: [ubuntu-22.04, windows-2022]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout repository
|
- name: checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v6
|
||||||
- name: validate gradle wrapper
|
- name: validate gradle wrapper
|
||||||
uses: gradle/wrapper-validation-action@v1
|
uses: gradle/actions/wrapper-validation@v6
|
||||||
- name: setup jdk ${{ matrix.java }}
|
- name: setup jdk
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.java }}
|
java-version: '25'
|
||||||
distribution: 'microsoft'
|
distribution: 'microsoft'
|
||||||
- name: make gradle wrapper executable
|
- name: make gradle wrapper executable
|
||||||
if: ${{ runner.os != 'Windows' }}
|
|
||||||
run: chmod +x ./gradlew
|
run: chmod +x ./gradlew
|
||||||
- name: build
|
- name: build all
|
||||||
run: ./gradlew build
|
run: ./gradlew buildAll
|
||||||
- name: capture build artifacts
|
- name: capture build artifacts
|
||||||
if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS
|
uses: actions/upload-artifact@v4
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
with:
|
||||||
name: Artifacts
|
name: Artifacts
|
||||||
path: build/libs/
|
path: build/libs/
|
||||||
@@ -38,3 +38,6 @@ hs_err_*.log
|
|||||||
replay_*.log
|
replay_*.log
|
||||||
*.hprof
|
*.hprof
|
||||||
*.jfr
|
*.jfr
|
||||||
|
|
||||||
|
# file auto-generated by build.gradle for preprocessor
|
||||||
|
build.properties
|
||||||
|
|||||||
@@ -1,16 +1,115 @@
|
|||||||
# ChatPlus
|
# Chat Plus
|
||||||
A Simple mod add bukkit style with an "&" and "[item]" display for Fabric Server.
|
|
||||||
|
|
||||||
It's a **server-side** mod and doesn't need to be installed on the client.
|

|
||||||
|
<a href="https://modrinth.com/mod/chatplus">
|
||||||
|
<img src="https://img.shields.io/badge/Modrinth-Chat_Plus-%234e910e?style=flat" />
|
||||||
|
</a>
|
||||||
|
|
||||||
Current Minecraft version: 1.20.1
|
A simple Fabric mod that adds Bukkit-style color codes (using "&") and "[item]" display in chat.
|
||||||
|
|
||||||
## Screenshot
|
It can be installed on the **client** or **server**:
|
||||||

|
- Install on the **server only** if you want players to send styled messages in-game
|
||||||
**^^^ Display the item in main hand**
|
- Install on the **host client** (the one creating the LAN multiplayer session) for LAN multiplayer functionality
|
||||||
|
- Install on the **client** for single-player functionality
|
||||||
|
|
||||||

|
|
||||||
**^^^ Colorful Text**
|
|
||||||
|
|
||||||

|
|
||||||
**^^^ Display items in slots**
|
Compatibility has been implemented for these mods: Styled Chat, Dynmap<br>
|
||||||
|
_* Other mods may work without explicit support. Report compatibility requests via [GitHub Issues](https://github.com/CPTProgrammer/ChatPlus/issues)._
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<br>
|
||||||
|
**^^^ Display the item in the main hand**
|
||||||
|
|
||||||
|
<br>
|
||||||
|
**^^^ Colorful Text**
|
||||||
|
|
||||||
|
<br>
|
||||||
|
**^^^ Display items in slots**
|
||||||
|
|
||||||
|
<br>
|
||||||
|
**^^^ Escape character `&`**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Minecraft Versions
|
||||||
|
|
||||||
|
| Development Version | Compatible Versions |
|
||||||
|
| ------------------- | ------------------- |
|
||||||
|
| 1.19 | 1.19 |
|
||||||
|
| 1.19.1 | 1.19.1 - 1.19.2 |
|
||||||
|
| 1.19.3 | 1.19.3 - 1.19.4 |
|
||||||
|
| 1.20 | 1.20 - 1.20.2 |
|
||||||
|
| 1.20.3 | 1.20.3 - 1.20.6 |
|
||||||
|
| 1.21 | 1.21 - 1.21.11 |
|
||||||
|
| 26.1 | 26.1 - 26.1.2 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
#### Environment
|
||||||
|
|
||||||
|
- Java 25 or higher
|
||||||
|
- (Optional) Java IDE with Manifold support (e.g., IntelliJ IDEA)<br>
|
||||||
|
_* If using IntelliJ IDEA, the Manifold plugin should be installed_
|
||||||
|
|
||||||
|
#### Switching Versions
|
||||||
|
|
||||||
|
Set `minecraft_version` in `gradle.properties`, or append `-Pmc=x.x.x` parameter to Gradle commands (e.g., `./gradlew build -Pmc=1.20.3`) to switch Minecraft versions for development.
|
||||||
|
|
||||||
|
> **Note for IDE users:**
|
||||||
|
>
|
||||||
|
> After modifying `gradle.properties` or `./properties/*.properties`, remember to reload the Gradle project (or click "Load Gradle Changes" button)
|
||||||
|
|
||||||
|
**Cross-version Testing**
|
||||||
|
|
||||||
|
To test mod compatibility with newer Minecraft versions:
|
||||||
|
|
||||||
|
- Method 1:
|
||||||
|
- Set `minecraft_version` to target version, and configure matching `test_fabric_api_version` (e.g., `0.121.0+1.21.5`)
|
||||||
|
- Reload project to download dependencies (for IDE users)
|
||||||
|
- Place additional test mods in `./run/mods`
|
||||||
|
- Run Gradle task `runClient` or `runServer` (_May encounter unexpected launch issues - if this occurs, try Method 2_)
|
||||||
|
- Method 2: Build JAR file and deploy to `mods` folder of the target Minecraft version client/server
|
||||||
|
|
||||||
|
> **Note:**
|
||||||
|
>
|
||||||
|
> The `minecraft_version` can be a version not explicitly listed in `./properties/*.properties` files. The `settings.gradle` script will automatically select the nearest compatible properties configuration.
|
||||||
|
|
||||||
|
#### Build
|
||||||
|
|
||||||
|
Run one of the following commands to build the JAR:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the JAR for the currently configured Minecraft version
|
||||||
|
./gradlew build # Windows: .\gradlew build
|
||||||
|
|
||||||
|
# Build for a different Minecraft version, e.g.
|
||||||
|
./gradlew build -Pmc=1.20.3
|
||||||
|
```
|
||||||
|
|
||||||
|
To build JARs for all Minecraft versions defined in `./properties`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew buildAll # Windows: .\gradlew buildAll
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:**
|
||||||
|
>
|
||||||
|
> All compiled JARs are output to `./build/libs`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
<a href="https://github.com/CPTProgrammer/ChatPlus/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=CPTProgrammer/ChatPlus" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
#### Special Thanks
|
||||||
|
|
||||||
|
- [@SAGUMEDREAM](https://github.com/SAGUMEDREAM) for advice on mixin development.
|
||||||
|
- [Distant-Horizons-Team/Distant Horizons](https://gitlab.com/distant-horizons-team/distant-horizons/) for inspiring the build configuration design.
|
||||||
|
|
||||||
|
|||||||
+169
-26
@@ -1,9 +1,28 @@
|
|||||||
|
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'fabric-loom' version '1.3-SNAPSHOT'
|
id "net.fabricmc.fabric-loom-remap" version "1.16-SNAPSHOT" apply false
|
||||||
id 'maven-publish'
|
id "net.fabricmc.fabric-loom" version "1.16-SNAPSHOT" apply false
|
||||||
|
id "maven-publish"
|
||||||
|
|
||||||
|
// Manifold preprocessor
|
||||||
|
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||||
}
|
}
|
||||||
|
|
||||||
version = project.mod_version
|
// Transfer gradle extra properties to root project extra properties
|
||||||
|
gradle.ext.properties.each { prop -> project.ext.set(prop.key, prop.value) }
|
||||||
|
|
||||||
|
def loomRemapStr = project.findProperty("fabric_loom_remap")?.toString()
|
||||||
|
assert loomRemapStr in ["true", "false"] :
|
||||||
|
"${loomRemapStr == null ? "Missing" : "Invalid"} property in ${Paths.get(version_properties_path, "${project.targetVersion}.properties")} : " +
|
||||||
|
"fabric_loom_remap${loomRemapStr == null ? "" : "=$loomRemapStr"}"
|
||||||
|
def loomRemap = loomRemapStr.toBoolean()
|
||||||
|
apply plugin: loomRemap ? "net.fabricmc.fabric-loom-remap" : "net.fabricmc.fabric-loom"
|
||||||
|
|
||||||
|
generateBuildProperties(project.minecraftVersions, project.targetVersion)
|
||||||
|
|
||||||
|
version = "${project.mod_version}-mc${project.targetVersion}"
|
||||||
group = project.maven_group
|
group = project.maven_group
|
||||||
|
|
||||||
base {
|
base {
|
||||||
@@ -16,45 +35,141 @@ repositories {
|
|||||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
// for more information about repositories.
|
// for more information about repositories.
|
||||||
}
|
|
||||||
|
|
||||||
loom {
|
mavenCentral()
|
||||||
splitEnvironmentSourceSets()
|
|
||||||
|
|
||||||
mods {
|
// Modrinth Maven
|
||||||
"chat-plus" {
|
exclusiveContent {
|
||||||
sourceSet sourceSets.main
|
forRepository {
|
||||||
sourceSet sourceSets.client
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Placeholder API (for StyledChat mod) Maven
|
||||||
|
maven {
|
||||||
|
url "https://maven.nucleoid.xyz/"
|
||||||
|
name "Nucleoid"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manifold preprocessor
|
||||||
|
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||||
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
// splitEnvironmentSourceSets()
|
||||||
|
//
|
||||||
|
// mods {
|
||||||
|
// "modid" {
|
||||||
|
// sourceSet sourceSets.main
|
||||||
|
// sourceSet sourceSets.client
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
remappableImplementation
|
||||||
|
remappableCompileOnly
|
||||||
|
remappableLocalRuntime
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loomRemap) {
|
||||||
|
configurations.modImplementation.extendsFrom(configurations.remappableImplementation)
|
||||||
|
configurations.modCompileOnly.extendsFrom(configurations.remappableCompileOnly)
|
||||||
|
configurations.modLocalRuntime.extendsFrom(configurations.remappableLocalRuntime)
|
||||||
|
} else {
|
||||||
|
configurations.implementation.extendsFrom(configurations.remappableImplementation)
|
||||||
|
configurations.compileOnly.extendsFrom(configurations.remappableCompileOnly)
|
||||||
|
configurations.localRuntime.extendsFrom(configurations.remappableLocalRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// To change the versions see the gradle.properties file
|
// To change the versions see the gradle.properties file or the ./properties/${minecraftVersion}.properties file
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
if (loomRemap) mappings loom.officialMojangMappings()
|
||||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
remappableImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}"
|
||||||
|
remappableImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}+${project.targetVersion}"
|
||||||
|
|
||||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
// Override Fabric API version for local testing (runClient/runServer)
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
if (project.hasProperty("test_fabric_api_version"))
|
||||||
|
remappableLocalRuntime "net.fabricmc.fabric-api:fabric-api:${project.test_fabric_api_version}"
|
||||||
|
|
||||||
// Uncomment the following line to enable the deprecated Fabric API modules.
|
// Mod Compatibility
|
||||||
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.
|
if (project.hasProperty("mod_dynmap_version") && !project.mod_dynmap_version.allWhitespace)
|
||||||
|
remappableCompileOnly "maven.modrinth:dynmap:${project.mod_dynmap_version}"
|
||||||
|
if (project.hasProperty("mod_styled_chat_version") && !project.mod_styled_chat_version.allWhitespace)
|
||||||
|
remappableCompileOnly "maven.modrinth:styled-chat:${project.mod_styled_chat_version}"
|
||||||
|
if (project.hasProperty("mod_styled_chat_placeholder_api_version") && !project.mod_styled_chat_placeholder_api_version.allWhitespace)
|
||||||
|
remappableCompileOnly "eu.pb4:placeholder-api:${project.mod_styled_chat_placeholder_api_version}"
|
||||||
|
|
||||||
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
// Manifold
|
||||||
|
annotationProcessor "systems.manifold:manifold-preprocessor:${project.manifold_version}"
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
inputs.property "version", project.version
|
def resourceTargets = [
|
||||||
|
"fabric.mod.json"
|
||||||
|
]
|
||||||
|
def expandProperties = [
|
||||||
|
"version": mod_version,
|
||||||
|
"group": maven_group,
|
||||||
|
"minecraft_version": minecraft_version,
|
||||||
|
"java_version": java_version,
|
||||||
|
"fabric_loader_version": fabric_loader_version,
|
||||||
|
"fabric_loader_version_range": hasProperty("min_fabric_loader_version") && !min_fabric_loader_version.allWhitespace ? ">=${min_fabric_loader_version}" : "*",
|
||||||
|
"fabric_api_version": fabric_api_version,
|
||||||
|
"fabric_api_mod_id": fabric_api_mod_id
|
||||||
|
]
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
inputs.properties(expandProperties)
|
||||||
expand "version": project.version
|
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand inputs.properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("buildAll") {
|
||||||
|
group = "build"
|
||||||
|
description = "Builds JARs for all defined Minecraft versions"
|
||||||
|
doLast {
|
||||||
|
// Locate the project-specific Java runtime
|
||||||
|
def javaToolchain = javaToolchains.launcherFor(java.toolchain).get()
|
||||||
|
def projectJavaHome = javaToolchain.metadata.installationPath
|
||||||
|
|
||||||
|
logger.lifecycle("Using Java ${javaToolchain.metadata.javaRuntimeVersion} (path=\"${projectJavaHome}\")")
|
||||||
|
|
||||||
|
def failedVersions = new ArrayList<String>()
|
||||||
|
|
||||||
|
project.minecraftVersions.each { version ->
|
||||||
|
logger.lifecycle("================ Building for Minecraft ${version} ================")
|
||||||
|
// TODO: Refactor this (is there a better approach?)
|
||||||
|
def execOutput = project.providers.exec {
|
||||||
|
commandLine Paths.get(rootProject.rootDir.absolutePath, DefaultNativePlatform.currentOperatingSystem.windows ? "gradlew.bat" : "gradlew"),
|
||||||
|
"build", "-Pmc=${version}"
|
||||||
|
ignoreExitValue true
|
||||||
|
environment "JAVA_HOME": projectJavaHome
|
||||||
|
}
|
||||||
|
def result = execOutput.result.get()
|
||||||
|
def output = execOutput.standardOutput.asText.get()
|
||||||
|
def error = execOutput.standardError.asText.get()
|
||||||
|
logger.lifecycle("[Minecraft ${version}] BUILD ${result.exitValue == 0 ? "SUCCESSFUL" : "FAILED"}. Process exited with code: ${result.exitValue}")
|
||||||
|
if (result.exitValue != 0) {
|
||||||
|
failedVersions.addLast(version as String)
|
||||||
|
logger.lifecycle("[Minecraft ${version}] Error: ${error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failedVersions.isEmpty()) throw new GradleException("Build failed for Minecraft versions: ${failedVersions.join(", ")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
it.options.release = 17
|
it.options.release = project.java_version.toInteger()
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -63,20 +178,22 @@ java {
|
|||||||
// If you remove this line, sources will not be generated.
|
// If you remove this line, sources will not be generated.
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = sourceCompatibility = JavaVersion.toVersion(project.java_version)
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
inputs.property "archivesName", project.base.archivesName
|
||||||
|
|
||||||
from("LICENSE") {
|
from("LICENSE") {
|
||||||
rename { "${it}_${project.base.archivesName.get()}"}
|
rename { "${it}_${inputs.properties.archivesName}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure the maven publication
|
// configure the maven publication
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
mavenJava(MavenPublication) {
|
create("mavenJava", MavenPublication) {
|
||||||
|
artifactId = project.archives_base_name
|
||||||
from components.java
|
from components.java
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,3 +206,29 @@ publishing {
|
|||||||
// retrieving dependencies.
|
// retrieving dependencies.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** ======================================= */
|
||||||
|
/** ================ Utils ================ */
|
||||||
|
/** ======================================= */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Generates version mapping properties file for preprocessor with format:</p>
|
||||||
|
* - {@code MC_VER=<current_version_index>}<br>
|
||||||
|
* - {@code MC_X_Y_Z=<version_index>} for each sorted version
|
||||||
|
*
|
||||||
|
* @param sortedVersions Pre-ordered list of Minecraft versions
|
||||||
|
* @param currentVersion Target version to mark as {@code MC_VER}
|
||||||
|
*/
|
||||||
|
def generateBuildProperties(List<String> sortedVersions, String currentVersion) {
|
||||||
|
def currentIndex = sortedVersions.findIndexOf { it == currentVersion }
|
||||||
|
file(Paths.get(rootDir.absolutePath, "./build.properties")).write("""\
|
||||||
|
# ========================================================
|
||||||
|
# ====!! AUTO-GENERATED FILE - DO NOT MANUALLY EDIT !!====
|
||||||
|
# ========================================================
|
||||||
|
|
||||||
|
MC_VER=${currentIndex}
|
||||||
|
${sortedVersions.indexed().collect { index, version -> "MC_${version.replace('.', '_')}=${index}" }.join("\n")}
|
||||||
|
""".replace('\t', ''))
|
||||||
|
}
|
||||||
|
|||||||
+10
-7
@@ -2,16 +2,19 @@
|
|||||||
org.gradle.jvmargs=-Xmx1G
|
org.gradle.jvmargs=-Xmx1G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
# Fabric Properties
|
# Directory path containing version-specific properties files for Minecraft
|
||||||
# check these on https://fabricmc.net/develop
|
version_properties_path=./properties
|
||||||
minecraft_version=1.20.1
|
|
||||||
yarn_mappings=1.20.1+build.9
|
|
||||||
loader_version=0.14.21
|
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.20.0
|
mod_version=1.1.0
|
||||||
maven_group=cn.revaria.chatplus
|
maven_group=cn.revaria.chatplus
|
||||||
archives_base_name=chat-plus
|
archives_base_name=chat-plus
|
||||||
|
|
||||||
|
# Minecraft
|
||||||
|
minecraft_version=26.1
|
||||||
|
|
||||||
|
# Override Fabric API version for local testing (runClient/runServer)
|
||||||
|
#test_fabric_api_version=
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
fabric_version=0.85.0+1.20.1
|
manifold_version=2025.1.9
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright © 2015 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -83,7 +85,8 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -111,7 +114,6 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -169,7 +171,6 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -201,16 +202,15 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command:
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# and any embedded shellness will be escaped.
|
||||||
# double quotes to make sure that they get re-expanded; and
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
Vendored
+13
-12
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=17
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.58.4
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-4
|
||||||
|
mod_dynmap_version=c0uFN8Lt
|
||||||
|
! Styled Chat 1.4.0+1.19.1
|
||||||
|
mod_styled_chat_version=1.4.0+1.19.1
|
||||||
|
mod_styled_chat_placeholder_api_version=2.0.0-beta.7+1.19
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=17
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.68.1
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric-api
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-4
|
||||||
|
mod_dynmap_version=SrVT9jSf
|
||||||
|
! Styled Chat 2.1.4+1.19.3
|
||||||
|
mod_styled_chat_version=2.1.4+1.19.3
|
||||||
|
mod_styled_chat_placeholder_api_version=2.0.0-rc.1+1.19.3
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=17
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.55.1
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-4
|
||||||
|
mod_dynmap_version=nLhQSh2j
|
||||||
|
! Styled Chat 1.3.3+1.19
|
||||||
|
mod_styled_chat_version=1.3.3+1.19
|
||||||
|
mod_styled_chat_placeholder_api_version=2.0.0-beta.7+1.19
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=17
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.91.1
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric-api
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-6
|
||||||
|
mod_dynmap_version=icNjNwag
|
||||||
|
! Styled Chat 2.2.0+1.20
|
||||||
|
mod_styled_chat_version=2.4.2+1.20.4
|
||||||
|
mod_styled_chat_placeholder_api_version=2.4.0-pre.3+1.20.4
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=17
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.83.0
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric-api
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-6
|
||||||
|
mod_dynmap_version=IIQSYMHC
|
||||||
|
! Styled Chat 2.2.0+1.20
|
||||||
|
mod_styled_chat_version=2.2.0+1.20
|
||||||
|
mod_styled_chat_placeholder_api_version=2.1.1+1.20
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=21
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=true
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.16.10
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.100.1
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric-api
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.7-beta-8
|
||||||
|
mod_dynmap_version=1pMUPhY2
|
||||||
|
! Styled Chat 2.6.1+1.21
|
||||||
|
mod_styled_chat_version=2.6.1+1.21
|
||||||
|
mod_styled_chat_placeholder_api_version=2.4.2+1.21
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
java_version=25
|
||||||
|
|
||||||
|
# Fabric Loom
|
||||||
|
# - For Minecraft versions <26.1: enable remap
|
||||||
|
# - For Minecraft versions >=26.1: disable remap
|
||||||
|
fabric_loom_remap=false
|
||||||
|
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://fabricmc.net/develop
|
||||||
|
fabric_loader_version=0.19.1
|
||||||
|
min_fabric_loader_version=
|
||||||
|
fabric_api_version=0.144.0
|
||||||
|
# Fabric API mod ID conventions:
|
||||||
|
# - For Minecraft versions <1.19.2: use "fabric"
|
||||||
|
# - For Minecraft versions >=1.19.2: use "fabric-api"
|
||||||
|
# Ref: https://wiki.fabricmc.net/tutorial:setup
|
||||||
|
fabric_api_mod_id=fabric-api
|
||||||
|
|
||||||
|
# Mod Compatibility
|
||||||
|
! Dynmap 3.8
|
||||||
|
mod_dynmap_version=4UHHD4t6
|
||||||
|
! Styled Chat 2.12.0-pre.1+26.1
|
||||||
|
mod_styled_chat_version=2.12.0-pre.1+26.1
|
||||||
|
mod_styled_chat_placeholder_api_version=3.0.0-beta.2+26.1
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
@@ -8,3 +10,91 @@ pluginManagement {
|
|||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load compatible properties file for current Minecraft version in {@code version_properties_path} and
|
||||||
|
* define {@code minecraftVersions}, {@code targetVersion}
|
||||||
|
*/
|
||||||
|
def loadProperties() {
|
||||||
|
def propertyFiles = fileTree(Paths.get(rootDir.absolutePath, version_properties_path as String)).files.name
|
||||||
|
def minecraftVersions = propertyFiles.collect { it.replaceAll(/\.properties$/, "") }
|
||||||
|
|
||||||
|
minecraftVersions.sort { a, b -> compareMinecraftVersion(a, b) }
|
||||||
|
gradle.ext.minecraftVersions = minecraftVersions
|
||||||
|
|
||||||
|
// Prefer the version defined by the command line argument -Pmc=x.x.x
|
||||||
|
def inputVersion = hasProperty("mc") ?
|
||||||
|
validateMinecraftVersionFormat(mc as String, "Invalid Minecraft version provided via -Pmc=${mc}") :
|
||||||
|
validateMinecraftVersionFormat(minecraft_version, "Invalid Minecraft version in gradle.properties: minecraft_version=${minecraft_version}")
|
||||||
|
gradle.ext.minecraft_version = inputVersion
|
||||||
|
|
||||||
|
def targetVersion = findLatestCompatibleVersion(minecraftVersions, inputVersion) ?:
|
||||||
|
{ throw new GradleException("Unsupported Minecraft version: ${inputVersion}") }()
|
||||||
|
println "Target Minecraft version: ${targetVersion}"
|
||||||
|
gradle.ext.targetVersion = targetVersion
|
||||||
|
|
||||||
|
def props = new Properties()
|
||||||
|
file(Paths.get(rootDir.absolutePath, version_properties_path as String, "${targetVersion}.properties")).withInputStream { props.load(it) }
|
||||||
|
props.each { prop -> gradle.ext.set(prop.key, prop.value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
loadProperties()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** ======================================= */
|
||||||
|
/** ================ Utils ================ */
|
||||||
|
/** ======================================= */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the latest compatible version that is less than or equal to the target version
|
||||||
|
* while maintaining matching major and minor version components.
|
||||||
|
*
|
||||||
|
* @param sortedVersions A pre-sorted ascending list of semantic version strings <br> (e.g., {@code ["1.18", "1.18.2", "1.19.1"]})
|
||||||
|
* @param version
|
||||||
|
*
|
||||||
|
* @return The latest compatible version string, or {@code null} if no matching version is found
|
||||||
|
*/
|
||||||
|
static String findLatestCompatibleVersion(List<String> sortedVersions, String version) {
|
||||||
|
def targetVersionList = version.tokenize(".")*.toInteger()
|
||||||
|
sortedVersions.findAll {
|
||||||
|
def versionList = it.tokenize(".")*.toInteger()
|
||||||
|
compareMinecraftVersion(versionList, targetVersionList) <= 0 &&
|
||||||
|
(targetVersionList[0] == versionList[0] && targetVersionList[1] == versionList[1])
|
||||||
|
}.max { a, b -> compareMinecraftVersion(a, b) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two Minecraft version
|
||||||
|
* @return comparison result with equivalent semantics to {@link Integer#compareTo(Integer) compareTo()}
|
||||||
|
*/
|
||||||
|
static int compareMinecraftVersion(String versionA, String versionB) {
|
||||||
|
def versionListA = versionA.tokenize(".")*.toInteger()
|
||||||
|
def versionListB = versionB.tokenize(".")*.toInteger()
|
||||||
|
compareMinecraftVersion(versionListA, versionListB)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Compares two Minecraft version
|
||||||
|
* @return comparison result with equivalent semantics to {@link Integer#compareTo(Integer) compareTo()}
|
||||||
|
*/
|
||||||
|
static int compareMinecraftVersion(List<Integer> versionA, List<Integer> versionB) {
|
||||||
|
(versionA[0] <=> versionB[0]) ?: (versionA[1] <=> versionB[1]) ?:
|
||||||
|
(versionA.size() <=> versionB.size() ?: versionA[2] <=> versionB[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates Minecraft version format ({@code major.minor[.patch]} numeric components).<br>
|
||||||
|
* Throws {@link GradleException} with provided or default message if validation fails.
|
||||||
|
*
|
||||||
|
* @param version Version string to validate
|
||||||
|
* @param errorMessage Optional custom exception message (default: {@code "Invalid Minecraft version: X.Y[.Z]"})
|
||||||
|
* @return Original version if valid
|
||||||
|
* @throws GradleException If version format is invalid
|
||||||
|
*/
|
||||||
|
static String validateMinecraftVersionFormat(String version, String errorMessage = null) {
|
||||||
|
def versionList = version.tokenize(".")
|
||||||
|
if ((2 <= versionList.size() && versionList.size() <= 3) && versionList.every { it.isInteger() }) {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
throw new GradleException(errorMessage ?: "Invalid Minecraft version: ${version}")
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
package cn.revaria.chatplus;
|
package cn.revaria.chatplus;
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
|
|
||||||
import net.minecraft.network.message.MessageType;
|
|
||||||
import net.minecraft.network.message.SignedMessage;
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ChatPlus implements ModInitializer {
|
public class ChatPlus implements ModInitializer {
|
||||||
|
public static final String MOD_ID = "chat-plus";
|
||||||
|
|
||||||
// This logger is used to write text to the console and the log file.
|
// This logger is used to write text to the console and the log file.
|
||||||
// It is considered best practice to use your mod id as the logger's name.
|
// It is considered best practice to use your mod id as the logger's name.
|
||||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
// That way, it's clear which mod wrote info, warnings, and errors.
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger("chat-plus");
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
@@ -21,6 +18,6 @@ public class ChatPlus implements ModInitializer {
|
|||||||
// However, some things (like resources) may still be uninitialized.
|
// However, some things (like resources) may still be uninitialized.
|
||||||
// Proceed with mild caution.
|
// Proceed with mild caution.
|
||||||
|
|
||||||
LOGGER.info("§2ChatPlus Loaded!");
|
LOGGER.info("Chat Plus loaded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package cn.revaria.chatplus.mixin;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_19
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.server.network.FilteredText;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import cn.revaria.chatplus.plugin.annotation.DisableIfModsLoaded;
|
||||||
|
import net.minecraft.network.chat.ChatType;
|
||||||
|
import net.minecraft.network.chat.PlayerChatMessage;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import net.minecraft.server.players.PlayerList;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import static cn.revaria.chatplus.util.TextStyleFormatter.applyStyle;
|
||||||
|
|
||||||
|
@DisableIfModsLoaded("styledchat")
|
||||||
|
@Mixin(ServerGamePacketListenerImpl.class)
|
||||||
|
public abstract class ChatMixin {
|
||||||
|
@Redirect(method = "broadcastChatMessage", at = @At(value = "INVOKE", target =
|
||||||
|
#if MC_VER <= MC_1_19
|
||||||
|
"Lnet/minecraft/server/players/PlayerList;broadcastChatMessage(Lnet/minecraft/server/network/FilteredText;Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/resources/ResourceKey;)V"
|
||||||
|
#else
|
||||||
|
"Lnet/minecraft/server/players/PlayerList;broadcastChatMessage(Lnet/minecraft/network/chat/PlayerChatMessage;Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/network/chat/ChatType$Bound;)V"
|
||||||
|
#endif
|
||||||
|
))
|
||||||
|
#if MC_VER <= MC_1_19
|
||||||
|
private void replaceText(PlayerList instance, FilteredText<PlayerChatMessage> message, ServerPlayer sender, ResourceKey<ChatType> typeKey) {
|
||||||
|
var newMessage = new FilteredText<>(
|
||||||
|
message.raw().withUnsignedContent(applyStyle(message.raw().serverContent(), sender)),
|
||||||
|
message.filtered() != null ? message.filtered().withUnsignedContent(applyStyle(message.filtered().serverContent(), sender)) : null
|
||||||
|
);
|
||||||
|
instance.broadcastChatMessage(newMessage, sender, typeKey);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
private void replaceText(PlayerList instance, PlayerChatMessage message, ServerPlayer sender, ChatType.Bound params) {
|
||||||
|
instance.broadcastChatMessage(
|
||||||
|
message.withUnsignedContent(
|
||||||
|
applyStyle(message.#if MC_VER <= MC_1_19_1 serverContent() #else decoratedContent() #endif, sender)
|
||||||
|
),
|
||||||
|
sender, params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package cn.revaria.chatplus.mixin;
|
|
||||||
|
|
||||||
import io.netty.util.internal.StringUtil;
|
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
|
||||||
import net.minecraft.SharedConstants;
|
|
||||||
import net.minecraft.block.AbstractBlock;
|
|
||||||
import net.minecraft.block.AirBlock;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
|
||||||
import net.minecraft.item.Item;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.item.Items;
|
|
||||||
import net.minecraft.network.message.LastSeenMessageList;
|
|
||||||
import net.minecraft.network.message.MessageChain;
|
|
||||||
import net.minecraft.network.message.MessageType;
|
|
||||||
import net.minecraft.network.message.SignedMessage;
|
|
||||||
import net.minecraft.network.message.MessageChainTaskQueue;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket;
|
|
||||||
import net.minecraft.network.listener.ServerPlayPacketListener;
|
|
||||||
import net.minecraft.server.filter.FilteredMessage;
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
|
||||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
|
||||||
import net.minecraft.text.LiteralTextContent;
|
|
||||||
import net.minecraft.text.MutableText;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.item.AirBlockItem;
|
|
||||||
import net.minecraft.text.TextContent;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
import net.minecraft.nbt.NbtCompound;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.logging.log4j.core.jmx.Server;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
@Mixin(ServerPlayNetworkHandler.class)
|
|
||||||
public abstract class MixinChat {
|
|
||||||
@Shadow @Final
|
|
||||||
static Logger LOGGER;
|
|
||||||
|
|
||||||
@Final
|
|
||||||
@Shadow
|
|
||||||
private MinecraftServer server;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void disconnect(Text reason);
|
|
||||||
|
|
||||||
@Final
|
|
||||||
@Shadow
|
|
||||||
private MessageChainTaskQueue messageChainTaskQueue;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private ServerPlayerEntity player;
|
|
||||||
|
|
||||||
@Shadow protected abstract Optional<LastSeenMessageList> validateMessage(String message, Instant timestamp, LastSeenMessageList.Acknowledgment acknowledgment);
|
|
||||||
|
|
||||||
@Shadow protected abstract SignedMessage getSignedMessage(ChatMessageC2SPacket packet, LastSeenMessageList lastSeenMessages) throws MessageChain.MessageChainException;
|
|
||||||
|
|
||||||
@Shadow protected abstract void handleMessageChainException(MessageChain.MessageChainException exception);
|
|
||||||
|
|
||||||
@Shadow protected abstract void handleDecoratedMessage(SignedMessage message);
|
|
||||||
|
|
||||||
@Shadow protected abstract CompletableFuture<FilteredMessage> filterText(String text);
|
|
||||||
|
|
||||||
@Inject(method = "onChatMessage", at = @At("HEAD"), cancellable = true)
|
|
||||||
public void onChatMessage(ChatMessageC2SPacket packet, CallbackInfo ci) {
|
|
||||||
// LOGGER.info("CHAT_MESSAGE: " + packet.chatMessage());
|
|
||||||
|
|
||||||
if (hasIllegalCharacter(packet.chatMessage())) {
|
|
||||||
disconnect(Text.translatable("multiplayer.disconnect.illegal_characters"));
|
|
||||||
} else {
|
|
||||||
Optional<LastSeenMessageList> optional = this.validateMessage(packet.chatMessage(), packet.timestamp(), packet.acknowledgment());
|
|
||||||
if (optional.isPresent()) {
|
|
||||||
if (!packet.chatMessage().startsWith("/")){
|
|
||||||
|
|
||||||
String changedMessage = packet.chatMessage().replace('&', '§');
|
|
||||||
String regex = "\\[item(?:=([1-9]))?\\]";
|
|
||||||
String[] messages = changedMessage.split(regex, -1);
|
|
||||||
Deque<Integer> itemDeque = new ArrayDeque<>();
|
|
||||||
|
|
||||||
Matcher matcher = Pattern.compile(regex).matcher(changedMessage);
|
|
||||||
while (matcher.find()){
|
|
||||||
String digit = matcher.group(1);
|
|
||||||
if (digit == null){
|
|
||||||
itemDeque.addLast(-1);
|
|
||||||
}else {
|
|
||||||
itemDeque.addLast(Integer.parseInt(digit));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MutableText changedText = MutableText.of(TextContent.EMPTY);
|
|
||||||
for (int i = 0; i < messages.length; i++) {
|
|
||||||
changedText.append(Text.of(messages[i]));
|
|
||||||
if (!itemDeque.isEmpty()) {
|
|
||||||
ItemStack itemStack;
|
|
||||||
if (itemDeque.getFirst() == -1) {
|
|
||||||
itemStack = player.getMainHandStack();
|
|
||||||
} else {
|
|
||||||
itemStack = player.getInventory().getStack(itemDeque.getFirst() - 1);
|
|
||||||
}
|
|
||||||
changedText.append(itemStack.toHoverableText());
|
|
||||||
itemDeque.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
SignedMessage signedMessage = getSignedMessage(packet, (LastSeenMessageList) optional.get());
|
|
||||||
server.getPlayerManager().broadcast(signedMessage.withUnsignedContent(
|
|
||||||
changedText
|
|
||||||
), player, MessageType.params(MessageType.CHAT, player));
|
|
||||||
} catch (MessageChain.MessageChainException e) {
|
|
||||||
handleMessageChainException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.server.submit(() -> {
|
|
||||||
SignedMessage signedMessage;
|
|
||||||
try {
|
|
||||||
signedMessage = this.getSignedMessage(packet, (LastSeenMessageList) optional.get());
|
|
||||||
} catch (MessageChain.MessageChainException var6) {
|
|
||||||
handleMessageChainException(var6);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletableFuture<FilteredMessage> completableFuture = filterText(signedMessage.getSignedContent());
|
|
||||||
CompletableFuture<Text> completableFuture2 = this.server.getMessageDecorator().decorate(this.player, signedMessage.getContent());
|
|
||||||
messageChainTaskQueue.append((executor) -> {
|
|
||||||
return CompletableFuture.allOf(completableFuture, completableFuture2).thenAcceptAsync((void_) -> {
|
|
||||||
SignedMessage signedMessage2 = signedMessage.withUnsignedContent((Text) completableFuture2.join()).withFilterMask(((FilteredMessage) completableFuture.join()).mask());
|
|
||||||
handleDecoratedMessage(signedMessage2);
|
|
||||||
}, executor);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasIllegalCharacter(String message) {
|
|
||||||
for(int i = 0; i < message.length(); ++i) {
|
|
||||||
if (!SharedConstants.isValidChar(message.charAt(i))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package cn.revaria.chatplus.mixin.compat;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import static cn.revaria.chatplus.util.TextStyleFormatter.applyStyle;
|
||||||
|
|
||||||
|
@Pseudo
|
||||||
|
@Mixin(targets =
|
||||||
|
#if MC_VER <= MC_1_19
|
||||||
|
"org.dynmap.fabric_1_19.DynmapPlugin$ChatHandler"
|
||||||
|
#elif MC_VER <= MC_1_19_1
|
||||||
|
"org.dynmap.fabric_1_19_1.DynmapPlugin$ChatHandler"
|
||||||
|
#elif MC_VER <= MC_1_19_3
|
||||||
|
{"org.dynmap.fabric_1_19_3.DynmapPlugin$ChatHandler", "org.dynmap.fabric_1_19_4.DynmapPlugin$ChatHandler"}
|
||||||
|
#elif MC_VER <= MC_1_20
|
||||||
|
{"org.dynmap.fabric_1_20.DynmapPlugin$ChatHandler", "org.dynmap.fabric_1_20_2.DynmapPlugin$ChatHandler"}
|
||||||
|
#elif MC_VER <= MC_1_20_3
|
||||||
|
{"org.dynmap.fabric_1_20_4.DynmapPlugin$ChatHandler", "org.dynmap.fabric_1_20_6.DynmapPlugin$ChatHandler"}
|
||||||
|
#elif MC_VER <= MC_1_21
|
||||||
|
{
|
||||||
|
"org.dynmap.fabric_1_21.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_1.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_3.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_5.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_7.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_9_10.DynmapPlugin$ChatHandler",
|
||||||
|
"org.dynmap.fabric_1_21_11.DynmapPlugin$ChatHandler",
|
||||||
|
}
|
||||||
|
#elif MC_VER <= MC_26_1
|
||||||
|
// TODO: Since Dynmap has not yet been updated to be compatible with Minecraft 26.1,
|
||||||
|
// the compatibility Mixins for Dynmap are currently not enabled for this version.
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
public abstract class DynmapMixin {
|
||||||
|
@Inject(method = "handleChat", at = @At("HEAD"), remap = false)
|
||||||
|
private void modifyMessage(ServerPlayer player, String message, CallbackInfo ci, @Local(argsOnly = true) LocalRef<String> messageRef) {
|
||||||
|
messageRef.set(applyStyle(Component.nullToEmpty(message), player).getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package cn.revaria.chatplus.mixin.compat;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21
|
||||||
|
import eu.pb4.placeholders.api.PlaceholderContext;
|
||||||
|
#else
|
||||||
|
import eu.pb4.placeholders.api.ServerPlaceholderContext;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import eu.pb4.styledchat.StyledChatUtils;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import static cn.revaria.chatplus.util.TextStyleFormatter.applyStyle;
|
||||||
|
|
||||||
|
@Pseudo
|
||||||
|
@Mixin(StyledChatUtils.class)
|
||||||
|
public abstract class StyledChatMixin {
|
||||||
|
@Inject(method =
|
||||||
|
#if MC_VER <= MC_1_21
|
||||||
|
"formatFor(Leu/pb4/placeholders/api/PlaceholderContext;Ljava/lang/String;)Lnet/minecraft/network/chat/Component;"
|
||||||
|
#else
|
||||||
|
"formatFor(Leu/pb4/placeholders/api/ServerPlaceholderContext;Ljava/lang/String;)Lnet/minecraft/network/chat/Component;"
|
||||||
|
#endif,
|
||||||
|
at = @At("RETURN"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private static void modifyText(
|
||||||
|
#if MC_VER <= MC_1_21 PlaceholderContext #else ServerPlaceholderContext #endif context,
|
||||||
|
String input, CallbackInfoReturnable<Component> cir
|
||||||
|
) {
|
||||||
|
cir.setReturnValue(applyStyle(cir.getReturnValue(), context.#if MC_VER <= MC_1_21 player() #else serverPlayer() #endif));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package cn.revaria.chatplus.plugin;
|
||||||
|
|
||||||
|
import cn.revaria.chatplus.plugin.annotation.DisableIfModsLoaded;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import org.objectweb.asm.tree.AnnotationNode;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
|
import org.spongepowered.asm.service.MixinService;
|
||||||
|
import org.spongepowered.asm.util.Annotations;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class MixinConfigPlugin implements IMixinConfigPlugin {
|
||||||
|
@Override
|
||||||
|
public void onLoad(String mixinPackage) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRefMapperConfig() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||||
|
try {
|
||||||
|
ClassNode classNode = MixinService.getService().getBytecodeProvider().getClassNode(mixinClassName);
|
||||||
|
AnnotationNode annotationNode = Annotations.getVisible(classNode, DisableIfModsLoaded.class);
|
||||||
|
|
||||||
|
if (annotationNode == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> modIds = Annotations.getValue(annotationNode);
|
||||||
|
return modIds.stream().noneMatch(modId -> FabricLoader.getInstance().isModLoaded(modId));
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getMixins() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package cn.revaria.chatplus.plugin.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditionally disables the annotated mixin when specified mods are loaded.
|
||||||
|
*
|
||||||
|
* <p>When applied, the mixin config plugin should disable the annotated class
|
||||||
|
* if any mod ID in the value list is present in the runtime environment.</p>
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface DisableIfModsLoaded {
|
||||||
|
String[] value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package cn.revaria.chatplus.util;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20
|
||||||
|
import net.minecraft.network.chat.contents.LiteralContents;
|
||||||
|
#else
|
||||||
|
import net.minecraft.network.chat.contents.PlainTextContents;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class TextStyleFormatter {
|
||||||
|
public static int MAIN_HAND = -1; // Must be smaller than or equal to 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes text styling with two key functions:
|
||||||
|
* <p>
|
||||||
|
* 1. Replaces {@code &} with {@code §}, using {@code &&} to escape literal {@code &}<br>
|
||||||
|
* 2. Substitutes {@code [item]} with main-hand item hover text and {@code [item=N]} with Nth slot's hover text
|
||||||
|
* </p>
|
||||||
|
* Recursively processes nested text components.
|
||||||
|
*
|
||||||
|
* @param sourceText Original text to process (supports nested text components)
|
||||||
|
* @param sourcePlayer Player used for item stack references
|
||||||
|
* @return Processed text with styling and item hover elements
|
||||||
|
*/
|
||||||
|
public static MutableComponent applyStyle(Component sourceText, ServerPlayer sourcePlayer) {
|
||||||
|
MutableComponent sourceMutableText = sourceText.copy();
|
||||||
|
|
||||||
|
MutableComponent finalText = Component.empty().setStyle(sourceMutableText.getStyle());
|
||||||
|
|
||||||
|
if (sourceText.getContents() instanceof #if MC_VER <= MC_1_20 LiteralContents #else PlainTextContents #endif plainTextContent) {
|
||||||
|
String changedMessage = plainTextContent.text()
|
||||||
|
.replace('&', '§')
|
||||||
|
.replace("§§", "&");
|
||||||
|
String regex = "\\[item(?:=([1-9]))?\\]";
|
||||||
|
String[] messages = changedMessage.split(regex, -1);
|
||||||
|
Deque<Integer> itemDeque = new ArrayDeque<>();
|
||||||
|
|
||||||
|
Matcher matcher = Pattern.compile(regex).matcher(changedMessage);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String digit = matcher.group(1);
|
||||||
|
if (digit == null) {
|
||||||
|
itemDeque.addLast(MAIN_HAND);
|
||||||
|
} else {
|
||||||
|
itemDeque.addLast(Integer.parseInt(digit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String message : messages) {
|
||||||
|
finalText.append(Component.literal(message));
|
||||||
|
if (!itemDeque.isEmpty()) {
|
||||||
|
ItemStack itemStack;
|
||||||
|
if (itemDeque.getFirst() == MAIN_HAND) {
|
||||||
|
itemStack = sourcePlayer.getMainHandItem();
|
||||||
|
} else {
|
||||||
|
itemStack = sourcePlayer.getInventory().getItem(itemDeque.getFirst() - 1);
|
||||||
|
}
|
||||||
|
finalText.append(itemStack.getDisplayName());
|
||||||
|
itemDeque.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Component> sourceTexts = sourceMutableText.getSiblings();
|
||||||
|
for (Component text : sourceTexts) {
|
||||||
|
finalText.append(applyStyle(text, sourcePlayer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalText;
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 3.6 KiB |
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"package": "cn.revaria.chatplus.mixin",
|
"package": "cn.revaria.chatplus.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"plugin": "cn.revaria.chatplus.plugin.MixinConfigPlugin",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"MixinChat"
|
"ChatMixin",
|
||||||
|
"compat.DynmapMixin",
|
||||||
|
"compat.StyledChatMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
"id": "chat-plus",
|
"id": "chat-plus",
|
||||||
"version": "${version}",
|
"version": "${version}",
|
||||||
"name": "Chat Plus",
|
"name": "Chat Plus",
|
||||||
"description": "Add bukkit style with an & and [item] for Fabric Server",
|
"description": "Add Bukkit-style color codes (using \"&\") and \"[item]\" display in chat.",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Rev_Aria"
|
"Rev_Aria"
|
||||||
],
|
],
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://fabricmc.net/",
|
"homepage": "https://modrinth.com/mod/chatplus",
|
||||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
"sources": "https://github.com/CPTProgrammer/ChatPlus/",
|
||||||
|
"issues": "https://github.com/CPTProgrammer/ChatPlus/issues"
|
||||||
},
|
},
|
||||||
"license": "CC0-1.0",
|
"license": "GPL-3.0-or-later",
|
||||||
"icon": "assets/chat-plus/icon.png",
|
"icon": "assets/chat-plus/icon.png",
|
||||||
"environment": "*",
|
"environment": "*",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
@@ -20,19 +21,12 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"chat-plus.mixins.json",
|
"chat-plus.mixins.json"
|
||||||
{
|
|
||||||
"config": "chat-plus.client.mixins.json",
|
|
||||||
"environment": "client"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.14.21",
|
"fabricloader": "${fabric_loader_version_range}",
|
||||||
"minecraft": "~1.20.1",
|
"minecraft": "~${minecraft_version}",
|
||||||
"java": ">=17",
|
"java": ">=${java_version}",
|
||||||
"fabric-api": "*"
|
"${fabric_api_mod_id}": ">=${fabric_api_version}"
|
||||||
},
|
|
||||||
"suggests": {
|
|
||||||
"another-mod": "*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user