更新版本为1.0.7
1. 修复 #5 #9 的问题: 服务器端崩溃(因为依赖加载了客户端专属类,感谢 璃之雨 和 AtinyFurina 的指正) 2.添加了Datagen 3.引入自写的库[Lib39](https://github.com/3944Realms/Lib39/tree/Forge_1_20_1)来辅助Datagen,理论上是不需要安装Lib39的 4.更新了Readme
This commit is contained in:
parent
bf5e9f98b9
commit
9511f0074c
51
README.md
51
README.md
|
|
@ -15,8 +15,8 @@ All you need is a cannon and enough gunpowder, and you can experience a journey
|
||||||
| Mod Update Plan | Status |
|
| Mod Update Plan | Status |
|
||||||
|----------------|--------|
|
|----------------|--------|
|
||||||
| Migration to Forge 1.20.1 | ✅ Completed |
|
| Migration to Forge 1.20.1 | ✅ Completed |
|
||||||
| Migration to higher versions of NeoForge | Not started, planned for July/August |
|
| Migration to higher versions of NeoForge | Not started |
|
||||||
| Open API for cross-mod compatibility | Not started, planned for July/August |
|
| Open API for cross-mod compatibility | Not started, |
|
||||||
| Improve and refactor the original mod's operations | Not started |
|
| Improve and refactor the original mod's operations | Not started |
|
||||||
|
|
||||||
## Mod Development Statement
|
## Mod Development Statement
|
||||||
|
|
@ -26,33 +26,30 @@ This mod is a migration and refactor of **Blast Travel** (the original mod only
|
||||||
- The **1.20.1 Quilt version** is based on **Abbie5's fork**, with the MODID remaining as `blasttravel`.
|
- The **1.20.1 Quilt version** is based on **Abbie5's fork**, with the MODID remaining as `blasttravel`.
|
||||||
- The **1.20.1 Forge version** is a partial logic refactor by the author, with the MODID changed to `blasttravelreborn`. Please note the difference.
|
- The **1.20.1 Forge version** is a partial logic refactor by the author, with the MODID changed to `blasttravelreborn`. Please note the difference.
|
||||||
|
|
||||||
## Q&A
|
|
||||||
|
|
||||||
**Q1: Will there be Fabric support for future higher versions?**
|
|
||||||
**A1:** Probably not. The author is not a fan of Fabric's development workflow. However, anyone is welcome to fork the project and develop a Fabric version. That said, the author might consider using the **Architectury** framework for multi-loader support (though it would be quite a hassle).
|
|
||||||
|
|
||||||
**Q2: Can my mod integrate with this mod?**
|
|
||||||
**A2:** Yes! The author welcomes mod integrations. If you're a mod developer interested in compatibility, feel free to submit an **ISSUE** in this repository. The author is happy to provide code-level support.
|
|
||||||
|
|
||||||
**Q3: Will you support versions below 1.19.2?**
|
|
||||||
**A3:** No. The author will **never** backport to lower versions. However, there is a mod with similar functionality—**Cannon (Teacon2022 Example Mod)**, which supports **1.18–1.18.2** and can serve as an alternative.
|
|
||||||
|
|
||||||
# Adding to Your Project
|
# Adding to Your Project
|
||||||
1. Download mod jar file,and put it under your project's 'libs/' dir, and rename it into "{modid}-{minecraft-version}-{mod_version}.jar"(for example, "blasttravelreborn-1.20.1-1.0.6-forge-all.jar")
|
# For Developer
|
||||||
2. Ensure your `build.gradle` has enable 'libs' flatDir repositories
|
You can integrate and automatically download JsonEM for your mod project using Gradle.
|
||||||
```groovy
|
Just add the following to your build script (`build.gradle`):
|
||||||
repositories {
|
|
||||||
flatDir {
|
## Repositories
|
||||||
dir 'libs'
|
```gradle
|
||||||
}
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "LTD Maven"
|
||||||
|
url = "https://nexus.bot.leisuretimedock.top/repository/maven-public/"
|
||||||
}
|
}
|
||||||
````
|
}
|
||||||
3. Add it to dependencies
|
```
|
||||||
```groovy
|
### Forge
|
||||||
dependencies {
|
```gradle
|
||||||
implementation fg.deobf("blank:blasttravelreborn-1.20.1:1.0.6-forge-all")//for example
|
dependencies {
|
||||||
}
|
implementation fg.deobf("com.leisuretimedock.blastravelreborn:${minecraft_version}-${blasttravelreborn_version})"
|
||||||
````
|
}
|
||||||
|
```
|
||||||
|
### Choose a Version
|
||||||
|
|
||||||
|
`${mc_version}` gets replaced by the current Minecraft version. (i.e. `1.20.1`)
|
||||||
|
`${blasttravelreborn_version}` gets replaced by the version of JEI you want to use (i.e `1.0.7`)
|
||||||
Cannon Model please install [BlockBench Plugin](https://github.com/LeisureTimeDock/JsonEM_Neo_Forge/blob/1.21/jsonem_models.js) in your BlockBench.
|
Cannon Model please install [BlockBench Plugin](https://github.com/LeisureTimeDock/JsonEM_Neo_Forge/blob/1.21/jsonem_models.js) in your BlockBench.
|
||||||
|
|
||||||
And import 'entity/cannon/main.json' with this jsonem plugin. Then you can view the cannon model correctly and create its texture.
|
And import 'entity/cannon/main.json' with this jsonem plugin. Then you can view the cannon model correctly and create its texture.
|
||||||
54
build.gradle
54
build.gradle
|
|
@ -8,6 +8,7 @@ buildscript {
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'eclipse'
|
id 'eclipse'
|
||||||
|
id 'maven-publish'
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'net.minecraftforge.gradle' version '[6.0.16,6.2)'
|
id 'net.minecraftforge.gradle' version '[6.0.16,6.2)'
|
||||||
id 'org.parchmentmc.librarian.forgegradle' version '1.+'
|
id 'org.parchmentmc.librarian.forgegradle' version '1.+'
|
||||||
|
|
@ -152,7 +153,11 @@ repositories {
|
||||||
}
|
}
|
||||||
// If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
|
// If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
|
||||||
flatDir {
|
maven {
|
||||||
|
name = "LTD Maven"
|
||||||
|
url = "https://nexus.bot.leisuretimedock.top/repository/maven-public/"
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
dir 'libs'
|
dir 'libs'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,9 +172,12 @@ dependencies {
|
||||||
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
||||||
implementation 'org.spongepowered:mixin:0.8.5'
|
implementation 'org.spongepowered:mixin:0.8.5'
|
||||||
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
|
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
|
||||||
implementation jarJar(fg.deobf("blank:jsonem-${minecraft_version}:${jsonem_version}")) {
|
implementation "top.r3944realms.lib39:lib39:${lib39_version}"
|
||||||
jarJar.ranged(it, "[0.0,)")
|
implementation jarJar(fg.deobf("com.leisuretimedock:jsonem-forge-${minecraft_version}:${jsonem_version}")) {
|
||||||
|
jarJar.ranged(it, "[${jsonem_version},)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings
|
// Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings
|
||||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||||
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")
|
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")
|
||||||
|
|
@ -226,3 +234,43 @@ tasks.named('jar', Jar).configure {
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
artifactId = base.archivesName.get()
|
||||||
|
from components.java
|
||||||
|
artifactId = "${mod_id}-${project.name}-${minecraft_version}"
|
||||||
|
|
||||||
|
pom {
|
||||||
|
name = rootProject.mod_id
|
||||||
|
description = rootProject.mod_description
|
||||||
|
url = rootProject.mod_source
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = rootProject.mod_license
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = rootProject.mod_id
|
||||||
|
name = rootProject.mod_authors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file://${project.projectDir}/mcmodsrepo"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'LTDNexus'
|
||||||
|
url = 'https://nexus.bot.leisuretimedock.top/repository/maven-releases/'
|
||||||
|
credentials {
|
||||||
|
username = System.getenv('LTDNexusUsername') ?: ''
|
||||||
|
password = System.getenv('LTDNexusPassword') ?: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,8 +38,10 @@ mod_name=BlastTravel-Reborn
|
||||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||||
mod_license=MIT
|
mod_license=MIT
|
||||||
# The mod version. See https://semver.org/
|
# The mod version. See https://semver.org/
|
||||||
mod_version=1.0.6+1.20.1-forge
|
mod_version=1.0.7
|
||||||
jsonem_version=0.2.2+1.20-fabrge
|
jsonem_version=0.2.4
|
||||||
|
lib39_version=1.20.1-0.0.17
|
||||||
|
mod_source=https://github.com/LeisureTimeDock/BlastTravel_Neo_Forge
|
||||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||||
# This should match the base package used for the mod sources.
|
# This should match the base package used for the mod sources.
|
||||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
|
|
@ -47,4 +49,4 @@ mod_group_id=com.leisuretimedock.blasttravelreborn
|
||||||
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
||||||
mod_authors=FoundationGames(Original Author), Abbie5(Migrate into Quilt 1.20.1), R3944Realms
|
mod_authors=FoundationGames(Original Author), Abbie5(Migrate into Quilt 1.20.1), R3944Realms
|
||||||
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
||||||
mod_description=Migrate from Quilt 1.20.1,1.19.2
|
mod_description=Migrate from Quilt 1.20.1, 1.19.2
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
787f3aedc203dff6fcef2b438729cc7e
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0446695fdc79163fa7a1ce6e792172fbcdbaafc1
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0195af1841c2087eb2a10cbc75e0b9fc1d30f62f2a752a6797acbb3d503b8af3
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ac8caf27e4c5d9e7d04fb6b4eff0bc5aa27e8e0440be346cbf2161c775a5a23c5326c201a83d93fbaea95ee40c8a6fb0a649b5db0d3cc0b14f11dfb8568c3c0f
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.leisuretimedock.blasttravelreborn</groupId>
|
||||||
|
<artifactId>blasttravel-reborn</artifactId>
|
||||||
|
<version>1.0.6+1.20.1-forge</version>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
e3426fd0c4b900d1cad53c5308a75011
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
8e2b7ac803f1a5d1bf02a9ef77fcf48d6f138cbb
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
48136ed719d64d3e436b1782f494892fdb7abd6f08b9ff7750c07201bc9ff8f8
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
30938abad6f11d4d26e73abe9cee3cb8321def9421f530574e68a89010f79e56e3bd860ec491e25a5a841a4787ea93a094675ecfc114b193137f808a558ab16c
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<metadata>
|
||||||
|
<groupId>com.leisuretimedock.blasttravelreborn</groupId>
|
||||||
|
<artifactId>blasttravel-reborn</artifactId>
|
||||||
|
<versioning>
|
||||||
|
<latest>1.0.6+1.20.1-forge</latest>
|
||||||
|
<release>1.0.6+1.20.1-forge</release>
|
||||||
|
<versions>
|
||||||
|
<version>1.0.6+1.20.1-forge</version>
|
||||||
|
</versions>
|
||||||
|
<lastUpdated>20250612155714</lastUpdated>
|
||||||
|
</versioning>
|
||||||
|
</metadata>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
7be97661cf89db9c24d0e144216f7911
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
bcbda3d6ce62aa2d5daa5cd991285b008b51ea81
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
e56c09fc1d1fa062ea5b77ea5673c19c4a56ee4b91450646d2aed786832ce267
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
3bdb8ae4325fd516bfaafeb33b0221f51f88eadd8388e3c49ea7f160eca95d34f5e04809a389afd6af913e21bf4985dd3a6d99cb4b491e12961b458293110f62
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Registries
|
||||||
|
e615490187adee92d48183e84dd6953d340753c2 data/blasttravelreborn/damage_type/cannon.json
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Languages: zh_tw
|
||||||
|
094e7efc852fc45d55f97c0976bf2453de88e219 assets/blasttravelreborn/lang/zh_tw.json
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Languages: zh_cn
|
||||||
|
03cccc87a6370bef5c6b95b1d76cd9d22547b86c assets/blasttravelreborn/lang/zh_cn.json
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Item Models: blasttravelreborn
|
||||||
|
3efedd95103ec88f295ab752f9591da6f20e9cb2 assets/blasttravelreborn/models/item/cannon.json
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Recipes
|
||||||
|
d38155e7a052e0f1143b0b82dc1a595026c4d98c data/blasttravelreborn/advancements/recipes/misc/cannon.json
|
||||||
|
7fd4c6df73dc342481e69f6d24914ca8e767b578 data/blasttravelreborn/recipes/cannon.json
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:28:42.6814983 Particle Descriptions
|
||||||
|
1aacb18bd6bc829ecf1ac93ae1e3e4a9c30459b9 assets/blasttravelreborn/particles/cannon_blast.json
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// 1.20.1 2025-11-22T19:25:06.9619789 Languages: en_us
|
||||||
|
c3f0d412d3d39f47d1dd4065782d0984a17ed4e7 assets/blasttravelreborn/lang/en_us.json
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"container.blasttravelreborn.cannon_container_menu": "Cannon",
|
||||||
|
"death.attack.blasttravelreborn.cannon": "%s was knocked out by a flying %s",
|
||||||
|
"dialog.blasttravelreborn.full_cannon": "Cannon is full!",
|
||||||
|
"dialog.blasttravelreborn.no_gunpowder": "Cannon has no gunpowder!",
|
||||||
|
"entity.blasttravelreborn.cannon": "Cannon",
|
||||||
|
"item.blasttravelreborn.cannon": "Cannon",
|
||||||
|
"mount.blasttravelreborn.cannon.onboard": "Press %s to Exit, or %s to Fire"
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
{
|
{
|
||||||
"container.blasttravelreborn.cannon_container_menu": "大炮",
|
"container.blasttravelreborn.cannon_container_menu": "大炮实体",
|
||||||
"item.blasttravelreborn.cannon": "大炮",
|
|
||||||
"entity.blasttravelreborn.cannon": "大炮实体",
|
|
||||||
|
|
||||||
"death.attack.blasttravelreborn.cannon": "%s被飞行的%s击倒了",
|
"death.attack.blasttravelreborn.cannon": "%s被飞行的%s击倒了",
|
||||||
"dialog.blasttravelreborn.full_cannon": "大炮已装满!",
|
"dialog.blasttravelreborn.full_cannon": "大炮已装满!",
|
||||||
"dialog.blasttravelreborn.no_gunpowder": "大炮没有火药了!",
|
"dialog.blasttravelreborn.no_gunpowder": "大炮没有火药了!",
|
||||||
|
"entity.blasttravelreborn.cannon": "大炮",
|
||||||
|
"item.blasttravelreborn.cannon": "大炮",
|
||||||
"mount.blasttravelreborn.cannon.onboard": "按%s离开,或按%s发射"
|
"mount.blasttravelreborn.cannon.onboard": "按%s离开,或按%s发射"
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"container.blasttravelreborn.cannon_container_menu": "大砲實體",
|
||||||
|
"death.attack.blasttravelreborn.cannon": "%s被飛行的%s擊倒了",
|
||||||
|
"dialog.blasttravelreborn.full_cannon": "大砲已裝滿!",
|
||||||
|
"dialog.blasttravelreborn.no_gunpowder": "大砲沒有火藥了!",
|
||||||
|
"entity.blasttravelreborn.cannon": "大砲",
|
||||||
|
"item.blasttravelreborn.cannon": "大砲",
|
||||||
|
"mount.blasttravelreborn.cannon.onboard": "按%s離開,或按%s發射"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "blasttravelreborn:item/cannon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
"blasttravelreborn:blast_smoke_0",
|
||||||
|
"blasttravelreborn:blast_smoke_1",
|
||||||
|
"blasttravelreborn:blast_smoke_2",
|
||||||
|
"blasttravelreborn:blast_smoke_3",
|
||||||
|
"blasttravelreborn:blast_smoke_4",
|
||||||
|
"blasttravelreborn:blast_smoke_5",
|
||||||
|
"blasttravelreborn:blast_smoke_6",
|
||||||
|
"blasttravelreborn:blast_smoke_7"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:recipes/root",
|
||||||
|
"criteria": {
|
||||||
|
"has_iron_block": {
|
||||||
|
"conditions": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
"minecraft:iron_block"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trigger": "minecraft:inventory_changed"
|
||||||
|
},
|
||||||
|
"has_the_recipe": {
|
||||||
|
"conditions": {
|
||||||
|
"recipe": "blasttravelreborn:cannon"
|
||||||
|
},
|
||||||
|
"trigger": "minecraft:recipe_unlocked"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requirements": [
|
||||||
|
[
|
||||||
|
"has_iron_block",
|
||||||
|
"has_the_recipe"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"rewards": {
|
||||||
|
"recipes": [
|
||||||
|
"blasttravelreborn:cannon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sends_telemetry_event": false
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"exhaustion": 0.0,
|
||||||
"message_id": "cannon",
|
"message_id": "cannon",
|
||||||
"exhaustion": 0,
|
|
||||||
"scaling": "when_caused_by_living_non_player"
|
"scaling": "when_caused_by_living_non_player"
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shaped",
|
||||||
|
"category": "misc",
|
||||||
|
"key": {
|
||||||
|
"A": {
|
||||||
|
"item": "minecraft:iron_block"
|
||||||
|
},
|
||||||
|
"B": {
|
||||||
|
"item": "minecraft:string"
|
||||||
|
},
|
||||||
|
"C": {
|
||||||
|
"tag": "minecraft:stone_crafting_materials"
|
||||||
|
},
|
||||||
|
"D": {
|
||||||
|
"item": "minecraft:stick"
|
||||||
|
},
|
||||||
|
"E": {
|
||||||
|
"tag": "minecraft:logs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pattern": [
|
||||||
|
" A",
|
||||||
|
"BA ",
|
||||||
|
"CDE"
|
||||||
|
],
|
||||||
|
"result": {
|
||||||
|
"item": "blasttravelreborn:cannon"
|
||||||
|
},
|
||||||
|
"show_notification": true
|
||||||
|
}
|
||||||
|
|
@ -9,12 +9,10 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
@Mod(value = BlastTravelReborn.MOD_ID)
|
@Mod(value = BlastTravelReborn.MOD_ID)
|
||||||
public class BlastTravelReborn {
|
public class BlastTravelReborn {
|
||||||
public static final String MOD_ID = "blasttravelreborn";
|
public static final String MOD_ID = "blasttravelreborn";
|
||||||
public static final Logger LOG = LoggerFactory.getLogger("Blast Travel Reborn");
|
|
||||||
public BlastTravelReborn() {
|
public BlastTravelReborn() {
|
||||||
FMLJavaModLoadingContext fmlJavaModLoadingContext = FMLJavaModLoadingContext.get();
|
FMLJavaModLoadingContext fmlJavaModLoadingContext = FMLJavaModLoadingContext.get();
|
||||||
IEventBus modEventBus = fmlJavaModLoadingContext.getModEventBus();
|
IEventBus modEventBus = fmlJavaModLoadingContext.getModEventBus();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.api.events;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.entity.cannon.CannonBehavior;
|
||||||
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
import net.minecraftforge.fml.event.IModBusEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class RegisterCannonBehaviorEvent extends Event implements IModBusEvent {
|
||||||
|
public void registerCannonBehavior(@NotNull CannonBehavior behavior) {
|
||||||
|
behavior.register();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ import net.minecraft.util.Mth;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class CannonEntityRenderer extends EntityRenderer<CannonEntity> {
|
public class CannonEntityRenderer extends EntityRenderer<CannonEntity> {
|
||||||
public static final ModelLayerLocation MODEL = new ModelLayerLocation(BlastTravelReborn.id("cannon"), "main");
|
public static final ModelLayerLocation MODEL = new ModelLayerLocation(BlastTravelReborn.id("cannon"), "main");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.content;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.data.worldgen.BootstapContext;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.damagesource.DamageScaling;
|
||||||
|
import net.minecraft.world.damagesource.DamageType;
|
||||||
|
|
||||||
|
public class BTRDamageTypes {
|
||||||
|
public static final ResourceKey<DamageType> CANNON = ResourceKey.create(Registries.DAMAGE_TYPE,
|
||||||
|
BlastTravelReborn.id("cannon"));
|
||||||
|
|
||||||
|
public static void bootstrap(BootstapContext<DamageType> context) {
|
||||||
|
context.register(CANNON, new DamageType(
|
||||||
|
"cannon",
|
||||||
|
DamageScaling.WHEN_CAUSED_BY_LIVING_NON_PLAYER,
|
||||||
|
0.0F
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,6 @@ import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
|
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
|
@ -163,6 +162,11 @@ public class CannonEntity extends Entity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand) {
|
public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand) {
|
||||||
|
ItemStack handItem = player.getItemInHand(hand);
|
||||||
|
// 如果手持火药,填充到大炮中
|
||||||
|
if(!player.isShiftKeyDown()) {
|
||||||
|
if (testAndInteract(player, handItem)) return InteractionResult.sidedSuccess(level().isClientSide());
|
||||||
|
}
|
||||||
if (player == this.getFirstPassenger()) {
|
if (player == this.getFirstPassenger()) {
|
||||||
return super.interact(player, hand);
|
return super.interact(player, hand);
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +200,90 @@ public class CannonEntity extends Entity {
|
||||||
return super.interact(player, hand);
|
return super.interact(player, hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean testAndInteract(Player player, @NotNull ItemStack stack) {
|
||||||
|
if (stack.is(Items.GUNPOWDER)) {
|
||||||
|
handlerGunPower(player, stack);
|
||||||
|
return true;
|
||||||
|
} else if (stack.is(Items.CHAIN)) {
|
||||||
|
handlerChain(player, stack);
|
||||||
|
return true;
|
||||||
|
} else if (CannonBehavior.isValidBehaviorStack(stack)) {
|
||||||
|
handlerBehaviorItem(player, stack);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlerGunPower(Player player, ItemStack stack) {
|
||||||
|
if (!level().isClientSide()) {
|
||||||
|
ItemStack currentGunpowder = inventory.getItem(0);
|
||||||
|
|
||||||
|
// 如果炮内已有火药,先还给玩家
|
||||||
|
if (currentGunpowder.getCount() >= currentGunpowder.getMaxStackSize()) {
|
||||||
|
if (!player.isCreative() && !player.getInventory().add(currentGunpowder)) {
|
||||||
|
// 如果背包满了,掉落在地上
|
||||||
|
player.drop(currentGunpowder, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的火药到炮中
|
||||||
|
ItemStack newGunpowder = stack.copy();
|
||||||
|
newGunpowder.setCount(currentGunpowder.getCount() + 1); // 只放一个火药
|
||||||
|
((ServerPlayer) player).sendSystemMessage(Component.literal(String.format("%d / %d", currentGunpowder.getCount(), currentGunpowder.getMaxStackSize())), true);
|
||||||
|
inventory.setItem(0, newGunpowder);
|
||||||
|
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
stack.shrink(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
level().playSound(null, this.blockPosition(), SoundEvents.SAND_PLACE, SoundSource.BLOCKS, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlerChain(Player player, ItemStack stack) {
|
||||||
|
if (!level().isClientSide()) {
|
||||||
|
ItemStack currentChain = inventory.getItem(2);
|
||||||
|
if (currentChain.isEmpty()) { // 添加锁链
|
||||||
|
ItemStack item = stack.copy();
|
||||||
|
item.setCount(1);
|
||||||
|
inventory.setItem(2, item);
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
stack.shrink(1);
|
||||||
|
}
|
||||||
|
level().playSound(null, this.blockPosition(), SoundEvents.CHAIN_PLACE, SoundSource.BLOCKS, 1.0f, 1.0f);
|
||||||
|
} else {
|
||||||
|
inventory.setItem(2, ItemStack.EMPTY);
|
||||||
|
if (!player.isCreative()) { // 移除锁链
|
||||||
|
if (!player.getInventory().add(currentChain)) {
|
||||||
|
player.drop(currentChain, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
level().playSound(null, this.blockPosition(), SoundEvents.CHAIN_FALL, SoundSource.BLOCKS, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlerBehaviorItem(Player player, ItemStack stack) {
|
||||||
|
if (!level().isClientSide()) {
|
||||||
|
ItemStack currentBehaviorItem = inventory.getItem(2);
|
||||||
|
if (currentBehaviorItem.isEmpty()) { // 添加物品
|
||||||
|
ItemStack item = stack.copy();
|
||||||
|
item.setCount(1);
|
||||||
|
inventory.setItem(2, item);
|
||||||
|
if (!player.isCreative()) {
|
||||||
|
stack.shrink(1);
|
||||||
|
}
|
||||||
|
level().playSound(null, this.blockPosition(), getBehavior().getPlaceInSound(), SoundSource.BLOCKS, 1.0f, 1.0f);
|
||||||
|
} else {
|
||||||
|
if (stack.is(currentBehaviorItem.getItem())) { //同类物品 +1
|
||||||
|
|
||||||
|
} else { //不同类替换
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean skipAttackInteraction(@NotNull Entity attacker) {
|
public boolean skipAttackInteraction(@NotNull Entity attacker) {
|
||||||
if (attacker instanceof Player player && player != this.getFirstPassenger()) {
|
if (attacker instanceof Player player && player != this.getFirstPassenger()) {
|
||||||
|
|
@ -299,12 +387,17 @@ public class CannonEntity extends Entity {
|
||||||
System.out.println(" - [B]Server: Bounding Box = " + player.getBoundingBox());
|
System.out.println(" - [B]Server: Bounding Box = " + player.getBoundingBox());
|
||||||
System.out.println(" - [B]Server: Delta Movement = " + player.getDeltaMovement());
|
System.out.println(" - [B]Server: Delta Movement = " + player.getDeltaMovement());
|
||||||
}
|
}
|
||||||
player.stopRiding();
|
|
||||||
((ServerPlayer) player).connection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
|
// 关键修改:先设置速度,再停止乘坐
|
||||||
((ServerPlayer) player).connection.send(new ClientboundSetEntityMotionPacket(player));
|
|
||||||
player.setDeltaMovement(vel);
|
player.setDeltaMovement(vel);
|
||||||
player.hurtMarked = true;
|
player.hurtMarked = true; // 强制同步运动状态
|
||||||
|
|
||||||
|
// 然后停止乘坐
|
||||||
|
player.stopRiding();
|
||||||
|
|
||||||
|
// 设置飞行状态
|
||||||
((PlayerEntityDuck)player).blasttravel$setCannonFlight(true);
|
((PlayerEntityDuck)player).blasttravel$setCannonFlight(true);
|
||||||
|
|
||||||
if (!FMLEnvironment.production) {
|
if (!FMLEnvironment.production) {
|
||||||
System.out.println(" - [A]Server: Is Passenger = " + player.isPassenger());
|
System.out.println(" - [A]Server: Is Passenger = " + player.isPassenger());
|
||||||
System.out.println(" - [A]Server: On Ground = " + player.onGround());
|
System.out.println(" - [A]Server: On Ground = " + player.onGround());
|
||||||
|
|
@ -315,7 +408,6 @@ public class CannonEntity extends Entity {
|
||||||
System.out.println(" - [A]Server: Delta Movement = " + player.getDeltaMovement());
|
System.out.println(" - [A]Server: Delta Movement = " + player.getDeltaMovement());
|
||||||
}
|
}
|
||||||
firedPlayer = player;
|
firedPlayer = player;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.level().playSound(null, this.blockPosition(), SoundEvents.GENERIC_EXPLODE, SoundSource.BLOCKS, 1, 1);
|
this.level().playSound(null, this.blockPosition(), SoundEvents.GENERIC_EXPLODE, SoundSource.BLOCKS, 1, 1);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import com.leisuretimedock.blasttravelreborn.content.entity.CannonEntity;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
@ -16,13 +18,15 @@ import org.joml.Vector3f;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class CannonBehavior {
|
public class CannonBehavior {
|
||||||
protected static final Vector3f WHITE = new Vector3f(1, 1, 1);
|
protected static final Vector3f WHITE = new Vector3f(1, 1, 1);
|
||||||
private static final List<CannonBehavior> ID_TO_BEHAVIOR = new ArrayList<>();
|
private static final List<CannonBehavior> ID_TO_BEHAVIOR = new ArrayList<>();
|
||||||
private static final Object2IntMap<Predicate<ItemStack>> FILTER_TO_BEHAVIOR_ID = new Object2IntOpenHashMap<>();
|
private static final Object2IntMap<Predicate<ItemStack>> FILTER_TO_BEHAVIOR_ID = new Object2IntOpenHashMap<>();
|
||||||
|
private final AtomicBoolean registered = new AtomicBoolean(false);
|
||||||
|
private SoundEvent placeInSound = SoundEvents.SAND_PLACE, takeOutSound = SoundEvents.EMPTY;
|
||||||
public final Item icon;
|
public final Item icon;
|
||||||
public final Predicate<ItemStack> filter;
|
public final Predicate<ItemStack> filter;
|
||||||
private final ResourceLocation texture;
|
private final ResourceLocation texture;
|
||||||
|
|
@ -41,10 +45,28 @@ public class CannonBehavior {
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CannonBehavior register() {
|
public void setPlaceInSound(SoundEvent placeInSound) {
|
||||||
FILTER_TO_BEHAVIOR_ID.put(this.filter, ID_TO_BEHAVIOR.size());
|
this.placeInSound = placeInSound;
|
||||||
ID_TO_BEHAVIOR.add(this);
|
}
|
||||||
|
|
||||||
|
public SoundEvent getPlaceInSound() {
|
||||||
|
return placeInSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SoundEvent getTakeOutSound() {
|
||||||
|
return takeOutSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTakeOutSound(SoundEvent takeOutSound) {
|
||||||
|
this.takeOutSound = takeOutSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CannonBehavior register() {
|
||||||
|
if (!registered.get()) {
|
||||||
|
FILTER_TO_BEHAVIOR_ID.put(this.filter, ID_TO_BEHAVIOR.size());
|
||||||
|
ID_TO_BEHAVIOR.add(this);
|
||||||
|
registered.set(true);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +108,7 @@ public class CannonBehavior {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public ResourceLocation headTexture(CannonEntity entity) {
|
public ResourceLocation headTexture(CannonEntity entity) {
|
||||||
var player = entity.getClientPlayer();
|
var player = entity.getClientPlayer();
|
||||||
|
|
@ -105,4 +128,5 @@ public class CannonBehavior {
|
||||||
public @Nullable Vector3f fireColor(CannonEntity entity) {
|
public @Nullable Vector3f fireColor(CannonEntity entity) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.BTRDamageTypes;
|
||||||
|
import net.minecraft.core.RegistrySetBuilder;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
|
||||||
|
public class BTRRegistries {
|
||||||
|
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
|
||||||
|
.add(Registries.DAMAGE_TYPE, BTRDamageTypes::bootstrap)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.datagen.provider.BTRItemModelProvider;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.datagen.provider.BTRParticleProvider;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.datagen.provider.BTRRecipeProvider;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.datagen.value.BTRLangKeys;
|
||||||
|
import net.minecraft.data.DataProvider;
|
||||||
|
import net.minecraftforge.common.data.DatapackBuiltinEntriesProvider;
|
||||||
|
import net.minecraftforge.data.event.GatherDataEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.r3944realms.lib39.datagen.provider.SimpleLanguageProvider;
|
||||||
|
import top.r3944realms.lib39.datagen.value.McLocale;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mod.EventBusSubscriber(modid = BlastTravelReborn.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||||
|
public class DataGeneratorHandler {
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void generatorDataEvent(GatherDataEvent event) {
|
||||||
|
LanguageGenerate(event, McLocale.EN_US);
|
||||||
|
LanguageGenerate(event, McLocale.ZH_CN);
|
||||||
|
LanguageGenerate(event, McLocale.ZH_TW);
|
||||||
|
ModelDataGenerate(event);
|
||||||
|
ParticleGenerate(event);
|
||||||
|
RecipeGenerate(event);
|
||||||
|
DatapackBuiltinEntriesGenerate(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LanguageGenerate(@NotNull GatherDataEvent event, McLocale language) {
|
||||||
|
event.getGenerator().addProvider(
|
||||||
|
event.includeClient(),
|
||||||
|
(DataProvider.Factory<SimpleLanguageProvider>) pOutput -> new SimpleLanguageProvider(pOutput, BlastTravelReborn.MOD_ID ,language , BTRLangKeys.INSTANCE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private static void ModelDataGenerate(GatherDataEvent event) {
|
||||||
|
event.getGenerator().addProvider(
|
||||||
|
event.includeClient(),
|
||||||
|
(DataProvider.Factory<BTRItemModelProvider>) pOutput -> new BTRItemModelProvider(pOutput, event.getExistingFileHelper())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private static void RecipeGenerate(GatherDataEvent event) {
|
||||||
|
event.getGenerator().addProvider(
|
||||||
|
event.includeServer(),
|
||||||
|
(DataProvider.Factory<BTRRecipeProvider>) BTRRecipeProvider::new
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private static void ParticleGenerate(GatherDataEvent event) {
|
||||||
|
event.getGenerator().addProvider(
|
||||||
|
event.includeClient(),
|
||||||
|
(DataProvider.Factory<BTRParticleProvider>) pOutput -> new BTRParticleProvider(pOutput, event.getExistingFileHelper())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private static void DatapackBuiltinEntriesGenerate(GatherDataEvent event) {
|
||||||
|
event.getGenerator().addProvider(
|
||||||
|
event.includeServer(),
|
||||||
|
(DataProvider.Factory<DatapackBuiltinEntriesProvider>) pOutput -> new DatapackBuiltinEntriesProvider(pOutput, event.getLookupProvider(), BTRRegistries.BUILDER, Set.of(BlastTravelReborn.MOD_ID))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen.provider;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.item.BTRItems;
|
||||||
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraftforge.client.model.generators.ItemModelProvider;
|
||||||
|
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||||
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class BTRItemModelProvider extends ItemModelProvider {
|
||||||
|
public static final String GENERATED = "item/generated";
|
||||||
|
public BTRItemModelProvider(PackOutput packOutput, ExistingFileHelper existingFileHelper) {
|
||||||
|
super(packOutput, BlastTravelReborn.MOD_ID, existingFileHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerModels() {
|
||||||
|
itemGeneratedModel(BTRItems.CANNON_ITEM.get(), resourceItem("cannon"));
|
||||||
|
}
|
||||||
|
public void itemGeneratedModel(Item item, ResourceLocation texture) {
|
||||||
|
withExistingParent(itemName(item), GENERATED).texture("layer0", texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String itemName(Item item) {
|
||||||
|
return Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)).getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation resourceItem(String path) {
|
||||||
|
return BlastTravelReborn.id("item/" + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen.provider;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.BTRParticleTypes;
|
||||||
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||||
|
import net.minecraftforge.common.data.ParticleDescriptionProvider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BTRParticleProvider extends ParticleDescriptionProvider {
|
||||||
|
|
||||||
|
public BTRParticleProvider(PackOutput output, ExistingFileHelper fileHelper) {
|
||||||
|
super(output, fileHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addDescriptions() {
|
||||||
|
List<ResourceLocation> cannonBlastTextures = new ArrayList<>();
|
||||||
|
for (int i = 0; i <= 7; i++){
|
||||||
|
cannonBlastTextures.add(BlastTravelReborn.id("blast_smoke_" + i));
|
||||||
|
}
|
||||||
|
spriteSet(BTRParticleTypes.CANNON_BLAST.get(), cannonBlastTextures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen.provider;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.item.BTRItems;
|
||||||
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.data.recipes.FinishedRecipe;
|
||||||
|
import net.minecraft.data.recipes.RecipeCategory;
|
||||||
|
import net.minecraft.data.recipes.RecipeProvider;
|
||||||
|
import net.minecraft.data.recipes.ShapedRecipeBuilder;
|
||||||
|
import net.minecraft.tags.ItemTags;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class BTRRecipeProvider extends RecipeProvider {
|
||||||
|
public BTRRecipeProvider(PackOutput pOutput) {
|
||||||
|
super(pOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void buildRecipes(@NotNull Consumer<FinishedRecipe> pWriter) {
|
||||||
|
// 第二个配方(您提供的JSON转换而来)
|
||||||
|
ShapedRecipeBuilder.shaped(RecipeCategory.MISC, BTRItems.CANNON_ITEM.get(), 1)
|
||||||
|
.define('A', Items.IRON_BLOCK)
|
||||||
|
.define('B', Items.STRING)
|
||||||
|
.define('C', ItemTags.STONE_CRAFTING_MATERIALS)
|
||||||
|
.define('D', Items.STICK)
|
||||||
|
.define('E', ItemTags.LOGS)
|
||||||
|
.pattern(" A")
|
||||||
|
.pattern("BA ")
|
||||||
|
.pattern("CDE")
|
||||||
|
.unlockedBy("has_iron_block", has(Items.IRON_BLOCK))
|
||||||
|
.save(pWriter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
package com.leisuretimedock.blasttravelreborn.datagen.value;
|
||||||
|
|
||||||
|
import com.leisuretimedock.blasttravelreborn.BlastTravelReborn;
|
||||||
|
import com.leisuretimedock.blasttravelreborn.content.item.BTRItems;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
import top.r3944realms.lib39.datagen.value.ILangKeyValueCollection;
|
||||||
|
import top.r3944realms.lib39.datagen.value.LangKeyValue;
|
||||||
|
import top.r3944realms.lib39.datagen.value.ModPartEnum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public enum BTRLangKeys implements ILangKeyValueCollection {
|
||||||
|
INSTANCE;
|
||||||
|
BTRLangKeys() {
|
||||||
|
initLangKeyValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<LangKeyValue> langKeyValues = new ArrayList<>();
|
||||||
|
public void initLangKeyValues() {
|
||||||
|
addLang(LangKeyValue.ofSupplier(
|
||||||
|
BTRItems.CANNON_ITEM, ModPartEnum.ITEM,
|
||||||
|
"Cannon",
|
||||||
|
"大炮",
|
||||||
|
"大砲",
|
||||||
|
true
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
ModPartEnum.ENTITY.getFullKey(BlastTravelReborn.MOD_ID, "cannon"), ModPartEnum.ENTITY,
|
||||||
|
"Cannon",
|
||||||
|
"大炮",
|
||||||
|
"大砲"
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
"container.blasttravelreborn.cannon_container_menu", ModPartEnum.GUI,
|
||||||
|
"Cannon",
|
||||||
|
"大炮实体",
|
||||||
|
"大砲實體"
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
"death.attack.blasttravelreborn.cannon", ModPartEnum.MESSAGE,
|
||||||
|
"%s was knocked out by a flying %s",
|
||||||
|
"%s被飞行的%s击倒了",
|
||||||
|
"%s被飛行的%s擊倒了"
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
"dialog.blasttravelreborn.full_cannon", ModPartEnum.MESSAGE,
|
||||||
|
"Cannon is full!",
|
||||||
|
"大炮已装满!",
|
||||||
|
"大砲已裝滿!"
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
"dialog.blasttravelreborn.no_gunpowder", ModPartEnum.MESSAGE,
|
||||||
|
"Cannon has no gunpowder!",
|
||||||
|
"大炮没有火药了!",
|
||||||
|
"大砲沒有火藥了!"
|
||||||
|
));
|
||||||
|
addLang(LangKeyValue.ofKey(
|
||||||
|
"mount.blasttravelreborn.cannon.onboard", ModPartEnum.MESSAGE,
|
||||||
|
"Press %s to Exit, or %s to Fire",
|
||||||
|
"按%s离开,或按%s发射",
|
||||||
|
"按%s離開,或按%s發射"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLang(LangKeyValue keyValue) {
|
||||||
|
langKeyValues.add(keyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
langKeyValues.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
@Override
|
||||||
|
public @Unmodifiable List<LangKeyValue> getValues() {
|
||||||
|
return List.copyOf(langKeyValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@ package com.leisuretimedock.blasttravelreborn.network.toClient;
|
||||||
|
|
||||||
import com.leisuretimedock.blasttravelreborn.content.entity.CannonEntity;
|
import com.leisuretimedock.blasttravelreborn.content.entity.CannonEntity;
|
||||||
import com.leisuretimedock.blasttravelreborn.util.PlayerEntityDuck;
|
import com.leisuretimedock.blasttravelreborn.util.PlayerEntityDuck;
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
@ -40,45 +39,35 @@ public record FireCannonPayload(int cannonId, Optional<Integer> launchedId, doub
|
||||||
}
|
}
|
||||||
public void handler(Supplier<NetworkEvent.Context> ctx) {
|
public void handler(Supplier<NetworkEvent.Context> ctx) {
|
||||||
NetworkEvent.Context context = ctx.get();
|
NetworkEvent.Context context = ctx.get();
|
||||||
if(context.getNetworkManager().getPacketListener() instanceof ClientPacketListener clientPacketListener) {
|
if (context.getNetworkManager().getPacketListener() instanceof ClientPacketListener clientPacketListener) {
|
||||||
context.enqueueWork(() -> {
|
context.enqueueWork(() -> {
|
||||||
if(hasPlayer()) {
|
if (hasPlayer()) {
|
||||||
//noinspection OptionalGetWithoutIsPresent
|
|
||||||
if (clientPacketListener.getLevel().getEntity(launchedId.get()) instanceof Player launchedPlayer) {
|
if (clientPacketListener.getLevel().getEntity(launchedId.get()) instanceof Player launchedPlayer) {
|
||||||
|
// 记录发射前状态
|
||||||
if (!FMLEnvironment.production) {
|
if (!FMLEnvironment.production) {
|
||||||
System.out.println(" - [B]Client: Is Passenger = " + launchedPlayer.isPassenger());
|
System.out.println(" - [B]Client: Is Passenger = " + launchedPlayer.isPassenger());
|
||||||
System.out.println(" - [B]Client: On Ground = " + launchedPlayer.onGround());
|
|
||||||
System.out.println(" - [B]Client: noPhysics =" + launchedPlayer.noPhysics);
|
|
||||||
System.out.println(" - [B]Client: Pose = " + launchedPlayer.getPose());
|
|
||||||
System.out.println(" - [B]Client: riding entity = " + launchedPlayer.getVehicle());
|
|
||||||
System.out.println(" - [B]Client: Bounding Box = " + launchedPlayer.getBoundingBox());
|
|
||||||
System.out.println(" - [B]Client: Delta Movement = " + launchedPlayer.getDeltaMovement());
|
System.out.println(" - [B]Client: Delta Movement = " + launchedPlayer.getDeltaMovement());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 立即停止乘坐并设置速度
|
||||||
if (launchedPlayer.isPassenger()) {
|
if (launchedPlayer.isPassenger()) {
|
||||||
launchedPlayer.stopRiding();
|
launchedPlayer.stopRiding();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 延迟一个 tick 执行飞行初始化逻辑
|
// 直接设置速度,不要延迟
|
||||||
Minecraft.getInstance().tell(() -> {
|
launchedPlayer.setDeltaMovement(velocityX, velocityY, velocityZ);
|
||||||
// 此时已脱离炮台,设置速度
|
launchedPlayer.hurtMarked = true; // 强制同步运动
|
||||||
launchedPlayer.getAbilities().flying = false;
|
((PlayerEntityDuck) launchedPlayer).blasttravel$setCannonFlight(true);
|
||||||
launchedPlayer.setPos(launchedPlayer.getX(), launchedPlayer.getY(), launchedPlayer.getZ());
|
|
||||||
launchedPlayer.setDeltaMovement(velocityX, velocityY, velocityZ);
|
|
||||||
((PlayerEntityDuck) launchedPlayer).blasttravel$setCannonFlight(true);
|
|
||||||
|
|
||||||
// 输出变更后状态
|
// 记录发射后状态
|
||||||
if (!FMLEnvironment.production) {
|
if (!FMLEnvironment.production) {
|
||||||
System.out.println(" - [A]Client: Is Passenger = " + launchedPlayer.isPassenger());
|
System.out.println(" - [A]Client: Is Passenger = " + launchedPlayer.isPassenger());
|
||||||
System.out.println(" - [A]Client: On Ground = " + launchedPlayer.onGround());
|
System.out.println(" - [A]Client: Delta Movement = " + launchedPlayer.getDeltaMovement());
|
||||||
System.out.println(" - [A]Client: noPhysics = " + launchedPlayer.noPhysics);
|
}
|
||||||
System.out.println(" - [A]Client: Pose = " + launchedPlayer.getPose());
|
|
||||||
System.out.println(" - [A]Client: riding entity = " + launchedPlayer.getVehicle());
|
|
||||||
System.out.println(" - [A]Client: Bounding Box = " + launchedPlayer.getBoundingBox());
|
|
||||||
System.out.println(" - [A]Client: Delta Movement = " + launchedPlayer.getDeltaMovement());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理炮实体效果
|
||||||
Entity entity = clientPacketListener.getLevel().getEntity(cannonId);
|
Entity entity = clientPacketListener.getLevel().getEntity(cannonId);
|
||||||
if (entity instanceof CannonEntity cannonEntity) {
|
if (entity instanceof CannonEntity cannonEntity) {
|
||||||
cannonEntity.fireClient();
|
cannonEntity.fireClient();
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,6 @@ import net.minecraftforge.network.NetworkEvent;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public record StopCannonFlightClientPayload(int flyingId) {
|
public record StopCannonFlightClientPayload(int flyingId) {
|
||||||
public StopCannonFlightClientPayload(FriendlyByteBuf buf) {
|
|
||||||
this(buf.readInt());
|
|
||||||
}
|
|
||||||
public StopCannonFlightClientPayload(Player flying) {
|
public StopCannonFlightClientPayload(Player flying) {
|
||||||
this(flying.getId());
|
this(flying.getId());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,7 @@ public record RequestFirePayload(int cannonId) {
|
||||||
public RequestFirePayload(CannonEntity cannonEntity) {
|
public RequestFirePayload(CannonEntity cannonEntity) {
|
||||||
this(cannonEntity.getId());
|
this(cannonEntity.getId());
|
||||||
}
|
}
|
||||||
public RequestFirePayload(FriendlyByteBuf buf) {
|
|
||||||
this(buf.readInt());
|
|
||||||
}
|
|
||||||
public void write(FriendlyByteBuf buf) {
|
public void write(FriendlyByteBuf buf) {
|
||||||
buf.writeInt(cannonId);
|
buf.writeInt(cannonId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,12 @@ versionRange = "${minecraft_version_range}"
|
||||||
ordering = "NONE"
|
ordering = "NONE"
|
||||||
side = "BOTH"
|
side = "BOTH"
|
||||||
[[dependencies."${mod_id}"]]
|
[[dependencies."${mod_id}"]]
|
||||||
versionRange = "[0.2.1+1.20-fabrge,)"
|
versionRange = "[0.2.3,)"
|
||||||
modId = "jsonem"
|
modId = "jsonem"
|
||||||
mandatory = false
|
mandatory = false
|
||||||
side = "CLIENT"
|
side = "CLIENT"
|
||||||
|
[[dependencies."${mod_id}"]]
|
||||||
|
versionRange = "[0.0.17,)"
|
||||||
|
modId = "lib39"
|
||||||
|
mandatory = false
|
||||||
|
side = "BOTH"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"container.blasttravelreborn.cannon_container_menu": "Cannon",
|
|
||||||
"item.blasttravelreborn.cannon": "Cannon",
|
|
||||||
"entity.blasttravelreborn.cannon": "Cannon",
|
|
||||||
|
|
||||||
"death.attack.blasttravelreborn.cannon": "%s was knocked out by a flying %s",
|
|
||||||
"dialog.blasttravelreborn.full_cannon": "Cannon is full!",
|
|
||||||
"dialog.blasttravelreborn.no_gunpowder": "Cannon has no gunpowder!",
|
|
||||||
"mount.blasttravelreborn.cannon.onboard": "Press %s to Exit, or %s to Fire"
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"parent": "item/generated",
|
|
||||||
"textures": {
|
|
||||||
"layer0": "blasttravelreborn:item/cannon"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"textures": [
|
|
||||||
"blasttravelreborn:blast_smoke_0",
|
|
||||||
"blasttravelreborn:blast_smoke_1",
|
|
||||||
"blasttravelreborn:blast_smoke_2",
|
|
||||||
"blasttravelreborn:blast_smoke_3",
|
|
||||||
"blasttravelreborn:blast_smoke_4",
|
|
||||||
"blasttravelreborn:blast_smoke_5",
|
|
||||||
"blasttravelreborn:blast_smoke_6",
|
|
||||||
"blasttravelreborn:blast_smoke_7",
|
|
||||||
"blasttravelreborn:blast_smoke_8"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,10 @@
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"LivingEntityAccess",
|
"LivingEntityAccess",
|
||||||
"PlayerEntityMixin",
|
"PlayerEntityMixin"
|
||||||
"PlayerEntityMixinClient"
|
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
"PlayerEntityMixinClient",
|
||||||
"ClientPlayerEntityMixin",
|
"ClientPlayerEntityMixin",
|
||||||
"ClientPlayNetworkHandlerMixin",
|
"ClientPlayNetworkHandlerMixin",
|
||||||
"PlayerEntityModelMixin",
|
"PlayerEntityModelMixin",
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"type": "minecraft:crafting_shaped",
|
|
||||||
"pattern": [
|
|
||||||
" A",
|
|
||||||
"BA ",
|
|
||||||
"CDE"
|
|
||||||
],
|
|
||||||
"key": {
|
|
||||||
"A": {"item": "minecraft:iron_block"},
|
|
||||||
"B": {"item": "minecraft:string"},
|
|
||||||
"C": {"tag": "minecraft:stone_crafting_materials"},
|
|
||||||
"D": {"item": "minecraft:stick"},
|
|
||||||
"E": {"tag": "minecraft:logs"}
|
|
||||||
},
|
|
||||||
"result": {
|
|
||||||
"item": "blasttravelreborn:cannon",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user