mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-28 07:20:28 +01:00
Merge remote-tracking branch 'origin/master' into floodgate-2.0
# Conflicts: # connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java # connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java # connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java
This commit is contained in:
commit
643098e09e
56 changed files with 1163 additions and 511 deletions
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
|
@ -35,8 +35,8 @@ pipeline {
|
||||||
rtMavenResolver(
|
rtMavenResolver(
|
||||||
id: "maven-resolver",
|
id: "maven-resolver",
|
||||||
serverId: "opencollab-artifactory",
|
serverId: "opencollab-artifactory",
|
||||||
releaseRepo: "release",
|
releaseRepo: "maven-deploy-release",
|
||||||
snapshotRepo: "snapshot"
|
snapshotRepo: "maven-deploy-snapshot"
|
||||||
)
|
)
|
||||||
rtMavenRun(
|
rtMavenRun(
|
||||||
pom: 'pom.xml',
|
pom: 'pom.xml',
|
||||||
|
|
|
@ -18,7 +18,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 now joined us here!
|
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
|
||||||
|
|
||||||
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.201 and Minecraft Java v1.16.4 - v1.16.5.
|
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.210 and Minecraft Java v1.16.4 - v1.16.5.
|
||||||
|
|
||||||
## Setting Up
|
## Setting Up
|
||||||
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
<id>spigot-public</id>
|
<id>spigot-public</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/public/</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/public/</url>
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
|
||||||
<id>bukkit-public</id>
|
|
||||||
<url>https://repo.md-5.net/content/repositories/public/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>sponge-repo</id>
|
<id>sponge-repo</id>
|
||||||
<url>https://repo.spongepowered.org/repository/maven-public/</url>
|
<url>https://repo.spongepowered.org/repository/maven-public/</url>
|
||||||
|
|
|
@ -53,11 +53,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
|
||||||
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
|
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
|
||||||
placeBlockSoundPacket.setBabySound(false);
|
placeBlockSoundPacket.setBabySound(false);
|
||||||
if (worldManager.isLegacy()) {
|
if (worldManager.isLegacy()) {
|
||||||
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(worldManager.getBlockAt(session,
|
placeBlockSoundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(worldManager.getBlockAt(session,
|
||||||
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
||||||
} else {
|
} else {
|
||||||
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
||||||
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID)));
|
placeBlockSoundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID)));
|
||||||
}
|
}
|
||||||
placeBlockSoundPacket.setIdentifier(":");
|
placeBlockSoundPacket.setIdentifier(":");
|
||||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<netty.version>4.1.59.Final</netty.version>
|
<netty.version>4.1.59.Final</netty.version>
|
||||||
|
<fastutil.version>8.5.2</fastutil.version>
|
||||||
|
<adventure.version>4.5.0</adventure.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -40,14 +42,10 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
||||||
<artifactId>bedrock-v422</artifactId>
|
<artifactId>bedrock-v428</artifactId>
|
||||||
<version>294e7e5</version>
|
<version>42da92f</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
|
||||||
<groupId>net.sf.trove4j</groupId>
|
|
||||||
<artifactId>trove</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>com.nukkitx.network</groupId>
|
<groupId>com.nukkitx.network</groupId>
|
||||||
<artifactId>raknet</artifactId>
|
<artifactId>raknet</artifactId>
|
||||||
|
@ -55,9 +53,9 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.CloudburstMC.Network</groupId>
|
<groupId>com.nukkitx.network</groupId>
|
||||||
<artifactId>raknet</artifactId>
|
<artifactId>raknet</artifactId>
|
||||||
<version>a94d2dd</version>
|
<version>1.6.26-20210217.205834-2</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
|
@ -69,61 +67,61 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-int-maps</artifactId>
|
<artifactId>fastutil-int-int-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-float-maps</artifactId>
|
<artifactId>fastutil-int-float-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-long-long-maps</artifactId>
|
<artifactId>fastutil-long-long-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-object-long-maps</artifactId>
|
<artifactId>fastutil-object-long-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-byte-maps</artifactId>
|
<artifactId>fastutil-int-byte-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-double-maps</artifactId>
|
<artifactId>fastutil-int-double-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-int-boolean-maps</artifactId>
|
<artifactId>fastutil-int-boolean-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-object-int-maps</artifactId>
|
<artifactId>fastutil-object-int-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-object-byte-maps</artifactId>
|
<artifactId>fastutil-object-byte-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nukkitx.fastutil</groupId>
|
<groupId>com.nukkitx.fastutil</groupId>
|
||||||
<artifactId>fastutil-object-object-maps</artifactId>
|
<artifactId>fastutil-object-object-maps</artifactId>
|
||||||
<version>8.3.1</version>
|
<version>${fastutil.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -225,25 +223,25 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-api</artifactId>
|
<artifactId>adventure-api</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>${adventure.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
<artifactId>adventure-text-serializer-gson</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>${adventure.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>${adventure.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.kyori</groupId>
|
<groupId>net.kyori</groupId>
|
||||||
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
|
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>${adventure.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -105,27 +106,38 @@ public class BoatEntity extends Entity {
|
||||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
} else if (entityMetadata.getId() == 11) {
|
} else if (entityMetadata.getId() == 11) {
|
||||||
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||||
if (!isPaddlingLeft) {
|
if (isPaddlingLeft) {
|
||||||
metadata.put(EntityData.ROW_TIME_LEFT, 0f);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||||
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
||||||
paddleTimeLeft = 0f;
|
paddleTimeLeft = 0f;
|
||||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
if (!this.passengers.isEmpty()) {
|
||||||
updateLeftPaddle(session, entityMetadata)
|
// Get the entity by the first stored passenger and convey motion in this manner
|
||||||
);
|
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||||
|
if (entity != null) {
|
||||||
|
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||||
|
updateLeftPaddle(session, entity)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Indicate that the row position should be reset
|
||||||
|
metadata.put(EntityData.ROW_TIME_LEFT, 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (entityMetadata.getId() == 12) {
|
else if (entityMetadata.getId() == 12) {
|
||||||
isPaddlingRight = (boolean) entityMetadata.getValue();
|
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||||
if (!isPaddlingRight) {
|
if (isPaddlingRight) {
|
||||||
metadata.put(EntityData.ROW_TIME_RIGHT, 0f);
|
|
||||||
} else {
|
|
||||||
paddleTimeRight = 0f;
|
paddleTimeRight = 0f;
|
||||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
if (!this.passengers.isEmpty()) {
|
||||||
updateRightPaddle(session, entityMetadata)
|
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||||
);
|
if (entity != null) {
|
||||||
|
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||||
|
updateRightPaddle(session, entity)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
metadata.put(EntityData.ROW_TIME_RIGHT, 0.0f);
|
||||||
}
|
}
|
||||||
} else if (entityMetadata.getId() == 13) {
|
} else if (entityMetadata.getId() == 13) {
|
||||||
// Possibly - I don't think this does anything?
|
// Possibly - I don't think this does anything?
|
||||||
|
@ -135,27 +147,46 @@ public class BoatEntity extends Entity {
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
@Override
|
||||||
|
public void updateBedrockMetadata(GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(session);
|
||||||
|
|
||||||
|
// As these indicate to reset rowing, remove them until it is time to send them out again.
|
||||||
|
metadata.remove(EntityData.ROW_TIME_LEFT);
|
||||||
|
metadata.remove(EntityData.ROW_TIME_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLeftPaddle(GeyserSession session, Entity rower) {
|
||||||
if (isPaddlingLeft) {
|
if (isPaddlingLeft) {
|
||||||
paddleTimeLeft += ROWING_SPEED;
|
paddleTimeLeft += ROWING_SPEED;
|
||||||
metadata.put(EntityData.ROW_TIME_LEFT, paddleTimeLeft);
|
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
updateLeftPaddle(session, entityMetadata),
|
updateLeftPaddle(session, rower),
|
||||||
100,
|
100,
|
||||||
TimeUnit.MILLISECONDS
|
TimeUnit.MILLISECONDS
|
||||||
);
|
);
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
private void updateRightPaddle(GeyserSession session, Entity rower) {
|
||||||
if (isPaddlingRight) {
|
if (isPaddlingRight) {
|
||||||
paddleTimeRight += ROWING_SPEED;
|
paddleTimeRight += ROWING_SPEED;
|
||||||
metadata.put(EntityData.ROW_TIME_RIGHT, paddleTimeRight);
|
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
updateRightPaddle(session, entityMetadata),
|
updateRightPaddle(session, rower),
|
||||||
100,
|
100,
|
||||||
TimeUnit.MILLISECONDS
|
TimeUnit.MILLISECONDS
|
||||||
);
|
);
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
|
||||||
|
AnimatePacket packet = new AnimatePacket();
|
||||||
|
packet.setRuntimeEntityId(rower.getGeyserId());
|
||||||
|
packet.setAction(action);
|
||||||
|
packet.setRowingTime(rowTime);
|
||||||
|
session.sendUpstreamPacket(packet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||||
|
|
||||||
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
|
@ -60,8 +59,8 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
* By default, the command block shown is purple on Bedrock, which does not match Java Edition's orange.
|
* By default, the command block shown is purple on Bedrock, which does not match Java Edition's orange.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void updateDefaultBlockMetadata() {
|
public void updateDefaultBlockMetadata(GeyserSession session) {
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.BEDROCK_RUNTIME_COMMAND_BLOCK_ID);
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockRuntimeCommandBlockId());
|
||||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used as a base for minecarts with a default block to display like furnaces and spawners
|
* This class is used as a base for minecarts with a default block to display like furnaces and spawners
|
||||||
|
@ -44,10 +43,15 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||||
public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
updateDefaultBlockMetadata();
|
|
||||||
metadata.put(EntityData.CUSTOM_DISPLAY, (byte) 1);
|
metadata.put(EntityData.CUSTOM_DISPLAY, (byte) 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
updateDefaultBlockMetadata(session);
|
||||||
|
super.spawnEntity(session);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
|
||||||
|
@ -56,7 +60,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||||
customBlock = (int) entityMetadata.getValue();
|
customBlock = (int) entityMetadata.getValue();
|
||||||
|
|
||||||
if (showCustomBlock) {
|
if (showCustomBlock) {
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(customBlock));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,16 +77,16 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||||
if (entityMetadata.getId() == 12) {
|
if (entityMetadata.getId() == 12) {
|
||||||
if ((boolean) entityMetadata.getValue()) {
|
if ((boolean) entityMetadata.getValue()) {
|
||||||
showCustomBlock = true;
|
showCustomBlock = true;
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(customBlock));
|
||||||
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||||
} else {
|
} else {
|
||||||
showCustomBlock = false;
|
showCustomBlock = false;
|
||||||
updateDefaultBlockMetadata();
|
updateDefaultBlockMetadata(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateDefaultBlockMetadata() { }
|
public void updateDefaultBlockMetadata(GeyserSession session) { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,13 +273,9 @@ public class Entity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers
|
metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers
|
||||||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||||
|
|
||||||
if ((xd & 0x20) == 0x20) {
|
// Armour stands are handled in their own class
|
||||||
// Armour stands are handled in their own class
|
if (!this.is(ArmorStandEntity.class)) {
|
||||||
if (!this.is(ArmorStandEntity.class)) {
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, (xd & 0x20) == 0x20);
|
||||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shield code
|
// Shield code
|
||||||
|
|
|
@ -31,14 +31,19 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
public class FallingBlockEntity extends Entity {
|
public class FallingBlockEntity extends Entity {
|
||||||
|
private final int javaId;
|
||||||
|
|
||||||
public FallingBlockEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, int javaId) {
|
public FallingBlockEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, int javaId) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
this.javaId = javaId;
|
||||||
|
}
|
||||||
|
|
||||||
this.metadata.put(EntityData.VARIANT, BlockTranslator.getBedrockBlockId(javaId));
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
this.metadata.put(EntityData.VARIANT, session.getBlockTranslator().getBedrockBlockId(javaId));
|
||||||
|
super.spawnEntity(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,15 +44,15 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
||||||
hasFuel = (boolean) entityMetadata.getValue();
|
hasFuel = (boolean) entityMetadata.getValue();
|
||||||
updateDefaultBlockMetadata();
|
updateDefaultBlockMetadata(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDefaultBlockMetadata() {
|
public void updateDefaultBlockMetadata(GeyserSession session) {
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
||||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -49,15 +48,19 @@ import java.util.concurrent.TimeUnit;
|
||||||
*/
|
*/
|
||||||
public class ItemFrameEntity extends Entity {
|
public class ItemFrameEntity extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to construct the block entity tag on spawning.
|
||||||
|
*/
|
||||||
|
private final HangingDirection direction;
|
||||||
/**
|
/**
|
||||||
* Used for getting the Bedrock block position.
|
* Used for getting the Bedrock block position.
|
||||||
* Blocks deal with integers whereas entities deal with floats.
|
* Blocks deal with integers whereas entities deal with floats.
|
||||||
*/
|
*/
|
||||||
private final Vector3i bedrockPosition;
|
private Vector3i bedrockPosition;
|
||||||
/**
|
/**
|
||||||
* Specific block 'state' we are emulating in Bedrock.
|
* Specific block 'state' we are emulating in Bedrock.
|
||||||
*/
|
*/
|
||||||
private final int bedrockRuntimeId;
|
private int bedrockRuntimeId;
|
||||||
/**
|
/**
|
||||||
* Rotation of item in frame.
|
* Rotation of item in frame.
|
||||||
*/
|
*/
|
||||||
|
@ -69,19 +72,21 @@ public class ItemFrameEntity extends Entity {
|
||||||
|
|
||||||
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
this.direction = direction;
|
||||||
.putString("name", "minecraft:frame")
|
|
||||||
.putInt("version", BlockTranslator.getBlockStateVersion());
|
|
||||||
blockBuilder.put("states", NbtMap.builder()
|
|
||||||
.putInt("facing_direction", direction.ordinal())
|
|
||||||
.putByte("item_frame_map_bit", (byte) 0)
|
|
||||||
.build());
|
|
||||||
bedrockRuntimeId = BlockTranslator.getItemFrame(blockBuilder.build());
|
|
||||||
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||||
|
.putString("name", "minecraft:frame")
|
||||||
|
.putInt("version", session.getBlockTranslator().getBlockStateVersion());
|
||||||
|
blockBuilder.put("states", NbtMap.builder()
|
||||||
|
.putInt("facing_direction", direction.ordinal())
|
||||||
|
.putByte("item_frame_map_bit", (byte) 0)
|
||||||
|
.build());
|
||||||
|
bedrockRuntimeId = session.getBlockTranslator().getItemFrame(blockBuilder.build());
|
||||||
|
bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ());
|
||||||
|
|
||||||
session.getItemFrameCache().put(bedrockPosition, entityId);
|
session.getItemFrameCache().put(bedrockPosition, entityId);
|
||||||
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||||
|
@ -136,7 +141,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
updateBlockPacket.setDataLayer(0);
|
updateBlockPacket.setDataLayer(0);
|
||||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||||
updateBlockPacket.setRuntimeId(BlockTranslator.BEDROCK_AIR_ID);
|
updateBlockPacket.setRuntimeId(session.getBlockTranslator().getBedrockAirId());
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
|
|
|
@ -30,7 +30,6 @@ import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
public class MinecartEntity extends Entity {
|
public class MinecartEntity extends Entity {
|
||||||
|
|
||||||
|
@ -58,7 +57,7 @@ public class MinecartEntity extends Entity {
|
||||||
if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class
|
if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class
|
||||||
// Custom block
|
// Custom block
|
||||||
if (entityMetadata.getId() == 10) {
|
if (entityMetadata.getId() == 10) {
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId((int) entityMetadata.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom block offset
|
// Custom block offset
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
|
@ -37,8 +38,8 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDefaultBlockMetadata() {
|
public void updateDefaultBlockMetadata(GeyserSession session) {
|
||||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID));
|
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID));
|
||||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.entity.LivingEntity;
|
import org.geysermc.connector.entity.LivingEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
@ -42,15 +45,68 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
private boolean isInvisible = false;
|
private boolean isInvisible = false;
|
||||||
private boolean isSmall = false;
|
private boolean isSmall = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Java Edition, armor stands always show their name. Invisibility hides the name on Bedrock.
|
||||||
|
* By having a second entity, we can allow an invisible entity with the name tag.
|
||||||
|
* (This lets armor on armor stands still show)
|
||||||
|
*/
|
||||||
|
private ArmorStandEntity secondEntity = null;
|
||||||
|
/**
|
||||||
|
* Whether this is the primary armor stand that holds the armor and not the name tag.
|
||||||
|
*/
|
||||||
|
private boolean primaryEntity = true;
|
||||||
|
/**
|
||||||
|
* Whether the entity's position must be updated to included the offset.
|
||||||
|
*
|
||||||
|
* This should be true when the Java server marks the armor stand as invisible, but we shrink the entity
|
||||||
|
* to allow the nametag to appear. Basically:
|
||||||
|
* - Is visible: this is irrelevant (false)
|
||||||
|
* - Has armor, no name: false
|
||||||
|
* - Has armor, has name: false, with a second entity
|
||||||
|
* - No armor, no name: false
|
||||||
|
* - No armor, yes name: true
|
||||||
|
*/
|
||||||
|
private boolean positionRequiresOffset = false;
|
||||||
|
/**
|
||||||
|
* Whether we should update the position of this armor stand after metadata updates.
|
||||||
|
*/
|
||||||
|
private boolean positionUpdateRequired = false;
|
||||||
|
private GeyserSession session;
|
||||||
|
|
||||||
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
this.session = session;
|
||||||
|
this.rotation = Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX());
|
||||||
|
super.spawnEntity(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean despawnEntity(GeyserSession session) {
|
||||||
|
if (secondEntity != null) {
|
||||||
|
secondEntity.despawnEntity(session);
|
||||||
|
}
|
||||||
|
return super.despawnEntity(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||||
|
if (secondEntity != null) {
|
||||||
|
secondEntity.moveRelative(session, relX, relY, relZ, rotation, isOnGround);
|
||||||
|
}
|
||||||
|
super.moveRelative(session, relX, relY, relZ, rotation, isOnGround);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||||
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
if (secondEntity != null) {
|
||||||
if (!isMarker && isInvisible && passengers.isEmpty()) {
|
secondEntity.moveAbsolute(session, applyOffsetToPosition(position), rotation, isOnGround, teleported);
|
||||||
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
} else if (positionRequiresOffset) {
|
||||||
|
// Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
|
||||||
|
position = applyOffsetToPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()), isOnGround, teleported);
|
super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()), isOnGround, teleported);
|
||||||
|
@ -58,47 +114,250 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) {
|
if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
|
||||||
// Check if the armour stand is invisible and store accordingly
|
// Check if the armour stand is invisible and store accordingly
|
||||||
if ((xd & 0x20) == 0x20) {
|
if (primaryEntity) {
|
||||||
metadata.put(EntityData.SCALE, 0.0f);
|
isInvisible = (xd & 0x20) == 0x20;
|
||||||
isInvisible = true;
|
updateSecondEntityStatus(false);
|
||||||
}
|
}
|
||||||
|
} else if (entityMetadata.getId() == 2) {
|
||||||
|
updateSecondEntityStatus(false);
|
||||||
} else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
} else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
|
||||||
// isSmall
|
// isSmall
|
||||||
if ((xd & 0x01) == 0x01) {
|
boolean newIsSmall = (xd & 0x01) == 0x01;
|
||||||
isSmall = true;
|
if (newIsSmall != isSmall) {
|
||||||
|
if (positionRequiresOffset) {
|
||||||
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
// Fix new inconsistency with offset
|
||||||
metadata.put(EntityData.SCALE, 0.55f);
|
this.position = fixOffsetForSize(position, newIsSmall);
|
||||||
|
positionUpdateRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.5f)) {
|
isSmall = newIsSmall;
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.25f);
|
if (!isMarker) {
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.9875f);
|
toggleSmallStatus();
|
||||||
}
|
}
|
||||||
} else if (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.25f)) {
|
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
|
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setMarker
|
// setMarker
|
||||||
if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) == null || !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
|
boolean oldIsMarker = isMarker;
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
isMarker = (xd & 0x10) == 0x10;
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
if (oldIsMarker != isMarker) {
|
||||||
isMarker = true;
|
if (isMarker) {
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||||
|
metadata.put(EntityData.SCALE, 0f);
|
||||||
|
} else {
|
||||||
|
toggleSmallStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSecondEntityStatus(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
if (secondEntity != null) {
|
||||||
|
secondEntity.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void spawnEntity(GeyserSession session) {
|
public void updateBedrockMetadata(GeyserSession session) {
|
||||||
this.rotation = Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX());
|
if (secondEntity != null) {
|
||||||
super.spawnEntity(session);
|
secondEntity.updateBedrockMetadata(session);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(session);
|
||||||
|
if (positionUpdateRequired) {
|
||||||
|
positionUpdateRequired = false;
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHelmet(ItemData helmet) {
|
||||||
|
super.setHelmet(helmet);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChestplate(ItemData chestplate) {
|
||||||
|
super.setChestplate(chestplate);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLeggings(ItemData leggings) {
|
||||||
|
super.setLeggings(leggings);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBoots(ItemData boots) {
|
||||||
|
super.setBoots(boots);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHand(ItemData hand) {
|
||||||
|
super.setHand(hand);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOffHand(ItemData offHand) {
|
||||||
|
super.setOffHand(offHand);
|
||||||
|
updateSecondEntityStatus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if we need to load or unload the second entity.
|
||||||
|
*
|
||||||
|
* @param sendMetadata whether to send a metadata update after a change.
|
||||||
|
*/
|
||||||
|
private void updateSecondEntityStatus(boolean sendMetadata) {
|
||||||
|
// A secondary entity always has to have the offset applied, so it remains invisible and the nametag shows.
|
||||||
|
if (!primaryEntity) return;
|
||||||
|
if (!isInvisible || isMarker) {
|
||||||
|
// It is either impossible to show armor, or the armor stand isn't invisible. We good.
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||||
|
updateOffsetRequirement(false);
|
||||||
|
if (positionUpdateRequired) {
|
||||||
|
positionUpdateRequired = false;
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondEntity != null) {
|
||||||
|
secondEntity.despawnEntity(session);
|
||||||
|
secondEntity = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//boolean isNametagEmpty = metadata.getString(EntityData.NAMETAG).isEmpty() || metadata.getByte(EntityData.NAMETAG_ALWAYS_SHOW, (byte) -1) == (byte) 0; - may not be necessary?
|
||||||
|
boolean isNametagEmpty = metadata.getString(EntityData.NAMETAG).isEmpty();
|
||||||
|
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR)
|
||||||
|
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) {
|
||||||
|
// If the second entity exists, no need to recreate it.
|
||||||
|
// We can't stuff this check above or else it'll fall into another else case and delete the second entity
|
||||||
|
if (secondEntity != null) return;
|
||||||
|
|
||||||
|
// Create the second entity. It doesn't need to worry about the items, but it does need to worry about
|
||||||
|
// the metadata as it will hold the name tag.
|
||||||
|
secondEntity = new ArmorStandEntity(0, session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
EntityType.ARMOR_STAND, position, motion, rotation);
|
||||||
|
secondEntity.primaryEntity = false;
|
||||||
|
if (!this.positionRequiresOffset) {
|
||||||
|
// Ensure the offset is applied for the 0 scale
|
||||||
|
secondEntity.position = secondEntity.applyOffsetToPosition(secondEntity.position);
|
||||||
|
}
|
||||||
|
// Copy metadata
|
||||||
|
secondEntity.isSmall = isSmall;
|
||||||
|
secondEntity.getMetadata().putAll(metadata);
|
||||||
|
// Copy the flags so they aren't the same object in memory
|
||||||
|
secondEntity.getMetadata().putFlags(metadata.getFlags().copy());
|
||||||
|
// Guarantee this copy is NOT invisible
|
||||||
|
secondEntity.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||||
|
// Scale to 0 to show nametag
|
||||||
|
secondEntity.getMetadata().put(EntityData.SCALE, 0.0f);
|
||||||
|
// No bounding box as we don't want to interact with this entity
|
||||||
|
secondEntity.getMetadata().put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||||
|
secondEntity.getMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||||
|
secondEntity.spawnEntity(session);
|
||||||
|
|
||||||
|
// Reset scale of the proper armor stand
|
||||||
|
this.metadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||||
|
// Set the proper armor stand to invisible to show armor
|
||||||
|
this.metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||||
|
// Update the position of the armor stand
|
||||||
|
updateOffsetRequirement(false);
|
||||||
|
} else if (isNametagEmpty) {
|
||||||
|
// We can just make an invisible entity
|
||||||
|
// Reset scale of the proper armor stand
|
||||||
|
metadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||||
|
// Set the proper armor stand to invisible to show armor
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||||
|
// Update offset
|
||||||
|
updateOffsetRequirement(false);
|
||||||
|
|
||||||
|
if (secondEntity != null) {
|
||||||
|
secondEntity.despawnEntity(session);
|
||||||
|
secondEntity = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Nametag is not empty and there is no armor
|
||||||
|
// We don't need to make a new entity
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||||
|
metadata.put(EntityData.SCALE, 0.0f);
|
||||||
|
// As the above is applied, we need an offset
|
||||||
|
updateOffsetRequirement(true);
|
||||||
|
|
||||||
|
if (secondEntity != null) {
|
||||||
|
secondEntity.despawnEntity(session);
|
||||||
|
secondEntity = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sendMetadata) {
|
||||||
|
this.updateBedrockMetadata(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this armor stand is not a marker, set its bounding box size and scale.
|
||||||
|
*/
|
||||||
|
private void toggleSmallStatus() {
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, isSmall ? 0.25f : entityType.getWidth());
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, isSmall ? 0.9875f : entityType.getHeight());
|
||||||
|
metadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the selected position with the position offset applied.
|
||||||
|
*/
|
||||||
|
private Vector3f applyOffsetToPosition(Vector3f position) {
|
||||||
|
return position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an adjusted offset for the new small status.
|
||||||
|
*/
|
||||||
|
private Vector3f fixOffsetForSize(Vector3f position, boolean isNowSmall) {
|
||||||
|
position = removeOffsetFromPosition(position);
|
||||||
|
return position.add(0d, entityType.getHeight() * (isNowSmall ? 0.55d : 1d), 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the selected position with the position offset removed.
|
||||||
|
*/
|
||||||
|
private Vector3f removeOffsetFromPosition(Vector3f position) {
|
||||||
|
return position.sub(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the offset to a new value; if it changed, update the position, too.
|
||||||
|
*/
|
||||||
|
private void updateOffsetRequirement(boolean newValue) {
|
||||||
|
if (newValue != positionRequiresOffset) {
|
||||||
|
this.positionRequiresOffset = newValue;
|
||||||
|
if (positionRequiresOffset) {
|
||||||
|
this.position = applyOffsetToPosition(position);
|
||||||
|
} else {
|
||||||
|
this.position = removeOffsetFromPosition(position);
|
||||||
|
}
|
||||||
|
positionUpdateRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates position without calling movement code.
|
||||||
|
*/
|
||||||
|
private void updatePosition() {
|
||||||
|
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||||
|
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||||
|
moveEntityPacket.setPosition(position);
|
||||||
|
moveEntityPacket.setRotation(Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()));
|
||||||
|
moveEntityPacket.setOnGround(onGround);
|
||||||
|
moveEntityPacket.setTeleported(false);
|
||||||
|
session.sendUpstreamPacket(moveEntityPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
public class EndermanEntity extends MonsterEntity {
|
public class EndermanEntity extends MonsterEntity {
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ public class EndermanEntity extends MonsterEntity {
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
// Held block
|
// Held block
|
||||||
if (entityMetadata.getId() == 15) {
|
if (entityMetadata.getId() == 15) {
|
||||||
metadata.put(EntityData.CARRIED_BLOCK, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
|
metadata.put(EntityData.CARRIED_BLOCK, session.getBlockTranslator().getBedrockBlockId((int) entityMetadata.getValue()));
|
||||||
}
|
}
|
||||||
// "Is screaming" - controls sound
|
// "Is screaming" - controls sound
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||||
import com.nukkitx.protocol.bedrock.v419.Bedrock_v419;
|
import com.nukkitx.protocol.bedrock.v419.Bedrock_v419;
|
||||||
import com.nukkitx.protocol.bedrock.v422.Bedrock_v422;
|
import com.nukkitx.protocol.bedrock.v422.Bedrock_v422;
|
||||||
|
import com.nukkitx.protocol.bedrock.v428.Bedrock_v428;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -40,9 +41,7 @@ public class BedrockProtocol {
|
||||||
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
* Default Bedrock codec that should act as a fallback. Should represent the latest available
|
||||||
* release of the game that Geyser supports.
|
* release of the game that Geyser supports.
|
||||||
*/
|
*/
|
||||||
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v422.V422_CODEC.toBuilder()
|
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v428.V428_CODEC;
|
||||||
.minecraftVersion("1.16.201")
|
|
||||||
.build();
|
|
||||||
/**
|
/**
|
||||||
* A list of all supported Bedrock versions that can join Geyser
|
* A list of all supported Bedrock versions that can join Geyser
|
||||||
*/
|
*/
|
||||||
|
@ -52,9 +51,10 @@ public class BedrockProtocol {
|
||||||
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder()
|
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder()
|
||||||
.minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 is a beta
|
.minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 is a beta
|
||||||
.build());
|
.build());
|
||||||
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
|
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v422.V422_CODEC.toBuilder()
|
||||||
.minecraftVersion("1.16.200/1.16.201")
|
.minecraftVersion("1.16.200/1.16.201")
|
||||||
.build());
|
.build());
|
||||||
|
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,15 +26,18 @@
|
||||||
package org.geysermc.connector.network;
|
package org.geysermc.connector.network;
|
||||||
|
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.ResourcePackType;
|
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.ResourcePackType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
import com.nukkitx.protocol.bedrock.v428.Bedrock_v428;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.common.AuthType;
|
import org.geysermc.connector.common.AuthType;
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.session.cache.AdvancementsCache;
|
import org.geysermc.connector.network.session.cache.AdvancementsCache;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_100;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_210;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
||||||
import org.geysermc.connector.utils.MathUtils;
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
@ -72,6 +75,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
session.getUpstream().getSession().setPacketCodec(packetCodec);
|
session.getUpstream().getSession().setPacketCodec(packetCodec);
|
||||||
|
|
||||||
|
// Set the block translation based off of version
|
||||||
|
session.setBlockTranslator(packetCodec.getProtocolVersion() >= Bedrock_v428.V428_CODEC.getProtocolVersion()
|
||||||
|
? BlockTranslator1_16_210.INSTANCE : BlockTranslator1_16_100.INSTANCE);
|
||||||
|
|
||||||
LoginEncryptionUtils.encryptPlayerConnection(connector, session, loginPacket);
|
LoginEncryptionUtils.encryptPlayerConnection(connector, session, loginPacket);
|
||||||
|
|
||||||
PlayStatusPacket playStatus = new PlayStatusPacket();
|
PlayStatusPacket playStatus = new PlayStatusPacket();
|
||||||
|
|
|
@ -42,6 +42,7 @@ import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.login.client.LoginPluginResponsePacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket;
|
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket;
|
||||||
import com.github.steveice10.packetlib.BuiltinFlags;
|
import com.github.steveice10.packetlib.BuiltinFlags;
|
||||||
import com.github.steveice10.packetlib.Client;
|
import com.github.steveice10.packetlib.Client;
|
||||||
|
@ -85,6 +86,7 @@ import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||||
import org.geysermc.connector.network.translators.collision.CollisionManager;
|
import org.geysermc.connector.network.translators.collision.CollisionManager;
|
||||||
import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.skin.FloodgateSkinUploader;
|
import org.geysermc.connector.skin.FloodgateSkinUploader;
|
||||||
import org.geysermc.connector.skin.SkinManager;
|
import org.geysermc.connector.skin.SkinManager;
|
||||||
import org.geysermc.connector.utils.*;
|
import org.geysermc.connector.utils.*;
|
||||||
|
@ -136,6 +138,12 @@ public class GeyserSession implements CommandSender {
|
||||||
*/
|
*/
|
||||||
private final CollisionManager collisionManager;
|
private final CollisionManager collisionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the block translations for this specific version.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private BlockTranslator blockTranslator;
|
||||||
|
|
||||||
private final Map<Vector3i, SkullPlayerEntity> skullCache = new ConcurrentHashMap<>();
|
private final Map<Vector3i, SkullPlayerEntity> skullCache = new ConcurrentHashMap<>();
|
||||||
private final Long2ObjectMap<ClientboundMapItemDataPacket> storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
private final Long2ObjectMap<ClientboundMapItemDataPacket> storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
||||||
|
|
||||||
|
@ -949,7 +957,7 @@ public class GeyserSession implements CommandSender {
|
||||||
* @param packet the java edition packet from MCProtocolLib
|
* @param packet the java edition packet from MCProtocolLib
|
||||||
*/
|
*/
|
||||||
public void sendDownstreamPacket(Packet packet) {
|
public void sendDownstreamPacket(Packet packet) {
|
||||||
if (downstream != null && downstream.getSession() != null && protocol.getSubProtocol().equals(SubProtocol.GAME)) {
|
if (downstream != null && downstream.getSession() != null && (protocol.getSubProtocol().equals(SubProtocol.GAME) || packet.getClass() == LoginPluginResponsePacket.class)) {
|
||||||
downstream.getSession().send(packet);
|
downstream.getSession().send(packet);
|
||||||
} else {
|
} else {
|
||||||
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
|
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bedrock sends block interact code for a Java entity so we send entity code back to Java
|
// Bedrock sends block interact code for a Java entity so we send entity code back to Java
|
||||||
if (BlockTranslator.isItemFrame(packet.getBlockRuntimeId()) &&
|
if (session.getBlockTranslator().isItemFrame(packet.getBlockRuntimeId()) &&
|
||||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||||
Vector3f vector = packet.getClickPosition();
|
Vector3f vector = packet.getClickPosition();
|
||||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||||
|
@ -192,7 +192,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
if (packet.getActions().isEmpty()) {
|
if (packet.getActions().isEmpty()) {
|
||||||
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
||||||
// Otherwise insufficient permissions
|
// Otherwise insufficient permissions
|
||||||
int blockState = BlockTranslator.getJavaBlockState(packet.getBlockRuntimeId());
|
int blockState = session.getBlockTranslator().getJavaBlockState(packet.getBlockRuntimeId());
|
||||||
String blockName = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(blockState, "");
|
String blockName = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(blockState, "");
|
||||||
// In the future this can be used for structure blocks too, however not all elements
|
// In the future this can be used for structure blocks too, however not all elements
|
||||||
// are available in each GUI
|
// are available in each GUI
|
||||||
|
@ -253,7 +253,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
LevelEventPacket blockBreakPacket = new LevelEventPacket();
|
||||||
blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
||||||
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
||||||
blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState));
|
blockBreakPacket.setData(session.getBlockTranslator().getBedrockBlockId(blockState));
|
||||||
session.sendUpstreamPacket(blockBreakPacket);
|
session.sendUpstreamPacket(blockBreakPacket);
|
||||||
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID);
|
||||||
|
|
||||||
|
@ -342,14 +342,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
updateBlockPacket.setDataLayer(0);
|
updateBlockPacket.setDataLayer(0);
|
||||||
updateBlockPacket.setBlockPosition(blockPos);
|
updateBlockPacket.setBlockPosition(blockPos);
|
||||||
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(javaBlockState));
|
updateBlockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(javaBlockState));
|
||||||
updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
updateBlockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
session.sendUpstreamPacket(updateBlockPacket);
|
session.sendUpstreamPacket(updateBlockPacket);
|
||||||
|
|
||||||
UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateWaterPacket = new UpdateBlockPacket();
|
||||||
updateWaterPacket.setDataLayer(1);
|
updateWaterPacket.setDataLayer(1);
|
||||||
updateWaterPacket.setBlockPosition(blockPos);
|
updateWaterPacket.setBlockPosition(blockPos);
|
||||||
updateWaterPacket.setRuntimeId(BlockTranslator.isWaterlogged(javaBlockState) ? BlockTranslator.BEDROCK_WATER_ID : BlockTranslator.BEDROCK_AIR_ID);
|
updateWaterPacket.setRuntimeId(BlockTranslator.isWaterlogged(javaBlockState) ? session.getBlockTranslator().getBedrockWaterId() : session.getBlockTranslator().getBedrockAirId());
|
||||||
updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
updateWaterPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
session.sendUpstreamPacket(updateWaterPacket);
|
session.sendUpstreamPacket(updateWaterPacket);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.utils.SettingsUtils;
|
import org.geysermc.connector.utils.SettingsUtils;
|
||||||
import org.geysermc.cumulus.CustomForm;
|
import org.geysermc.cumulus.CustomForm;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Translator(packet = ServerSettingsRequestPacket.class)
|
@Translator(packet = ServerSettingsRequestPacket.class)
|
||||||
public class BedrockServerSettingsRequestTranslator extends PacketTranslator<ServerSettingsRequestPacket> {
|
public class BedrockServerSettingsRequestTranslator extends PacketTranslator<ServerSettingsRequestPacket> {
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,9 +42,12 @@ public class BedrockServerSettingsRequestTranslator extends PacketTranslator<Ser
|
||||||
CustomForm window = SettingsUtils.buildForm(session);
|
CustomForm window = SettingsUtils.buildForm(session);
|
||||||
int windowId = session.getFormCache().addForm(window);
|
int windowId = session.getFormCache().addForm(window);
|
||||||
|
|
||||||
ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket();
|
// Fixes https://bugs.mojang.com/browse/MCPE-94012 because of the delay
|
||||||
serverSettingsResponsePacket.setFormData(window.getJsonData());
|
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||||
serverSettingsResponsePacket.setFormId(windowId);
|
ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket();
|
||||||
session.sendUpstreamPacket(serverSettingsResponsePacket);
|
serverSettingsResponsePacket.setFormData(window.getJsonData());
|
||||||
|
serverSettingsResponsePacket.setFormId(windowId);
|
||||||
|
session.sendUpstreamPacket(serverSettingsResponsePacket);
|
||||||
|
}, 1, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||||
}
|
}
|
||||||
LevelEventPacket continueBreakPacket = new LevelEventPacket();
|
LevelEventPacket continueBreakPacket = new LevelEventPacket();
|
||||||
continueBreakPacket.setType(LevelEventType.PARTICLE_CRACK_BLOCK);
|
continueBreakPacket.setType(LevelEventType.PARTICLE_CRACK_BLOCK);
|
||||||
continueBreakPacket.setData((BlockTranslator.getBedrockBlockId(session.getBreakingBlock())) | (packet.getFace() << 24));
|
continueBreakPacket.setData((session.getBlockTranslator().getBedrockBlockId(session.getBreakingBlock())) | (packet.getFace() << 24));
|
||||||
continueBreakPacket.setPosition(vector.toFloat());
|
continueBreakPacket.setPosition(vector.toFloat());
|
||||||
session.sendUpstreamPacket(continueBreakPacket);
|
session.sendUpstreamPacket(continueBreakPacket);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,8 +40,7 @@ public class BlockInventoryTranslator extends BaseInventoryTranslator {
|
||||||
public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) {
|
public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) {
|
||||||
super(size);
|
super(size);
|
||||||
int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier);
|
int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier);
|
||||||
int blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
this.holder = new BlockInventoryHolder(javaBlockState, containerType);
|
||||||
this.holder = new BlockInventoryHolder(blockId, containerType);
|
|
||||||
this.updater = updater;
|
this.updater = updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,23 +37,23 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||||
private final int blockId;
|
private final int javaBlockState;
|
||||||
|
|
||||||
public DoubleChestInventoryTranslator(int size) {
|
public DoubleChestInventoryTranslator(int size) {
|
||||||
super(size, 54);
|
super(size, 54);
|
||||||
int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
this.javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||||
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||||
Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP);
|
Vector3i position = session.getPlayerEntity().getPosition().toInt().add(Vector3i.UP);
|
||||||
Vector3i pairPosition = position.add(Vector3i.UNIT_X);
|
Vector3i pairPosition = position.add(Vector3i.UNIT_X);
|
||||||
|
int bedrockBlockId = session.getBlockTranslator().getBedrockBlockId(javaBlockState);
|
||||||
|
|
||||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(position);
|
blockPacket.setBlockPosition(position);
|
||||||
blockPacket.setRuntimeId(blockId);
|
blockPacket.setRuntimeId(bedrockBlockId);
|
||||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||||
blockPacket = new UpdateBlockPacket();
|
blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(pairPosition);
|
blockPacket.setBlockPosition(pairPosition);
|
||||||
blockPacket.setRuntimeId(blockId);
|
blockPacket.setRuntimeId(bedrockBlockId);
|
||||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(holderPos);
|
blockPacket.setBlockPosition(holderPos);
|
||||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock));
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
|
|
||||||
holderPos = holderPos.add(Vector3i.UNIT_X);
|
holderPos = holderPos.add(Vector3i.UNIT_X);
|
||||||
|
@ -120,7 +120,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||||
blockPacket = new UpdateBlockPacket();
|
blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(holderPos);
|
blockPacket.setBlockPosition(holderPos);
|
||||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock));
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||||
public SingleChestInventoryTranslator(int size) {
|
public SingleChestInventoryTranslator(int size) {
|
||||||
super(size, 27);
|
super(size, 27);
|
||||||
int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||||
this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER);
|
this.holder = new BlockInventoryHolder(javaBlockState, ContainerType.CONTAINER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,11 +36,10 @@ import lombok.AllArgsConstructor;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class BlockInventoryHolder extends InventoryHolder {
|
public class BlockInventoryHolder extends InventoryHolder {
|
||||||
private final int blockId;
|
private final int javaBlockState;
|
||||||
private final ContainerType containerType;
|
private final ContainerType containerType;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,7 +49,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(position);
|
blockPacket.setBlockPosition(position);
|
||||||
blockPacket.setRuntimeId(blockId);
|
blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(javaBlockState));
|
||||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
inventory.setHolderPosition(position);
|
inventory.setHolderPosition(position);
|
||||||
|
@ -84,7 +83,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
||||||
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket blockPacket = new UpdateBlockPacket();
|
||||||
blockPacket.setDataLayer(0);
|
blockPacket.setDataLayer(0);
|
||||||
blockPacket.setBlockPosition(holderPos);
|
blockPacket.setBlockPosition(holderPos);
|
||||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
blockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(realBlock));
|
||||||
session.sendUpstreamPacket(blockPacket);
|
session.sendUpstreamPacket(blockPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
import org.geysermc.connector.network.translators.chat.MessageTranslator;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
|
@ -160,8 +159,8 @@ public abstract class ItemTranslator {
|
||||||
String[] canBreak = new String[0];
|
String[] canBreak = new String[0];
|
||||||
ListTag canPlaceOn = nbt.get("CanPlaceOn");
|
ListTag canPlaceOn = nbt.get("CanPlaceOn");
|
||||||
String[] canPlace = new String[0];
|
String[] canPlace = new String[0];
|
||||||
canBreak = getCanModify(canDestroy, canBreak);
|
canBreak = getCanModify(session, canDestroy, canBreak);
|
||||||
canPlace = getCanModify(canPlaceOn, canPlace);
|
canPlace = getCanModify(session, canPlaceOn, canPlace);
|
||||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), itemData.getTag(), canPlace, canBreak);
|
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), itemData.getTag(), canPlace, canBreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,11 +170,12 @@ public abstract class ItemTranslator {
|
||||||
/**
|
/**
|
||||||
* Translates the Java NBT of canDestroy and canPlaceOn to its Bedrock counterparts.
|
* Translates the Java NBT of canDestroy and canPlaceOn to its Bedrock counterparts.
|
||||||
* In Java, this is treated as normal NBT, but in Bedrock, these arguments are extra parts of the item data itself.
|
* In Java, this is treated as normal NBT, but in Bedrock, these arguments are extra parts of the item data itself.
|
||||||
|
*
|
||||||
* @param canModifyJava the list of items in Java
|
* @param canModifyJava the list of items in Java
|
||||||
* @param canModifyBedrock the empty list of items in Bedrock
|
* @param canModifyBedrock the empty list of items in Bedrock
|
||||||
* @return the new list of items in Bedrock
|
* @return the new list of items in Bedrock
|
||||||
*/
|
*/
|
||||||
private static String[] getCanModify(ListTag canModifyJava, String[] canModifyBedrock) {
|
private static String[] getCanModify(GeyserSession session, ListTag canModifyJava, String[] canModifyBedrock) {
|
||||||
if (canModifyJava != null && canModifyJava.size() > 0) {
|
if (canModifyJava != null && canModifyJava.size() > 0) {
|
||||||
canModifyBedrock = new String[canModifyJava.size()];
|
canModifyBedrock = new String[canModifyJava.size()];
|
||||||
for (int i = 0; i < canModifyBedrock.length; i++) {
|
for (int i = 0; i < canModifyBedrock.length; i++) {
|
||||||
|
@ -185,7 +185,7 @@ public abstract class ItemTranslator {
|
||||||
if (!block.startsWith("minecraft:")) block = "minecraft:" + block;
|
if (!block.startsWith("minecraft:")) block = "minecraft:" + block;
|
||||||
// Get the Bedrock identifier of the item and replace it.
|
// Get the Bedrock identifier of the item and replace it.
|
||||||
// This will unfortunately be limited - for example, beds and banners will be translated weirdly
|
// This will unfortunately be limited - for example, beds and banners will be translated weirdly
|
||||||
canModifyBedrock[i] = BlockTranslator.getBedrockBlockIdentifier(block).replace("minecraft:", "");
|
canModifyBedrock[i] = session.getBlockTranslator().getBedrockBlockIdentifier(block).replace("minecraft:", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return canModifyBedrock;
|
return canModifyBedrock;
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.item.translators.nbt;
|
||||||
|
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||||
|
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||||
|
import org.geysermc.connector.utils.FireworkColor;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores common code for firework rockets and firework stars.
|
||||||
|
*/
|
||||||
|
public abstract class FireworkBaseTranslator extends NbtItemStackTranslator {
|
||||||
|
|
||||||
|
protected CompoundTag translateExplosionToBedrock(CompoundTag explosion, String newName) {
|
||||||
|
CompoundTag newExplosionData = new CompoundTag(newName);
|
||||||
|
|
||||||
|
if (explosion.get("Type") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("FireworkType", MathUtils.convertByte(explosion.get("Type").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("Colors") != null) {
|
||||||
|
int[] oldColors = (int[]) explosion.get("Colors").getValue();
|
||||||
|
byte[] colors = new byte[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||||
|
}
|
||||||
|
|
||||||
|
newExplosionData.put(new ByteArrayTag("FireworkColor", colors));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("FadeColors") != null) {
|
||||||
|
int[] oldColors = (int[]) explosion.get("FadeColors").getValue();
|
||||||
|
byte[] colors = new byte[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
||||||
|
}
|
||||||
|
|
||||||
|
newExplosionData.put(new ByteArrayTag("FireworkFade", colors));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("Trail") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("FireworkTrail", MathUtils.convertByte(explosion.get("Trail").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("Flicker") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("FireworkFlicker", MathUtils.convertByte(explosion.get("Flicker").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newExplosionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompoundTag translateExplosionToJava(CompoundTag explosion, String newName) {
|
||||||
|
CompoundTag newExplosionData = new CompoundTag(newName);
|
||||||
|
|
||||||
|
if (explosion.get("FireworkType") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("Type", MathUtils.convertByte(explosion.get("FireworkType").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("FireworkColor") != null) {
|
||||||
|
byte[] oldColors = (byte[]) explosion.get("FireworkColor").getValue();
|
||||||
|
int[] colors = new int[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (byte color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
||||||
|
}
|
||||||
|
|
||||||
|
newExplosionData.put(new IntArrayTag("Colors", colors));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("FireworkFade") != null) {
|
||||||
|
byte[] oldColors = (byte[]) explosion.get("FireworkFade").getValue();
|
||||||
|
int[] colors = new int[oldColors.length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (byte color : oldColors) {
|
||||||
|
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
||||||
|
}
|
||||||
|
|
||||||
|
newExplosionData.put(new IntArrayTag("FadeColors", colors));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("FireworkTrail") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("Trail", MathUtils.convertByte(explosion.get("FireworkTrail").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explosion.get("FireworkFlicker") != null) {
|
||||||
|
newExplosionData.put(new ByteTag("Flicker", MathUtils.convertByte(explosion.get("FireworkFlicker").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newExplosionData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.item.translators.nbt;
|
||||||
|
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
|
||||||
|
@ItemRemapper
|
||||||
|
public class FireworkRocketTranslator extends FireworkBaseTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) {
|
||||||
|
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||||
|
if (fireworks == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireworks.get("Flight") != null) {
|
||||||
|
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
ListTag explosions = fireworks.get("Explosions");
|
||||||
|
if (explosions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Tag effect : explosions.getValue()) {
|
||||||
|
CompoundTag effectData = (CompoundTag) effect;
|
||||||
|
CompoundTag newEffectData = translateExplosionToBedrock(effectData, "");
|
||||||
|
|
||||||
|
explosions.remove(effectData);
|
||||||
|
explosions.add(newEffectData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||||
|
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||||
|
if (fireworks == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireworks.contains("Flight")) {
|
||||||
|
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
ListTag explosions = fireworks.get("Explosions");
|
||||||
|
if (explosions == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Tag effect : explosions.getValue()) {
|
||||||
|
CompoundTag effectData = (CompoundTag) effect;
|
||||||
|
CompoundTag newEffectData = translateExplosionToJava(effectData, "");
|
||||||
|
|
||||||
|
explosions.remove(effect);
|
||||||
|
explosions.add(newEffectData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptItem(ItemEntry itemEntry) {
|
||||||
|
return "minecraft:firework_rocket".equals(itemEntry.getJavaIdentifier());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.item.translators.nbt;
|
||||||
|
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||||
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
|
||||||
|
@ItemRemapper
|
||||||
|
public class FireworkStarTranslator extends FireworkBaseTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) {
|
||||||
|
Tag explosion = itemTag.get("Explosion");
|
||||||
|
if (explosion instanceof CompoundTag) {
|
||||||
|
CompoundTag newExplosion = translateExplosionToBedrock((CompoundTag) explosion, "FireworksItem");
|
||||||
|
itemTag.remove("Explosion");
|
||||||
|
itemTag.put(newExplosion);
|
||||||
|
Tag color = ((CompoundTag) explosion).get("Colors");
|
||||||
|
if (color instanceof IntArrayTag) {
|
||||||
|
// Determine the custom color, if any.
|
||||||
|
// Mostly replicates Java's own rendering code, as Java determines the final firework star color client-side
|
||||||
|
// while Bedrock determines it server-side.
|
||||||
|
int[] colors = ((IntArrayTag) color).getValue();
|
||||||
|
if (colors.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int finalColor;
|
||||||
|
if (colors.length == 1) {
|
||||||
|
finalColor = colors[0];
|
||||||
|
} else {
|
||||||
|
int r = 0;
|
||||||
|
int g = 0;
|
||||||
|
int b = 0;
|
||||||
|
|
||||||
|
for (int fireworkColor : colors) {
|
||||||
|
r += (fireworkColor & (255 << 16)) >> 16;
|
||||||
|
g += (fireworkColor & (255 << 8)) >> 8;
|
||||||
|
b += fireworkColor & 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
r /= colors.length;
|
||||||
|
g /= colors.length;
|
||||||
|
b /= colors.length;
|
||||||
|
finalColor = r << 16 | g << 8 | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemTag.put(new IntTag("customColor", finalColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||||
|
Tag explosion = itemTag.get("FireworksItem");
|
||||||
|
if (explosion instanceof CompoundTag) {
|
||||||
|
CompoundTag newExplosion = translateExplosionToJava((CompoundTag) explosion, "Explosion");
|
||||||
|
itemTag.remove("FireworksItem");
|
||||||
|
itemTag.put(newExplosion);
|
||||||
|
}
|
||||||
|
// Remove custom color, if any, since this only exists on Bedrock
|
||||||
|
itemTag.remove("customColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptItem(ItemEntry itemEntry) {
|
||||||
|
return "minecraft:firework_star".equals(itemEntry.getJavaIdentifier());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,164 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021 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.connector.network.translators.item.translators.nbt;
|
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
|
||||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
|
||||||
import org.geysermc.connector.utils.FireworkColor;
|
|
||||||
import org.geysermc.connector.utils.MathUtils;
|
|
||||||
|
|
||||||
@ItemRemapper
|
|
||||||
public class FireworkTranslator extends NbtItemStackTranslator {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) {
|
|
||||||
if (!itemTag.contains("Fireworks")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
|
||||||
if (fireworks.get("Flight") != null) {
|
|
||||||
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
ListTag explosions = fireworks.get("Explosions");
|
|
||||||
if (explosions == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (Tag effect : explosions.getValue()) {
|
|
||||||
CompoundTag effectData = (CompoundTag) effect;
|
|
||||||
|
|
||||||
CompoundTag newEffectData = new CompoundTag("");
|
|
||||||
|
|
||||||
if (effectData.get("Type") != null) {
|
|
||||||
newEffectData.put(new ByteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("Colors") != null) {
|
|
||||||
int[] oldColors = (int[]) effectData.get("Colors").getValue();
|
|
||||||
byte[] colors = new byte[oldColors.length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (int color : oldColors) {
|
|
||||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
|
||||||
}
|
|
||||||
|
|
||||||
newEffectData.put(new ByteArrayTag("FireworkColor", colors));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("FadeColors") != null) {
|
|
||||||
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
|
|
||||||
byte[] colors = new byte[oldColors.length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (int color : oldColors) {
|
|
||||||
colors[i++] = FireworkColor.fromJavaID(color).getBedrockID();
|
|
||||||
}
|
|
||||||
|
|
||||||
newEffectData.put(new ByteArrayTag("FireworkFade", colors));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("Trail") != null) {
|
|
||||||
newEffectData.put(new ByteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("Flicker") != null) {
|
|
||||||
newEffectData.put(new ByteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
explosions.remove(effect);
|
|
||||||
explosions.add(newEffectData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
|
||||||
if (!itemTag.contains("Fireworks")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
|
||||||
if (fireworks.contains("Flight")) {
|
|
||||||
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!itemTag.contains("Explosions")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ListTag explosions = fireworks.get("Explosions");
|
|
||||||
for (Tag effect : explosions.getValue()) {
|
|
||||||
CompoundTag effectData = (CompoundTag) effect;
|
|
||||||
|
|
||||||
CompoundTag newEffectData = new CompoundTag("");
|
|
||||||
|
|
||||||
if (effectData.get("FireworkType") != null) {
|
|
||||||
newEffectData.put(new ByteTag("Type", MathUtils.convertByte(effectData.get("FireworkType").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("FireworkColor") != null) {
|
|
||||||
byte[] oldColors = (byte[]) effectData.get("FireworkColor").getValue();
|
|
||||||
int[] colors = new int[oldColors.length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (byte color : oldColors) {
|
|
||||||
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
|
||||||
}
|
|
||||||
|
|
||||||
newEffectData.put(new IntArrayTag("Colors", colors));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("FireworkFade") != null) {
|
|
||||||
byte[] oldColors = (byte[]) effectData.get("FireworkFade").getValue();
|
|
||||||
int[] colors = new int[oldColors.length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (byte color : oldColors) {
|
|
||||||
colors[i++] = FireworkColor.fromBedrockID(color).getJavaID();
|
|
||||||
}
|
|
||||||
|
|
||||||
newEffectData.put(new IntArrayTag("FadeColors", colors));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("FireworkTrail") != null) {
|
|
||||||
newEffectData.put(new ByteTag("Trail", MathUtils.convertByte(effectData.get("FireworkTrail").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectData.get("FireworkFlicker") != null) {
|
|
||||||
newEffectData.put(new ByteTag("Flicker", MathUtils.convertByte(effectData.get("FireworkFlicker").getValue())));
|
|
||||||
}
|
|
||||||
|
|
||||||
explosions.remove(effect);
|
|
||||||
explosions.add(newEffectData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptItem(ItemEntry itemEntry) {
|
|
||||||
return "minecraft:firework_rocket".equals(itemEntry.getJavaIdentifier());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,10 +33,11 @@ import com.github.steveice10.mc.protocol.packet.login.client.LoginPluginResponse
|
||||||
import com.github.steveice10.mc.protocol.packet.login.server.LoginPluginRequestPacket;
|
import com.github.steveice10.mc.protocol.packet.login.server.LoginPluginRequestPacket;
|
||||||
|
|
||||||
@Translator(packet = LoginPluginRequestPacket.class)
|
@Translator(packet = LoginPluginRequestPacket.class)
|
||||||
public class JavaLoginPluginMessageTranslator extends PacketTranslator<LoginPluginRequestPacket> {
|
public class JavaLoginPluginRequestTranslator extends PacketTranslator<LoginPluginRequestPacket> {
|
||||||
@Override
|
@Override
|
||||||
public void translate(LoginPluginRequestPacket packet, GeyserSession session) {
|
public void translate(LoginPluginRequestPacket packet, GeyserSession session) {
|
||||||
// A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either.
|
// A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either.
|
||||||
|
// Note: Fabric Networking API v1 will not let the client log in without sending this
|
||||||
session.sendDownstreamPacket(
|
session.sendDownstreamPacket(
|
||||||
new LoginPluginResponsePacket(packet.getMessageId(), null)
|
new LoginPluginResponsePacket(packet.getMessageId(), null)
|
||||||
);
|
);
|
|
@ -84,7 +84,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator<ServerBlockChang
|
||||||
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
|
placeBlockSoundPacket.setSound(SoundEvent.PLACE);
|
||||||
placeBlockSoundPacket.setPosition(lastPlacePos.toFloat());
|
placeBlockSoundPacket.setPosition(lastPlacePos.toFloat());
|
||||||
placeBlockSoundPacket.setBabySound(false);
|
placeBlockSoundPacket.setBabySound(false);
|
||||||
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(packet.getRecord().getBlock()));
|
placeBlockSoundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(packet.getRecord().getBlock()));
|
||||||
placeBlockSoundPacket.setIdentifier(":");
|
placeBlockSoundPacket.setIdentifier(":");
|
||||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||||
session.setLastBlockPlacePosition(null);
|
session.setLastBlockPlacePosition(null);
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
int size = 0;
|
int size = 0;
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
for (int i = 0; i < sectionCount; i++) {
|
||||||
ChunkSection section = sections[i];
|
ChunkSection section = sections[i];
|
||||||
size += (section != null ? section : ChunkUtils.EMPTY_SECTION).estimateNetworkSize();
|
size += (section != null ? section : session.getBlockTranslator().getEmptyChunkSection()).estimateNetworkSize();
|
||||||
}
|
}
|
||||||
size += 256; // Biomes
|
size += 256; // Biomes
|
||||||
size += 1; // Border blocks
|
size += 1; // Border blocks
|
||||||
|
@ -103,7 +103,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
for (int i = 0; i < sectionCount; i++) {
|
||||||
ChunkSection section = sections[i];
|
ChunkSection section = sections[i];
|
||||||
(section != null ? section : ChunkUtils.EMPTY_SECTION).writeToNetwork(byteBuf);
|
(section != null ? section : session.getBlockTranslator().getEmptyChunkSection()).writeToNetwork(byteBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
byteBuf.writeBytes(BiomeTranslator.toBedrockBiome(mergedColumn.getBiomeData())); // Biomes - 256 bytes
|
byteBuf.writeBytes(BiomeTranslator.toBedrockBiome(mergedColumn.getBiomeData())); // Biomes - 256 bytes
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator<ServerPlayB
|
||||||
soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(packet.getPitch()) / Math.log10(2)) * 12)) + 12);
|
soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(packet.getPitch()) / Math.log10(2)) * 12)) + 12);
|
||||||
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) {
|
} else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) {
|
||||||
if (!soundMapping.getIdentifier().equals(":")) {
|
if (!soundMapping.getIdentifier().equals(":")) {
|
||||||
soundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaBlockState(soundMapping.getIdentifier())));
|
soundPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(BlockTranslator.getJavaBlockState(soundMapping.getIdentifier())));
|
||||||
} else {
|
} else {
|
||||||
session.getConnector().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString());
|
session.getConnector().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.world;
|
package org.geysermc.connector.network.translators.java.world;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.effect.ParticleEffect;
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.effect.*;
|
import com.github.steveice10.mc.protocol.data.game.world.effect.*;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
@ -38,7 +37,6 @@ import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.effect.Effect;
|
import org.geysermc.connector.network.translators.effect.Effect;
|
||||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
import org.geysermc.connector.utils.LocaleUtils;
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
|
@ -205,7 +203,7 @@ public class JavaPlayEffectTranslator extends PacketTranslator<ServerPlayEffectP
|
||||||
effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK);
|
||||||
|
|
||||||
BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData();
|
BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData();
|
||||||
effectPacket.setData(BlockTranslator.getBedrockBlockId(breakBlockEffectData.getBlockState()));
|
effectPacket.setData(session.getBlockTranslator().getBedrockBlockId(breakBlockEffectData.getBlockState()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BREAK_SPLASH_POTION: {
|
case BREAK_SPLASH_POTION: {
|
||||||
|
|
|
@ -26,20 +26,21 @@
|
||||||
package org.geysermc.connector.network.translators.java.world;
|
package org.geysermc.connector.network.translators.java.world;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.particle.*;
|
import com.github.steveice10.mc.protocol.data.game.world.particle.BlockParticleData;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
import com.github.steveice10.mc.protocol.data.game.world.particle.DustParticleData;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.particle.FallingDustParticleData;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.particle.ItemParticleData;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SpawnParticleEffectPacket;
|
import com.nukkitx.protocol.bedrock.packet.SpawnParticleEffectPacket;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket;
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
|
||||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||||
import org.geysermc.connector.utils.DimensionUtils;
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerSpawnParticlePacket.class)
|
@Translator(packet = ServerSpawnParticlePacket.class)
|
||||||
|
@ -52,14 +53,14 @@ public class JavaSpawnParticleTranslator extends PacketTranslator<ServerSpawnPar
|
||||||
case BLOCK:
|
case BLOCK:
|
||||||
particle.setType(LevelEventType.PARTICLE_DESTROY_BLOCK_NO_SOUND);
|
particle.setType(LevelEventType.PARTICLE_DESTROY_BLOCK_NO_SOUND);
|
||||||
particle.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
particle.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
||||||
particle.setData(BlockTranslator.getBedrockBlockId(((BlockParticleData) packet.getParticle().getData()).getBlockState()));
|
particle.setData(session.getBlockTranslator().getBedrockBlockId(((BlockParticleData) packet.getParticle().getData()).getBlockState()));
|
||||||
session.sendUpstreamPacket(particle);
|
session.sendUpstreamPacket(particle);
|
||||||
break;
|
break;
|
||||||
case FALLING_DUST:
|
case FALLING_DUST:
|
||||||
//In fact, FallingDustParticle should have data like DustParticle,
|
//In fact, FallingDustParticle should have data like DustParticle,
|
||||||
//but in MCProtocol, its data is BlockState(1).
|
//but in MCProtocol, its data is BlockState(1).
|
||||||
particle.setType(LevelEventType.PARTICLE_FALLING_DUST);
|
particle.setType(LevelEventType.PARTICLE_FALLING_DUST);
|
||||||
particle.setData(BlockTranslator.getBedrockBlockId(((FallingDustParticleData)packet.getParticle().getData()).getBlockState()));
|
particle.setData(session.getBlockTranslator().getBedrockBlockId(((FallingDustParticleData)packet.getParticle().getData()).getBlockState()));
|
||||||
particle.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
particle.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()));
|
||||||
session.sendUpstreamPacket(particle);
|
session.sendUpstreamPacket(particle);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class GrassPathInteractionHandler implements BlockSoundInteractionHandler
|
||||||
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
||||||
levelSoundEventPacket.setIdentifier(":");
|
levelSoundEventPacket.setIdentifier(":");
|
||||||
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
||||||
levelSoundEventPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaBlockState(identifier)));
|
levelSoundEventPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(BlockTranslator.getJavaBlockState(identifier)));
|
||||||
session.sendUpstreamPacket(levelSoundEventPacket);
|
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class HoeInteractionHandler implements BlockSoundInteractionHandler {
|
||||||
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
||||||
levelSoundEventPacket.setIdentifier(":");
|
levelSoundEventPacket.setIdentifier(":");
|
||||||
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON);
|
||||||
levelSoundEventPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaBlockState(identifier)));
|
levelSoundEventPacket.setExtraData(session.getBlockTranslator().getBedrockBlockId(BlockTranslator.getJavaBlockState(identifier)));
|
||||||
session.sendUpstreamPacket(levelSoundEventPacket);
|
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,8 @@
|
||||||
package org.geysermc.connector.network.translators.world.block;
|
package org.geysermc.connector.network.translators.world.block;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.nukkitx.nbt.NbtMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +39,6 @@ public class BlockStateValues {
|
||||||
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
|
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
|
||||||
private static final Int2ObjectMap<DoubleChestValue> DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<DoubleChestValue> DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<String> FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Map<String, NbtMap> FLOWER_POT_BLOCKS = new HashMap<>();
|
|
||||||
private static final Int2IntMap NOTEBLOCK_PITCHES = new Int2IntOpenHashMap();
|
private static final Int2IntMap NOTEBLOCK_PITCHES = new Int2IntOpenHashMap();
|
||||||
private static final Int2BooleanMap IS_STICKY_PISTON = new Int2BooleanOpenHashMap();
|
private static final Int2BooleanMap IS_STICKY_PISTON = new Int2BooleanOpenHashMap();
|
||||||
private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap();
|
private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap();
|
||||||
|
@ -196,15 +193,6 @@ public class BlockStateValues {
|
||||||
return FLOWER_POT_VALUES;
|
return FLOWER_POT_VALUES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the map of contained flower pot plants to Bedrock CompoundTag
|
|
||||||
*
|
|
||||||
* @return Map of flower pot blocks.
|
|
||||||
*/
|
|
||||||
public static Map<String, NbtMap> getFlowerPotBlocks() {
|
|
||||||
return FLOWER_POT_BLOCKS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
||||||
* This gives an integer pitch that Bedrock can use.
|
* This gives an integer pitch that Bedrock can use.
|
||||||
|
|
|
@ -34,16 +34,20 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.network.translators.world.chunk.ChunkSection;
|
||||||
|
import org.geysermc.connector.network.translators.world.chunk.EmptyChunkProvider;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.reflections.Reflections;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
public class BlockTranslator {
|
public abstract class BlockTranslator {
|
||||||
/**
|
/**
|
||||||
* The Java block runtime ID of air
|
* The Java block runtime ID of air
|
||||||
*/
|
*/
|
||||||
|
@ -51,11 +55,11 @@ public class BlockTranslator {
|
||||||
/**
|
/**
|
||||||
* The Bedrock block runtime ID of air
|
* The Bedrock block runtime ID of air
|
||||||
*/
|
*/
|
||||||
public static final int BEDROCK_AIR_ID;
|
private final int bedrockAirId;
|
||||||
public static final int BEDROCK_WATER_ID;
|
private final int bedrockWaterId;
|
||||||
|
|
||||||
private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap();
|
private final Int2IntMap javaToBedrockBlockMap = new Int2IntOpenHashMap();
|
||||||
private static final Int2IntMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2IntOpenHashMap();
|
private final Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap();
|
||||||
/**
|
/**
|
||||||
* Stores a list of differences in block identifiers.
|
* Stores a list of differences in block identifiers.
|
||||||
* Items will not be added to this list if the key and value is the same.
|
* Items will not be added to this list if the key and value is the same.
|
||||||
|
@ -63,7 +67,8 @@ public class BlockTranslator {
|
||||||
private static final Object2ObjectMap<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = new Object2ObjectOpenHashMap<>();
|
private static final Object2ObjectMap<String, String> JAVA_TO_BEDROCK_IDENTIFIERS = new Object2ObjectOpenHashMap<>();
|
||||||
private static final BiMap<String, Integer> JAVA_ID_BLOCK_MAP = HashBiMap.create();
|
private static final BiMap<String, Integer> JAVA_ID_BLOCK_MAP = HashBiMap.create();
|
||||||
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
||||||
private static final Object2IntMap<NbtMap> ITEM_FRAMES = new Object2IntOpenHashMap<>();
|
private final Object2IntMap<NbtMap> itemFrames = new Object2IntOpenHashMap<>();
|
||||||
|
private final Map<String, NbtMap> flowerPotBlocks = new HashMap<>();
|
||||||
|
|
||||||
// Bedrock carpet ID, used in LlamaEntity.java for decoration
|
// Bedrock carpet ID, used in LlamaEntity.java for decoration
|
||||||
public static final int CARPET = 171;
|
public static final int CARPET = 171;
|
||||||
|
@ -85,7 +90,10 @@ public class BlockTranslator {
|
||||||
/**
|
/**
|
||||||
* Runtime command block ID, used for fixing command block minecart appearances
|
* Runtime command block ID, used for fixing command block minecart appearances
|
||||||
*/
|
*/
|
||||||
public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID;
|
@Getter
|
||||||
|
private final int bedrockRuntimeCommandBlockId;
|
||||||
|
|
||||||
|
private final EmptyChunkProvider emptyChunkProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of all Java runtime wool IDs, for use with block breaking math and shears
|
* A list of all Java runtime wool IDs, for use with block breaking math and shears
|
||||||
|
@ -98,63 +106,30 @@ public class BlockTranslator {
|
||||||
|
|
||||||
public static final int JAVA_RUNTIME_SPAWNER_ID;
|
public static final int JAVA_RUNTIME_SPAWNER_ID;
|
||||||
|
|
||||||
private static final int BLOCK_STATE_VERSION = 17825808;
|
/**
|
||||||
|
* Stores the raw blocks JSON until it is no longer needed.
|
||||||
|
*/
|
||||||
|
public static JsonNode BLOCKS_JSON;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/* Load block palette */
|
InputStream stream = FileUtils.getResource("mappings/blocks.json");
|
||||||
InputStream stream = FileUtils.getResource("bedrock/blockpalette.nbt");
|
|
||||||
|
|
||||||
NbtList<NbtMap> blocksTag;
|
|
||||||
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(stream))) {
|
|
||||||
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
|
||||||
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// New since 1.16.100 - find the block runtime ID by the order given to us in the block palette,
|
|
||||||
// as we no longer send a block palette
|
|
||||||
Object2IntMap<NbtMap> blockStateOrderedMap = new Object2IntOpenHashMap<>(blocksTag.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < blocksTag.size(); i++) {
|
|
||||||
NbtMap tag = blocksTag.get(i);
|
|
||||||
NbtMap blockTag = tag.getCompound("block");
|
|
||||||
if (blockStateOrderedMap.containsKey(blockTag)) {
|
|
||||||
throw new AssertionError("Duplicate block states in Bedrock palette");
|
|
||||||
}
|
|
||||||
blockStateOrderedMap.put(blockTag, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = FileUtils.getResource("mappings/blocks.json");
|
|
||||||
JsonNode blocks;
|
|
||||||
try {
|
try {
|
||||||
blocks = GeyserConnector.JSON_MAPPER.readTree(stream);
|
BLOCKS_JSON = GeyserConnector.JSON_MAPPER.readTree(stream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to load Java block mappings", e);
|
throw new AssertionError("Unable to load Java block mappings", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.world.block.entity")
|
|
||||||
: new Reflections("org.geysermc.connector.network.translators.world.block.entity");
|
|
||||||
|
|
||||||
int waterRuntimeId = -1;
|
|
||||||
int javaRuntimeId = -1;
|
int javaRuntimeId = -1;
|
||||||
int airRuntimeId = -1;
|
|
||||||
int cobwebRuntimeId = -1;
|
int cobwebRuntimeId = -1;
|
||||||
int commandBlockRuntimeId = -1;
|
|
||||||
int furnaceRuntimeId = -1;
|
int furnaceRuntimeId = -1;
|
||||||
int furnaceLitRuntimeId = -1;
|
int furnaceLitRuntimeId = -1;
|
||||||
int spawnerRuntimeId = -1;
|
int spawnerRuntimeId = -1;
|
||||||
int uniqueJavaId = -1;
|
int uniqueJavaId = -1;
|
||||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
javaRuntimeId++;
|
||||||
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
||||||
String javaId = entry.getKey();
|
String javaId = entry.getKey();
|
||||||
NbtMap blockTag = buildBedrockState(entry.getValue());
|
|
||||||
int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1);
|
|
||||||
if (bedrockRuntimeId == -1) {
|
|
||||||
throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO fix this, (no block should have a null hardness)
|
// TODO fix this, (no block should have a null hardness)
|
||||||
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
JsonNode hardnessNode = entry.getValue().get("block_hardness");
|
||||||
|
@ -196,42 +171,17 @@ public class BlockTranslator {
|
||||||
|
|
||||||
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
|
String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText();
|
||||||
|
|
||||||
|
// Keeping this here since this is currently unchanged between versions
|
||||||
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
|
if (!cleanJavaIdentifier.equals(bedrockIdentifier)) {
|
||||||
JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier);
|
JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tag needed for non-empty flower pots
|
if (javaId.contains("wool")) {
|
||||||
if (entry.getValue().get("pottable") != null) {
|
|
||||||
BlockStateValues.getFlowerPotBlocks().put(cleanJavaIdentifier, buildBedrockState(entry.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
|
||||||
waterRuntimeId = bedrockRuntimeId;
|
|
||||||
}
|
|
||||||
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
|
||||||
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
|
||||||
|
|
||||||
if (waterlogged) {
|
|
||||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
|
|
||||||
WATERLOGGED.add(javaRuntimeId);
|
|
||||||
} else {
|
|
||||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId);
|
|
||||||
|
|
||||||
if (bedrockIdentifier.equals("minecraft:air")) {
|
|
||||||
airRuntimeId = bedrockRuntimeId;
|
|
||||||
|
|
||||||
} else if (javaId.contains("wool")) {
|
|
||||||
JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId);
|
JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId);
|
||||||
|
|
||||||
} else if (javaId.contains("cobweb")) {
|
} else if (javaId.contains("cobweb")) {
|
||||||
cobwebRuntimeId = javaRuntimeId;
|
cobwebRuntimeId = javaRuntimeId;
|
||||||
|
|
||||||
} else if (javaId.equals("minecraft:command_block[conditional=false,facing=north]")) {
|
|
||||||
commandBlockRuntimeId = bedrockRuntimeId;
|
|
||||||
|
|
||||||
} else if (javaId.startsWith("minecraft:furnace[facing=north")) {
|
} else if (javaId.startsWith("minecraft:furnace[facing=north")) {
|
||||||
if (javaId.contains("lit=true")) {
|
if (javaId.contains("lit=true")) {
|
||||||
furnaceLitRuntimeId = javaRuntimeId;
|
furnaceLitRuntimeId = javaRuntimeId;
|
||||||
|
@ -249,11 +199,6 @@ public class BlockTranslator {
|
||||||
}
|
}
|
||||||
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
||||||
|
|
||||||
if (commandBlockRuntimeId == -1) {
|
|
||||||
throw new AssertionError("Unable to find command block in palette");
|
|
||||||
}
|
|
||||||
BEDROCK_RUNTIME_COMMAND_BLOCK_ID = commandBlockRuntimeId;
|
|
||||||
|
|
||||||
if (furnaceRuntimeId == -1) {
|
if (furnaceRuntimeId == -1) {
|
||||||
throw new AssertionError("Unable to find furnace in palette");
|
throw new AssertionError("Unable to find furnace in palette");
|
||||||
}
|
}
|
||||||
|
@ -269,35 +214,117 @@ public class BlockTranslator {
|
||||||
}
|
}
|
||||||
JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
|
JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
|
||||||
|
|
||||||
|
BlockTranslator1_16_100.init();
|
||||||
|
BlockTranslator1_16_210.init();
|
||||||
|
BLOCKS_JSON = null; // We no longer require this so let it garbage collect away
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockTranslator(String paletteFile) {
|
||||||
|
/* Load block palette */
|
||||||
|
InputStream stream = FileUtils.getResource(paletteFile);
|
||||||
|
|
||||||
|
NbtList<NbtMap> blocksTag;
|
||||||
|
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) {
|
||||||
|
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
||||||
|
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New since 1.16.100 - find the block runtime ID by the order given to us in the block palette,
|
||||||
|
// as we no longer send a block palette
|
||||||
|
Object2IntMap<NbtMap> blockStateOrderedMap = new Object2IntOpenHashMap<>(blocksTag.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < blocksTag.size(); i++) {
|
||||||
|
NbtMap tag = blocksTag.get(i);
|
||||||
|
if (blockStateOrderedMap.containsKey(tag)) {
|
||||||
|
throw new AssertionError("Duplicate block states in Bedrock palette: " + tag);
|
||||||
|
}
|
||||||
|
blockStateOrderedMap.put(tag, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int airRuntimeId = -1;
|
||||||
|
int commandBlockRuntimeId = -1;
|
||||||
|
int javaRuntimeId = -1;
|
||||||
|
int waterRuntimeId = -1;
|
||||||
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
|
||||||
|
while (blocksIterator.hasNext()) {
|
||||||
|
javaRuntimeId++;
|
||||||
|
Map.Entry<String, JsonNode> entry = blocksIterator.next();
|
||||||
|
String javaId = entry.getKey();
|
||||||
|
|
||||||
|
NbtMap blockTag = buildBedrockState(entry.getValue());
|
||||||
|
int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1);
|
||||||
|
if (bedrockRuntimeId == -1) {
|
||||||
|
throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID! Built compound tag: \n" + blockTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (javaId) {
|
||||||
|
case "minecraft:air":
|
||||||
|
airRuntimeId = bedrockRuntimeId;
|
||||||
|
break;
|
||||||
|
case "minecraft:water[level=0]":
|
||||||
|
waterRuntimeId = bedrockRuntimeId;
|
||||||
|
break;
|
||||||
|
case "minecraft:command_block[conditional=false,facing=north]":
|
||||||
|
commandBlockRuntimeId = bedrockRuntimeId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
||||||
|
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
||||||
|
|
||||||
|
if (waterlogged) {
|
||||||
|
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId);
|
||||||
|
WATERLOGGED.add(javaRuntimeId);
|
||||||
|
} else {
|
||||||
|
bedrockToJavaBlockMap.putIfAbsent(bedrockRuntimeId, javaRuntimeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
String cleanJavaIdentifier = entry.getKey().split("\\[")[0];
|
||||||
|
|
||||||
|
// Get the tag needed for non-empty flower pots
|
||||||
|
if (entry.getValue().get("pottable") != null) {
|
||||||
|
flowerPotBlocks.put(cleanJavaIdentifier, buildBedrockState(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
javaToBedrockBlockMap.put(javaRuntimeId, bedrockRuntimeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandBlockRuntimeId == -1) {
|
||||||
|
throw new AssertionError("Unable to find command block in palette");
|
||||||
|
}
|
||||||
|
bedrockRuntimeCommandBlockId = commandBlockRuntimeId;
|
||||||
|
|
||||||
if (waterRuntimeId == -1) {
|
if (waterRuntimeId == -1) {
|
||||||
throw new AssertionError("Unable to find water in palette");
|
throw new AssertionError("Unable to find water in palette");
|
||||||
}
|
}
|
||||||
BEDROCK_WATER_ID = waterRuntimeId;
|
bedrockWaterId = waterRuntimeId;
|
||||||
|
|
||||||
if (airRuntimeId == -1) {
|
if (airRuntimeId == -1) {
|
||||||
throw new AssertionError("Unable to find air in palette");
|
throw new AssertionError("Unable to find air in palette");
|
||||||
}
|
}
|
||||||
BEDROCK_AIR_ID = airRuntimeId;
|
bedrockAirId = airRuntimeId;
|
||||||
|
|
||||||
// Loop around again to find all item frame runtime IDs
|
// Loop around again to find all item frame runtime IDs
|
||||||
for (Object2IntMap.Entry<NbtMap> entry : blockStateOrderedMap.object2IntEntrySet()) {
|
for (Object2IntMap.Entry<NbtMap> entry : blockStateOrderedMap.object2IntEntrySet()) {
|
||||||
if (entry.getKey().getString("name").equals("minecraft:frame")) {
|
if (entry.getKey().getString("name").equals("minecraft:frame")) {
|
||||||
ITEM_FRAMES.put(entry.getKey(), entry.getIntValue());
|
itemFrames.put(entry.getKey(), entry.getIntValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private BlockTranslator() {
|
this.emptyChunkProvider = new EmptyChunkProvider(bedrockAirId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NbtMap buildBedrockState(JsonNode node) {
|
private NbtMap buildBedrockState(JsonNode node) {
|
||||||
NbtMapBuilder tagBuilder = NbtMap.builder();
|
NbtMapBuilder tagBuilder = NbtMap.builder();
|
||||||
tagBuilder.putString("name", node.get("bedrock_identifier").textValue())
|
String bedrockIdentifier = node.get("bedrock_identifier").textValue();
|
||||||
.putInt("version", BlockTranslator.BLOCK_STATE_VERSION);
|
tagBuilder.putString("name", bedrockIdentifier)
|
||||||
|
.putInt("version", getBlockStateVersion());
|
||||||
|
|
||||||
NbtMapBuilder statesBuilder = NbtMap.builder();
|
NbtMapBuilder statesBuilder = NbtMap.builder();
|
||||||
|
|
||||||
|
@ -320,36 +347,67 @@ public class BlockTranslator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tagBuilder.put("states", statesBuilder.build());
|
tagBuilder.put("states", adjustBlockStateForVersion(bedrockIdentifier, statesBuilder).build());
|
||||||
return tagBuilder.build();
|
return tagBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getBedrockBlockId(int state) {
|
/**
|
||||||
return JAVA_TO_BEDROCK_BLOCK_MAP.get(state);
|
* @return an adjusted state list, if necessary, that converts Geyser's new mapping to Bedrock's older version
|
||||||
|
* of the mapping.
|
||||||
|
*/
|
||||||
|
protected NbtMapBuilder adjustBlockStateForVersion(String bedrockIdentifier, NbtMapBuilder statesBuilder) {
|
||||||
|
return statesBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getJavaBlockState(int bedrockId) {
|
public int getBedrockBlockId(int state) {
|
||||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
return javaToBedrockBlockMap.get(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getJavaBlockState(int bedrockId) {
|
||||||
|
return bedrockToJavaBlockMap.get(bedrockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param javaIdentifier the Java identifier of the block to search for
|
* @param javaIdentifier the Java identifier of the block to search for
|
||||||
* @return the Bedrock identifier if different, or else the Java identifier
|
* @return the Bedrock identifier if different, or else the Java identifier
|
||||||
*/
|
*/
|
||||||
public static String getBedrockBlockIdentifier(String javaIdentifier) {
|
public String getBedrockBlockIdentifier(String javaIdentifier) {
|
||||||
return JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(javaIdentifier, javaIdentifier);
|
return JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(javaIdentifier, javaIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getItemFrame(NbtMap tag) {
|
public int getItemFrame(NbtMap tag) {
|
||||||
return ITEM_FRAMES.getOrDefault(tag, -1);
|
return itemFrames.getOrDefault(tag, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isItemFrame(int bedrockBlockRuntimeId) {
|
public boolean isItemFrame(int bedrockBlockRuntimeId) {
|
||||||
return ITEM_FRAMES.values().contains(bedrockBlockRuntimeId);
|
return itemFrames.values().contains(bedrockBlockRuntimeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getBlockStateVersion() {
|
/**
|
||||||
return BLOCK_STATE_VERSION;
|
* Get the map of contained flower pot plants to Bedrock CompoundTag
|
||||||
|
*
|
||||||
|
* @return Map of flower pot blocks.
|
||||||
|
*/
|
||||||
|
public Map<String, NbtMap> getFlowerPotBlocks() {
|
||||||
|
return flowerPotBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBedrockAirId() {
|
||||||
|
return bedrockAirId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBedrockWaterId() {
|
||||||
|
return bedrockWaterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getBlockStateVersion();
|
||||||
|
|
||||||
|
public byte[] getEmptyChunkData() {
|
||||||
|
return emptyChunkProvider.getEmptyLevelChunkData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkSection getEmptyChunkSection() {
|
||||||
|
return emptyChunkProvider.getEmptySection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -368,10 +426,6 @@ public class BlockTranslator {
|
||||||
return JAVA_ID_BLOCK_MAP;
|
return JAVA_ID_BLOCK_MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getJavaWaterloggedState(int bedrockId) {
|
|
||||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the item a Java client would receive when pressing
|
* Get the item a Java client would receive when pressing
|
||||||
* the Pick Block key on a specific Java block state.
|
* the Pick Block key on a specific Java block state.
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.world.block;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class BlockTranslator1_16_100 extends BlockTranslator {
|
||||||
|
private static final Set<String> CORRECTED_STATES = ImmutableSet.of("minecraft:stripped_warped_stem",
|
||||||
|
"minecraft:stripped_warped_hyphae", "minecraft:stripped_crimson_stem", "minecraft:stripped_crimson_hyphae");
|
||||||
|
|
||||||
|
public static final BlockTranslator1_16_100 INSTANCE = new BlockTranslator1_16_100();
|
||||||
|
|
||||||
|
public BlockTranslator1_16_100() {
|
||||||
|
super("bedrock/blockpalette.1_16_100.nbt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockStateVersion() {
|
||||||
|
return 17825808;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NbtMapBuilder adjustBlockStateForVersion(String bedrockIdentifier, NbtMapBuilder statesBuilder) {
|
||||||
|
if (CORRECTED_STATES.contains(bedrockIdentifier)) {
|
||||||
|
statesBuilder.putInt("deprecated", 0);
|
||||||
|
}
|
||||||
|
return super.adjustBlockStateForVersion(bedrockIdentifier, statesBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.world.block;
|
||||||
|
|
||||||
|
public class BlockTranslator1_16_210 extends BlockTranslator {
|
||||||
|
public static final BlockTranslator1_16_210 INSTANCE = new BlockTranslator1_16_210();
|
||||||
|
|
||||||
|
public BlockTranslator1_16_210() {
|
||||||
|
super("bedrock/blockpalette.1_16_210.nbt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockStateVersion() {
|
||||||
|
return 17879555;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,9 +47,9 @@ public interface BedrockOnlyBlockEntity {
|
||||||
* @param blockState Java BlockState of block.
|
* @param blockState Java BlockState of block.
|
||||||
* @return Bedrock tag, or null if not a Bedrock-only Block Entity
|
* @return Bedrock tag, or null if not a Bedrock-only Block Entity
|
||||||
*/
|
*/
|
||||||
static NbtMap getTag(Vector3i position, int blockState) {
|
static NbtMap getTag(GeyserSession session, Vector3i position, int blockState) {
|
||||||
if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) {
|
if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) {
|
||||||
return FlowerPotBlockEntityTranslator.getTag(blockState, position);
|
return FlowerPotBlockEntityTranslator.getTag(session, blockState, position);
|
||||||
} else if (PistonBlockEntityTranslator.isBlock(blockState)) {
|
} else if (PistonBlockEntityTranslator.isBlock(blockState)) {
|
||||||
return PistonBlockEntityTranslator.getTag(blockState, position);
|
return PistonBlockEntityTranslator.getTag(blockState, position);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||||
|
|
||||||
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||||
|
@ -50,7 +49,7 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, R
|
||||||
* @param position Bedrock position of flower pot.
|
* @param position Bedrock position of flower pot.
|
||||||
* @return Bedrock tag of flower pot.
|
* @return Bedrock tag of flower pot.
|
||||||
*/
|
*/
|
||||||
public static NbtMap getTag(int blockState, Vector3i position) {
|
public static NbtMap getTag(GeyserSession session, int blockState, Vector3i position) {
|
||||||
NbtMapBuilder tagBuilder = NbtMap.builder()
|
NbtMapBuilder tagBuilder = NbtMap.builder()
|
||||||
.putInt("x", position.getX())
|
.putInt("x", position.getX())
|
||||||
.putInt("y", position.getY())
|
.putInt("y", position.getY())
|
||||||
|
@ -62,7 +61,7 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, R
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
// Get the Bedrock CompoundTag of the block.
|
// Get the Bedrock CompoundTag of the block.
|
||||||
// This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states.
|
// This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states.
|
||||||
NbtMap plant = BlockStateValues.getFlowerPotBlocks().get(name);
|
NbtMap plant = session.getBlockTranslator().getFlowerPotBlocks().get(name);
|
||||||
if (plant != null) {
|
if (plant != null) {
|
||||||
tagBuilder.put("PlantBlock", plant.toBuilder().build());
|
tagBuilder.put("PlantBlock", plant.toBuilder().build());
|
||||||
}
|
}
|
||||||
|
@ -77,15 +76,16 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, R
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
NbtMap tag = getTag(session, blockState, position);
|
||||||
|
BlockEntityUtils.updateBlockEntity(session, tag, position);
|
||||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
updateBlockPacket.setDataLayer(0);
|
updateBlockPacket.setDataLayer(0);
|
||||||
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(blockState));
|
updateBlockPacket.setRuntimeId(session.getBlockTranslator().getBedrockBlockId(blockState));
|
||||||
updateBlockPacket.setBlockPosition(position);
|
updateBlockPacket.setBlockPosition(position);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||||
session.sendUpstreamPacket(updateBlockPacket);
|
session.sendUpstreamPacket(updateBlockPacket);
|
||||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
BlockEntityUtils.updateBlockEntity(session, tag, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import io.netty.buffer.ByteBuf;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray;
|
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray;
|
||||||
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion;
|
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion;
|
||||||
|
|
||||||
|
@ -44,14 +43,14 @@ public class BlockStorage {
|
||||||
private final IntList palette;
|
private final IntList palette;
|
||||||
private BitArray bitArray;
|
private BitArray bitArray;
|
||||||
|
|
||||||
public BlockStorage() {
|
public BlockStorage(int airBlockId) {
|
||||||
this(BitArrayVersion.V2);
|
this(airBlockId, BitArrayVersion.V2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockStorage(BitArrayVersion version) {
|
public BlockStorage(int airBlockId, BitArrayVersion version) {
|
||||||
this.bitArray = version.createArray(SIZE);
|
this.bitArray = version.createArray(SIZE);
|
||||||
this.palette = new IntArrayList(16);
|
this.palette = new IntArrayList(16);
|
||||||
this.palette.add(BlockTranslator.BEDROCK_AIR_ID); // Air is at the start of every palette and controls what the default block is in second-layer non-air block spaces.
|
this.palette.add(airBlockId); // Air is at the start of every palette and controls what the default block is in second-layer non-air block spaces.
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockStorage(BitArray bitArray, IntList palette) {
|
public BlockStorage(BitArray bitArray, IntList palette) {
|
||||||
|
|
|
@ -34,8 +34,8 @@ public class ChunkSection {
|
||||||
|
|
||||||
private final BlockStorage[] storage;
|
private final BlockStorage[] storage;
|
||||||
|
|
||||||
public ChunkSection() {
|
public ChunkSection(int airBlockId) {
|
||||||
this(new BlockStorage[]{new BlockStorage(), new BlockStorage()});
|
this(new BlockStorage[]{new BlockStorage(airBlockId), new BlockStorage(airBlockId)});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkSection(BlockStorage[] storage) {
|
public ChunkSection(BlockStorage[] storage) {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.connector.network.translators.world.chunk;
|
||||||
|
|
||||||
|
import com.nukkitx.nbt.NBTOutputStream;
|
||||||
|
import com.nukkitx.nbt.NbtMap;
|
||||||
|
import com.nukkitx.nbt.NbtUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EmptyChunkProvider {
|
||||||
|
@Getter
|
||||||
|
private final byte[] emptyLevelChunkData;
|
||||||
|
@Getter
|
||||||
|
private final ChunkSection emptySection;
|
||||||
|
|
||||||
|
public EmptyChunkProvider(int airId) {
|
||||||
|
BlockStorage emptyStorage = new BlockStorage(airId);
|
||||||
|
emptySection = new ChunkSection(new BlockStorage[]{emptyStorage});
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||||
|
outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size
|
||||||
|
|
||||||
|
try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) {
|
||||||
|
stream.writeTag(NbtMap.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyLevelChunkData = outputStream.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AssertionError("Unable to generate empty level chunk data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -412,15 +412,32 @@ public class SkinProvider {
|
||||||
|
|
||||||
// if the requested image is a cape
|
// if the requested image is a cape
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
if (image.getWidth() > 64) {
|
if (image.getWidth() > 64 || image.getHeight() > 32) {
|
||||||
image = scale(image, 64, 32);
|
// Prevent weirdly-scaled capes from being cut off
|
||||||
|
BufferedImage newImage = new BufferedImage(128, 64, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics g = newImage.createGraphics();
|
||||||
|
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
|
||||||
|
g.dispose();
|
||||||
|
image.flush();
|
||||||
|
image = scale(newImage, 64, 32);
|
||||||
|
} else if (image.getWidth() < 64 || image.getHeight() < 32) {
|
||||||
|
// Bedrock doesn't like smaller-sized capes, either.
|
||||||
|
BufferedImage newImage = new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics g = newImage.createGraphics();
|
||||||
|
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
|
||||||
|
g.dispose();
|
||||||
|
image.flush();
|
||||||
|
image = newImage;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Very rarely, skins can be larger than Minecraft's default.
|
// Very rarely, skins can be larger than Minecraft's default.
|
||||||
// Bedrock will not render anything above a width of 128.
|
// Bedrock will not render anything above a width of 128.
|
||||||
if (image.getWidth() > 128) {
|
if (image.getWidth() > 128) {
|
||||||
image = scale(image, 128, image.getHeight() / (image.getWidth() / 128));
|
// On Height: Scale by the amount we divided width by, or simply cut down to 128
|
||||||
|
image = scale(image, 128, image.getHeight() >= 256 ? (image.getHeight() / (image.getWidth() / 128)) : 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove alpha channel
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = bufferedImageToImageData(image);
|
byte[] data = bufferedImageToImageData(image);
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class BlockUtils {
|
||||||
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
||||||
|
|
||||||
boolean isInWater = session.getConnector().getConfig().isCacheChunks()
|
boolean isInWater = session.getConnector().getConfig().isCacheChunks()
|
||||||
&& BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == BlockTranslator.BEDROCK_WATER_ID;
|
&& session.getBlockTranslator().getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == session.getBlockTranslator().getBedrockWaterId();
|
||||||
|
|
||||||
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
||||||
ItemUtils.getEnchantmentLevel(Optional.ofNullable(session.getInventory().getItem(5)).map(ItemStack::getNbt).orElse(null), "minecraft:aqua_affinity") < 1;
|
ItemUtils.getEnchantmentLevel(Optional.ofNullable(session.getInventory().getItem(5)).map(ItemStack::getNbt).orElse(null), "minecraft:aqua_affinity") < 1;
|
||||||
|
|
|
@ -36,9 +36,7 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
import com.nukkitx.math.vector.Vector2i;
|
import com.nukkitx.math.vector.Vector2i;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.nbt.NBTOutputStream;
|
|
||||||
import com.nukkitx.nbt.NbtMap;
|
import com.nukkitx.nbt.NbtMap;
|
||||||
import com.nukkitx.nbt.NbtUtils;
|
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
@ -64,13 +62,11 @@ import org.geysermc.connector.network.translators.world.chunk.ChunkSection;
|
||||||
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray;
|
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray;
|
||||||
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion;
|
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.geysermc.connector.network.translators.world.block.BlockTranslator.*;
|
import static org.geysermc.connector.network.translators.world.block.BlockTranslator.JAVA_AIR_ID;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ChunkUtils {
|
public class ChunkUtils {
|
||||||
|
@ -80,26 +76,6 @@ public class ChunkUtils {
|
||||||
*/
|
*/
|
||||||
public static final Object2IntMap<Position> CACHED_BLOCK_ENTITIES = new Object2IntOpenHashMap<>();
|
public static final Object2IntMap<Position> CACHED_BLOCK_ENTITIES = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
private static final NbtMap EMPTY_TAG = NbtMap.builder().build();
|
|
||||||
public static final byte[] EMPTY_LEVEL_CHUNK_DATA;
|
|
||||||
|
|
||||||
public static final BlockStorage EMPTY_STORAGE = new BlockStorage();
|
|
||||||
public static final ChunkSection EMPTY_SECTION = new ChunkSection(new BlockStorage[]{ EMPTY_STORAGE });
|
|
||||||
|
|
||||||
static {
|
|
||||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
||||||
outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size
|
|
||||||
|
|
||||||
try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) {
|
|
||||||
stream.writeTag(EMPTY_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError("Unable to generate empty level chunk data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int indexYZXtoXZY(int yzx) {
|
private static int indexYZXtoXZY(int yzx) {
|
||||||
return (yzx >> 8) | (yzx & 0x0F0) | ((yzx & 0x00F) << 8);
|
return (yzx >> 8) | (yzx & 0x0F0) | ((yzx & 0x00F) << 8);
|
||||||
}
|
}
|
||||||
|
@ -161,20 +137,20 @@ public class ChunkUtils {
|
||||||
|
|
||||||
if (javaPalette instanceof GlobalPalette) {
|
if (javaPalette instanceof GlobalPalette) {
|
||||||
// As this is the global palette, simply iterate through the whole chunk section once
|
// As this is the global palette, simply iterate through the whole chunk section once
|
||||||
ChunkSection section = new ChunkSection();
|
ChunkSection section = new ChunkSection(session.getBlockTranslator().getBedrockAirId());
|
||||||
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
||||||
int javaId = javaData.get(yzx);
|
int javaId = javaData.get(yzx);
|
||||||
int bedrockId = BlockTranslator.getBedrockBlockId(javaId);
|
int bedrockId = session.getBlockTranslator().getBedrockBlockId(javaId);
|
||||||
int xzy = indexYZXtoXZY(yzx);
|
int xzy = indexYZXtoXZY(yzx);
|
||||||
section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId);
|
section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId);
|
||||||
|
|
||||||
if (BlockTranslator.isWaterlogged(javaId)) {
|
if (BlockTranslator.isWaterlogged(javaId)) {
|
||||||
section.getBlockStorageArray()[1].setFullBlock(xzy, BEDROCK_WATER_ID);
|
section.getBlockStorageArray()[1].setFullBlock(xzy, session.getBlockTranslator().getBedrockWaterId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock
|
// Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock
|
||||||
if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) {
|
if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) {
|
||||||
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(
|
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
||||||
Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
||||||
javaId
|
javaId
|
||||||
));
|
));
|
||||||
|
@ -191,7 +167,7 @@ public class ChunkUtils {
|
||||||
// Iterate through palette and convert state IDs to Bedrock, doing some additional checks as we go
|
// Iterate through palette and convert state IDs to Bedrock, doing some additional checks as we go
|
||||||
for (int i = 0; i < javaPalette.size(); i++) {
|
for (int i = 0; i < javaPalette.size(); i++) {
|
||||||
int javaId = javaPalette.idToState(i);
|
int javaId = javaPalette.idToState(i);
|
||||||
bedrockPalette.add(BlockTranslator.getBedrockBlockId(javaId));
|
bedrockPalette.add(session.getBlockTranslator().getBedrockBlockId(javaId));
|
||||||
|
|
||||||
if (BlockTranslator.isWaterlogged(javaId)) {
|
if (BlockTranslator.isWaterlogged(javaId)) {
|
||||||
waterloggedPaletteIds.set(i);
|
waterloggedPaletteIds.set(i);
|
||||||
|
@ -210,7 +186,7 @@ public class ChunkUtils {
|
||||||
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) {
|
||||||
int paletteId = javaData.get(yzx);
|
int paletteId = javaData.get(yzx);
|
||||||
if (pistonOrFlowerPaletteIds.get(paletteId)) {
|
if (pistonOrFlowerPaletteIds.get(paletteId)) {
|
||||||
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(
|
bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(session,
|
||||||
Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)),
|
||||||
javaPalette.idToState(paletteId)
|
javaPalette.idToState(paletteId)
|
||||||
));
|
));
|
||||||
|
@ -247,8 +223,8 @@ public class ChunkUtils {
|
||||||
|
|
||||||
// V1 palette
|
// V1 palette
|
||||||
IntList layer1Palette = new IntArrayList(2);
|
IntList layer1Palette = new IntArrayList(2);
|
||||||
layer1Palette.add(BEDROCK_AIR_ID); // Air - see BlockStorage's constructor for more information
|
layer1Palette.add(session.getBlockTranslator().getBedrockAirId()); // Air - see BlockStorage's constructor for more information
|
||||||
layer1Palette.add(BEDROCK_WATER_ID);
|
layer1Palette.add(session.getBlockTranslator().getBedrockWaterId());
|
||||||
|
|
||||||
layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) };
|
layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) };
|
||||||
}
|
}
|
||||||
|
@ -368,7 +344,7 @@ public class ChunkUtils {
|
||||||
skull.despawnEntity(session, position);
|
skull.despawnEntity(session, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockId = BlockTranslator.getBedrockBlockId(blockState);
|
int blockId = session.getBlockTranslator().getBedrockBlockId(blockState);
|
||||||
|
|
||||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||||
updateBlockPacket.setDataLayer(0);
|
updateBlockPacket.setDataLayer(0);
|
||||||
|
@ -382,9 +358,9 @@ public class ChunkUtils {
|
||||||
waterPacket.setDataLayer(1);
|
waterPacket.setDataLayer(1);
|
||||||
waterPacket.setBlockPosition(position);
|
waterPacket.setBlockPosition(position);
|
||||||
if (BlockTranslator.isWaterlogged(blockState)) {
|
if (BlockTranslator.isWaterlogged(blockState)) {
|
||||||
waterPacket.setRuntimeId(BEDROCK_WATER_ID);
|
waterPacket.setRuntimeId(session.getBlockTranslator().getBedrockWaterId());
|
||||||
} else {
|
} else {
|
||||||
waterPacket.setRuntimeId(BEDROCK_AIR_ID);
|
waterPacket.setRuntimeId(session.getBlockTranslator().getBedrockAirId());
|
||||||
}
|
}
|
||||||
session.sendUpstreamPacket(waterPacket);
|
session.sendUpstreamPacket(waterPacket);
|
||||||
|
|
||||||
|
@ -417,7 +393,7 @@ public class ChunkUtils {
|
||||||
data.setChunkX(chunkX + x);
|
data.setChunkX(chunkX + x);
|
||||||
data.setChunkZ(chunkZ + z);
|
data.setChunkZ(chunkZ + z);
|
||||||
data.setSubChunksLength(0);
|
data.setSubChunksLength(0);
|
||||||
data.setData(EMPTY_LEVEL_CHUNK_DATA);
|
data.setData(session.getBlockTranslator().getEmptyChunkData());
|
||||||
data.setCachingEnabled(false);
|
data.setCachingEnabled(false);
|
||||||
session.sendUpstreamPacket(data);
|
session.sendUpstreamPacket(data);
|
||||||
|
|
||||||
|
|
BIN
connector/src/main/resources/bedrock/blockpalette.1_16_100.nbt
Normal file
BIN
connector/src/main/resources/bedrock/blockpalette.1_16_100.nbt
Normal file
Binary file not shown.
BIN
connector/src/main/resources/bedrock/blockpalette.1_16_210.nbt
Normal file
BIN
connector/src/main/resources/bedrock/blockpalette.1_16_210.nbt
Normal file
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
||||||
Subproject commit bffb5617c1ecdacc10031c6ec36988a5f04cb5c6
|
Subproject commit 3d3b60de724f3f552f351c5f400269fde7598b67
|
|
@ -1 +1 @@
|
||||||
Subproject commit bf0610450ce94507a18286e94af2965550ff9eaa
|
Subproject commit ef994d8fea421524cbc11f565a3f5ec59fc05741
|
Loading…
Reference in a new issue