mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-23 15:00:37 +01:00
Merge branch 'master' of https://github.com/GeyserMC/Geyser into feature/configurate
This commit is contained in:
commit
528de86340
157 changed files with 3138 additions and 1837 deletions
14
.editorconfig
Normal file
14
.editorconfig
Normal file
|
@ -0,0 +1,14 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
max_line_length = off
|
||||
|
||||
[*.java]
|
||||
ij_java_class_count_to_use_import_on_demand = 9999
|
||||
ij_java_doc_align_exception_comments = false
|
||||
ij_java_doc_align_param_comments = false
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
|
@ -103,19 +103,13 @@ jobs:
|
|||
bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
|
||||
changelog: ${{ steps.metadata.outputs.body }}
|
||||
|
||||
- name: Publish to Modrinth (Fabric)
|
||||
- name: Publish to Modrinth
|
||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||
env:
|
||||
CHANGELOG: ${{ steps.metadata.outputs.body }}
|
||||
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
run: ./gradlew fabric:modrinth
|
||||
|
||||
- name: Publish to Modrinth (NeoForge)
|
||||
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
|
||||
env:
|
||||
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
run: ./gradlew neoforge:modrinth
|
||||
run: ./gradlew modrinth
|
||||
|
||||
- name: Notify Discord
|
||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||
|
|
|
@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
|||
|
||||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
|
||||
|
||||
### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.20.5/1.20.6
|
||||
### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.1 and Minecraft Java 1.21
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
|
||||
|
|
|
@ -73,7 +73,10 @@ public interface JavaBlockState {
|
|||
* Gets whether the block state has block entity
|
||||
*
|
||||
* @return whether the block state has block entity
|
||||
* @deprecated Does not have an effect. If you were using this to
|
||||
* set piston behavior, use {@link #pistonBehavior()} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
boolean hasBlockEntity();
|
||||
|
||||
/**
|
||||
|
@ -104,6 +107,11 @@ public interface JavaBlockState {
|
|||
|
||||
Builder pistonBehavior(@Nullable String pistonBehavior);
|
||||
|
||||
/**
|
||||
* @deprecated Does not have an effect. If you were using this to
|
||||
* * set piston behavior, use {@link #pistonBehavior(String)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
Builder hasBlockEntity(boolean hasBlockEntity);
|
||||
|
||||
JavaBlockState build();
|
||||
|
|
|
@ -34,3 +34,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("io.netty:netty-resolver-dns:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.add("bungeecord")
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
// Copied from ViaVersion.
|
||||
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
|
||||
try {
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_20_5");
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_21");
|
||||
} catch (NoSuchFieldException e) {
|
||||
geyserLogger.error(" / \\");
|
||||
geyserLogger.error(" / \\");
|
||||
|
|
|
@ -6,6 +6,13 @@ loom {
|
|||
mixin.defaultRefmapName.set("geyser-refmap.json")
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
// We don't need these
|
||||
tasks.named("remapModrinthJar").configure {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core)
|
||||
compileOnly(libs.mixin)
|
||||
|
|
|
@ -63,6 +63,7 @@ tasks {
|
|||
|
||||
modrinth {
|
||||
loaders.add("fabric")
|
||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||
dependencies {
|
||||
required.project("fabric-api")
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
"geyser.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.10",
|
||||
"fabricloader": ">=0.15.11",
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.20.5"
|
||||
"minecraft": ">=1.21"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,5 @@ tasks {
|
|||
|
||||
modrinth {
|
||||
loaders.add("neoforge")
|
||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||
}
|
|
@ -14,12 +14,12 @@ config = "geyser.mixins.json"
|
|||
[[dependencies.geyser_neoforge]]
|
||||
modId="neoforge"
|
||||
type="required"
|
||||
versionRange="[20.5.0-beta,)"
|
||||
versionRange="[21.0.0-beta,)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
[[dependencies.geyser_neoforge]]
|
||||
modId="minecraft"
|
||||
type="required"
|
||||
versionRange="[1.20.5,1.21)"
|
||||
versionRange="[1.21,)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
|
@ -30,6 +30,7 @@ import net.minecraft.SharedConstants;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
@ -39,14 +40,17 @@ import net.minecraft.world.level.block.Block;
|
|||
import net.minecraft.world.level.block.entity.BannerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BannerPatternLayers;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||
|
@ -55,6 +59,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponen
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class GeyserModWorldManager extends GeyserWorldManager {
|
||||
|
||||
|
@ -160,6 +165,27 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
|||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer<List<String>> apply) {
|
||||
server.execute(() -> {
|
||||
ServerPlayer player = getPlayer(session);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos blockPos = new BlockPos(pos.getX(), pos.getY(), pos.getZ());
|
||||
// Don't create a new block entity if invalid
|
||||
//noinspection resource - level() is just a getter
|
||||
BlockEntity blockEntity = player.level().getChunkAt(blockPos).getBlockEntity(blockPos);
|
||||
if (blockEntity instanceof DecoratedPotBlockEntity pot) {
|
||||
List<String> sherds = pot.getDecorations().ordered()
|
||||
.stream().map(item -> BuiltInRegistries.ITEM.getKey(item).toString())
|
||||
.toList();
|
||||
apply.accept(sherds);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ServerPlayer getPlayer(GeyserSession session) {
|
||||
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
||||
}
|
||||
|
@ -173,7 +199,7 @@ public class GeyserModWorldManager extends GeyserWorldManager {
|
|||
return patternLayers.layers().stream()
|
||||
.map(layer -> {
|
||||
BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern(
|
||||
layer.pattern().value().assetId().toString(), layer.pattern().value().translationKey()
|
||||
MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey()
|
||||
);
|
||||
return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId());
|
||||
})
|
||||
|
|
|
@ -78,3 +78,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("com.mojang:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.addAll("spigot", "paper")
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||
geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion);
|
||||
} catch (Exception e) { // Likely running on Paper 1.20.5+
|
||||
geyserLogger.debug("Unable to find spigot world manager: " + e.getMessage());
|
||||
//noinspection deprecation
|
||||
int protocolVersion = Bukkit.getUnsafe().getProtocolVersion();
|
||||
PaperAdapters.registerClosestWorldAdapter(protocolVersion);
|
||||
|
|
|
@ -29,10 +29,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.DecoratedPot;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.geysermc.erosion.bukkit.BukkitUtils;
|
||||
import org.geysermc.erosion.bukkit.PickBlockUtils;
|
||||
import org.geysermc.erosion.bukkit.SchedulerUtils;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
@ -43,8 +46,10 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The base world manager to use when there is no supported NMS revision
|
||||
|
@ -146,6 +151,21 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
|||
return future.thenApply(RAW_TRANSFORMER);
|
||||
}
|
||||
|
||||
public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer<List<String>> apply) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
|
||||
return;
|
||||
}
|
||||
Block block = bukkitPlayer.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
SchedulerUtils.runTask(this.plugin, () -> {
|
||||
var state = BukkitUtils.getBlockState(block);
|
||||
if (!(state instanceof DecoratedPot pot)) {
|
||||
return;
|
||||
}
|
||||
apply.accept(pot.getShards().stream().map(material -> material.getKey().toString()).toList());
|
||||
}, block);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
|
||||
* to the current one.
|
||||
|
|
|
@ -69,4 +69,9 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
|
||||
exclude(dependency("net.kyori:adventure-nbt:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.addAll("velocity")
|
||||
}
|
|
@ -12,6 +12,9 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
// this is OK as long as the same version catalog is used in the main build and build-logic
|
||||
// see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
|
||||
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
|
||||
implementation(libs.indra)
|
||||
implementation(libs.shadow)
|
||||
implementation(libs.architectury.plugin)
|
||||
|
|
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
|
@ -0,0 +1,6 @@
|
|||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
val Project.libs: LibrariesForLibs
|
||||
get() = rootProject.extensions.getByType()
|
|
@ -8,7 +8,6 @@ plugins {
|
|||
id("geyser.publish-conventions")
|
||||
id("architectury-plugin")
|
||||
id("dev.architectury.loom")
|
||||
id("com.modrinth.minotaur")
|
||||
}
|
||||
|
||||
// These are provided by Minecraft/modded platforms already, no need to include them
|
||||
|
@ -39,7 +38,7 @@ provided("io.netty", "netty-resolver-dns-native-macos")
|
|||
provided("org.ow2.asm", "asm")
|
||||
|
||||
architectury {
|
||||
minecraft = "1.20.5"
|
||||
minecraft = libs.minecraft.get().version as String
|
||||
}
|
||||
|
||||
loom {
|
||||
|
@ -83,7 +82,7 @@ tasks {
|
|||
register("remapModrinthJar", RemapJarTask::class) {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.get().archiveFile)
|
||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
|
||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER"))
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +92,7 @@ afterEvaluate {
|
|||
|
||||
// These are shaded, no need to JiJ them
|
||||
configurations["shadow"].dependencies.forEach {shadowed ->
|
||||
println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
|
||||
//println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
|
||||
providedDependencies.add("${shadowed.group}:${shadowed.name}")
|
||||
}
|
||||
|
||||
|
@ -101,39 +100,24 @@ afterEvaluate {
|
|||
configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep ->
|
||||
if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}")
|
||||
and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) {
|
||||
println("Including dependency via JiJ: ${dep.id}")
|
||||
//println("Including dependency via JiJ: ${dep.id}")
|
||||
dependencies.add("include", dep.moduleVersion.id.toString())
|
||||
} else {
|
||||
println("Not including ${dep.id} for ${project.name}!")
|
||||
//println("Not including ${dep.id} for ${project.name}!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft("com.mojang:minecraft:1.20.5")
|
||||
minecraft(libs.minecraft)
|
||||
mappings(loom.officialMojangMappings())
|
||||
}
|
||||
|
||||
repositories {
|
||||
// mavenLocal()
|
||||
maven("https://repo.opencollab.dev/maven-releases/")
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://repo.opencollab.dev/main")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://maven.neoforged.net/releases")
|
||||
}
|
||||
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||
projectId.set("wKkoqHrH")
|
||||
versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER"))
|
||||
versionType.set("beta")
|
||||
changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
|
||||
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
|
||||
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||
gameVersions.addAll("1.20.5", "1.20.6")
|
||||
failSilently.set(true)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
plugins {
|
||||
id("com.modrinth.minotaur")
|
||||
}
|
||||
|
||||
// Ensure that the readme is synched
|
||||
tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody)
|
||||
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||
projectId.set("geyser")
|
||||
versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER"))
|
||||
versionType.set("beta")
|
||||
changelog.set(System.getenv("CHANGELOG") ?: "")
|
||||
gameVersions.add(libs.minecraft.get().version as String)
|
||||
failSilently.set(true)
|
||||
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
}
|
|
@ -26,6 +26,14 @@ val moddedPlatforms = setOf(
|
|||
projects.mod
|
||||
).map { it.dependencyProject }
|
||||
|
||||
val modrinthPlatforms = setOf(
|
||||
projects.bungeecord,
|
||||
projects.fabric,
|
||||
projects.neoforge,
|
||||
projects.spigot,
|
||||
projects.velocity
|
||||
).map { it.dependencyProject }
|
||||
|
||||
subprojects {
|
||||
apply {
|
||||
plugin("java-library")
|
||||
|
@ -38,4 +46,10 @@ subprojects {
|
|||
in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
|
||||
else -> plugins.apply("geyser.base-conventions")
|
||||
}
|
||||
|
||||
// Not combined with platform-conventions as that also contains
|
||||
// platforms which we cant publish to modrinth
|
||||
if (modrinthPlatforms.contains(this)) {
|
||||
plugins.apply("geyser.modrinth-uploading-conventions")
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import net.kyori.blossom.BlossomExtension
|
||||
|
||||
plugins {
|
||||
// Allow blossom to mark sources root of templates
|
||||
idea
|
||||
alias(libs.plugins.blossom)
|
||||
id("geyser.publish-conventions")
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ tasks.processResources {
|
|||
expand(
|
||||
"branch" to info.branch,
|
||||
"buildNumber" to info.buildNumber,
|
||||
"projectVersion" to project.version,
|
||||
"projectVersion" to info.version,
|
||||
"commit" to info.commit,
|
||||
"commitAbbrev" to info.commitAbbrev,
|
||||
"commitMessage" to info.commitMessage,
|
||||
|
@ -87,21 +87,30 @@ tasks.processResources {
|
|||
}
|
||||
}
|
||||
|
||||
configure<BlossomExtension> {
|
||||
val mainFile = "src/main/java/org/geysermc/geyser/GeyserImpl.java"
|
||||
val info = GitInfo()
|
||||
|
||||
replaceToken("\${version}", "${project.version} (${info.gitVersion})", mainFile)
|
||||
replaceToken("\${gitVersion}", info.gitVersion, mainFile)
|
||||
replaceToken("\${buildNumber}", info.buildNumber, mainFile)
|
||||
replaceToken("\${branch}", info.branch, mainFile)
|
||||
replaceToken("\${commit}", info.commit, mainFile)
|
||||
replaceToken("\${repository}", info.repository, mainFile)
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
val info = GitInfo()
|
||||
javaSources {
|
||||
property("version", "${info.version} (${info.gitVersion})")
|
||||
property("gitVersion", info.gitVersion)
|
||||
property("buildNumber", info.buildNumber.toString())
|
||||
property("branch", info.branch)
|
||||
property("commit", info.commit)
|
||||
property("repository", info.repository)
|
||||
property("devVersion", info.isDev.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.buildNumber(): Int =
|
||||
fun buildNumber(): Int =
|
||||
(System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1
|
||||
|
||||
fun isDevBuild(branch: String, repository: String): Boolean {
|
||||
return branch != "master" || repository.equals("https://github.com/GeyserMC/Geyser", ignoreCase = true).not()
|
||||
}
|
||||
|
||||
inner class GitInfo {
|
||||
val branch: String
|
||||
val commit: String
|
||||
|
@ -114,22 +123,25 @@ inner class GitInfo {
|
|||
val commitMessage: String
|
||||
val repository: String
|
||||
|
||||
val isDev: Boolean
|
||||
|
||||
init {
|
||||
// On Jenkins, a detached head is checked out, so indra cannot determine the branch.
|
||||
// Fortunately, this environment variable is available.
|
||||
branch = indraGit.branchName() ?: System.getenv("BRANCH_NAME") ?: "DEV"
|
||||
branch = indraGit.branchName() ?: "DEV"
|
||||
|
||||
val commit = indraGit.commit()
|
||||
this.commit = commit?.name ?: "0".repeat(40)
|
||||
commitAbbrev = commit?.name?.substring(0, 7) ?: "0".repeat(7)
|
||||
|
||||
gitVersion = "git-${branch}-${commitAbbrev}"
|
||||
version = "${project.version} ($gitVersion)"
|
||||
buildNumber = buildNumber()
|
||||
|
||||
val git = indraGit.git()
|
||||
commitMessage = git?.commit()?.message ?: ""
|
||||
repository = git?.repository?.config?.getString("remote", "origin", "url") ?: ""
|
||||
|
||||
buildNumber = buildNumber()
|
||||
isDev = isDevBuild(branch, repository)
|
||||
val projectVersion = if (isDev) project.version else project.version.toString().replace("SNAPSHOT", "b${buildNumber}")
|
||||
version = "$projectVersion ($gitVersion)"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser;
|
||||
|
||||
// The constants are replaced before compilation
|
||||
public class BuildData {
|
||||
public static final String GIT_VERSION = "{{ gitVersion }}";
|
||||
public static final String VERSION = "{{ version }}";
|
||||
|
||||
public static final String BUILD_NUMBER = "{{ buildNumber }}";
|
||||
public static final String BRANCH = "{{ branch }}";
|
||||
public static final String COMMIT = "{{ commit }}";
|
||||
public static final String REPOSITORY = "{{ repository }}";
|
||||
private static final String DEV = "{{ devVersion }}";
|
||||
|
||||
public static boolean isDevBuild() {
|
||||
return Boolean.parseBoolean(DEV);
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ public final class Constants {
|
|||
public static final String NEWS_OVERVIEW_URL = "https://api.geysermc.org/v2/news/";
|
||||
public static final String NEWS_PROJECT_NAME = "geyser";
|
||||
|
||||
public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/";
|
||||
public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://geysermc.org/download#floodgate";
|
||||
|
||||
public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download";
|
||||
public static final String UPDATE_PERMISSION = "geyser.update";
|
||||
|
|
|
@ -121,13 +121,14 @@ public class GeyserImpl implements GeyserApi {
|
|||
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
public static final String NAME = "Geyser";
|
||||
public static final String GIT_VERSION = "${gitVersion}";
|
||||
public static final String VERSION = "${version}";
|
||||
public static final String GIT_VERSION = BuildData.GIT_VERSION;
|
||||
public static final String VERSION = BuildData.VERSION;
|
||||
|
||||
public static final String BUILD_NUMBER = "${buildNumber}";
|
||||
public static final String BRANCH = "${branch}";
|
||||
public static final String COMMIT = "${commit}";
|
||||
public static final String REPOSITORY = "${repository}";
|
||||
public static final String BUILD_NUMBER = BuildData.BUILD_NUMBER;
|
||||
public static final String BRANCH = BuildData.BRANCH;
|
||||
public static final String COMMIT = BuildData.COMMIT;
|
||||
public static final String REPOSITORY = BuildData.REPOSITORY;
|
||||
public static final boolean IS_DEV = BuildData.isDevBuild();
|
||||
|
||||
/**
|
||||
* Oauth client ID for Microsoft authentication
|
||||
|
@ -213,6 +214,12 @@ public class GeyserImpl implements GeyserApi {
|
|||
logger.info("");
|
||||
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.load", NAME, VERSION));
|
||||
logger.info("");
|
||||
if (IS_DEV) {
|
||||
// TODO cloud use language string
|
||||
//logger.info(GeyserLocale.getLocaleStringLog("geyser.core.dev_build", "https://discord.gg/geysermc"));
|
||||
logger.info("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s".formatted("https://discord.gg/geysermc"));
|
||||
logger.info("");
|
||||
}
|
||||
logger.info("******************************************");
|
||||
|
||||
/* Initialize registries */
|
||||
|
@ -690,6 +697,7 @@ public class GeyserImpl implements GeyserApi {
|
|||
*
|
||||
* @return true if the version number is not 'DEV'.
|
||||
*/
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isProductionEnvironment() {
|
||||
// First is if Blossom runs, second is if Blossom doesn't run
|
||||
//noinspection ConstantConditions,MismatchedStringCase - changes in production
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.command.defaults;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
|
@ -37,8 +37,7 @@ import org.geysermc.geyser.text.ChatColor;
|
|||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.WebUtils;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class VersionCommand extends GeyserCommand {
|
||||
|
@ -72,27 +71,36 @@ public class VersionCommand extends GeyserCommand {
|
|||
GeyserImpl.NAME, GeyserImpl.VERSION, javaVersions, bedrockVersions));
|
||||
|
||||
// Disable update checking in dev mode and for players in Geyser Standalone
|
||||
if (GeyserImpl.getInstance().isProductionEnvironment() && !(!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) {
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale()));
|
||||
try {
|
||||
String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" +
|
||||
URLEncoder.encode(GeyserImpl.BRANCH, StandardCharsets.UTF_8) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
|
||||
if (buildXML.startsWith("<buildNumber>")) {
|
||||
int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
|
||||
int buildNum = this.geyser.buildNumber();
|
||||
if (latestBuildNum == buildNum) {
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale()));
|
||||
} else {
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.outdated",
|
||||
sender.locale(), (latestBuildNum - buildNum), Constants.GEYSER_DOWNLOAD_LOCATION));
|
||||
}
|
||||
} else {
|
||||
throw new AssertionError("buildNumber missing");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e);
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale()));
|
||||
if (!GeyserImpl.getInstance().isProductionEnvironment() || (!sender.isConsole() && geyser.getPlatformType() == PlatformType.STANDALONE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GeyserImpl.IS_DEV) {
|
||||
// TODO cloud use language string
|
||||
sender.sendMessage("You are running a development build of Geyser! Please report any bugs you find on our Discord server: %s"
|
||||
.formatted("https://discord.gg/geysermc"));
|
||||
//sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.core.dev_build", sender.locale(), "https://discord.gg/geysermc"));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.checking", sender.locale()));
|
||||
try {
|
||||
int buildNumber = this.geyser.buildNumber();
|
||||
JsonNode response = WebUtils.getJson("https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest");
|
||||
int latestBuildNumber = response.get("build").asInt();
|
||||
|
||||
if (latestBuildNumber == buildNumber) {
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale()));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString(
|
||||
"geyser.commands.version.outdated",
|
||||
sender.locale(), (latestBuildNumber - buildNumber), "https://geysermc.org/download"
|
||||
));
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.version.failed"), e);
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.version.failed", sender.locale()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import java.util.function.BiConsumer;
|
|||
* metadata translators needed to translate the properties sent from the server. The translators are structured in such
|
||||
* a way that inserting a new one (for example in version updates) is convenient.
|
||||
*
|
||||
* @param identifier the Bedrock identifier of this entity
|
||||
* @param <T> the entity type this definition represents
|
||||
*/
|
||||
public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, EntityType entityType, String identifier,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.entity;
|
||||
|
||||
import org.geysermc.geyser.entity.type.AbstractWindChargeEntity;
|
||||
import org.geysermc.geyser.entity.factory.EntityFactory;
|
||||
import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
|
@ -63,6 +65,9 @@ public final class EntityDefinitions {
|
|||
public static final EntityDefinition<BeeEntity> BEE;
|
||||
public static final EntityDefinition<BlazeEntity> BLAZE;
|
||||
public static final EntityDefinition<BoatEntity> BOAT;
|
||||
public static final EntityDefinition<BoggedEntity> BOGGED;
|
||||
public static final EntityDefinition<BreezeEntity> BREEZE;
|
||||
public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE;
|
||||
public static final EntityDefinition<CamelEntity> CAMEL;
|
||||
public static final EntityDefinition<CatEntity> CAT;
|
||||
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
|
||||
|
@ -165,6 +170,7 @@ public final class EntityDefinitions {
|
|||
public static final EntityDefinition<VindicatorEntity> VINDICATOR;
|
||||
public static final EntityDefinition<AbstractMerchantEntity> WANDERING_TRADER;
|
||||
public static final EntityDefinition<WardenEntity> WARDEN;
|
||||
public static final EntityDefinition<AbstractWindChargeEntity> WIND_CHARGE;
|
||||
public static final EntityDefinition<RaidParticipantEntity> WITCH;
|
||||
public static final EntityDefinition<WitherEntity> WITHER;
|
||||
public static final EntityDefinition<AbstractSkeletonEntity> WITHER_SKELETON;
|
||||
|
@ -375,6 +381,18 @@ public final class EntityDefinitions {
|
|||
.heightAndWidth(0.25f)
|
||||
.build();
|
||||
|
||||
EntityFactory<AbstractWindChargeEntity> windChargeSupplier = AbstractWindChargeEntity::new;
|
||||
BREEZE_WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||
.type(EntityType.BREEZE_WIND_CHARGE)
|
||||
.identifier("minecraft:breeze_wind_charge_projectile")
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||
.type(EntityType.WIND_CHARGE)
|
||||
.identifier("minecraft:wind_charge_projectile")
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
|
||||
EntityDefinition<AbstractArrowEntity> abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
|
||||
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
|
||||
.addTranslator(null) // "Piercing level"
|
||||
|
@ -503,11 +521,20 @@ public final class EntityDefinitions {
|
|||
.height(0.9f).width(0.5f)
|
||||
.addTranslator(MetadataType.BYTE, BatEntity::setBatFlags)
|
||||
.build();
|
||||
BOGGED = EntityDefinition.inherited(BoggedEntity::new, mobEntityBase)
|
||||
.type(EntityType.BOGGED)
|
||||
.height(1.99f).width(0.6f)
|
||||
.addTranslator(MetadataType.BOOLEAN, BoggedEntity::setSheared)
|
||||
.build();
|
||||
BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase)
|
||||
.type(EntityType.BLAZE)
|
||||
.height(1.8f).width(0.6f)
|
||||
.addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags)
|
||||
.build();
|
||||
BREEZE = EntityDefinition.inherited(BreezeEntity::new, mobEntityBase)
|
||||
.type(EntityType.BREEZE)
|
||||
.height(1.77f).width(0.6f)
|
||||
.build();
|
||||
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
|
||||
.type(EntityType.CREEPER)
|
||||
.height(1.7f).width(0.6f)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.entity.type;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Note that, as of 1.21, a wind charge entity does not actually implement the thrown item. We're just reusing
|
||||
* the "hide until far away" aspect.
|
||||
*/
|
||||
public class AbstractWindChargeEntity extends ThrowableItemEntity {
|
||||
public AbstractWindChargeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getDrag() {
|
||||
// Always, even in water. As of 1.21.
|
||||
return 1f;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
|
|||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
|
||||
|
@ -46,12 +46,7 @@ public class ArrowEntity extends AbstractArrowEntity {
|
|||
if (potionColor == -1) {
|
||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
|
||||
} else {
|
||||
TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor);
|
||||
if (potion != null && potion.getJavaColor() != -1) {
|
||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) potion.getBedrockId());
|
||||
} else {
|
||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
|
||||
}
|
||||
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, Potion.toTippedArrowId(potionColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BoatEntity extends Entity implements Tickable {
|
||||
public class BoatEntity extends Entity implements Leashable, Tickable {
|
||||
|
||||
/**
|
||||
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
|
||||
|
@ -65,6 +65,8 @@ public class BoatEntity extends Entity implements Tickable {
|
|||
@Getter
|
||||
private int variant;
|
||||
|
||||
private long leashHolderBedrockId = -1;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.1f;
|
||||
|
||||
|
@ -147,8 +149,18 @@ public class BoatEntity extends Entity implements Tickable {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashHolderBedrockId(long bedrockId) {
|
||||
this.leashHolderBedrockId = bedrockId;
|
||||
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InteractiveTag testInteraction(Hand hand) {
|
||||
InteractiveTag tag = super.testInteraction(hand);
|
||||
if (tag != InteractiveTag.NONE) {
|
||||
return tag;
|
||||
}
|
||||
if (session.isSneaking()) {
|
||||
return InteractiveTag.NONE;
|
||||
} else if (passengers.size() < 2) {
|
||||
|
@ -160,6 +172,10 @@ public class BoatEntity extends Entity implements Tickable {
|
|||
|
||||
@Override
|
||||
public InteractionResult interact(Hand hand) {
|
||||
InteractionResult result = super.interact(hand);
|
||||
if (result != InteractionResult.PASS) {
|
||||
return result;
|
||||
}
|
||||
if (session.isSneaking()) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
|
@ -191,6 +207,11 @@ public class BoatEntity extends Entity implements Tickable {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long leashHolderBedrockId() {
|
||||
return leashHolderBedrockId;
|
||||
}
|
||||
|
||||
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
||||
AnimatePacket packet = new AnimatePacket();
|
||||
packet.setRuntimeEntityId(rower.getGeyserId());
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
|||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
|
||||
import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
|
@ -557,6 +558,17 @@ public class Entity implements GeyserEntity {
|
|||
* Should usually mirror {@link #interact(Hand)} without any side effects.
|
||||
*/
|
||||
protected InteractiveTag testInteraction(Hand hand) {
|
||||
if (isAlive() && this instanceof Leashable leashable) {
|
||||
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
|
||||
// Note this might be client side. Has yet to be an issue though, as of Java 1.21.
|
||||
return InteractiveTag.REMOVE_LEASH;
|
||||
}
|
||||
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
|
||||
// We shall leash
|
||||
return InteractiveTag.LEASH;
|
||||
}
|
||||
}
|
||||
|
||||
return InteractiveTag.NONE;
|
||||
}
|
||||
|
||||
|
@ -565,6 +577,18 @@ public class Entity implements GeyserEntity {
|
|||
* to ensure packet parity as well as functionality parity (such as sound effect responses).
|
||||
*/
|
||||
public InteractionResult interact(Hand hand) {
|
||||
if (isAlive() && this instanceof Leashable leashable) {
|
||||
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
|
||||
// Note this might also update client side (a theoretical Geyser/client desync and Java parity issue).
|
||||
// Has yet to be an issue though, as of Java 1.21.
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
|
||||
// We shall leash
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.entity.type;
|
||||
|
||||
/**
|
||||
* I can haz lead
|
||||
* (The item, not the mineral)
|
||||
*/
|
||||
public interface Leashable {
|
||||
void setLeashHolderBedrockId(long bedrockId);
|
||||
|
||||
long leashHolderBedrockId();
|
||||
|
||||
default boolean canBeLeashed() {
|
||||
return isNotLeashed();
|
||||
}
|
||||
|
||||
default boolean isNotLeashed() {
|
||||
return leashHolderBedrockId() == -1L;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,8 @@ import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket;
|
|||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.level.PaintingType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
|
||||
|
@ -49,8 +51,14 @@ public class PaintingEntity extends Entity {
|
|||
// Wait until we get the metadata needed
|
||||
}
|
||||
|
||||
public void setPaintingType(ObjectEntityMetadata<org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType> entityMetadata) {
|
||||
PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue());
|
||||
public void setPaintingType(ObjectEntityMetadata<Holder<PaintingVariant>> entityMetadata) {
|
||||
if (!entityMetadata.getValue().isId()) {
|
||||
return;
|
||||
}
|
||||
PaintingType type = session.getRegistryCache().paintings().byId(entityMetadata.getValue().id());
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
|
||||
addPaintingPacket.setUniqueEntityId(geyserId);
|
||||
addPaintingPacket.setRuntimeEntityId(geyserId);
|
||||
|
@ -78,8 +86,12 @@ public class PaintingEntity extends Entity {
|
|||
|
||||
private Vector3f fixOffset(PaintingType paintingName) {
|
||||
Vector3f position = super.position;
|
||||
position = position.add(0.5, 0.5, 0.5);
|
||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
||||
// ViaVersion already adds the offset for us on older versions,
|
||||
// so no need to do it then otherwise it will be spaced
|
||||
if (session.isEmulatePost1_18Logic()) {
|
||||
position = position.add(0.5, 0.5, 0.5);
|
||||
}
|
||||
double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||
|
||||
return switch (direction) {
|
||||
|
|
|
@ -38,7 +38,7 @@ public class AmbientEntity extends MobEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class DolphinEntity extends WaterEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
|
||||
package org.geysermc.geyser.entity.type.living;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.type.Leashable;
|
||||
import org.geysermc.geyser.entity.type.LivingEntity;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
|
@ -43,11 +43,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
public class MobEntity extends LivingEntity {
|
||||
public class MobEntity extends LivingEntity implements Leashable {
|
||||
/**
|
||||
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
|
||||
*/
|
||||
@Getter
|
||||
private long leashHolderBedrockId;
|
||||
|
||||
public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
|
@ -65,6 +64,7 @@ public class MobEntity extends LivingEntity {
|
|||
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashHolderBedrockId(long bedrockId) {
|
||||
this.leashHolderBedrockId = bedrockId;
|
||||
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
|
||||
|
@ -79,10 +79,7 @@ public class MobEntity extends LivingEntity {
|
|||
return InteractiveTag.REMOVE_LEASH;
|
||||
} else {
|
||||
GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand);
|
||||
if (itemStack.asItem() == Items.LEAD && canBeLeashed()) {
|
||||
// We shall leash
|
||||
return InteractiveTag.LEASH;
|
||||
} else if (itemStack.asItem() == Items.NAME_TAG) {
|
||||
if (itemStack.asItem() == Items.NAME_TAG) {
|
||||
InteractionResult result = checkInteractWithNameTag(itemStack);
|
||||
if (result.consumesAction()) {
|
||||
return InteractiveTag.NAME;
|
||||
|
@ -99,9 +96,6 @@ public class MobEntity extends LivingEntity {
|
|||
if (!isAlive()) {
|
||||
// dead lol
|
||||
return InteractionResult.PASS;
|
||||
} else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) {
|
||||
// TODO looks like the client assumes it will go through and removes the attachment itself?
|
||||
return InteractionResult.SUCCESS;
|
||||
} else {
|
||||
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand);
|
||||
InteractionResult result = checkPriorityInteractions(itemInHand);
|
||||
|
@ -115,10 +109,7 @@ public class MobEntity extends LivingEntity {
|
|||
}
|
||||
|
||||
private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) {
|
||||
if (itemInHand.asItem() == Items.LEAD && canBeLeashed()) {
|
||||
// We shall leash
|
||||
return InteractionResult.SUCCESS;
|
||||
} else if (itemInHand.asItem() == Items.NAME_TAG) {
|
||||
if (itemInHand.asItem() == Items.NAME_TAG) {
|
||||
InteractionResult result = checkInteractWithNameTag(itemInHand);
|
||||
if (result.consumesAction()) {
|
||||
return result;
|
||||
|
@ -143,12 +134,14 @@ public class MobEntity extends LivingEntity {
|
|||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
protected boolean canBeLeashed() {
|
||||
@Override
|
||||
public boolean canBeLeashed() {
|
||||
return isNotLeashed() && !isEnemy();
|
||||
}
|
||||
|
||||
protected final boolean isNotLeashed() {
|
||||
return leashHolderBedrockId == -1L;
|
||||
@Override
|
||||
public long leashHolderBedrockId() {
|
||||
return leashHolderBedrockId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -122,7 +122,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return isNotLeashed();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public class WaterEntity extends CreatureEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class AxolotlEntity extends AnimalEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ public class HoglinEntity extends AnimalEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return isNotLeashed();
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ public class PandaEntity extends AnimalEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ public class TurtleEntity extends AnimalEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public abstract class TameableEntity extends AnimalEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return isNotLeashed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,36 +33,28 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
|
||||
import org.geysermc.geyser.item.type.DyeItem;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.geyser.util.ItemUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WolfEntity extends TameableEntity {
|
||||
/**
|
||||
* A list of all foods a wolf can eat on Java Edition.
|
||||
* Used to display interactive tag or particles if needed.
|
||||
* TODO generate
|
||||
*/
|
||||
private static final Set<Item> WOLF_FOODS = Set.of(Items.PUFFERFISH, Items.TROPICAL_FISH, Items.CHICKEN, Items.COOKED_CHICKEN,
|
||||
Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
|
||||
Items.COOKED_RABBIT);
|
||||
|
||||
private byte collarColor = 14; // Red - default
|
||||
|
||||
private boolean isCurseOfBinding = false;
|
||||
|
@ -112,12 +104,14 @@ public class WolfEntity extends TameableEntity {
|
|||
}
|
||||
|
||||
// 1.20.5+
|
||||
public void setWolfVariant(IntEntityMetadata entityMetadata) {
|
||||
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue());
|
||||
if (wolfVariant == null) {
|
||||
wolfVariant = WolfVariant.PALE;
|
||||
}
|
||||
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
|
||||
public void setWolfVariant(ObjectEntityMetadata<Holder<WolfVariant>> entityMetadata) {
|
||||
entityMetadata.getValue().ifId(id -> {
|
||||
BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id);
|
||||
if (wolfVariant == null) {
|
||||
wolfVariant = BuiltInWolfVariant.PALE;
|
||||
}
|
||||
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -129,11 +123,11 @@ public class WolfEntity extends TameableEntity {
|
|||
@Override
|
||||
public void setChestplate(ItemStack stack) {
|
||||
super.setChestplate(stack);
|
||||
isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0;
|
||||
isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
|
||||
}
|
||||
|
||||
|
@ -187,7 +181,7 @@ public class WolfEntity extends TameableEntity {
|
|||
}
|
||||
|
||||
// Ordered by bedrock id
|
||||
public enum WolfVariant {
|
||||
public enum BuiltInWolfVariant {
|
||||
PALE,
|
||||
ASHEN,
|
||||
BLACK,
|
||||
|
@ -198,16 +192,16 @@ public class WolfEntity extends TameableEntity {
|
|||
STRIPED,
|
||||
WOODS;
|
||||
|
||||
private static final WolfVariant[] VALUES = values();
|
||||
private static final BuiltInWolfVariant[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
|
||||
WolfVariant() {
|
||||
BuiltInWolfVariant() {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) {
|
||||
for (WolfVariant wolfVariant : VALUES) {
|
||||
public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) {
|
||||
for (BuiltInWolfVariant wolfVariant : VALUES) {
|
||||
if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
|
||||
return wolfVariant;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.entity.type.living.monster;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.InteractionResult;
|
||||
import org.geysermc.geyser.util.InteractiveTag;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BoggedEntity extends AbstractSkeletonEntity {
|
||||
private boolean sheared = false;
|
||||
|
||||
public BoggedEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
public void setSheared(BooleanEntityMetadata entityMetadata) {
|
||||
this.sheared = entityMetadata.getPrimitiveValue();
|
||||
setFlag(EntityFlag.SHEARED, this.sheared);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
|
||||
if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
|
||||
return InteractiveTag.SHEAR;
|
||||
}
|
||||
return super.testMobInteraction(hand, itemInHand);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
|
||||
if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
return super.mobInteract(hand, itemInHand);
|
||||
}
|
||||
|
||||
private boolean readyForShearing() {
|
||||
return !this.sheared && this.isAlive();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.entity.type.living.monster;
|
||||
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BreezeEntity extends MonsterEntity {
|
||||
public BreezeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPose(Pose pose) {
|
||||
// TODO Test
|
||||
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, pose == Pose.SHOOTING);
|
||||
setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.INHALING);
|
||||
super.setPose(pose);
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ public class ZoglinEntity extends MonsterEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeLeashed() {
|
||||
public boolean canBeLeashed() {
|
||||
return isNotLeashed();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,15 +27,18 @@ package org.geysermc.geyser.entity.type.player;
|
|||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.level.BedrockDimension;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.AttributeUtils;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
|
@ -69,6 +72,15 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
|
||||
private int lastAirSupply = getMaxAir();
|
||||
|
||||
/**
|
||||
* Determines if our position is currently out-of-sync with the Java server
|
||||
* due to our workaround for the void floor
|
||||
* <p>
|
||||
* Must be reset when dying, switching worlds, or being teleported out of the void
|
||||
*/
|
||||
@Getter @Setter
|
||||
private boolean voidPositionDesynched;
|
||||
|
||||
public SessionPlayerEntity(GeyserSession session) {
|
||||
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
||||
|
||||
|
@ -87,10 +99,25 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
|
||||
@Override
|
||||
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) {
|
||||
if (voidPositionDesynched) {
|
||||
if (!isBelowVoidFloor()) {
|
||||
voidPositionDesynched = false; // No need to fix our offset; we've been moved
|
||||
}
|
||||
}
|
||||
super.moveRelative(relX, relY, relZ, yaw, pitch, headYaw, isOnGround);
|
||||
session.getCollisionManager().updatePlayerBoundingBox(this.position.down(definition.offset()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
|
||||
if (voidPositionDesynched) {
|
||||
if (!isBelowVoidFloor()) {
|
||||
voidPositionDesynched = false; // No need to fix our offset; we've been moved
|
||||
}
|
||||
}
|
||||
super.moveAbsolute(position, yaw, pitch, headYaw, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(Vector3f position) {
|
||||
if (valid) { // Don't update during session init
|
||||
|
@ -220,11 +247,14 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
||||
if (pos != null) {
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension().asString()));
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true);
|
||||
} else {
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
||||
}
|
||||
|
||||
// We're either respawning or switching worlds, either way, we are no longer desynched
|
||||
this.setVoidPositionDesynched(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -276,4 +306,48 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
public void resetAir() {
|
||||
this.setAirSupply(getMaxAir());
|
||||
}
|
||||
|
||||
private boolean isBelowVoidFloor() {
|
||||
return position.getY() < voidFloorPosition();
|
||||
}
|
||||
|
||||
public int voidFloorPosition() {
|
||||
// The void floor is offset about 40 blocks below the bottom of the world
|
||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
||||
return bedrockDimension.minY() - 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles teleporting the player below or above the Bedrock void floor.
|
||||
* The Java server should never see this desync as we adjust the position that we send to it
|
||||
*
|
||||
* @param up in which direction to teleport - true to resync our position, or false to be
|
||||
* teleported below the void floor.
|
||||
*/
|
||||
public void teleportVoidFloorFix(boolean up) {
|
||||
// Safety to avoid double teleports
|
||||
if ((voidPositionDesynched && !up) || (!voidPositionDesynched && up)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Work around there being a floor at the bottom of the world and teleport the player below it
|
||||
// Moving from below to above the void floor works fine
|
||||
Vector3f newPosition = this.getPosition();
|
||||
if (up) {
|
||||
newPosition = newPosition.up(4f);
|
||||
voidPositionDesynched = false;
|
||||
} else {
|
||||
newPosition = newPosition.down(4f);
|
||||
voidPositionDesynched = true;
|
||||
}
|
||||
|
||||
this.setPositionManual(newPosition);
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(newPosition);
|
||||
movePlayerPacket.setRotation(getBedrockRotation());
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT);
|
||||
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR);
|
||||
session.sendUpstreamPacketImmediately(movePlayerPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ public class SkullPlayerEntity extends PlayerEntity {
|
|||
case EAST -> x -= 0.24f;
|
||||
}
|
||||
} else {
|
||||
rotation = (180f + (blockState.getValue(Properties.ROTATION_16) * 22.5f)) % 360;
|
||||
rotation = (180f + blockState.getValue(Properties.ROTATION_16, 0) * 22.5f) % 360;
|
||||
}
|
||||
|
||||
moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true);
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.jetbrains.annotations.Range;
|
|||
*/
|
||||
@Getter
|
||||
public class Container extends Inventory {
|
||||
private final PlayerInventory playerInventory;
|
||||
protected final PlayerInventory playerInventory;
|
||||
private final int containerSize;
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,13 +25,19 @@
|
|||
|
||||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.CrafterInventoryTranslator;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
@Getter
|
||||
public class CrafterContainer extends Container {
|
||||
private GeyserItemStack resultItem = GeyserItemStack.EMPTY;
|
||||
|
||||
@Setter
|
||||
private boolean triggered = false;
|
||||
|
@ -46,8 +52,36 @@ public class CrafterContainer extends Container {
|
|||
super(title, id, size, containerType, playerInventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserItemStack getItem(int slot) {
|
||||
if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
|
||||
return this.resultItem;
|
||||
} else if (isCraftingGrid(slot)) {
|
||||
return super.getItem(slot);
|
||||
} else {
|
||||
return playerInventory.getItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) {
|
||||
return playerInventory.getOffsetForHotbar(slot) - InventoryTranslator.PLAYER_INVENTORY_OFFSET + CrafterInventoryTranslator.GRID_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
|
||||
if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
|
||||
// Result item probably won't be an item that needs to worry about net ID or lodestone compasses
|
||||
this.resultItem = newItem;
|
||||
} else if (isCraftingGrid(slot)) {
|
||||
super.setItem(slot, newItem, session);
|
||||
} else {
|
||||
playerInventory.setItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET, newItem, session);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSlot(int slot, boolean enabled) {
|
||||
if (slot < 0 || slot > 8) {
|
||||
if (!isCraftingGrid(slot)) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Crafter slot out of bounds: " + slot);
|
||||
return;
|
||||
}
|
||||
|
@ -58,4 +92,8 @@ public class CrafterContainer extends Container {
|
|||
disabledSlotsMask = (short) (disabledSlotsMask | (1 << slot));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCraftingGrid(int slot) {
|
||||
return slot >= 0 && slot <= 8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,11 @@
|
|||
|
||||
package org.geysermc.geyser.inventory;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -44,13 +43,13 @@ public class GeyserEnchantOption {
|
|||
* is controlled by the server.
|
||||
* So, of course, we have to throw in some easter eggs. ;)
|
||||
*/
|
||||
private static final List<String> ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better",
|
||||
"explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa",
|
||||
"tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
|
||||
"more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft",
|
||||
"strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this",
|
||||
"stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out",
|
||||
"xp heals tools", "dragon proxy waz here");
|
||||
private static final List<String> ENCHANT_NAMES = List.of("tougher armor", "lukeeey", "fall better",
|
||||
"explode less", "camo toy", "armor stab", "breathe better", "water walk", "rtm five one six", "oof ouch owie",
|
||||
"enemy on fire", "spider sad", "aj ferguson", "redned", "more items thx", "fast tool", "give me block",
|
||||
"less breaky break", "cube craft", "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser",
|
||||
"come here fish", "you are elsa", "xp heals tools", "tim two zero three", "dragon proxy waz here",
|
||||
"stabby stab", "supreme mortal", "i like this", "avatar i guess", "more arrows", "in and out",
|
||||
"fly finder seventeen", "fast walk nether", "davchoo", "onechris", "death bringer thirteen", "kastle");
|
||||
|
||||
@Getter
|
||||
private final int javaIndex;
|
||||
|
@ -62,7 +61,6 @@ public class GeyserEnchantOption {
|
|||
private boolean hasChanged;
|
||||
|
||||
private int xpCost = 0;
|
||||
private int javaEnchantIndex = -1;
|
||||
private int bedrockEnchantIndex = -1;
|
||||
private int enchantLevel = -1;
|
||||
|
||||
|
@ -74,7 +72,7 @@ public class GeyserEnchantOption {
|
|||
this.hasChanged = false;
|
||||
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
|
||||
enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
|
||||
javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
|
||||
bedrockEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(bedrockEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
|
@ -88,10 +86,9 @@ public class GeyserEnchantOption {
|
|||
}
|
||||
}
|
||||
|
||||
public void setEnchantIndex(int javaEnchantIndex, int bedrockEnchantIndex) {
|
||||
if (this.javaEnchantIndex != javaEnchantIndex) {
|
||||
public void setEnchantIndex(int bedrockEnchantIndex) {
|
||||
if (this.bedrockEnchantIndex != bedrockEnchantIndex) {
|
||||
hasChanged = true;
|
||||
this.javaEnchantIndex = javaEnchantIndex;
|
||||
this.bedrockEnchantIndex = bedrockEnchantIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
package org.geysermc.geyser.inventory.item;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -72,21 +74,23 @@ public enum BannerPattern {
|
|||
SKULL("sku"),
|
||||
FLOWER("flo"),
|
||||
MOJANG("moj"),
|
||||
PIGLIN("pig");
|
||||
PIGLIN("pig"),
|
||||
FLOW("flw"),
|
||||
GUSTER("gus");
|
||||
|
||||
private static final BannerPattern[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final Key javaIdentifier;
|
||||
private final String bedrockIdentifier;
|
||||
|
||||
BannerPattern(String bedrockIdentifier) {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
||||
this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT));
|
||||
this.bedrockIdentifier = bedrockIdentifier;
|
||||
}
|
||||
|
||||
public static @Nullable BannerPattern getByJavaIdentifier(String javaIdentifier) {
|
||||
public static @Nullable BannerPattern getByJavaIdentifier(Key key) {
|
||||
for (BannerPattern bannerPattern : VALUES) {
|
||||
if (bannerPattern.javaIdentifier.equals(javaIdentifier)) {
|
||||
if (bannerPattern.javaIdentifier.equals(key)) {
|
||||
return bannerPattern;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,11 @@
|
|||
|
||||
package org.geysermc.geyser.inventory.item;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
public enum Enchantment {
|
||||
public enum BedrockEnchantment {
|
||||
PROTECTION,
|
||||
FIRE_PROTECTION,
|
||||
FEATHER_FALLING,
|
||||
|
@ -69,18 +67,21 @@ public enum Enchantment {
|
|||
PIERCING,
|
||||
QUICK_CHARGE,
|
||||
SOUL_SPEED,
|
||||
SWIFT_SNEAK;
|
||||
SWIFT_SNEAK,
|
||||
WIND_BURST,
|
||||
DENSITY,
|
||||
BREACH;
|
||||
|
||||
private static final Enchantment[] VALUES = values();
|
||||
private static final BedrockEnchantment[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
|
||||
Enchantment() {
|
||||
BedrockEnchantment() {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public static @Nullable Enchantment getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Enchantment enchantment : VALUES) {
|
||||
public static @Nullable BedrockEnchantment getByJavaIdentifier(String javaIdentifier) {
|
||||
for (BedrockEnchantment enchantment : VALUES) {
|
||||
if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) {
|
||||
return enchantment;
|
||||
}
|
||||
|
@ -88,88 +89,10 @@ public enum Enchantment {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable Enchantment getByBedrockId(int bedrockId) {
|
||||
public static @Nullable BedrockEnchantment getByBedrockId(int bedrockId) {
|
||||
if (bedrockId >= 0 && bedrockId < VALUES.length) {
|
||||
return VALUES[bedrockId];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enchantments classified by their Java index
|
||||
*/
|
||||
public enum JavaEnchantment {
|
||||
PROTECTION,
|
||||
FIRE_PROTECTION,
|
||||
FEATHER_FALLING,
|
||||
BLAST_PROTECTION,
|
||||
PROJECTILE_PROTECTION,
|
||||
RESPIRATION,
|
||||
AQUA_AFFINITY,
|
||||
THORNS,
|
||||
DEPTH_STRIDER,
|
||||
FROST_WALKER,
|
||||
BINDING_CURSE,
|
||||
SOUL_SPEED,
|
||||
SWIFT_SNEAK,
|
||||
SHARPNESS,
|
||||
SMITE,
|
||||
BANE_OF_ARTHROPODS,
|
||||
KNOCKBACK,
|
||||
FIRE_ASPECT,
|
||||
LOOTING,
|
||||
SWEEPING_EDGE,
|
||||
EFFICIENCY,
|
||||
SILK_TOUCH,
|
||||
UNBREAKING,
|
||||
FORTUNE,
|
||||
POWER,
|
||||
PUNCH,
|
||||
FLAME,
|
||||
INFINITY,
|
||||
LUCK_OF_THE_SEA,
|
||||
LURE,
|
||||
LOYALTY,
|
||||
IMPALING,
|
||||
RIPTIDE,
|
||||
CHANNELING,
|
||||
MULTISHOT,
|
||||
QUICK_CHARGE,
|
||||
PIERCING,
|
||||
DENSITY,
|
||||
BREACH,
|
||||
WIND_BURST,
|
||||
MENDING,
|
||||
VANISHING_CURSE;
|
||||
|
||||
private static final JavaEnchantment[] VALUES = JavaEnchantment.values();
|
||||
|
||||
public static JavaEnchantment of(int index) {
|
||||
return VALUES[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all enchantment Java identifiers for use with command suggestions.
|
||||
*/
|
||||
public static final String[] ALL_JAVA_IDENTIFIERS;
|
||||
|
||||
public static @Nullable JavaEnchantment getByJavaIdentifier(String javaIdentifier) {
|
||||
if (!javaIdentifier.startsWith("minecraft:")) {
|
||||
javaIdentifier = "minecraft:" + javaIdentifier;
|
||||
}
|
||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
||||
if (ALL_JAVA_IDENTIFIERS[i].equalsIgnoreCase(javaIdentifier)) {
|
||||
return VALUES[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static {
|
||||
ALL_JAVA_IDENTIFIERS = new String[VALUES.length];
|
||||
for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
|
||||
ALL_JAVA_IDENTIFIERS[i] = "minecraft:" + VALUES[i].name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,63 +34,83 @@ import java.util.Locale;
|
|||
|
||||
@Getter
|
||||
public enum Potion {
|
||||
WATER(0),
|
||||
MUNDANE(1),
|
||||
THICK(3),
|
||||
AWKWARD(4),
|
||||
NIGHT_VISION(5),
|
||||
LONG_NIGHT_VISION(6),
|
||||
INVISIBILITY(7),
|
||||
LONG_INVISIBILITY(8),
|
||||
LEAPING(9),
|
||||
LONG_LEAPING(10),
|
||||
STRONG_LEAPING(11),
|
||||
FIRE_RESISTANCE(12),
|
||||
LONG_FIRE_RESISTANCE(13),
|
||||
SWIFTNESS(14),
|
||||
LONG_SWIFTNESS(15),
|
||||
STRONG_SWIFTNESS(16),
|
||||
SLOWNESS(17),
|
||||
LONG_SLOWNESS(18),
|
||||
STRONG_SLOWNESS(42),
|
||||
TURTLE_MASTER(37),
|
||||
LONG_TURTLE_MASTER(38),
|
||||
STRONG_TURTLE_MASTER(39),
|
||||
WATER_BREATHING(19),
|
||||
LONG_WATER_BREATHING(20),
|
||||
HEALING(21),
|
||||
STRONG_HEALING(22),
|
||||
HARMING(23),
|
||||
STRONG_HARMING(24),
|
||||
POISON(25),
|
||||
LONG_POISON(26),
|
||||
STRONG_POISON(27),
|
||||
REGENERATION(28),
|
||||
LONG_REGENERATION(29),
|
||||
STRONG_REGENERATION(30),
|
||||
STRENGTH(31),
|
||||
LONG_STRENGTH(32),
|
||||
STRONG_STRENGTH(33),
|
||||
WEAKNESS(34),
|
||||
LONG_WEAKNESS(35),
|
||||
LUCK(2), //does not exist
|
||||
SLOW_FALLING(40),
|
||||
LONG_SLOW_FALLING(41);
|
||||
WATER(0, ArrowParticleColors.NONE),
|
||||
MUNDANE(1, ArrowParticleColors.NONE), // 2 is extended?
|
||||
THICK(3, ArrowParticleColors.NONE),
|
||||
AWKWARD(4, ArrowParticleColors.NONE),
|
||||
NIGHT_VISION(5, ArrowParticleColors.NIGHT_VISION),
|
||||
LONG_NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
|
||||
INVISIBILITY(7, ArrowParticleColors.INVISIBILITY),
|
||||
LONG_INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
|
||||
LEAPING(9, ArrowParticleColors.LEAPING),
|
||||
LONG_LEAPING(10, ArrowParticleColors.LEAPING),
|
||||
STRONG_LEAPING(11, ArrowParticleColors.LEAPING),
|
||||
FIRE_RESISTANCE(12, ArrowParticleColors.FIRE_RESISTANCE),
|
||||
LONG_FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
|
||||
SWIFTNESS(14, ArrowParticleColors.SWIFTNESS),
|
||||
LONG_SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
|
||||
STRONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
|
||||
SLOWNESS(17, ArrowParticleColors.SLOWNESS),
|
||||
LONG_SLOWNESS(18, ArrowParticleColors.SLOWNESS),
|
||||
STRONG_SLOWNESS(42, ArrowParticleColors.SLOWNESS),
|
||||
TURTLE_MASTER(37, ArrowParticleColors.TURTLE_MASTER),
|
||||
LONG_TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
|
||||
STRONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
|
||||
WATER_BREATHING(19, ArrowParticleColors.WATER_BREATHING),
|
||||
LONG_WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
|
||||
HEALING(21, ArrowParticleColors.HEALING),
|
||||
STRONG_HEALING(22, ArrowParticleColors.HEALING),
|
||||
HARMING(23, ArrowParticleColors.HARMING),
|
||||
STRONG_HARMING(24, ArrowParticleColors.HARMING),
|
||||
POISON(25, ArrowParticleColors.POISON),
|
||||
LONG_POISON(26, ArrowParticleColors.POISON),
|
||||
STRONG_POISON(27, ArrowParticleColors.POISON),
|
||||
REGENERATION(28, ArrowParticleColors.REGENERATION),
|
||||
LONG_REGENERATION(29, ArrowParticleColors.REGENERATION),
|
||||
STRONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
|
||||
STRENGTH(31, ArrowParticleColors.STRENGTH),
|
||||
LONG_STRENGTH(32, ArrowParticleColors.STRENGTH),
|
||||
STRONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
|
||||
WEAKNESS(34, ArrowParticleColors.WEAKNESS),
|
||||
LONG_WEAKNESS(35, ArrowParticleColors.WEAKNESS),
|
||||
LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
|
||||
SLOW_FALLING(40, ArrowParticleColors.SLOW_FALLING),
|
||||
LONG_SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
|
||||
WIND_CHARGING(43, ArrowParticleColors.WIND_CHARGING),
|
||||
WEAVING(44, ArrowParticleColors.WEAVING),
|
||||
OOZING(45, ArrowParticleColors.OOZING),
|
||||
INFESTATION(46, ArrowParticleColors.INFESTATION);
|
||||
|
||||
public static final Potion[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final short bedrockId;
|
||||
private final int javaColor;
|
||||
|
||||
Potion(int bedrockId) {
|
||||
Potion(int bedrockId, int javaColor) {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||
this.bedrockId = (short) bedrockId;
|
||||
this.javaColor = javaColor;
|
||||
}
|
||||
|
||||
public int tippedArrowId() {
|
||||
// +1 likely to offset 0 as nothing?
|
||||
return this.bedrockId + 1;
|
||||
}
|
||||
|
||||
public PotionContents toComponent() {
|
||||
return new PotionContents(this.ordinal(), -1, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static Potion getByJavaIdentifier(String javaIdentifier) {
|
||||
for (Potion potion : VALUES) {
|
||||
if (potion.javaIdentifier.equals(javaIdentifier)) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable Potion getByJavaId(int javaId) {
|
||||
if (javaId >= 0 && javaId < VALUES.length) {
|
||||
return VALUES[javaId];
|
||||
|
@ -106,4 +126,44 @@ public enum Potion {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable Potion getByTippedArrowDamage(int bedrockId) {
|
||||
return getByBedrockId(bedrockId - 1);
|
||||
}
|
||||
|
||||
public static byte toTippedArrowId(int javaParticleColor) {
|
||||
for (Potion potion : VALUES) {
|
||||
if (potion.javaColor == javaParticleColor) {
|
||||
return (byte) (potion.bedrockId + 1);
|
||||
}
|
||||
}
|
||||
return (byte) 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For tipped arrow usage
|
||||
*/
|
||||
private static final class ArrowParticleColors {
|
||||
static final int NONE = 1;
|
||||
static final int NIGHT_VISION = 2039713;
|
||||
static final int INVISIBILITY = 8356754;
|
||||
static final int LEAPING = 2293580;
|
||||
static final int FIRE_RESISTANCE = 14981690;
|
||||
static final int SWIFTNESS = 8171462;
|
||||
static final int SLOWNESS = 5926017;
|
||||
static final int TURTLE_MASTER = 7691106;
|
||||
static final int WATER_BREATHING = 3035801;
|
||||
static final int HEALING = 16262179;
|
||||
static final int HARMING = 4393481;
|
||||
static final int POISON = 5149489;
|
||||
static final int REGENERATION = 13458603;
|
||||
static final int STRENGTH = 9643043;
|
||||
static final int WEAKNESS = 4738376;
|
||||
static final int LUCK = 3381504;
|
||||
static final int SLOW_FALLING = 16773073;
|
||||
static final int WIND_CHARGING = 12438015;
|
||||
static final int WEAVING = 7891290;
|
||||
static final int OOZING = 10092451;
|
||||
static final int INFESTATION = 9214860;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.inventory.item;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Potion identifiers and their respective Bedrock IDs used with arrows.
|
||||
* <a href="https://minecraft.wiki/w/Arrow#Data_values">See here</a>
|
||||
*/
|
||||
@Getter
|
||||
public enum TippedArrowPotion {
|
||||
WATER(-1, ArrowParticleColors.NONE), // Guessing this based off of the Potion enum. TODO merge?
|
||||
MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended?
|
||||
THICK(4, ArrowParticleColors.NONE),
|
||||
AWKWARD(5, ArrowParticleColors.NONE),
|
||||
NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
|
||||
LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION),
|
||||
INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
|
||||
LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY),
|
||||
LEAPING(10, ArrowParticleColors.LEAPING),
|
||||
LONG_LEAPING(11, ArrowParticleColors.LEAPING),
|
||||
STRONG_LEAPING(12, ArrowParticleColors.LEAPING),
|
||||
FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
|
||||
LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE),
|
||||
SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
|
||||
LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
|
||||
STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS),
|
||||
SLOWNESS(18, ArrowParticleColors.SLOWNESS),
|
||||
LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS),
|
||||
STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS),
|
||||
WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
|
||||
LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING),
|
||||
HEALING(22, ArrowParticleColors.HEALING),
|
||||
STRONG_HEALING(23, ArrowParticleColors.HEALING),
|
||||
HARMING(24, ArrowParticleColors.HARMING),
|
||||
STRONG_HARMING(25, ArrowParticleColors.HARMING),
|
||||
POISON(26, ArrowParticleColors.POISON),
|
||||
LONG_POISON(27, ArrowParticleColors.POISON),
|
||||
STRONG_POISON(28, ArrowParticleColors.POISON),
|
||||
REGENERATION(29, ArrowParticleColors.REGENERATION),
|
||||
LONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
|
||||
STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION),
|
||||
STRENGTH(32, ArrowParticleColors.STRENGTH),
|
||||
LONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
|
||||
STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH),
|
||||
WEAKNESS(35, ArrowParticleColors.WEAKNESS),
|
||||
LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS),
|
||||
LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
|
||||
TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
|
||||
LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
|
||||
STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER),
|
||||
SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
|
||||
LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING);
|
||||
|
||||
private static final TippedArrowPotion[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final short bedrockId;
|
||||
/**
|
||||
* The Java color associated with this ID.
|
||||
* Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock
|
||||
*/
|
||||
private final int javaColor;
|
||||
|
||||
TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
|
||||
this.bedrockId = (short) bedrockId;
|
||||
this.javaColor = arrowParticleColor.getColor();
|
||||
}
|
||||
|
||||
public static @Nullable TippedArrowPotion of(int id) {
|
||||
if (id >= 0 && id < VALUES.length) {
|
||||
return VALUES[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) {
|
||||
for (TippedArrowPotion potion : VALUES) {
|
||||
if (potion.bedrockId == bedrockId) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param color the potion color to look up
|
||||
* @return the tipped arrow potion that most closely resembles that color.
|
||||
*/
|
||||
public static @Nullable TippedArrowPotion getByJavaColor(int color) {
|
||||
for (TippedArrowPotion potion : VALUES) {
|
||||
if (potion.javaColor == color) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private enum ArrowParticleColors {
|
||||
NONE(-1),
|
||||
NIGHT_VISION(2039713),
|
||||
INVISIBILITY(8356754),
|
||||
LEAPING(2293580),
|
||||
FIRE_RESISTANCE(14981690),
|
||||
SWIFTNESS(8171462),
|
||||
SLOWNESS(5926017),
|
||||
TURTLE_MASTER(7691106),
|
||||
WATER_BREATHING(3035801),
|
||||
HEALING(16262179),
|
||||
HARMING(4393481),
|
||||
POISON(5149489),
|
||||
REGENERATION(13458603),
|
||||
STRENGTH(9643043),
|
||||
WEAKNESS(4738376),
|
||||
LUCK(3381504),
|
||||
SLOW_FALLING(16773073);
|
||||
|
||||
@Getter
|
||||
private final int color;
|
||||
|
||||
ArrowParticleColors(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
package org.geysermc.geyser.inventory.recipe;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
|
||||
/**
|
||||
* A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}.
|
||||
*/
|
||||
|
@ -33,4 +36,7 @@ public interface GeyserRecipe {
|
|||
* Whether the recipe is flexible or not in which items can be placed where.
|
||||
*/
|
||||
boolean isShaped();
|
||||
|
||||
@Nullable
|
||||
ItemStack result();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public final class TrimRecipe {
|
|||
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
|
||||
|
||||
public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
|
||||
String key = stripMinecraftNamespace(entry.getId());
|
||||
String key = entry.getId().asMinimalString();
|
||||
|
||||
// Color is used when hovering over the item
|
||||
// Find the nearest legacy color from the RGB Java gives us to work with
|
||||
|
@ -67,7 +67,7 @@ public final class TrimRecipe {
|
|||
}
|
||||
|
||||
public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
|
||||
String key = stripMinecraftNamespace(entry.getId());
|
||||
String key = entry.getId().asMinimalString();
|
||||
|
||||
String itemIdentifier = entry.getData().getString("template_item");
|
||||
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
|
||||
|
@ -78,19 +78,6 @@ public final class TrimRecipe {
|
|||
return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
|
||||
}
|
||||
|
||||
// TODO find a good place for a stripNamespace util method
|
||||
private static String stripMinecraftNamespace(String identifier) {
|
||||
int i = identifier.indexOf(':');
|
||||
if (i >= 0) {
|
||||
String namespace = identifier.substring(0, i);
|
||||
// Only strip minecraft namespace
|
||||
if (namespace.equals("minecraft")) {
|
||||
return identifier.substring(i + 1);
|
||||
}
|
||||
}
|
||||
return identifier;
|
||||
}
|
||||
|
||||
private TrimRecipe() {
|
||||
//no-op
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package org.geysermc.geyser.inventory.updater;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
|
@ -38,10 +37,9 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.inventory.AnvilContainer;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.EnchantmentData;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
|
@ -307,22 +305,22 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
*/
|
||||
private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) {
|
||||
boolean hasCompatible = false;
|
||||
Object2IntMap<JavaEnchantment> combinedEnchantments = getEnchantments(input);
|
||||
Object2IntMap<Enchantment> combinedEnchantments = getEnchantments(session, input);
|
||||
int cost = 0;
|
||||
for (Object2IntMap.Entry<JavaEnchantment> entry : getEnchantments(material).object2IntEntrySet()) {
|
||||
JavaEnchantment enchantment = entry.getKey();
|
||||
EnchantmentData data = Registries.ENCHANTMENTS.get(enchantment);
|
||||
if (data == null) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Java enchantment not in registry: " + enchantment);
|
||||
continue;
|
||||
}
|
||||
for (Object2IntMap.Entry<Enchantment> entry : getEnchantments(session, material).object2IntEntrySet()) {
|
||||
Enchantment enchantment = entry.getKey();
|
||||
|
||||
boolean canApply = isEnchantedBook(input) || data.validItems().contains(input.getJavaId());
|
||||
for (JavaEnchantment incompatible : data.incompatibleEnchantments()) {
|
||||
if (combinedEnchantments.containsKey(incompatible)) {
|
||||
canApply = false;
|
||||
if (!bedrock) {
|
||||
cost++;
|
||||
boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input);
|
||||
var exclusiveSet = enchantment.exclusiveSet();
|
||||
if (exclusiveSet != null) {
|
||||
int[] incompatibleEnchantments = session.getTagCache().get(exclusiveSet);
|
||||
for (int i : incompatibleEnchantments) {
|
||||
Enchantment incompatible = session.getRegistryCache().enchantments().byId(i);
|
||||
if (combinedEnchantments.containsKey(incompatible)) {
|
||||
canApply = false;
|
||||
if (!bedrock) {
|
||||
cost++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,12 +332,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
newLevel++;
|
||||
}
|
||||
newLevel = Math.max(currentLevel, newLevel);
|
||||
if (newLevel > data.maxLevel()) {
|
||||
newLevel = data.maxLevel();
|
||||
if (newLevel > enchantment.maxLevel()) {
|
||||
newLevel = enchantment.maxLevel();
|
||||
}
|
||||
combinedEnchantments.put(enchantment, newLevel);
|
||||
|
||||
int rarityMultiplier = data.rarityMultiplier();
|
||||
int rarityMultiplier = enchantment.anvilCost();
|
||||
if (isEnchantedBook(material) && rarityMultiplier > 1) {
|
||||
rarityMultiplier /= 2;
|
||||
}
|
||||
|
@ -347,11 +345,11 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
if (newLevel > currentLevel) {
|
||||
hasCompatible = true;
|
||||
}
|
||||
if (enchantment == JavaEnchantment.IMPALING) {
|
||||
if (enchantment.bedrockEnchantment() == BedrockEnchantment.IMPALING) {
|
||||
// Multiplier is halved on Bedrock for some reason
|
||||
rarityMultiplier /= 2;
|
||||
} else if (enchantment == JavaEnchantment.SWEEPING_EDGE) {
|
||||
// Doesn't exist on Bedrock
|
||||
} else if (enchantment.bedrockEnchantment() == null) {
|
||||
// Whatever this is, doesn't exist on Bedrock
|
||||
rarityMultiplier = 0;
|
||||
}
|
||||
cost += rarityMultiplier * (newLevel - currentLevel);
|
||||
|
@ -368,7 +366,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
return cost;
|
||||
}
|
||||
|
||||
private Object2IntMap<JavaEnchantment> getEnchantments(GeyserItemStack itemStack) {
|
||||
private Object2IntMap<Enchantment> getEnchantments(GeyserSession session, GeyserItemStack itemStack) {
|
||||
ItemEnchantments enchantmentComponent;
|
||||
if (isEnchantedBook(itemStack)) {
|
||||
enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS);
|
||||
|
@ -376,9 +374,9 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
|
|||
enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS);
|
||||
}
|
||||
if (enchantmentComponent != null) {
|
||||
Object2IntMap<JavaEnchantment> enchantments = new Object2IntOpenHashMap<>();
|
||||
Object2IntMap<Enchantment> enchantments = new Object2IntOpenHashMap<>();
|
||||
for (Map.Entry<Integer, Integer> entry : enchantmentComponent.getEnchantments().entrySet()) {
|
||||
JavaEnchantment enchantment = JavaEnchantment.of(entry.getKey());
|
||||
Enchantment enchantment = session.getRegistryCache().enchantments().byId(entry.getKey());
|
||||
if (enchantment == null) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey());
|
||||
continue;
|
||||
|
|
|
@ -834,8 +834,9 @@ public final class Items {
|
|||
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275)));
|
||||
public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
|
||||
public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
|
||||
public static final Item WOLF_ARMOR = register(new ArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64)));
|
||||
public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64)));
|
||||
public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64)));
|
||||
public static final Item BOWL = register(new Item("bowl", builder()));
|
||||
public static final Item APPLE = register(new Item("apple", builder()));
|
||||
public static final Item BOW = register(new Item("bow", builder().stackSize(1).maxDamage(384)));
|
||||
public static final Item ARROW = register(new ArrowItem("arrow", builder()));
|
||||
|
@ -885,7 +886,6 @@ public final class Items {
|
|||
public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(10.0)));
|
||||
public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(1.0)));
|
||||
public static final Item STICK = register(new Item("stick", builder()));
|
||||
public static final Item BOWL = register(new Item("bowl", builder()));
|
||||
public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1)));
|
||||
public static final Item STRING = register(new BlockItem("string", builder(), Blocks.TRIPWIRE));
|
||||
public static final Item FEATHER = register(new Item("feather", builder()));
|
||||
|
@ -1042,7 +1042,7 @@ public final class Items {
|
|||
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
|
||||
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
|
||||
public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
|
||||
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.WATER_CAULDRON));
|
||||
public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON));
|
||||
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
|
||||
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
|
||||
public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
|
||||
|
@ -1130,7 +1130,7 @@ public final class Items {
|
|||
public static final Item WIND_CHARGE = register(new Item("wind_charge", builder()));
|
||||
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1)));
|
||||
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16)));
|
||||
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(250)));
|
||||
public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500)));
|
||||
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
|
||||
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
|
||||
public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));
|
||||
|
@ -1209,6 +1209,8 @@ public final class Items {
|
|||
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1)));
|
||||
|
@ -1221,6 +1223,7 @@ public final class Items {
|
|||
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
|
||||
public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1)));
|
||||
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
|
||||
public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
|
||||
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
|
||||
|
@ -1365,7 +1368,7 @@ public final class Items {
|
|||
public static final Item TRIAL_KEY = register(new Item("trial_key", builder()));
|
||||
public static final Item OMINOUS_TRIAL_KEY = register(new Item("ominous_trial_key", builder()));
|
||||
public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT));
|
||||
public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder()));
|
||||
public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder()));
|
||||
public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
|
||||
|
||||
public static final int AIR_ID = AIR.javaId();
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.enchantment;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @param description only populated if {@link #bedrockEnchantment()} is not null.
|
||||
* @param anvilCost also as a rarity multiplier
|
||||
*/
|
||||
public record Enchantment(String identifier,
|
||||
Set<EnchantmentComponent> effects,
|
||||
ItemTag supportedItems,
|
||||
int maxLevel,
|
||||
String description,
|
||||
int anvilCost,
|
||||
@Nullable EnchantmentTag exclusiveSet,
|
||||
@Nullable BedrockEnchantment bedrockEnchantment) {
|
||||
|
||||
// Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes.
|
||||
// I'm not sure how that's wired over the network, so we'll put it off.
|
||||
public static Enchantment read(RegistryEntry entry) {
|
||||
NbtMap data = entry.getData();
|
||||
Set<EnchantmentComponent> effects = readEnchantmentComponents(data.getCompound("effects"));
|
||||
String supportedItems = data.getString("supported_items").substring(1); // Remove '#' at beginning that indicates tag
|
||||
int maxLevel = data.getInt("max_level");
|
||||
int anvilCost = data.getInt("anvil_cost");
|
||||
String exclusiveSet = data.getString("exclusive_set", null);
|
||||
EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1)));
|
||||
BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString());
|
||||
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null;
|
||||
|
||||
return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel,
|
||||
description, anvilCost, exclusiveSetTag, bedrockEnchantment);
|
||||
}
|
||||
|
||||
private static Set<EnchantmentComponent> readEnchantmentComponents(NbtMap effects) {
|
||||
Set<EnchantmentComponent> components = new HashSet<>();
|
||||
for (Map.Entry<String, Object> entry : effects.entrySet()) {
|
||||
switch (entry.getKey()) {
|
||||
case "minecraft:prevent_armor_change" -> components.add(EnchantmentComponent.PREVENT_ARMOR_CHANGE);
|
||||
}
|
||||
}
|
||||
return Set.copyOf(components); // Also ensures any empty sets are consolidated
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.enchantment;
|
||||
|
||||
public class EnchantmentComponent {
|
||||
/**
|
||||
* Singleton with no additional data
|
||||
*/
|
||||
public static final EnchantmentComponent PREVENT_ARMOR_CHANGE = new EnchantmentComponent();
|
||||
}
|
|
@ -28,15 +28,13 @@ package org.geysermc.geyser.item.type;
|
|||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class ArrowItem extends Item {
|
||||
public ArrowItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
|
@ -44,13 +42,18 @@ public class ArrowItem extends Item {
|
|||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage());
|
||||
Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage());
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
if (tippedArrowPotion != null) {
|
||||
if (potion != null) {
|
||||
itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
|
||||
PotionContents contents = new PotionContents(tippedArrowPotion.ordinal(), -1, Collections.emptyList());
|
||||
PotionContents contents = potion.toComponent();
|
||||
itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents);
|
||||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreDamage() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.item.type;
|
||||
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
@ -40,8 +41,8 @@ import org.geysermc.geyser.registry.type.ItemMapping;
|
|||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
@ -60,9 +61,6 @@ public class BannerItem extends BlockItem {
|
|||
*/
|
||||
private static final List<Pair<BannerPattern, DyeColor>> OMINOUS_BANNER_PATTERN;
|
||||
|
||||
// TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/
|
||||
private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 };
|
||||
|
||||
static {
|
||||
// Construct what an ominous banner is supposed to look like
|
||||
OMINOUS_BANNER_PATTERN = List.of(
|
||||
|
@ -109,7 +107,7 @@ public class BannerItem extends BlockItem {
|
|||
if (color != pair.right()) {
|
||||
return false;
|
||||
}
|
||||
String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch
|
||||
Key id = MinecraftKey.key(patternLayer.getString("pattern")); // Ouch
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id);
|
||||
if (bannerPattern != pair.left()) {
|
||||
return false;
|
||||
|
@ -146,8 +144,8 @@ public class BannerItem extends BlockItem {
|
|||
} else {
|
||||
List<NbtMap> patternList = new ArrayList<>(patterns.size());
|
||||
for (BannerPatternLayer patternLayer : patterns) {
|
||||
patternLayer.getPattern().ifId(holder -> {
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id());
|
||||
patternLayer.getPattern().ifId(id -> {
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(id);
|
||||
if (bannerPattern != null) {
|
||||
NbtMap tag = NbtMap.builder()
|
||||
.putString("Pattern", bannerPattern.getBedrockIdentifier())
|
||||
|
@ -169,7 +167,7 @@ public class BannerItem extends BlockItem {
|
|||
*/
|
||||
private static NbtMap getBedrockBannerPattern(NbtMap pattern) {
|
||||
// ViaVersion 1.20.4 -> 1.20.5 can send without the namespace
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern")));
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(MinecraftKey.key(pattern.getString("pattern")));
|
||||
DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color"));
|
||||
if (bannerPattern == null || dyeColor == null) {
|
||||
return null;
|
||||
|
@ -215,20 +213,22 @@ public class BannerItem extends BlockItem {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
||||
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||
|
||||
if (bedrockTag.getInt("Type") == 1) {
|
||||
// Ominous banner pattern
|
||||
List<BannerPatternLayer> patternLayers = new ArrayList<>();
|
||||
for (int i = 0; i < ominousBannerPattern.length; i++) {
|
||||
patternLayers.add(new BannerPatternLayer(Holder.ofId(ominousBannerPattern[i]), OMINOUS_BANNER_PATTERN.get(i).right().ordinal()));
|
||||
for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) {
|
||||
var pair = OMINOUS_BANNER_PATTERN.get(i);
|
||||
patternLayers.add(new BannerPatternLayer(Holder.ofId(session.getRegistryCache().bannerPatterns().byValue(pair.left())),
|
||||
pair.right().ordinal()));
|
||||
}
|
||||
|
||||
components.put(DataComponentType.BANNER_PATTERNS, patternLayers);
|
||||
components.put(DataComponentType.HIDE_ADDITIONAL_TOOLTIP, Unit.INSTANCE);
|
||||
components.put(DataComponentType.ITEM_NAME, Component
|
||||
.translatable("block.minecraft.ominous_banner") // thank god this works
|
||||
.translatable("block.minecraft.ominous_banner")
|
||||
.style(Style.style(TextColor.color(16755200)))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,9 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.geysermc.geyser.item.ArmorMaterial;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor;
|
||||
|
||||
public class DyeableArmorItem extends ArmorItem {
|
||||
public DyeableArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) {
|
||||
|
@ -44,9 +42,6 @@ public class DyeableArmorItem extends ArmorItem {
|
|||
|
||||
// Note that this is handled as of 1.20.5 in the ItemColors class.
|
||||
// But horse leather armor and body leather armor are now both armor items. So it works!
|
||||
DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR);
|
||||
if (dyedItemColor != null) {
|
||||
builder.putInt("customColor", dyedItemColor.getRgb());
|
||||
}
|
||||
translateDyedColor(components, builder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
|
@ -69,8 +70,8 @@ public class EnchantedBookItem extends Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
||||
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||
|
||||
List<NbtMap> enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND);
|
||||
if (enchantmentTag != null) {
|
||||
|
@ -78,11 +79,16 @@ public class EnchantedBookItem extends Item {
|
|||
for (NbtMap bedrockEnchantment : enchantmentTag) {
|
||||
short bedrockId = bedrockEnchantment.getShort("id");
|
||||
|
||||
Enchantment enchantment = Enchantment.getByBedrockId(bedrockId);
|
||||
BedrockEnchantment enchantment = BedrockEnchantment.getByBedrockId(bedrockId);
|
||||
if (enchantment != null) {
|
||||
int level = bedrockEnchantment.getShort("lvl", (short) 1);
|
||||
// TODO
|
||||
javaEnchantments.put(Enchantment.JavaEnchantment.valueOf(enchantment.name()).ordinal(), level);
|
||||
List<Enchantment> enchantments = session.getRegistryCache().enchantments().values();
|
||||
for (int i = 0; i < enchantments.size(); i++) {
|
||||
if (enchantments.get(i).bedrockEnchantment() == enchantment) {
|
||||
int level = bedrockEnchantment.getShort("lvl", (short) 1);
|
||||
javaEnchantments.put(i, level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public class FilledMapItem extends MapItem {
|
|||
switch (mapColor) {
|
||||
case 3830373 -> builder.damage(3); // Ocean Monument
|
||||
case 5393476 -> builder.damage(4); // Woodland explorer
|
||||
case 12741452 -> builder.damage(14); // Trial Chamber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,8 +70,8 @@ public class FireworkRocketItem extends Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
||||
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||
|
||||
NbtMap fireworksTag = bedrockTag.getCompound("Fireworks");
|
||||
if (!fireworksTag.isEmpty()) {
|
||||
|
|
|
@ -78,8 +78,8 @@ public class FireworkStarItem extends Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(bedrockTag, components, mapping);
|
||||
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
super.translateNbtToJava(session, bedrockTag, components, mapping);
|
||||
|
||||
NbtMap explosion = bedrockTag.getCompound("FireworksItem");
|
||||
if (!explosion.isEmpty()) {
|
||||
|
@ -90,4 +90,9 @@ public class FireworkStarItem extends Item {
|
|||
components.put(DataComponentType.FIREWORK_EXPLOSION, newExplosion);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreDamage() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,4 +62,9 @@ public class GoatHornItem extends Item {
|
|||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreDamage() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,9 @@ import org.cloudburstmc.nbt.NbtType;
|
|||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment;
|
||||
import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
|
@ -44,9 +45,10 @@ import org.geysermc.geyser.text.MinecraftLocale;
|
|||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -63,7 +65,7 @@ public class Item {
|
|||
private final int maxDamage;
|
||||
|
||||
public Item(String javaIdentifier, Builder builder) {
|
||||
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
|
||||
this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern();
|
||||
this.stackSize = builder.stackSize;
|
||||
this.maxDamage = builder.maxDamage;
|
||||
this.attackDamage = builder.attackDamage;
|
||||
|
@ -123,7 +125,7 @@ public class Item {
|
|||
*/
|
||||
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
|
||||
List<Component> loreComponents = components.get(DataComponentType.LORE);
|
||||
if (loreComponents != null) {
|
||||
if (loreComponents != null && components.get(DataComponentType.HIDE_TOOLTIP) == null) {
|
||||
List<String> lore = builder.getOrCreateLore();
|
||||
for (Component loreComponent : loreComponents) {
|
||||
lore.add(MessageTranslator.convertMessage(loreComponent, session.locale()));
|
||||
|
@ -170,7 +172,7 @@ public class Item {
|
|||
* </ul>
|
||||
* Therefore, if translation cannot be achieved for a certain item, it is not necessarily bad.
|
||||
*/
|
||||
public void translateNbtToJava(@NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
public void translateNbtToJava(@NonNull GeyserSession session, @NonNull NbtMap bedrockTag, @NonNull DataComponents components, @NonNull ItemMapping mapping) {
|
||||
// TODO see if any items from the creative menu need this
|
||||
// CompoundTag displayTag = tag.get("display");
|
||||
// if (displayTag != null) {
|
||||
|
@ -188,71 +190,25 @@ public class Item {
|
|||
// }
|
||||
// displayTag.put(new ListTag("Lore", lore));
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO no creative item should have enchantments *except* enchanted books
|
||||
// List<NbtMap> enchantmentTag = bedrockTag.getList("ench", NbtType.COMPOUND);
|
||||
// if (enchantmentTag != null) {
|
||||
// List<Tag> enchantments = new ArrayList<>();
|
||||
// for (Tag value : enchantmentTag.getValue()) {
|
||||
// if (!(value instanceof CompoundTag tagValue))
|
||||
// continue;
|
||||
//
|
||||
// ShortTag bedrockId = tagValue.get("id");
|
||||
// if (bedrockId == null) continue;
|
||||
//
|
||||
// Enchantment enchantment = Enchantment.getByBedrockId(bedrockId.getValue());
|
||||
// if (enchantment != null) {
|
||||
// CompoundTag javaTag = new CompoundTag("");
|
||||
// Map<String, Tag> javaValue = javaTag.getValue();
|
||||
// javaValue.put("id", new StringTag("id", enchantment.getJavaIdentifier()));
|
||||
// ShortTag levelTag = tagValue.get("lvl");
|
||||
// javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1));
|
||||
// javaTag.setValue(javaValue);
|
||||
//
|
||||
// enchantments.add(javaTag);
|
||||
// } else {
|
||||
// GeyserImpl.getInstance().getLogger().debug("Unknown bedrock enchantment: " + bedrockId);
|
||||
// }
|
||||
// }
|
||||
// if (!enchantments.isEmpty()) {
|
||||
// if ((this instanceof EnchantedBookItem)) {
|
||||
// bedrockTag.put(new ListTag("StoredEnchantments", enchantments));
|
||||
// components.put(DataComponentType.STORED_ENCHANTMENTS, enchantments);
|
||||
// } else {
|
||||
// components.put(DataComponentType.ENCHANTMENTS, enchantments);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a map from Java-only enchantments to their translation keys so that we can
|
||||
* map these enchantments to Bedrock clients, since they don't actually exist there.
|
||||
*/
|
||||
private static final Map<Enchantment.JavaEnchantment, String> ENCHANTMENT_TRANSLATION_KEYS = Map.of(
|
||||
Enchantment.JavaEnchantment.SWEEPING_EDGE, "enchantment.minecraft.sweeping",
|
||||
Enchantment.JavaEnchantment.DENSITY, "enchantment.minecraft.density",
|
||||
Enchantment.JavaEnchantment.BREACH, "enchantment.minecraft.breach",
|
||||
Enchantment.JavaEnchantment.WIND_BURST, "enchantment.minecraft.wind_burst");
|
||||
|
||||
protected final @Nullable NbtMap remapEnchantment(GeyserSession session, int enchantId, int level, BedrockItemBuilder builder) {
|
||||
// TODO verify
|
||||
// TODO streamline Enchantment process
|
||||
Enchantment.JavaEnchantment enchantment = Enchantment.JavaEnchantment.of(enchantId);
|
||||
String translationKey = ENCHANTMENT_TRANSLATION_KEYS.get(enchantment);
|
||||
if (translationKey != null) {
|
||||
String enchantmentTranslation = MinecraftLocale.getLocaleString(translationKey, session.locale());
|
||||
addJavaOnlyEnchantment(session, builder, enchantmentTranslation, level);
|
||||
return null;
|
||||
}
|
||||
Enchantment enchantment = session.getRegistryCache().enchantments().byId(enchantId);
|
||||
if (enchantment == null) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + enchantId);
|
||||
return null;
|
||||
}
|
||||
|
||||
BedrockEnchantment bedrockEnchantment = enchantment.bedrockEnchantment();
|
||||
if (bedrockEnchantment == null) {
|
||||
String enchantmentTranslation = MinecraftLocale.getLocaleString(enchantment.description(), session.locale());
|
||||
addJavaOnlyEnchantment(session, builder, enchantmentTranslation, level);
|
||||
return null;
|
||||
}
|
||||
|
||||
return NbtMap.builder()
|
||||
.putShort("id", (short) Enchantment.valueOf(enchantment.name()).ordinal())
|
||||
.putShort("id", (short) bedrockEnchantment.ordinal())
|
||||
.putShort("lvl", (short) level)
|
||||
.build();
|
||||
}
|
||||
|
@ -260,7 +216,22 @@ public class Item {
|
|||
private void addJavaOnlyEnchantment(GeyserSession session, BedrockItemBuilder builder, String enchantmentName, int level) {
|
||||
String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale());
|
||||
|
||||
builder.getOrCreateLore().add(ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation);
|
||||
builder.getOrCreateLore().add(0, ChatColor.RESET + ChatColor.GRAY + enchantmentName + " " + lvlTranslation);
|
||||
}
|
||||
|
||||
protected final void translateDyedColor(DataComponents components, BedrockItemBuilder builder) {
|
||||
DyedItemColor dyedItemColor = components.get(DataComponentType.DYED_COLOR);
|
||||
if (dyedItemColor != null) {
|
||||
builder.putInt("customColor", dyedItemColor.getRgb());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override if the Bedrock equivalent of an item uses damage for extra data, and should not be tracked
|
||||
* when translating an item.
|
||||
*/
|
||||
public boolean ignoreDamage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Translation methods end */
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.type;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
public class OminousBottleItem extends Item {
|
||||
public OminousBottleItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) {
|
||||
var builder = super.translateToBedrock(count, components, mapping, mappings);
|
||||
if (components == null) {
|
||||
// Level 1 ominous bottle is null components - Java 1.21.
|
||||
return builder;
|
||||
}
|
||||
Integer amplifier = components.get(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER);
|
||||
if (amplifier != null) {
|
||||
builder.damage(amplifier);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
|
||||
// This item can be pulled from the creative inventory with amplifiers.
|
||||
GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
|
||||
int damage = itemData.getDamage();
|
||||
if (damage == 0) {
|
||||
return itemStack;
|
||||
}
|
||||
itemStack.getOrCreateComponents().put(DataComponentType.OMINOUS_BOTTLE_AMPLIFIER, damage);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreDamage() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -76,4 +76,9 @@ public class PotionItem extends Item {
|
|||
}
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreDamage() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ package org.geysermc.geyser.item.type;
|
|||
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
|
@ -44,11 +44,11 @@ public class TippedArrowItem extends ArrowItem {
|
|||
if (components != null) {
|
||||
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
|
||||
if (potionContents != null) {
|
||||
TippedArrowPotion tippedArrowPotion = TippedArrowPotion.of(potionContents.getPotionId());
|
||||
if (tippedArrowPotion != null) {
|
||||
Potion potion = Potion.getByJavaId(potionContents.getPotionId());
|
||||
if (potion != null) {
|
||||
return ItemData.builder()
|
||||
.definition(mapping.getBedrockDefinition())
|
||||
.damage(tippedArrowPotion.getBedrockId())
|
||||
.damage(potion.tippedArrowId())
|
||||
.count(count);
|
||||
}
|
||||
GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId());
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.type;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.item.ArmorMaterial;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
public class WolfArmorItem extends ArmorItem {
|
||||
public WolfArmorItem(String javaIdentifier, ArmorMaterial material, Builder builder) {
|
||||
super(javaIdentifier, material, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
|
||||
super.translateComponentsToBedrock(session, components, builder);
|
||||
|
||||
// Note that this is handled as of 1.21 in the ItemColors class.
|
||||
translateDyedColor(components, builder);
|
||||
}
|
||||
}
|
|
@ -63,7 +63,8 @@ public enum BedrockMapIcon {
|
|||
ICON_SNOWY_VILLAGE(MapIconType.SNOWY_VILLAGE, 20),
|
||||
ICON_TAIGA_VILLAGE(MapIconType.TAIGA_VILLAGE, 21),
|
||||
ICON_JUNGLE_TEMPLE(MapIconType.JUNGLE_TEMPLE, 22),
|
||||
ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23);
|
||||
ICON_SWAMP_HUT(MapIconType.SWAMP_HUT, 23),
|
||||
ICON_TRIAL_CHAMBERS(MapIconType.TRIAL_CHAMBERS, 24);
|
||||
|
||||
private static final BedrockMapIcon[] VALUES = values();
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.level;
|
||||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
|
||||
public record JukeboxSong(String soundEvent, String description) {
|
||||
|
||||
public static JukeboxSong read(RegistryEntry entry) {
|
||||
NbtMap data = entry.getData();
|
||||
Object soundEventObject = data.get("sound_event");
|
||||
String soundEvent;
|
||||
if (soundEventObject instanceof NbtMap map) {
|
||||
soundEvent = map.getString("sound_id");
|
||||
} else if (soundEventObject instanceof String string) {
|
||||
soundEvent = string;
|
||||
} else {
|
||||
soundEvent = "";
|
||||
GeyserImpl.getInstance().getLogger().debug("Sound event for " + entry.getId() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject);
|
||||
}
|
||||
String description = MessageTranslator.deserializeDescription(data);
|
||||
return new JukeboxSong(soundEvent, description);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,9 @@ package org.geysermc.geyser.level;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
|
@ -61,21 +64,40 @@ public enum PaintingType {
|
|||
EARTH("Earth", 2, 2),
|
||||
WIND("Wind", 2, 2),
|
||||
WATER("Water", 2, 2),
|
||||
FIRE("Fire", 2, 2);
|
||||
FIRE("Fire", 2, 2),
|
||||
MEDITATIVE("meditative", 1, 1),
|
||||
PRAIRIE_RIDE("prairie_ride", 1, 2),
|
||||
BAROQUE("baroque", 2, 2),
|
||||
HUMBLE("humble", 2, 2),
|
||||
UNPACKED("unpacked", 4, 4),
|
||||
BACKYARD("backyard", 3, 4),
|
||||
BOUQUET("bouquet", 3, 3),
|
||||
CAVEBIRD("cavebird", 3, 3),
|
||||
CHANGING("changing", 4, 2),
|
||||
COTAN("cotan", 3, 3),
|
||||
ENDBOSS("endboss", 3, 3),
|
||||
FERN("fern", 3, 3),
|
||||
FINDING("finding", 4, 2),
|
||||
LOWMIST("lowmist", 4, 2),
|
||||
ORB("orb", 4, 4),
|
||||
OWLEMONS("owlemons", 3, 3),
|
||||
PASSAGE("passage", 4, 2),
|
||||
POND("pond", 3, 4),
|
||||
SUNFLOWERS("sunflowers", 3, 3),
|
||||
TIDES("tides", 3, 3);
|
||||
|
||||
private static final PaintingType[] VALUES = values();
|
||||
private final String bedrockName;
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public static PaintingType getByName(String javaName) {
|
||||
for (PaintingType paintingName : VALUES) {
|
||||
if (paintingName.name().equalsIgnoreCase(javaName)) return paintingName;
|
||||
public static PaintingType getByName(Key key) {
|
||||
if (!key.namespace().equals("minecraft")) {
|
||||
return null;
|
||||
}
|
||||
return KEBAB;
|
||||
}
|
||||
|
||||
public static PaintingType getByPaintingType(org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType paintingType) {
|
||||
return getByName(paintingType.name());
|
||||
for (PaintingType paintingName : VALUES) {
|
||||
if (paintingName.name().toLowerCase(Locale.ROOT).equals(key.value())) return paintingName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,9 +43,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemCodecHel
|
|||
import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
|
@ -209,6 +211,13 @@ public abstract class WorldManager {
|
|||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves decorated pot sherds from the server. Used to ensure the data is not erased on animation sent
|
||||
* through the BlockEntityDataPacket.
|
||||
*/
|
||||
public void getDecoratedPotData(GeyserSession session, Vector3i pos, Consumer<List<String>> apply) {
|
||||
}
|
||||
|
||||
protected static final Function<Int2ObjectMap<byte[]>, DataComponents> RAW_TRANSFORMER = map -> {
|
||||
try {
|
||||
Map<DataComponentType<?>, DataComponent<?, ?>> components = new HashMap<>();
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.geysermc.geyser.level.physics.Axis;
|
|||
import org.geysermc.geyser.level.physics.Direction;
|
||||
import org.geysermc.geyser.level.physics.PistonBehavior;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
|
||||
import static org.geysermc.geyser.level.block.property.Properties.*;
|
||||
import static org.geysermc.geyser.level.block.type.Block.builder;
|
||||
|
@ -89,11 +90,11 @@ public final class Blocks {
|
|||
public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(LEVEL)));
|
||||
public static final Block SAND = register(new Block("sand", builder().destroyTime(0.5f)));
|
||||
public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(DUSTED)));
|
||||
public static final Block RED_SAND = register(new Block("red_sand", builder().destroyTime(0.5f)));
|
||||
public static final Block GRAVEL = register(new Block("gravel", builder().destroyTime(0.6f)));
|
||||
public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity().destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(DUSTED)));
|
||||
public static final Block GOLD_ORE = register(new Block("gold_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f)));
|
||||
public static final Block DEEPSLATE_GOLD_ORE = register(new Block("deepslate_gold_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f)));
|
||||
|
@ -220,7 +221,7 @@ public final class Blocks {
|
|||
public static final Block LAPIS_ORE = register(new Block("lapis_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f)));
|
||||
public static final Block DEEPSLATE_LAPIS_ORE = register(new Block("deepslate_lapis_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f)));
|
||||
public static final Block LAPIS_BLOCK = register(new Block("lapis_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f)));
|
||||
public static final Block DISPENSER = register(new Block("dispenser", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block DISPENSER = register(new Block("dispenser", builder().setBlockEntity(BlockEntityType.DISPENSER).requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)
|
||||
.booleanState(TRIGGERED)));
|
||||
public static final Block SANDSTONE = register(new Block("sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f)));
|
||||
|
@ -230,67 +231,67 @@ public final class Blocks {
|
|||
.enumState(NOTEBLOCK_INSTRUMENT)
|
||||
.intState(NOTE)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OCCUPIED)
|
||||
.enumState(BED_PART)));
|
||||
|
@ -335,7 +336,7 @@ public final class Blocks {
|
|||
public static final Block GREEN_WOOL = register(new Block("green_wool", builder().destroyTime(0.8f)));
|
||||
public static final Block RED_WOOL = register(new Block("red_wool", builder().destroyTime(0.8f)));
|
||||
public static final Block BLACK_WOOL = register(new Block("black_wool", builder().destroyTime(0.8f)));
|
||||
public static final Block MOVING_PISTON = register(new MovingPistonBlock("moving_piston", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)
|
||||
public static final Block MOVING_PISTON = register(new MovingPistonBlock("moving_piston", builder().setBlockEntity(BlockEntityType.PISTON).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)
|
||||
.enumState(PISTON_TYPE)));
|
||||
public static final Block DANDELION = register(new Block("dandelion", builder().pushReaction(PistonBehavior.DESTROY)));
|
||||
|
@ -360,7 +361,7 @@ public final class Blocks {
|
|||
public static final Block TNT = register(new Block("tnt", builder()
|
||||
.booleanState(UNSTABLE)));
|
||||
public static final Block BOOKSHELF = register(new Block("bookshelf", builder().destroyTime(1.5f)));
|
||||
public static final Block CHISELED_BOOKSHELF = register(new Block("chiseled_bookshelf", builder().setBlockEntity().destroyTime(1.5f)
|
||||
public static final Block CHISELED_BOOKSHELF = register(new Block("chiseled_bookshelf", builder().setBlockEntity(BlockEntityType.CHISELED_BOOKSHELF).destroyTime(1.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(CHISELED_BOOKSHELF_SLOT_0_OCCUPIED)
|
||||
.booleanState(CHISELED_BOOKSHELF_SLOT_1_OCCUPIED)
|
||||
|
@ -381,13 +382,13 @@ public final class Blocks {
|
|||
.booleanState(UP)
|
||||
.booleanState(WEST)));
|
||||
public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY)));
|
||||
public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity(BlockEntityType.MOB_SPAWNER).requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder().destroyTime(2.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.enumState(HALF)
|
||||
.enumState(STAIRS_SHAPE)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity().destroyTime(2.5f)
|
||||
public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity(BlockEntityType.CHEST).destroyTime(2.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.enumState(CHEST_TYPE, ChestType.VALUES)
|
||||
.booleanState(WATERLOGGED)));
|
||||
|
@ -405,34 +406,34 @@ public final class Blocks {
|
|||
.intState(AGE_7)));
|
||||
public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f)
|
||||
.intState(MOISTURE)));
|
||||
public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity(BlockEntityType.FURNACE).requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)));
|
||||
public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block OAK_DOOR = register(new DoorBlock("oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
|
@ -452,108 +453,108 @@ public final class Blocks {
|
|||
.enumState(HALF)
|
||||
.enumState(STAIRS_SHAPE)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block SPRUCE_WALL_SIGN = register(new Block("spruce_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block SPRUCE_WALL_SIGN = register(new Block("spruce_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BIRCH_WALL_SIGN = register(new Block("birch_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BIRCH_WALL_SIGN = register(new Block("birch_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block ACACIA_WALL_SIGN = register(new Block("acacia_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ACACIA_WALL_SIGN = register(new Block("acacia_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CHERRY_WALL_SIGN = register(new Block("cherry_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CHERRY_WALL_SIGN = register(new Block("cherry_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block JUNGLE_WALL_SIGN = register(new Block("jungle_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block JUNGLE_WALL_SIGN = register(new Block("jungle_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block DARK_OAK_WALL_SIGN = register(new Block("dark_oak_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block DARK_OAK_WALL_SIGN = register(new Block("dark_oak_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block MANGROVE_WALL_SIGN = register(new Block("mangrove_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MANGROVE_WALL_SIGN = register(new Block("mangrove_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BAMBOO_WALL_SIGN = register(new Block("bamboo_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BAMBOO_WALL_SIGN = register(new Block("bamboo_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.booleanState(ATTACHED)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block SPRUCE_WALL_HANGING_SIGN = register(new Block("spruce_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block SPRUCE_WALL_HANGING_SIGN = register(new Block("spruce_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BIRCH_WALL_HANGING_SIGN = register(new Block("birch_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BIRCH_WALL_HANGING_SIGN = register(new Block("birch_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block ACACIA_WALL_HANGING_SIGN = register(new Block("acacia_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ACACIA_WALL_HANGING_SIGN = register(new Block("acacia_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CHERRY_WALL_HANGING_SIGN = register(new Block("cherry_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CHERRY_WALL_HANGING_SIGN = register(new Block("cherry_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block JUNGLE_WALL_HANGING_SIGN = register(new Block("jungle_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block JUNGLE_WALL_HANGING_SIGN = register(new Block("jungle_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block DARK_OAK_WALL_HANGING_SIGN = register(new Block("dark_oak_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block DARK_OAK_WALL_HANGING_SIGN = register(new Block("dark_oak_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block MANGROVE_WALL_HANGING_SIGN = register(new Block("mangrove_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MANGROVE_WALL_HANGING_SIGN = register(new Block("mangrove_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CRIMSON_WALL_HANGING_SIGN = register(new Block("crimson_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CRIMSON_WALL_HANGING_SIGN = register(new Block("crimson_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block WARPED_WALL_HANGING_SIGN = register(new Block("warped_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WARPED_WALL_HANGING_SIGN = register(new Block("warped_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
|
||||
|
@ -608,7 +609,7 @@ public final class Blocks {
|
|||
public static final Block CLAY = register(new Block("clay", builder().destroyTime(0.6f)));
|
||||
public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder().pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(AGE_15)));
|
||||
public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity().destroyTime(2.0f)
|
||||
public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity(BlockEntityType.JUKEBOX).destroyTime(2.0f)
|
||||
.booleanState(HAS_RECORD)));
|
||||
public static final Block OAK_FENCE = register(new Block("oak_fence", builder().destroyTime(2.0f)
|
||||
.booleanState(EAST)
|
||||
|
@ -819,8 +820,8 @@ public final class Blocks {
|
|||
.booleanState(WATERLOGGED)));
|
||||
public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(AGE_3)));
|
||||
public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(0.5f)
|
||||
public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity(BlockEntityType.ENCHANTING_TABLE).requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity(BlockEntityType.BREWING_STAND).requiresCorrectToolForDrops().destroyTime(0.5f)
|
||||
.booleanState(HAS_BOTTLE_0)
|
||||
.booleanState(HAS_BOTTLE_1)
|
||||
.booleanState(HAS_BOTTLE_2)));
|
||||
|
@ -830,7 +831,7 @@ public final class Blocks {
|
|||
public static final Block LAVA_CAULDRON = register(new CauldronBlock("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)));
|
||||
public static final Block POWDER_SNOW_CAULDRON = register(new CauldronBlock("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
.intState(LEVEL_CAULDRON)));
|
||||
public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)));
|
||||
public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity(BlockEntityType.END_PORTAL).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)));
|
||||
public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder().destroyTime(-1.0f)
|
||||
.booleanState(EYE)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
|
@ -848,7 +849,7 @@ public final class Blocks {
|
|||
.booleanState(WATERLOGGED)));
|
||||
public static final Block EMERALD_ORE = register(new Block("emerald_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f)));
|
||||
public static final Block DEEPSLATE_EMERALD_ORE = register(new Block("deepslate_emerald_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f)));
|
||||
public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(22.5f)
|
||||
public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity(BlockEntityType.ENDER_CHEST).requiresCorrectToolForDrops().destroyTime(22.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block TRIPWIRE_HOOK = register(new Block("tripwire_hook", builder().pushReaction(PistonBehavior.DESTROY)
|
||||
|
@ -879,10 +880,10 @@ public final class Blocks {
|
|||
.enumState(HALF)
|
||||
.enumState(STAIRS_SHAPE)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
.booleanState(CONDITIONAL)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block BEACON = register(new Block("beacon", builder().setBlockEntity().destroyTime(3.0f)));
|
||||
public static final Block BEACON = register(new Block("beacon", builder().setBlockEntity(BlockEntityType.BEACON).destroyTime(3.0f)));
|
||||
public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f)
|
||||
.enumState(EAST_WALL)
|
||||
.enumState(NORTH_WALL)
|
||||
|
@ -965,46 +966,46 @@ public final class Blocks {
|
|||
.enumState(ATTACH_FACE)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", SkullBlock.Type.PLAYER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", SkullBlock.Type.CREEPER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", SkullBlock.Type.DRAGON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(POWERED)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK)
|
||||
|
@ -1013,7 +1014,7 @@ public final class Blocks {
|
|||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity().destroyTime(2.5f)
|
||||
public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity(BlockEntityType.TRAPPED_CHEST).destroyTime(2.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.enumState(CHEST_TYPE, ChestType.VALUES)
|
||||
.booleanState(WATERLOGGED)));
|
||||
|
@ -1021,16 +1022,16 @@ public final class Blocks {
|
|||
.intState(POWER)));
|
||||
public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(POWER)));
|
||||
public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity(BlockEntityType.COMPARATOR).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.enumState(MODE_COMPARATOR)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity().destroyTime(0.2f)
|
||||
public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity(BlockEntityType.DAYLIGHT_DETECTOR).destroyTime(0.2f)
|
||||
.booleanState(INVERTED)
|
||||
.intState(POWER)));
|
||||
public static final Block REDSTONE_BLOCK = register(new Block("redstone_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f)));
|
||||
public static final Block NETHER_QUARTZ_ORE = register(new Block("nether_quartz_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f)));
|
||||
public static final Block HOPPER = register(new Block("hopper", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.0f)
|
||||
public static final Block HOPPER = register(new Block("hopper", builder().setBlockEntity(BlockEntityType.HOPPER).requiresCorrectToolForDrops().destroyTime(3.0f)
|
||||
.booleanState(ENABLED)
|
||||
.enumState(FACING_HOPPER, Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block QUARTZ_BLOCK = register(new Block("quartz_block", builder().requiresCorrectToolForDrops().destroyTime(0.8f)));
|
||||
|
@ -1046,7 +1047,7 @@ public final class Blocks {
|
|||
.booleanState(POWERED)
|
||||
.enumState(RAIL_SHAPE_STRAIGHT)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity(BlockEntityType.DROPPER).requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)
|
||||
.booleanState(TRIGGERED)));
|
||||
public static final Block WHITE_TERRACOTTA = register(new Block("white_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f)));
|
||||
|
@ -1264,69 +1265,69 @@ public final class Blocks {
|
|||
.enumState(DOUBLE_BLOCK_HALF)));
|
||||
public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(DOUBLE_BLOCK_HALF)));
|
||||
public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)));
|
||||
public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block ORANGE_WALL_BANNER = register(new BannerBlock("orange_wall_banner", 1, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block ORANGE_WALL_BANNER = register(new BannerBlock("orange_wall_banner", 1, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block MAGENTA_WALL_BANNER = register(new BannerBlock("magenta_wall_banner", 2, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block MAGENTA_WALL_BANNER = register(new BannerBlock("magenta_wall_banner", 2, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block LIGHT_BLUE_WALL_BANNER = register(new BannerBlock("light_blue_wall_banner", 3, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIGHT_BLUE_WALL_BANNER = register(new BannerBlock("light_blue_wall_banner", 3, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block YELLOW_WALL_BANNER = register(new BannerBlock("yellow_wall_banner", 4, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block YELLOW_WALL_BANNER = register(new BannerBlock("yellow_wall_banner", 4, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block LIME_WALL_BANNER = register(new BannerBlock("lime_wall_banner", 5, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIME_WALL_BANNER = register(new BannerBlock("lime_wall_banner", 5, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block PINK_WALL_BANNER = register(new BannerBlock("pink_wall_banner", 6, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block PINK_WALL_BANNER = register(new BannerBlock("pink_wall_banner", 6, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block GRAY_WALL_BANNER = register(new BannerBlock("gray_wall_banner", 7, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block GRAY_WALL_BANNER = register(new BannerBlock("gray_wall_banner", 7, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block LIGHT_GRAY_WALL_BANNER = register(new BannerBlock("light_gray_wall_banner", 8, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block LIGHT_GRAY_WALL_BANNER = register(new BannerBlock("light_gray_wall_banner", 8, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block CYAN_WALL_BANNER = register(new BannerBlock("cyan_wall_banner", 9, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CYAN_WALL_BANNER = register(new BannerBlock("cyan_wall_banner", 9, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block PURPLE_WALL_BANNER = register(new BannerBlock("purple_wall_banner", 10, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block PURPLE_WALL_BANNER = register(new BannerBlock("purple_wall_banner", 10, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block BLUE_WALL_BANNER = register(new BannerBlock("blue_wall_banner", 11, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BLUE_WALL_BANNER = register(new BannerBlock("blue_wall_banner", 11, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block BROWN_WALL_BANNER = register(new BannerBlock("brown_wall_banner", 12, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BROWN_WALL_BANNER = register(new BannerBlock("brown_wall_banner", 12, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block GREEN_WALL_BANNER = register(new BannerBlock("green_wall_banner", 13, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block GREEN_WALL_BANNER = register(new BannerBlock("green_wall_banner", 13, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block RED_WALL_BANNER = register(new BannerBlock("red_wall_banner", 14, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block RED_WALL_BANNER = register(new BannerBlock("red_wall_banner", 14, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block BLACK_WALL_BANNER = register(new BannerBlock("black_wall_banner", 15, builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block BLACK_WALL_BANNER = register(new BannerBlock("black_wall_banner", 15, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block RED_SANDSTONE = register(new Block("red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f)));
|
||||
public static final Block CHISELED_RED_SANDSTONE = register(new Block("chiseled_red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f)));
|
||||
|
@ -1578,11 +1579,11 @@ public final class Blocks {
|
|||
public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY)
|
||||
.intState(AGE_3)));
|
||||
public static final Block DIRT_PATH = register(new Block("dirt_path", builder().destroyTime(0.65f)));
|
||||
public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)));
|
||||
public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity(BlockEntityType.END_GATEWAY).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK)));
|
||||
public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
.booleanState(CONDITIONAL)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block CHAIN_COMMAND_BLOCK = register(new Block("chain_command_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
public static final Block CHAIN_COMMAND_BLOCK = register(new Block("chain_command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
.booleanState(CONDITIONAL)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block FROSTED_ICE = register(new Block("frosted_ice", builder().destroyTime(0.5f)
|
||||
|
@ -1596,39 +1597,39 @@ public final class Blocks {
|
|||
public static final Block OBSERVER = register(new Block("observer", builder().requiresCorrectToolForDrops().destroyTime(3.0f)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity().destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)));
|
||||
public static final Block WHITE_GLAZED_TERRACOTTA = register(new Block("white_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
|
@ -1787,7 +1788,7 @@ public final class Blocks {
|
|||
.intState(PICKLES)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BLUE_ICE = register(new Block("blue_ice", builder().destroyTime(2.8f)));
|
||||
public static final Block CONDUIT = register(new Block("conduit", builder().setBlockEntity().destroyTime(3.0f)
|
||||
public static final Block CONDUIT = register(new Block("conduit", builder().setBlockEntity(BlockEntityType.CONDUIT).destroyTime(3.0f)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.BAMBOO)));
|
||||
public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
|
@ -2005,13 +2006,13 @@ public final class Blocks {
|
|||
.booleanState(WATERLOGGED)));
|
||||
public static final Block LOOM = register(new Block("loom", builder().destroyTime(2.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block BARREL = register(new Block("barrel", builder().setBlockEntity().destroyTime(2.5f)
|
||||
public static final Block BARREL = register(new Block("barrel", builder().setBlockEntity(BlockEntityType.BARREL).destroyTime(2.5f)
|
||||
.enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN)
|
||||
.booleanState(OPEN)));
|
||||
public static final Block SMOKER = register(new Block("smoker", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block SMOKER = register(new Block("smoker", builder().setBlockEntity(BlockEntityType.SMOKER).requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)));
|
||||
public static final Block BLAST_FURNACE = register(new Block("blast_furnace", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
public static final Block BLAST_FURNACE = register(new Block("blast_furnace", builder().setBlockEntity(BlockEntityType.BLAST_FURNACE).requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)));
|
||||
public static final Block CARTOGRAPHY_TABLE = register(new Block("cartography_table", builder().destroyTime(2.5f)));
|
||||
|
@ -2019,14 +2020,14 @@ public final class Blocks {
|
|||
public static final Block GRINDSTONE = register(new Block("grindstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f).pushReaction(PistonBehavior.BLOCK)
|
||||
.enumState(ATTACH_FACE)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity().destroyTime(2.5f)
|
||||
public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity(BlockEntityType.LECTERN).destroyTime(2.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(HAS_BOOK)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block SMITHING_TABLE = register(new Block("smithing_table", builder().destroyTime(2.5f)));
|
||||
public static final Block STONECUTTER = register(new Block("stonecutter", builder().requiresCorrectToolForDrops().destroyTime(3.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)));
|
||||
public static final Block BELL = register(new Block("bell", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block BELL = register(new Block("bell", builder().setBlockEntity(BlockEntityType.BELL).requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY)
|
||||
.enumState(BELL_ATTACHMENT)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(POWERED)));
|
||||
|
@ -2036,12 +2037,12 @@ public final class Blocks {
|
|||
public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(HANGING)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity().destroyTime(2.0f)
|
||||
public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity(BlockEntityType.CAMPFIRE).destroyTime(2.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)
|
||||
.booleanState(SIGNAL_FIRE)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block SOUL_CAMPFIRE = register(new Block("soul_campfire", builder().setBlockEntity().destroyTime(2.0f)
|
||||
public static final Block SOUL_CAMPFIRE = register(new Block("soul_campfire", builder().setBlockEntity(BlockEntityType.CAMPFIRE).destroyTime(2.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(LIT)
|
||||
.booleanState(SIGNAL_FIRE)
|
||||
|
@ -2155,30 +2156,30 @@ public final class Blocks {
|
|||
.enumState(DOOR_HINGE)
|
||||
.booleanState(OPEN)
|
||||
.booleanState(POWERED)));
|
||||
public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.intState(ROTATION_16)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block WARPED_WALL_SIGN = register(new Block("warped_wall_sign", builder().setBlockEntity().destroyTime(1.0f)
|
||||
public static final Block WARPED_WALL_SIGN = register(new Block("warped_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity(BlockEntityType.STRUCTURE_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
.enumState(STRUCTUREBLOCK_MODE)));
|
||||
public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity(BlockEntityType.JIGSAW).requiresCorrectToolForDrops().destroyTime(-1.0f)
|
||||
.enumState(ORIENTATION, FrontAndTop.VALUES)));
|
||||
public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f)
|
||||
.intState(LEVEL_COMPOSTER)));
|
||||
public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f)
|
||||
.intState(POWER)));
|
||||
public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity().destroyTime(0.3f)
|
||||
public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity(BlockEntityType.BEEHIVE).destroyTime(0.3f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.intState(LEVEL_HONEY)));
|
||||
public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity().destroyTime(0.6f)
|
||||
public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity(BlockEntityType.BEEHIVE).destroyTime(0.6f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.intState(LEVEL_HONEY)));
|
||||
public static final Block HONEY_BLOCK = register(new HoneyBlock("honey_block", builder()));
|
||||
|
@ -2422,11 +2423,11 @@ public final class Blocks {
|
|||
public static final Block CALCITE = register(new Block("calcite", builder().requiresCorrectToolForDrops().destroyTime(0.75f)));
|
||||
public static final Block TINTED_GLASS = register(new Block("tinted_glass", builder().destroyTime(0.3f)));
|
||||
public static final Block POWDER_SNOW = register(new Block("powder_snow", builder().destroyTime(0.25f)));
|
||||
public static final Block SCULK_SENSOR = register(new Block("sculk_sensor", builder().setBlockEntity().destroyTime(1.5f)
|
||||
public static final Block SCULK_SENSOR = register(new Block("sculk_sensor", builder().setBlockEntity(BlockEntityType.SCULK_SENSOR).destroyTime(1.5f)
|
||||
.intState(POWER)
|
||||
.enumState(SCULK_SENSOR_PHASE)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity().destroyTime(1.5f)
|
||||
public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity(BlockEntityType.CALIBRATED_SCULK_SENSOR).destroyTime(1.5f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.intState(POWER)
|
||||
.enumState(SCULK_SENSOR_PHASE)
|
||||
|
@ -2440,9 +2441,9 @@ public final class Blocks {
|
|||
.booleanState(UP)
|
||||
.booleanState(WATERLOGGED)
|
||||
.booleanState(WEST)));
|
||||
public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity().destroyTime(3.0f)
|
||||
public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity(BlockEntityType.SCULK_CATALYST).destroyTime(3.0f)
|
||||
.booleanState(BLOOM)));
|
||||
public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder().setBlockEntity().destroyTime(3.0f)
|
||||
public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder().setBlockEntity(BlockEntityType.SCULK_SHRIEKER).destroyTime(3.0f)
|
||||
.booleanState(CAN_SUMMON)
|
||||
.booleanState(SHRIEKING)
|
||||
.booleanState(WATERLOGGED)));
|
||||
|
@ -2794,18 +2795,18 @@ public final class Blocks {
|
|||
.enumState(AXIS, Axis.VALUES)));
|
||||
public static final Block FROGSPAWN = register(new Block("frogspawn", builder().pushReaction(PistonBehavior.DESTROY)));
|
||||
public static final Block REINFORCED_DEEPSLATE = register(new Block("reinforced_deepslate", builder().destroyTime(55.0f)));
|
||||
public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity().pushReaction(PistonBehavior.DESTROY)
|
||||
public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity(BlockEntityType.DECORATED_POT).pushReaction(PistonBehavior.DESTROY)
|
||||
.booleanState(CRACKED)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(WATERLOGGED)));
|
||||
public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity().destroyTime(1.5f)
|
||||
public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity(BlockEntityType.CRAFTER).destroyTime(1.5f)
|
||||
.booleanState(CRAFTING)
|
||||
.enumState(ORIENTATION, FrontAndTop.VALUES)
|
||||
.booleanState(TRIGGERED)));
|
||||
public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f)
|
||||
public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity(BlockEntityType.TRIAL_SPAWNER).destroyTime(50.0f)
|
||||
.booleanState(OMINOUS)
|
||||
.enumState(TRIAL_SPAWNER_STATE)));
|
||||
public static final Block VAULT = register(new Block("vault", builder().setBlockEntity().requiresCorrectToolForDrops().destroyTime(50.0f)
|
||||
public static final Block VAULT = register(new Block("vault", builder().setBlockEntity(BlockEntityType.VAULT).destroyTime(50.0f)
|
||||
.enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST)
|
||||
.booleanState(OMINOUS)
|
||||
.enumState(VAULT_STATE)));
|
||||
|
|
|
@ -16,7 +16,6 @@ public class GeyserJavaBlockState implements JavaBlockState {
|
|||
boolean canBreakWithHand;
|
||||
String pickItem;
|
||||
String pistonBehavior;
|
||||
boolean hasBlockEntity;
|
||||
|
||||
private GeyserJavaBlockState(Builder builder) {
|
||||
this.identifier = builder.identifier;
|
||||
|
@ -28,7 +27,6 @@ public class GeyserJavaBlockState implements JavaBlockState {
|
|||
this.canBreakWithHand = builder.canBreakWithHand;
|
||||
this.pickItem = builder.pickItem;
|
||||
this.pistonBehavior = builder.pistonBehavior;
|
||||
this.hasBlockEntity = builder.hasBlockEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,9 +74,10 @@ public class GeyserJavaBlockState implements JavaBlockState {
|
|||
return pistonBehavior;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
public boolean hasBlockEntity() {
|
||||
return hasBlockEntity;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Builder implements JavaBlockState.Builder {
|
||||
|
@ -91,7 +90,6 @@ public class GeyserJavaBlockState implements JavaBlockState {
|
|||
private boolean canBreakWithHand;
|
||||
private String pickItem;
|
||||
private String pistonBehavior;
|
||||
private boolean hasBlockEntity;
|
||||
|
||||
@Override
|
||||
public Builder identifier(@NonNull String identifier) {
|
||||
|
@ -147,9 +145,13 @@ public class GeyserJavaBlockState implements JavaBlockState {
|
|||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
public Builder hasBlockEntity(boolean hasBlockEntity) {
|
||||
this.hasBlockEntity = hasBlockEntity;
|
||||
// keep the current behavior
|
||||
if (this.pistonBehavior == null && hasBlockEntity) {
|
||||
this.pistonBehavior = "BLOCK";
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
|
@ -41,6 +42,7 @@ import org.geysermc.geyser.level.physics.PistonBehavior;
|
|||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
import org.intellij.lang.annotations.Subst;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -55,7 +57,7 @@ public class Block {
|
|||
* Can you harvest this with your hand.
|
||||
*/
|
||||
private final boolean requiresCorrectToolForDrops;
|
||||
private final boolean hasBlockEntity;
|
||||
private final @Nullable BlockEntityType blockEntityType;
|
||||
private final float destroyTime;
|
||||
private final @NonNull PistonBehavior pushReaction;
|
||||
/**
|
||||
|
@ -75,7 +77,7 @@ public class Block {
|
|||
public Block(@Subst("empty") String javaIdentifier, Builder builder) {
|
||||
this.javaIdentifier = Key.key(javaIdentifier);
|
||||
this.requiresCorrectToolForDrops = builder.requiresCorrectToolForDrops;
|
||||
this.hasBlockEntity = builder.hasBlockEntity;
|
||||
this.blockEntityType = builder.blockEntityType;
|
||||
this.destroyTime = builder.destroyTime;
|
||||
this.pushReaction = builder.pushReaction;
|
||||
this.pickItem = builder.pickItem;
|
||||
|
@ -181,7 +183,12 @@ public class Block {
|
|||
}
|
||||
|
||||
public boolean hasBlockEntity() {
|
||||
return hasBlockEntity;
|
||||
return blockEntityType != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BlockEntityType blockEntityType() {
|
||||
return blockEntityType;
|
||||
}
|
||||
|
||||
public float destroyTime() {
|
||||
|
@ -227,7 +234,7 @@ public class Block {
|
|||
public static final class Builder {
|
||||
private final Map<Property<?>, List<Comparable<?>>> states = new LinkedHashMap<>();
|
||||
private boolean requiresCorrectToolForDrops = false;
|
||||
private boolean hasBlockEntity = false;
|
||||
private BlockEntityType blockEntityType = null;
|
||||
private PistonBehavior pushReaction = PistonBehavior.NORMAL;
|
||||
private float destroyTime;
|
||||
private Supplier<Item> pickItem;
|
||||
|
@ -271,8 +278,8 @@ public class Block {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setBlockEntity() {
|
||||
this.hasBlockEntity = true;
|
||||
public Builder setBlockEntity(BlockEntityType blockEntityType) {
|
||||
this.blockEntityType = blockEntityType;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.level.block.type;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.level.block.property.Property;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
|
@ -65,12 +66,13 @@ public final class BlockState {
|
|||
return (T) get(property);
|
||||
}
|
||||
|
||||
public boolean getValue(Property<Boolean> property, boolean def) {
|
||||
public <T extends Comparable<T>> T getValue(Property<T> property, T def) {
|
||||
var value = get(property);
|
||||
if (value == null) {
|
||||
return def;
|
||||
}
|
||||
return (Boolean) value;
|
||||
//noinspection unchecked
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -183,7 +185,14 @@ public final class BlockState {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe method that looks up a Java block state ID in the BLOCK_STATES registry, and defaults to air if not found.
|
||||
*
|
||||
* @param javaId the Java block state ID to look up.
|
||||
* @return the corresponding block state, or air if the given ID wasn't registered and returned null.
|
||||
*/
|
||||
@NonNull
|
||||
public static BlockState of(int javaId) {
|
||||
return BlockRegistries.BLOCK_STATES.get(javaId);
|
||||
return BlockRegistries.BLOCK_STATES.getOrDefault(javaId, BlockRegistries.BLOCK_STATES.get(Block.JAVA_AIR_ID));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public final class GameProtocol {
|
|||
* release of the game that Geyser supports.
|
||||
*/
|
||||
public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v685.CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.0")
|
||||
.minecraftVersion("1.21.1")
|
||||
.build());
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ public final class GameProtocol {
|
|||
.minecraftVersion("1.20.80/1.20.81")
|
||||
.build()));
|
||||
SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(DEFAULT_BEDROCK_CODEC.toBuilder()
|
||||
.minecraftVersion("1.21.0")
|
||||
.minecraftVersion("1.21.0/1.20.1")
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public final class GameProtocol {
|
|||
* @return the supported Minecraft: Java Edition version names
|
||||
*/
|
||||
public static List<String> getJavaVersions() {
|
||||
return List.of("1.20.5", DEFAULT_JAVA_CODEC.getMinecraftVersion());
|
||||
return List.of(DEFAULT_JAVA_CODEC.getMinecraftVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.registry;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.registry.loader.RegistryLoader;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A mapped registry with an integer as the key. This class is designed to minimize the need for boxing/unboxing keys.
|
||||
*
|
||||
* @param <V> the value
|
||||
*/
|
||||
public class IntMappedRegistry<V> extends AbstractMappedRegistry<Integer, V, Int2ObjectMap<V>> {
|
||||
protected <I> IntMappedRegistry(I input, RegistryLoader<I, Int2ObjectMap<V>> registryLoader) {
|
||||
super(input, registryLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value registered by the given integer.
|
||||
*
|
||||
* @param i the integer
|
||||
* @return the value registered by the given integer.
|
||||
*/
|
||||
public V get(int i) {
|
||||
return this.mappings.get(i);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@Deprecated
|
||||
public V get(Integer key) {
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value registered by the given key or the default value
|
||||
* specified if null.
|
||||
*
|
||||
* @param i the key
|
||||
* @param defaultValue the default value
|
||||
* @return the value registered by the given key or the default value
|
||||
* specified if null.
|
||||
*/
|
||||
public V getOrDefault(int i, V defaultValue) {
|
||||
return this.mappings.getOrDefault(i, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public V getOrDefault(Integer key, V defaultValue) {
|
||||
return super.getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new value into this registry with the given key.
|
||||
*
|
||||
* @param i the key
|
||||
* @param value the value
|
||||
* @return a new value into this registry with the given key.
|
||||
*/
|
||||
public V register(int i, V value) {
|
||||
return this.mappings.put(i, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public V register(Integer key, V value) {
|
||||
return super.register(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new integer mapped registry with the given {@link RegistryLoader}. The
|
||||
* input type is not specified here, meaning the loader return type is either
|
||||
* predefined, or the registry is populated at a later point.
|
||||
*
|
||||
* @param registryLoader the registry loader
|
||||
* @param <I> the input
|
||||
* @param <V> the map value
|
||||
* @return a new registry with the given RegistryLoader
|
||||
*/
|
||||
public static <I, V> IntMappedRegistry<V> create(RegistryLoader<I, Int2ObjectMap<V>> registryLoader) {
|
||||
return new IntMappedRegistry<>(null, registryLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new integer mapped registry with the given {@link RegistryLoader} and input.
|
||||
*
|
||||
* @param registryLoader the registry loader
|
||||
* @param <I> the input
|
||||
* @param <V> the map value
|
||||
* @return a new registry with the given RegistryLoader supplier
|
||||
*/
|
||||
public static <I, V> IntMappedRegistry<V> create(I input, Supplier<RegistryLoader<I, Int2ObjectMap<V>>> registryLoader) {
|
||||
return new IntMappedRegistry<>(input, registryLoader.get());
|
||||
}
|
||||
}
|
|
@ -25,33 +25,23 @@
|
|||
|
||||
package org.geysermc.geyser.registry;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||
import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.loader.*;
|
||||
import org.geysermc.geyser.registry.populator.ItemRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.populator.PacketRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.populator.RecipeRegistryPopulator;
|
||||
import org.geysermc.geyser.registry.loader.RecipeRegistryLoader;
|
||||
import org.geysermc.geyser.registry.provider.ProviderSupplier;
|
||||
import org.geysermc.geyser.registry.type.EnchantmentData;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.registry.type.ParticleMapping;
|
||||
import org.geysermc.geyser.registry.type.SoundMapping;
|
||||
|
@ -59,6 +49,12 @@ import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator;
|
|||
import org.geysermc.geyser.translator.level.event.LevelEventTranslator;
|
||||
import org.geysermc.geyser.translator.sound.SoundInteractionTranslator;
|
||||
import org.geysermc.geyser.translator.sound.SoundTranslator;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -97,16 +93,6 @@ public final class Registries {
|
|||
*/
|
||||
public static final SimpleMappedRegistry<BlockEntityType, BlockEntityTranslator> BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new);
|
||||
|
||||
/**
|
||||
* A versioned registry which holds a {@link RecipeType} to a corresponding list of {@link RecipeData}.
|
||||
*/
|
||||
public static final VersionedRegistry<Map<RecipeType, List<RecipeData>>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||
|
||||
/**
|
||||
* A registry holding data of all the known enchantments.
|
||||
*/
|
||||
public static final SimpleMappedRegistry<JavaEnchantment, EnchantmentData> ENCHANTMENTS;
|
||||
|
||||
/**
|
||||
* A map containing all entity types and their respective Geyser definitions
|
||||
*/
|
||||
|
@ -154,13 +140,7 @@ public final class Registries {
|
|||
/**
|
||||
* A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value.
|
||||
*/
|
||||
public static final VersionedRegistry<Int2ObjectMap<GeyserRecipe>> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||
|
||||
/**
|
||||
* A mapped registry holding the available records, with the ID of the record being the key, and the {@link org.cloudburstmc.protocol.bedrock.data.SoundEvent}
|
||||
* as the value.
|
||||
*/
|
||||
public static final IntMappedRegistry<org.cloudburstmc.protocol.bedrock.data.SoundEvent> RECORDS = IntMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new));
|
||||
public static final SimpleMappedRegistry<RecipeType, List<GeyserRecipe>> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new);
|
||||
|
||||
/**
|
||||
* A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys.
|
||||
|
@ -189,11 +169,9 @@ public final class Registries {
|
|||
static {
|
||||
PacketRegistryPopulator.populate();
|
||||
ItemRegistryPopulator.populate();
|
||||
RecipeRegistryPopulator.populate();
|
||||
|
||||
// Create registries that require other registries to load first
|
||||
POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new);
|
||||
ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new);
|
||||
|
||||
// Remove unneeded client generation data from NbtMapBuilder
|
||||
NbtMapBuilder biomesNbt = NbtMap.builder();
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.registry.loader;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.EnchantmentData;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
public class EnchantmentRegistryLoader implements RegistryLoader<String, Map<JavaEnchantment, EnchantmentData>> {
|
||||
@Override
|
||||
public Map<JavaEnchantment, EnchantmentData> load(String input) {
|
||||
JsonObject enchantmentsJson;
|
||||
try (InputStream enchantmentsStream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow(input)) {
|
||||
enchantmentsJson = new JsonParser().parse(new InputStreamReader(enchantmentsStream)).getAsJsonObject();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load enchantment data", e);
|
||||
}
|
||||
|
||||
Map<JavaEnchantment, EnchantmentData> enchantments = new EnumMap<>(JavaEnchantment.class);
|
||||
for (Map.Entry<String, JsonElement> entry : enchantmentsJson.entrySet()) {
|
||||
JavaEnchantment key = JavaEnchantment.getByJavaIdentifier(entry.getKey());
|
||||
JsonObject node = entry.getValue().getAsJsonObject();
|
||||
int rarityMultiplier = node.get("anvil_cost").getAsInt();
|
||||
int maxLevel = node.get("max_level").getAsInt();
|
||||
|
||||
EnumSet<JavaEnchantment> incompatibleEnchantments = EnumSet.noneOf(JavaEnchantment.class);
|
||||
JsonArray incompatibleEnchantmentsJson = node.getAsJsonArray("incompatible_enchantments");
|
||||
if (incompatibleEnchantmentsJson != null) {
|
||||
for (JsonElement incompatibleNode : incompatibleEnchantmentsJson) {
|
||||
incompatibleEnchantments.add(JavaEnchantment.getByJavaIdentifier(incompatibleNode.getAsString()));
|
||||
}
|
||||
}
|
||||
|
||||
IntSet validItems = new IntOpenHashSet();
|
||||
for (JsonElement itemNode : node.getAsJsonArray("valid_items")) {
|
||||
String javaIdentifier = itemNode.getAsString();
|
||||
Item item = Registries.JAVA_ITEM_IDENTIFIERS.get(javaIdentifier);
|
||||
if (item != null) {
|
||||
validItems.add(item.javaId());
|
||||
} else {
|
||||
throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
EnchantmentData enchantmentData = new EnchantmentData(rarityMultiplier, maxLevel, incompatibleEnchantments, validItems);
|
||||
enchantments.put(key, enchantmentData);
|
||||
}
|
||||
return enchantments;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.loader;
|
|||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
|
||||
import org.geysermc.geyser.inventory.item.Potion;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
|
@ -75,6 +74,11 @@ public class PotionMixRegistryLoader implements RegistryLoader<Object, Int2Objec
|
|||
ingredients.add(getNonNull(mappings, Items.GHAST_TEAR));
|
||||
ingredients.add(getNonNull(mappings, Items.TURTLE_HELMET));
|
||||
ingredients.add(getNonNull(mappings, Items.PHANTOM_MEMBRANE));
|
||||
// 1.21
|
||||
ingredients.add(getNonNull(mappings, Items.STONE));
|
||||
ingredients.add(getNonNull(mappings, Items.SLIME_BLOCK));
|
||||
ingredients.add(getNonNull(mappings, Items.COBWEB));
|
||||
ingredients.add(getNonNull(mappings, Items.BREEZE_ROD));
|
||||
|
||||
List<ItemMapping> inputs = List.of(
|
||||
getNonNull(mappings, Items.POTION),
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.registry.loader;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.cloudburstmc.nbt.NBTInputStream;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec;
|
||||
import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Populates the recipe registry with some recipes that Java does not send, to ensure they show up as intended
|
||||
* in the recipe book.
|
||||
*/
|
||||
public final class RecipeRegistryLoader implements RegistryLoader<String, Map<RecipeType, List<GeyserRecipe>>> {
|
||||
|
||||
@Override
|
||||
public Map<RecipeType, List<GeyserRecipe>> load(String input) {
|
||||
Map<RecipeType, List<GeyserRecipe>> deserializedRecipes = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
List<NbtMap> recipes;
|
||||
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.nbt")) {
|
||||
try (NBTInputStream nbtStream = new NBTInputStream(new DataInputStream(stream))) {
|
||||
recipes = ((NbtMap) nbtStream.readTag()).getList("recipes", NbtType.COMPOUND);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||
}
|
||||
|
||||
MinecraftCodecHelper helper = MinecraftCodec.CODEC.getHelperFactory().get();
|
||||
for (NbtMap recipeCollection : recipes) {
|
||||
var pair = getRecipes(recipeCollection, helper);
|
||||
deserializedRecipes.put(pair.key(), pair.value());
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
|
||||
private static Pair<RecipeType, List<GeyserRecipe>> getRecipes(NbtMap recipes, MinecraftCodecHelper helper) {
|
||||
List<NbtMap> typedRecipes = recipes.getList("recipes", NbtType.COMPOUND);
|
||||
RecipeType recipeType = RecipeType.from(recipes.getInt("recipe_type", -1));
|
||||
if (recipeType == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) {
|
||||
return Pair.of(recipeType, getShapedRecipes(typedRecipes, helper));
|
||||
} else {
|
||||
return Pair.of(recipeType, getShapelessRecipes(typedRecipes, helper));
|
||||
}
|
||||
}
|
||||
|
||||
private static List<GeyserRecipe> getShapelessRecipes(List<NbtMap> recipes, MinecraftCodecHelper helper) {
|
||||
List<GeyserRecipe> deserializedRecipes = new ObjectArrayList<>(recipes.size());
|
||||
for (NbtMap recipe : recipes) {
|
||||
ItemStack output = toItemStack(recipe.getCompound("output"), helper);
|
||||
List<NbtMap> rawInputs = recipe.getList("inputs", NbtType.COMPOUND);
|
||||
Ingredient[] javaInputs = new Ingredient[rawInputs.size()];
|
||||
for (int i = 0; i < rawInputs.size(); i++) {
|
||||
javaInputs[i] = new Ingredient(new ItemStack[] {toItemStack(rawInputs.get(i), helper)});
|
||||
}
|
||||
deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output));
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
|
||||
private static List<GeyserRecipe> getShapedRecipes(List<NbtMap> recipes, MinecraftCodecHelper helper) {
|
||||
List<GeyserRecipe> deserializedRecipes = new ObjectArrayList<>(recipes.size());
|
||||
for (NbtMap recipe : recipes) {
|
||||
ItemStack output = toItemStack(recipe.getCompound("output"), helper);
|
||||
List<int[]> shape = recipe.getList("shape", NbtType.INT_ARRAY);
|
||||
|
||||
// In the recipes mapping, each recipe is mapped by a number
|
||||
List<ItemStack> letterToRecipe = new ArrayList<>();
|
||||
for (NbtMap rawInput : recipe.getList("inputs", NbtType.COMPOUND)) {
|
||||
letterToRecipe.add(toItemStack(rawInput, helper));
|
||||
}
|
||||
|
||||
Ingredient[] inputs = new Ingredient[shape.size() * shape.get(0).length];
|
||||
int i = 0;
|
||||
// Create a linear array of items from the "cube" of the shape
|
||||
for (int j = 0; i < shape.size() * shape.get(0).length; j++) {
|
||||
for (int index : shape.get(j)) {
|
||||
ItemStack stack = letterToRecipe.get(index);
|
||||
inputs[i++] = new Ingredient(new ItemStack[] {stack});
|
||||
}
|
||||
}
|
||||
deserializedRecipes.add(new GeyserShapedRecipe(shape.size(), shape.get(0).length, inputs, output));
|
||||
}
|
||||
return deserializedRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts our serialized NBT into an ItemStack.
|
||||
* id is the Java item ID as an integer, components is an optional String of the data components serialized
|
||||
* as bytes in Base64 (so MCProtocolLib can parse the data).
|
||||
*/
|
||||
private static ItemStack toItemStack(NbtMap nbt, MinecraftCodecHelper helper) {
|
||||
int id = nbt.getInt("id");
|
||||
int count = nbt.getInt("count", 1);
|
||||
String componentsRaw = nbt.getString("components", null);
|
||||
if (componentsRaw != null) {
|
||||
byte[] bytes = Base64.getDecoder().decode(componentsRaw);
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(bytes);
|
||||
DataComponents components = helper.readDataComponentPatch(buf);
|
||||
return new ItemStack(id, count, components);
|
||||
}
|
||||
return new ItemStack(id, count);
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.mappings.versions;
|
|||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
@ -35,14 +34,9 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.api.block.custom.CustomBlockData;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockPermutation;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
|
||||
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents;
|
||||
import org.geysermc.geyser.api.block.custom.component.GeometryComponent;
|
||||
import org.geysermc.geyser.api.block.custom.component.MaterialInstance;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions;
|
||||
import org.geysermc.geyser.api.block.custom.component.*;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions.BlockFilterType;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions.Face;
|
||||
import org.geysermc.geyser.api.block.custom.component.TransformationComponent;
|
||||
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
||||
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||
import org.geysermc.geyser.api.util.CreativeCategory;
|
||||
|
@ -60,16 +54,10 @@ import org.geysermc.geyser.registry.mappings.util.CustomBlockStateMapping;
|
|||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -131,7 +119,7 @@ public class MappingsReader_v1 extends MappingsReader {
|
|||
blocksNode.fields().forEachRemaining(entry -> {
|
||||
if (entry.getValue().isObject()) {
|
||||
try {
|
||||
String identifier = Identifier.formalize(entry.getKey());
|
||||
String identifier = MinecraftKey.key(entry.getKey()).asString();
|
||||
CustomBlockMapping customBlockMapping = this.readBlockMappingEntry(identifier, entry.getValue());
|
||||
consumer.accept(identifier, customBlockMapping);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -435,9 +435,6 @@ public final class BlockRegistryPopulator {
|
|||
if (!javaBlockState.canBreakWithHand()) {
|
||||
builder.requiresCorrectToolForDrops();
|
||||
}
|
||||
if (javaBlockState.hasBlockEntity()) {
|
||||
builder.setBlockEntity();
|
||||
}
|
||||
String cleanJavaIdentifier = BlockUtils.getCleanIdentifier(javaBlockState.identifier());
|
||||
String pickItem = javaBlockState.pickItem();
|
||||
Block block = new Block(cleanJavaIdentifier, builder) {
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.registry.populator;
|
|||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.registry.type.GeyserMappingItem;
|
||||
|
||||
|
@ -41,10 +42,21 @@ public class Conversion685_671 {
|
|||
private static final List<String> OMINOUS_BLOCKS = List.of("minecraft:trial_spawner", "minecraft:vault");
|
||||
private static final List<String> NEW_BLOCKS = Stream.of(NEW_CORAL_BLOCKS, NEW_DOUBLE_PLANTS, NEW_STONE_BLOCK_SLABS, NEW_TALLGRASSES).flatMap(List::stream).toList();
|
||||
private static final List<String> MODIFIED_BLOCKS = Stream.of(NEW_BLOCKS, OMINOUS_BLOCKS).flatMap(List::stream).toList();
|
||||
private static final List<Item> NEW_MUSIC_DISCS = List.of(Items.MUSIC_DISC_CREATOR, Items.MUSIC_DISC_CREATOR_MUSIC_BOX, Items.MUSIC_DISC_PRECIPICE);
|
||||
|
||||
static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) {
|
||||
static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
|
||||
String identifer = mapping.getBedrockIdentifier();
|
||||
|
||||
if (NEW_MUSIC_DISCS.contains(item)) {
|
||||
return mapping.withBedrockIdentifier("minecraft:music_disc_otherside");
|
||||
}
|
||||
if (item == Items.OMINOUS_TRIAL_KEY) {
|
||||
return mapping.withBedrockIdentifier("minecraft:trial_key");
|
||||
}
|
||||
if (item == Items.OMINOUS_BOTTLE) {
|
||||
return mapping.withBedrockIdentifier("minecraft:glass_bottle");
|
||||
}
|
||||
|
||||
if (!NEW_BLOCKS.contains(identifer)) {
|
||||
return mapping;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.cloudburstmc.nbt.NbtType;
|
|||
import org.cloudburstmc.nbt.NbtUtils;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685;
|
||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||
import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition;
|
||||
|
@ -458,10 +457,6 @@ public class ItemRegistryPopulator {
|
|||
|
||||
if (javaItem.javaIdentifier().contains("bucket") && !javaItem.javaIdentifier().contains("milk")) {
|
||||
buckets.add(definition);
|
||||
} else if (javaItem.javaIdentifier().startsWith("minecraft:music_disc_")) {
|
||||
// The Java record level event uses the item ID as the "key" to play the record
|
||||
Registries.RECORDS.register(javaItem.javaId(), SoundEvent.valueOf("RECORD_" +
|
||||
mapping.getBedrockIdentifier().replace("minecraft:music_disc_", "").toUpperCase(Locale.ENGLISH)));
|
||||
}
|
||||
|
||||
mappings.add(mapping);
|
||||
|
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.registry.populator;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtUtils;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.MultiRecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.RecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe;
|
||||
import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID;
|
||||
|
||||
/**
|
||||
* Populates the recipe registry.
|
||||
*/
|
||||
public class RecipeRegistryPopulator {
|
||||
|
||||
public static void populate() {
|
||||
JsonNode items;
|
||||
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.json")) {
|
||||
items = GeyserImpl.JSON_MAPPER.readTree(stream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||
}
|
||||
|
||||
int currentRecipeId = LAST_RECIPE_NET_ID;
|
||||
for (Int2ObjectMap.Entry<ItemMappings> version : Registries.ITEMS.get().int2ObjectEntrySet()) {
|
||||
// Make a bit of an assumption here that the last recipe net ID will be equivalent between all versions
|
||||
LAST_RECIPE_NET_ID = currentRecipeId;
|
||||
Map<RecipeType, List<RecipeData>> craftingData = new EnumMap<>(RecipeType.class);
|
||||
Int2ObjectMap<GeyserRecipe> recipes = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
craftingData.put(RecipeType.CRAFTING_SPECIAL_BOOKCLONING,
|
||||
Collections.singletonList(MultiRecipeData.of(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), ++LAST_RECIPE_NET_ID)));
|
||||
craftingData.put(RecipeType.CRAFTING_SPECIAL_REPAIRITEM,
|
||||
Collections.singletonList(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000001"), ++LAST_RECIPE_NET_ID)));
|
||||
craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPEXTENDING,
|
||||
Collections.singletonList(MultiRecipeData.of(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), ++LAST_RECIPE_NET_ID)));
|
||||
craftingData.put(RecipeType.CRAFTING_SPECIAL_MAPCLONING,
|
||||
Collections.singletonList(MultiRecipeData.of(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), ++LAST_RECIPE_NET_ID)));
|
||||
|
||||
// https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php
|
||||
|
||||
for (JsonNode entry : items.get("leather_armor")) {
|
||||
// This won't be perfect, as we can't possibly send every leather input for every kind of color
|
||||
// But it does display the correct output from a base leather armor, and besides visuals everything works fine
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_ARMORDYE,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
for (JsonNode entry : items.get("firework_rockets")) {
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_ROCKET,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
for (JsonNode entry : items.get("firework_stars")) {
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
for (JsonNode entry : items.get("shulker_boxes")) {
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
for (JsonNode entry : items.get("suspicious_stew")) {
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_SUSPICIOUSSTEW,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
for (JsonNode entry : items.get("tipped_arrows")) {
|
||||
craftingData.computeIfAbsent(RecipeType.CRAFTING_SPECIAL_TIPPEDARROW,
|
||||
c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue()));
|
||||
}
|
||||
|
||||
Registries.CRAFTING_DATA.register(version.getIntKey(), craftingData);
|
||||
Registries.RECIPES.register(version.getIntKey(), recipes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a Bedrock crafting recipe from the given JSON data.
|
||||
* @param node the JSON data to compute
|
||||
* @param recipes a list of all the recipes
|
||||
* @return the {@link RecipeData} to send to the Bedrock client.
|
||||
*/
|
||||
private static RecipeData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap<GeyserRecipe> recipes, ItemMappings mappings) {
|
||||
int netId = ++LAST_RECIPE_NET_ID;
|
||||
int type = node.get("bedrockRecipeType").asInt();
|
||||
JsonNode outputNode = node.get("output");
|
||||
ItemMapping outputEntry = mappings.getMapping(outputNode.get("identifier").asText());
|
||||
ItemData output = getBedrockItemFromIdentifierJson(outputEntry, outputNode);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
if (type == 1) {
|
||||
// Shaped recipe
|
||||
List<String> shape = new ArrayList<>();
|
||||
// Get the shape of the recipe
|
||||
for (JsonNode chars : node.get("shape")) {
|
||||
shape.add(chars.asText());
|
||||
}
|
||||
|
||||
// In recipes.json each recipe is mapped by a letter
|
||||
Map<String, ItemData> letterToRecipe = new HashMap<>();
|
||||
Iterator<Map.Entry<String, JsonNode>> iterator = node.get("inputs").fields();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = iterator.next();
|
||||
JsonNode inputNode = entry.getValue();
|
||||
ItemMapping inputEntry = mappings.getMapping(inputNode.get("identifier").asText());
|
||||
letterToRecipe.put(entry.getKey(), getBedrockItemFromIdentifierJson(inputEntry, inputNode));
|
||||
}
|
||||
|
||||
List<ItemData> inputs = new ArrayList<>(shape.size() * shape.get(0).length());
|
||||
int i = 0;
|
||||
// Create a linear array of items from the "cube" of the shape
|
||||
for (int j = 0; i < shape.size() * shape.get(0).length(); j++) {
|
||||
for (char c : shape.get(j).toCharArray()) {
|
||||
ItemData data = letterToRecipe.getOrDefault(String.valueOf(c), ItemData.AIR);
|
||||
inputs.add(data);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert into a Java recipe class for autocrafting */
|
||||
List<Ingredient> ingredients = new ArrayList<>();
|
||||
for (ItemData input : inputs) {
|
||||
ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)}));
|
||||
}
|
||||
GeyserRecipe recipe = new GeyserShapedRecipe(shape.get(0).length(), shape.size(),
|
||||
ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings));
|
||||
recipes.put(netId, recipe);
|
||||
/* Convert end */
|
||||
|
||||
return ShapedRecipeData.shaped(uuid.toString(), shape.get(0).length(), shape.size(),
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID);
|
||||
}
|
||||
List<ItemData> inputs = new ObjectArrayList<>();
|
||||
for (JsonNode entry : node.get("inputs")) {
|
||||
ItemMapping inputEntry = mappings.getMapping(entry.get("identifier").asText());
|
||||
inputs.add(getBedrockItemFromIdentifierJson(inputEntry, entry));
|
||||
}
|
||||
|
||||
/* Convert into a Java Recipe class for autocrafting */
|
||||
List<Ingredient> ingredients = new ArrayList<>();
|
||||
for (ItemData input : inputs) {
|
||||
ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)}));
|
||||
}
|
||||
GeyserRecipe recipe = new GeyserShapelessRecipe(ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings));
|
||||
recipes.put(netId, recipe);
|
||||
/* Convert end */
|
||||
|
||||
if (type == 5) {
|
||||
// Shulker box
|
||||
return ShapelessRecipeData.shulkerBox(uuid.toString(),
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId);
|
||||
}
|
||||
return ShapelessRecipeData.shapeless(uuid.toString(),
|
||||
inputs.stream().map(ItemDescriptorWithCount::fromItem).toList(), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID);
|
||||
}
|
||||
|
||||
private static ItemData getBedrockItemFromIdentifierJson(ItemMapping mapping, JsonNode itemNode) {
|
||||
int count = 1;
|
||||
short damage = 0;
|
||||
NbtMap tag = null;
|
||||
JsonNode damageNode = itemNode.get("bedrockDamage");
|
||||
if (damageNode != null) {
|
||||
damage = damageNode.numberValue().shortValue();
|
||||
}
|
||||
JsonNode countNode = itemNode.get("count");
|
||||
if (countNode != null) {
|
||||
count = countNode.asInt();
|
||||
}
|
||||
JsonNode nbtNode = itemNode.get("bedrockNbt");
|
||||
if (nbtNode != null) {
|
||||
byte[] bytes = Base64.getDecoder().decode(nbtNode.asText());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
try {
|
||||
tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ItemData.builder()
|
||||
.definition(mapping.getBedrockDefinition())
|
||||
.damage(damage)
|
||||
.count(count)
|
||||
.blockDefinition(mapping.getBedrockBlockDefinition())
|
||||
.tag(tag)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
package org.geysermc.geyser.registry.type;
|
||||
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import lombok.Builder;
|
||||
|
@ -41,7 +40,7 @@ import org.geysermc.geyser.api.block.custom.CustomBlockData;
|
|||
import org.geysermc.geyser.inventory.item.StoredItemMappings;
|
||||
import org.geysermc.geyser.item.Items;
|
||||
import org.geysermc.geyser.item.type.Item;
|
||||
import org.geysermc.geyser.item.type.PotionItem;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -148,10 +147,8 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
|
|||
}
|
||||
} else {
|
||||
if (!(mapping.getBedrockData() == data.getDamage() ||
|
||||
// Make exceptions for potions, tipped arrows, firework stars, goat horns, and suspicious stews, whose damage values can vary
|
||||
(mapping.getJavaItem() instanceof PotionItem || mapping.getJavaItem() == Items.ARROW
|
||||
|| mapping.getJavaItem() == Items.FIREWORK_STAR || mapping.getJavaItem() == Items.GOAT_HORN
|
||||
|| mapping.getJavaItem() == Items.SUSPICIOUS_STEW))) {
|
||||
// Make exceptions for items whose damage values can vary
|
||||
(mapping.getJavaItem().ignoreDamage() || mapping.getJavaItem() == Items.SUSPICIOUS_STEW))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import lombok.AccessLevel;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
@ -290,7 +291,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* Keeps track of the world name for respawning.
|
||||
*/
|
||||
@Setter
|
||||
private String worldName = null;
|
||||
private Key worldName = null;
|
||||
/**
|
||||
* As of Java 1.19.3, the client only uses these for commands.
|
||||
*/
|
||||
|
@ -356,8 +357,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* Stores all Java recipes by recipe identifier, and matches them to all possible Bedrock recipe identifiers.
|
||||
* They are not 1:1, since Bedrock can have multiple recipes for the same Java recipe.
|
||||
*/
|
||||
@Setter
|
||||
private Map<String, List<String>> javaToBedrockRecipeIds;
|
||||
private final Map<String, List<String>> javaToBedrockRecipeIds;
|
||||
|
||||
@Setter
|
||||
private Int2ObjectMap<GeyserRecipe> craftingRecipes;
|
||||
|
@ -996,7 +996,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
@Override
|
||||
public void disconnected(DisconnectedEvent event) {
|
||||
loggingIn = false;
|
||||
loggedIn = false;
|
||||
|
||||
String disconnectMessage;
|
||||
Throwable cause = event.getCause();
|
||||
|
@ -1036,13 +1035,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
} else {
|
||||
GeyserImpl.getInstance().getLogger().error("An exception occurred: ", cause);
|
||||
}
|
||||
// GeyserSession is disconnected via session.disconnect() called indirectly be the server
|
||||
// This only needs to be "initiated" here when there is an exception, hence the cause clause
|
||||
GeyserSession.this.disconnect(disconnectMessage);
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ((!GeyserSession.this.closed && GeyserSession.this.loggedIn) || cause != null) {
|
||||
// GeyserSession is disconnected via session.disconnect() called indirectly be the server
|
||||
// This needs to be "initiated" here when there is an exception, but also when the Netty connection
|
||||
// is closed without a disconnect packet - in this case, closed will still be false, but loggedIn
|
||||
// will also be true as GeyserSession#disconnect will not have been called.
|
||||
GeyserSession.this.disconnect(disconnectMessage);
|
||||
}
|
||||
|
||||
loggedIn = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1307,22 +1312,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
this.cameraData.handleGameModeChange(currentlySpectator, newGamemode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to reduce amount of duplicate code. Sends ServerboundUseItemPacket.
|
||||
*/
|
||||
public void useItem(Hand hand) {
|
||||
sendDownstreamGamePacket(new ServerboundUseItemPacket(
|
||||
hand, worldCache.nextPredictionSequence(), playerEntity.getYaw(), playerEntity.getPitch()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display
|
||||
* blocking and sends a packet to the Java server.
|
||||
*/
|
||||
private boolean attemptToBlock() {
|
||||
ServerboundUseItemPacket useItemPacket;
|
||||
if (playerInventory.getItemInHand().asItem() == Items.SHIELD) {
|
||||
useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, worldCache.nextPredictionSequence());
|
||||
useItem(Hand.MAIN_HAND);
|
||||
} else if (playerInventory.getOffhand().asItem() == Items.SHIELD) {
|
||||
useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, worldCache.nextPredictionSequence());
|
||||
useItem(Hand.OFF_HAND);
|
||||
} else {
|
||||
// No blocking
|
||||
return false;
|
||||
}
|
||||
|
||||
sendDownstreamGamePacket(useItemPacket);
|
||||
playerEntity.setFlag(EntityFlag.BLOCKING, true);
|
||||
// Metadata should be updated later
|
||||
return true;
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.session.cache;
|
|||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos;
|
||||
|
@ -64,7 +65,7 @@ public final class LodestoneCache {
|
|||
int x = position.getX();
|
||||
int y = position.getY();
|
||||
int z = position.getZ();
|
||||
String dim = position.getDimension();
|
||||
Key dim = position.getDimension();
|
||||
|
||||
for (LodestonePos pos : this.activeLodestones.values()) {
|
||||
if (pos.equals(x, y, z, dim)) {
|
||||
|
@ -98,7 +99,7 @@ public final class LodestoneCache {
|
|||
int x = position.getX();
|
||||
int y = position.getY();
|
||||
int z = position.getZ();
|
||||
String dim = position.getDimension();
|
||||
Key dim = position.getDimension();
|
||||
|
||||
for (LodestonePos pos : this.activeLodestones.values()) {
|
||||
if (pos.equals(x, y, z, dim)) {
|
||||
|
@ -138,8 +139,8 @@ public final class LodestoneCache {
|
|||
this.lodestones.clear();
|
||||
}
|
||||
|
||||
public record LodestonePos(int id, int x, int y, int z, String dimension) {
|
||||
boolean equals(int x, int y, int z, String dimension) {
|
||||
public record LodestonePos(int id, int x, int y, int z, Key dimension) {
|
||||
boolean equals(int x, int y, int z, Key dimension) {
|
||||
return this.x == x && this.y == y && this.z == z && this.dimension.equals(dimension);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
|
||||
|
@ -38,14 +39,19 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
|
||||
import org.geysermc.geyser.item.enchantment.Enchantment;
|
||||
import org.geysermc.geyser.level.JavaDimension;
|
||||
import org.geysermc.geyser.level.JukeboxSong;
|
||||
import org.geysermc.geyser.level.PaintingType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
|
||||
import org.geysermc.geyser.text.TextDecoration;
|
||||
import org.geysermc.geyser.translator.level.BiomeTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -66,28 +72,31 @@ import java.util.function.ToIntFunction;
|
|||
@Accessors(fluent = true)
|
||||
@Getter
|
||||
public final class RegistryCache {
|
||||
private static final Map<String, Map<String, NbtMap>> DEFAULTS;
|
||||
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
private static final Map<Key, Map<Key, NbtMap>> DEFAULTS;
|
||||
private static final Map<Key, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
|
||||
static {
|
||||
register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry));
|
||||
register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry));
|
||||
register("enchantment", cache -> cache.enchantments, ($, entry) -> Enchantment.read(entry));
|
||||
register("jukebox_song", cache -> cache.jukeboxSongs, ($, entry) -> JukeboxSong.read(entry));
|
||||
register("painting_variant", cache -> cache.paintings, ($, entry) -> PaintingType.getByName(entry.getId()));
|
||||
register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial);
|
||||
register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern);
|
||||
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
||||
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId().asString()));
|
||||
|
||||
// Load from MCProtocolLib's classloader
|
||||
NbtMap tag = MinecraftProtocol.loadNetworkCodec();
|
||||
Map<String, Map<String, NbtMap>> defaults = new HashMap<>();
|
||||
Map<Key, Map<Key, NbtMap>> defaults = new HashMap<>();
|
||||
// Don't create a keySet - no need to create the cached object in HashMap if we don't use it again
|
||||
REGISTRIES.forEach((key, $) -> {
|
||||
List<NbtMap> rawValues = tag.getCompound(key)
|
||||
List<NbtMap> rawValues = tag.getCompound(key.asString())
|
||||
.getList("value", NbtType.COMPOUND);
|
||||
Map<String, NbtMap> values = new HashMap<>();
|
||||
Map<Key, NbtMap> values = new HashMap<>();
|
||||
for (NbtMap value : rawValues) {
|
||||
String name = value.getString("name");
|
||||
Key name = MinecraftKey.key(value.getString("name"));
|
||||
values.put(name, value.getCompound("element"));
|
||||
}
|
||||
// Can make these maps immutable and as efficient as possible after initialization
|
||||
|
@ -104,16 +113,19 @@ public final class RegistryCache {
|
|||
* Java -> Bedrock biome network IDs.
|
||||
*/
|
||||
private int[] biomeTranslations;
|
||||
private final JavaRegistry<TextDecoration> chatTypes = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<ChatType> chatTypes = new SimpleJavaRegistry<>();
|
||||
/**
|
||||
* All dimensions that the client could possibly connect to.
|
||||
*/
|
||||
private final JavaRegistry<JavaDimension> dimensions = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<Enchantment> enchantments = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<JukeboxSong> jukeboxSongs = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<PaintingType> paintings = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<TrimMaterial> trimMaterials = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<TrimPattern> trimPatterns = new SimpleJavaRegistry<>();
|
||||
|
||||
private final JavaRegistry<BannerPattern> bannerPatterns = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<WolfEntity.WolfVariant> wolfVariants = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<WolfEntity.BuiltInWolfVariant> wolfVariants = new SimpleJavaRegistry<>();
|
||||
|
||||
public RegistryCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
@ -138,9 +150,9 @@ public final class RegistryCache {
|
|||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
String key = "minecraft:" + registry;
|
||||
Key key = MinecraftKey.key(registry);
|
||||
REGISTRIES.put(key, (registryCache, entries) -> {
|
||||
Map<String, NbtMap> localRegistry = null;
|
||||
Map<Key, NbtMap> localRegistry = null;
|
||||
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||
// Clear each local cache every time a new registry entry is given to us
|
||||
// (e.g. proxy server switches)
|
||||
|
@ -166,7 +178,7 @@ public final class RegistryCache {
|
|||
* @param localCacheFunction the int array to set the final values to.
|
||||
*/
|
||||
private static void register(String registry, BiConsumer<RegistryCache, int[]> localCacheFunction, ToIntFunction<RegistryEntry> reader) {
|
||||
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> {
|
||||
REGISTRIES.put(MinecraftKey.key(registry), (registryCache, entries) -> {
|
||||
Int2IntMap temp = new Int2IntOpenHashMap();
|
||||
int greatestId = 0;
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue