forked from GeyserMC/Geyser
World border improvements (#488)
This commit is contained in:
parent
50c4c0b2d8
commit
498b058aba
243 changed files with 7471 additions and 1898 deletions
|
@ -98,14 +98,8 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
<version>1.4-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
<version>1.5-SNAPSHOT</version>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>4c315aa206</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -115,31 +109,11 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-resolver-dns</artifactId>
|
||||
<version>4.1.43.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>1.15.2-1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>packetlib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcauthlib</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
|
|
|
@ -31,13 +31,24 @@ import java.util.Map;
|
|||
|
||||
public interface GeyserConfiguration {
|
||||
|
||||
// Modify this when you update the config
|
||||
int CURRENT_CONFIG_VERSION = 3;
|
||||
|
||||
IBedrockConfiguration getBedrock();
|
||||
|
||||
IRemoteConfiguration getRemote();
|
||||
|
||||
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
|
||||
|
||||
boolean isPingPassthrough();
|
||||
boolean isCommandSuggestions();
|
||||
|
||||
boolean isPassthroughMotd();
|
||||
|
||||
boolean isPassthroughPlayerCounts();
|
||||
|
||||
boolean isLegacyPingPassthrough();
|
||||
|
||||
int getPingPassthroughInterval();
|
||||
|
||||
int getMaxPlayers();
|
||||
|
||||
|
@ -47,10 +58,14 @@ public interface GeyserConfiguration {
|
|||
|
||||
boolean isAllowThirdPartyCapes();
|
||||
|
||||
boolean isAllowThirdPartyEars();
|
||||
|
||||
String getDefaultLocale();
|
||||
|
||||
Path getFloodgateKeyFile();
|
||||
|
||||
boolean isAboveBedrockNetherBuilding();
|
||||
|
||||
boolean isCacheChunks();
|
||||
|
||||
IMetricsInfo getMetrics();
|
||||
|
@ -87,4 +102,14 @@ public interface GeyserConfiguration {
|
|||
|
||||
String getUniqueId();
|
||||
}
|
||||
|
||||
int getConfigVersion();
|
||||
|
||||
static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) {
|
||||
if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible.");
|
||||
} else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) {
|
||||
geyserLogger.warning("Your Geyser config is too new! Errors may occur.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.connector;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
||||
|
@ -37,10 +39,20 @@ import org.geysermc.connector.metrics.Metrics;
|
|||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.thread.PingPassthroughThread;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||
import org.geysermc.connector.utils.DimensionUtils;
|
||||
import org.geysermc.connector.utils.DockerCheck;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.geysermc.connector.network.translators.sound.SoundRegistry;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.text.DecimalFormat;
|
||||
|
@ -54,6 +66,8 @@ import java.util.concurrent.TimeUnit;
|
|||
@Getter
|
||||
public class GeyserConnector {
|
||||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
|
||||
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC;
|
||||
|
||||
public static final String NAME = "Geyser";
|
||||
|
@ -69,7 +83,6 @@ public class GeyserConnector {
|
|||
private boolean shuttingDown = false;
|
||||
|
||||
private final ScheduledExecutorService generalThreadPool;
|
||||
private PingPassthroughThread passthroughThread;
|
||||
|
||||
private BedrockServer bedrockServer;
|
||||
private PlatformType platformType;
|
||||
|
@ -99,15 +112,29 @@ public class GeyserConnector {
|
|||
|
||||
logger.setDebug(config.isDebugMode());
|
||||
|
||||
Toolbox.init();
|
||||
Translators.start();
|
||||
PacketTranslatorRegistry.init();
|
||||
|
||||
/* Initialize translators and registries */
|
||||
BiomeTranslator.init();
|
||||
BlockTranslator.init();
|
||||
BlockEntityTranslator.init();
|
||||
EffectRegistry.init();
|
||||
EntityIdentifierRegistry.init();
|
||||
ItemRegistry.init();
|
||||
ItemTranslator.init();
|
||||
LocaleUtils.init();
|
||||
SoundRegistry.init();
|
||||
SoundHandlerRegistry.init();
|
||||
|
||||
if (platformType != PlatformType.STANDALONE) {
|
||||
DockerCheck.check(bootstrap);
|
||||
}
|
||||
|
||||
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
|
||||
authType = AuthType.getByName(config.getRemote().getAuthType());
|
||||
|
||||
passthroughThread = new PingPassthroughThread(this);
|
||||
if (config.isPingPassthrough())
|
||||
generalThreadPool.scheduleAtFixedRate(passthroughThread, 1, 1, TimeUnit.SECONDS);
|
||||
if (config.isAboveBedrockNetherBuilding())
|
||||
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether
|
||||
|
||||
bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort()));
|
||||
bedrockServer.setHandler(new ConnectorServerEventHandler(this));
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
package org.geysermc.connector.bootstrap;
|
||||
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
|
@ -67,6 +68,13 @@ public interface GeyserBootstrap {
|
|||
*/
|
||||
CommandManager getGeyserCommandManager();
|
||||
|
||||
/**
|
||||
* Returns the current PingPassthrough manager
|
||||
*
|
||||
* @return The current PingPassthrough manager
|
||||
*/
|
||||
IGeyserPingPassthrough getGeyserPingPassthrough();
|
||||
|
||||
/**
|
||||
* Returns the current WorldManager
|
||||
*
|
||||
|
|
|
@ -55,7 +55,17 @@ public class OffhandCommand extends GeyserCommand {
|
|||
GeyserSession session = (GeyserSession) sender;
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||
BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(releaseItemPacket);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
return;
|
||||
}
|
||||
// Needed for Bukkit - sender is not an instance of GeyserSession
|
||||
for (GeyserSession session : connector.getPlayers().values()) {
|
||||
if (sender.getName().equals(session.getPlayerEntity().getUsername())) {
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
|
||||
BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class AbstractArrowEntity extends Entity {
|
||||
|
||||
public AbstractArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
byte data = (byte) entityMetadata.getValue();
|
||||
|
||||
metadata.getFlags().setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.particle.Particle;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.effect.EffectRegistry;
|
||||
|
||||
public class AreaEffectCloudEntity extends Entity {
|
||||
|
||||
public AreaEffectCloudEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
// Without this the cloud doesn't appear,
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600);
|
||||
|
||||
// This disabled client side shrink of the cloud
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS_PER_TICK, 0.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, (float) entityMetadata.getValue());
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 10) {
|
||||
Particle particle = (Particle) entityMetadata.getValue();
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectRegistry.getParticleString(particle.getType()));
|
||||
} else if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.POTION_COLOR, entityMetadata.getValue());
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BoatEntity extends Entity {
|
||||
|
||||
private boolean isPaddlingLeft;
|
||||
private float paddleTimeLeft;
|
||||
private boolean isPaddlingRight;
|
||||
private float paddleTimeRight;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.05f;
|
||||
|
||||
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
// Rotation is basically only called when entering/exiting a boat.
|
||||
// We don't include the rotation (y) as it causes the boat to appear sideways
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||
super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Time since last hit
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HURT_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Rocking direction
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// 'Health' in Bedrock, damage taken in Java
|
||||
if (entityMetadata.getId() == 9) {
|
||||
// Not exactly health but it makes motion in Bedrock
|
||||
metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 11) {
|
||||
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingLeft) {
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, 0f);
|
||||
}
|
||||
else {
|
||||
// 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.
|
||||
paddleTimeLeft = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateLeftPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (entityMetadata.getId() == 12) {
|
||||
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingRight) {
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f);
|
||||
} else {
|
||||
paddleTimeRight = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateRightPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
} else if (entityMetadata.getId() == 13) {
|
||||
// Possibly - I don't think this does anything?
|
||||
metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingLeft) {
|
||||
paddleTimeLeft += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateLeftPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
|
||||
public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateRightPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
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
|
||||
*/
|
||||
public class DefaultBlockMinecartEntity extends MinecartEntity {
|
||||
|
||||
public int customBlock = 0;
|
||||
public int customBlockOffset = 0;
|
||||
public boolean showCustomBlock = false;
|
||||
|
||||
public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
updateDefaultBlockMetadata();
|
||||
metadata.put(EntityData.HAS_DISPLAY, (byte) 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
customBlock = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
||||
}
|
||||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
customBlockOffset = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
if ((boolean) entityMetadata.getValue()) {
|
||||
showCustomBlock = true;
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
|
||||
} else {
|
||||
showCustomBlock = false;
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public void updateDefaultBlockMetadata() { }
|
||||
}
|
|
@ -31,7 +31,6 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
|
|
|
@ -27,32 +27,40 @@ 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.MetadataType;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityDataMap;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import org.geysermc.connector.entity.attribute.Attribute;
|
||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||
import org.geysermc.connector.entity.living.ArmorStandEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
@ -76,7 +84,7 @@ public class Entity {
|
|||
|
||||
protected boolean valid;
|
||||
|
||||
protected LongSet passengers = new LongOpenHashSet();
|
||||
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
|
||||
protected EntityDataMap metadata = new EntityDataMap();
|
||||
|
||||
|
@ -94,7 +102,7 @@ public class Entity {
|
|||
|
||||
metadata.put(EntityData.SCALE, 1f);
|
||||
metadata.put(EntityData.COLOR, 0);
|
||||
metadata.put(EntityData.MAX_AIR, (short) 400);
|
||||
metadata.put(EntityData.MAX_AIR, (short) 300);
|
||||
metadata.put(EntityData.AIR, (short) 0);
|
||||
metadata.put(EntityData.LEAD_HOLDER_EID, -1L);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||
|
@ -119,7 +127,7 @@ public class Entity {
|
|||
addEntityPacket.getMetadata().putAll(metadata);
|
||||
|
||||
valid = true;
|
||||
session.getUpstream().sendPacket(addEntityPacket);
|
||||
session.sendUpstreamPacket(addEntityPacket);
|
||||
|
||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||
}
|
||||
|
@ -135,7 +143,7 @@ public class Entity {
|
|||
|
||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||
removeEntityPacket.setUniqueEntityId(geyserId);
|
||||
session.getUpstream().sendPacket(removeEntityPacket);
|
||||
session.sendUpstreamPacket(removeEntityPacket);
|
||||
|
||||
valid = false;
|
||||
return true;
|
||||
|
@ -156,7 +164,7 @@ public class Entity {
|
|||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(false);
|
||||
|
||||
session.getUpstream().sendPacket(moveEntityPacket);
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) {
|
||||
|
@ -174,7 +182,7 @@ public class Entity {
|
|||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(teleported);
|
||||
|
||||
session.getUpstream().sendPacket(moveEntityPacket);
|
||||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
public void updateBedrockAttributes(GeyserSession session) {
|
||||
|
@ -191,7 +199,7 @@ public class Entity {
|
|||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||
updateAttributesPacket.setAttributes(attributes);
|
||||
session.getUpstream().sendPacket(updateAttributesPacket);
|
||||
session.sendUpstreamPacket(updateAttributesPacket);
|
||||
}
|
||||
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
@ -205,38 +213,55 @@ public class Entity {
|
|||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10);
|
||||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||
|
||||
if ((xd & 0x20) == 0x20) {
|
||||
// Armour stands are handled in their own class
|
||||
if (!this.is(ArmorStandEntity.class)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||
}
|
||||
} else {
|
||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||
}
|
||||
|
||||
// Shield code
|
||||
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
|
||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) ||
|
||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemTranslator.SHIELD)) {
|
||||
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) ||
|
||||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD)) {
|
||||
ClientPlayerUseItemPacket useItemPacket;
|
||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
|
||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) {
|
||||
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) {
|
||||
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
}
|
||||
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
|
||||
else {
|
||||
useItemPacket = new ClientPlayerUseItemPacket(Hand.OFF_HAND);
|
||||
}
|
||||
session.getDownstream().getSession().send(useItemPacket);
|
||||
session.sendDownstreamPacket(useItemPacket);
|
||||
}
|
||||
} else if (session.getPlayerEntity().getEntityId() == entityId && !metadata.getFlags().getFlag(EntityFlag.SNEAKING) && metadata.getFlags().getFlag(EntityFlag.BLOCKING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, false);
|
||||
metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true);
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0,0,0), BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(releaseItemPacket);
|
||||
}
|
||||
// metadata.getFlags().setFlag(EntityFlag.INVISIBLE, (xd & 0x20) == 0x20);
|
||||
if ((xd & 0x20) == 0x20)
|
||||
metadata.put(EntityData.SCALE, 0.0f);
|
||||
else
|
||||
metadata.put(EntityData.SCALE, scale);
|
||||
metadata.getFlags().setFlag(EntityFlag.BLOCKING, false);
|
||||
metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true);
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0, 0, 0), BlockFace.DOWN);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: // Air/bubbles
|
||||
if ((int) entityMetadata.getValue() == 300) {
|
||||
metadata.put(EntityData.AIR, (short) 0); // Otherwise the bubble counter remains in the UI
|
||||
} else {
|
||||
metadata.put(EntityData.AIR, (short) (int) entityMetadata.getValue());
|
||||
}
|
||||
break;
|
||||
case 2: // custom name
|
||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||
if (name != null)
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
||||
if (entityMetadata.getValue() instanceof TextMessage) {
|
||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||
if (name != null)
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
||||
} else if (entityMetadata.getValue() instanceof TranslationMessage) {
|
||||
TranslationMessage message = (TranslationMessage) entityMetadata.getValue();
|
||||
if (message != null)
|
||||
metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true));
|
||||
}
|
||||
break;
|
||||
case 3: // is custom name visible
|
||||
if (!this.is(PlayerEntity.class))
|
||||
|
@ -248,6 +273,32 @@ public class Entity {
|
|||
case 5: // no gravity
|
||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
||||
break;
|
||||
case 6: // Pose change
|
||||
if (entityMetadata.getValue().equals(Pose.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
||||
// Has to be a byte or it does not work
|
||||
metadata.put(EntityData.CAN_START_SLEEP, (byte) 2);
|
||||
if (entityId == session.getPlayerEntity().getEntityId()) {
|
||||
Vector3i lastInteractionPos = session.getLastInteractionPosition();
|
||||
metadata.put(EntityData.BED_RESPAWN_POS, lastInteractionPos);
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
BlockState bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(),
|
||||
lastInteractionPos.getY(), lastInteractionPos.getZ());
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, lastInteractionPos);
|
||||
}
|
||||
} else {
|
||||
metadata.put(EntityData.BED_RESPAWN_POS, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ()));
|
||||
}
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false);
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth());
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight());
|
||||
metadata.put(EntityData.CAN_START_SLEEP, (byte) 0);
|
||||
}
|
||||
break;
|
||||
case 7: // blocking
|
||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
@ -265,11 +316,12 @@ public class Entity {
|
|||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||
entityDataPacket.setRuntimeEntityId(geyserId);
|
||||
entityDataPacket.getMetadata().putAll(metadata);
|
||||
session.getUpstream().sendPacket(entityDataPacket);
|
||||
session.sendUpstreamPacket(entityDataPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* x = Pitch, y = HeadYaw, z = Yaw
|
||||
*
|
||||
* @return the bedrock rotation
|
||||
*/
|
||||
public Vector3f getBedrockRotation() {
|
||||
|
|
|
@ -27,13 +27,9 @@ package org.geysermc.connector.entity;
|
|||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ExpOrbEntity extends Entity {
|
||||
|
||||
private int amount;
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
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 com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.FireworkColor;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class FireworkEntity extends Entity {
|
||||
|
||||
public FireworkEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
ItemStack item = (ItemStack) entityMetadata.getValue();
|
||||
CompoundTag tag = item.getNbt();
|
||||
|
||||
if (tag == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompoundTag fireworks = tag.get("Fireworks");
|
||||
|
||||
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
|
||||
if (fireworks.get("Flight") != null) {
|
||||
fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()));
|
||||
}
|
||||
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> explosions = new ArrayList<>();
|
||||
if (fireworks.get("Explosions") != null) {
|
||||
for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
|
||||
CompoundTag effectData = (CompoundTag) effect;
|
||||
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
|
||||
|
||||
if (effectData.get("Type") != null) {
|
||||
effectBuilder.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();
|
||||
}
|
||||
|
||||
effectBuilder.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();
|
||||
}
|
||||
|
||||
effectBuilder.byteArrayTag("FireworkFade", colors);
|
||||
}
|
||||
|
||||
if (effectData.get("Trail") != null) {
|
||||
effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue()));
|
||||
}
|
||||
|
||||
if (effectData.get("Flicker") != null) {
|
||||
effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue()));
|
||||
}
|
||||
|
||||
explosions.add(effectBuilder.buildRootTag());
|
||||
}
|
||||
}
|
||||
|
||||
fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions));
|
||||
|
||||
metadata.put(EntityData.DISPLAY_ITEM, CompoundTagBuilder.builder().tag(fireworksBuilder.build("Fireworks")).buildRootTag());
|
||||
} else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||
//Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too.
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
float yaw = entity.getRotation().getX();
|
||||
float pitch = entity.getRotation().getY();
|
||||
//Uses math from NukkitX
|
||||
entity.setMotion(Vector3f.from(
|
||||
-Math.sin(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2,
|
||||
-Math.sin(Math.toRadians(pitch)) * 2,
|
||||
Math.cos(Math.toRadians(yaw)) * Math.cos(Math.toRadians(pitch)) * 2));
|
||||
//Need to update the EntityMotionPacket or else the player won't boost
|
||||
SetEntityMotionPacket entityMotionPacket = new SetEntityMotionPacket();
|
||||
entityMotionPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
entityMotionPacket.setMotion(entity.getMotion());
|
||||
|
||||
session.sendUpstreamPacket(entityMotionPacket);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -25,13 +25,44 @@
|
|||
|
||||
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.object.ProjectileData;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class FishingHookEntity extends Entity {
|
||||
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, ProjectileData data) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
for (GeyserSession session : GeyserConnector.getInstance().getPlayers().values()) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(data.getOwnerId());
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == data.getOwnerId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
this.metadata.put(EntityData.OWNER_EID, entity.getGeyserId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId((Integer) entityMetadata.getValue() - 1);
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue() - 1) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
metadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
private boolean hasFuel = false;
|
||||
|
||||
public FurnaceMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
||||
hasFuel = (boolean) entityMetadata.getValue();
|
||||
updateDefaultBlockMetadata();
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import com.nukkitx.protocol.bedrock.packet.AddItemEntityPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class ItemEntity extends Entity {
|
||||
|
||||
|
@ -49,8 +49,8 @@ public class ItemEntity extends Entity {
|
|||
itemPacket.setUniqueEntityId(geyserId);
|
||||
itemPacket.setFromFishing(false);
|
||||
itemPacket.getMetadata().putAll(metadata);
|
||||
itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||
session.getUpstream().sendPacket(itemPacket);
|
||||
itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||
session.sendUpstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -27,7 +27,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.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.object.HangingDirection;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
|
@ -38,10 +38,10 @@ import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -87,20 +87,23 @@ public class ItemFrameEntity extends Entity {
|
|||
@Override
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
session.getItemFrameCache().put(bedrockPosition, entityId);
|
||||
updateBlock(session);
|
||||
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
updateBlock(session);
|
||||
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
|
||||
}, 500, TimeUnit.MILLISECONDS);
|
||||
valid = true;
|
||||
session.getConnector().getLogger().debug("Spawned item frame at location " + bedrockPosition + " with java id " + entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
|
||||
ItemData itemData = Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue());
|
||||
ItemEntry itemEntry = Translators.getItemTranslator().getItem((ItemStack) entityMetadata.getValue());
|
||||
ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
|
||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||
CompoundTagBuilder builder = CompoundTag.builder();
|
||||
|
||||
String blockName = "";
|
||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry: Toolbox.ITEMS) {
|
||||
for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) {
|
||||
if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) {
|
||||
blockName = startGamePacketItemEntry.getIdentifier();
|
||||
break;
|
||||
|
@ -149,7 +152,7 @@ public class ItemFrameEntity extends Entity {
|
|||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
session.getUpstream().sendPacket(updateBlockPacket);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
session.getItemFrameCache().remove(position, entityId);
|
||||
valid = false;
|
||||
return true;
|
||||
|
@ -170,27 +173,24 @@ public class ItemFrameEntity extends Entity {
|
|||
* @param session GeyserSession.
|
||||
*/
|
||||
public void updateBlock(GeyserSession session) {
|
||||
// Delay is required, or else loading in frames on chunk load is sketchy at best
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
updateBlockPacket.setRuntimeId(bedrockRuntimeId);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
session.getUpstream().sendPacket(updateBlockPacket);
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
updateBlockPacket.setRuntimeId(bedrockRuntimeId);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
|
||||
BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket();
|
||||
blockEntityDataPacket.setBlockPosition(bedrockPosition);
|
||||
if (cachedTag != null) {
|
||||
blockEntityDataPacket.setData(cachedTag);
|
||||
} else {
|
||||
blockEntityDataPacket.setData(getDefaultTag());
|
||||
}
|
||||
BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket();
|
||||
blockEntityDataPacket.setBlockPosition(bedrockPosition);
|
||||
if (cachedTag != null) {
|
||||
blockEntityDataPacket.setData(cachedTag);
|
||||
} else {
|
||||
blockEntityDataPacket.setData(getDefaultTag());
|
||||
}
|
||||
|
||||
session.getUpstream().sendPacket(blockEntityDataPacket);
|
||||
}, 500, TimeUnit.MILLISECONDS);
|
||||
session.sendUpstreamPacket(blockEntityDataPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class LeashKnotEntity extends Entity {
|
||||
|
||||
public LeashKnotEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
// Position is incorrect by default
|
||||
super(entityId, geyserId, entityType, position.add(0.5f, 0.25f, 0.5f), motion, rotation);
|
||||
}
|
||||
|
||||
}
|
|
@ -96,8 +96,8 @@ public class LivingEntity extends Entity {
|
|||
offHandPacket.setInventorySlot(0);
|
||||
offHandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
|
||||
session.getUpstream().sendPacket(armorEquipmentPacket);
|
||||
session.getUpstream().sendPacket(handPacket);
|
||||
session.getUpstream().sendPacket(offHandPacket);
|
||||
session.sendUpstreamPacket(armorEquipmentPacket);
|
||||
session.sendUpstreamPacket(handPacket);
|
||||
session.sendUpstreamPacket(offHandPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,59 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class MinecartEntity extends Entity {
|
||||
|
||||
public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Direction in which the minecart is shaking
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Power in Java, time in Bedrock
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
||||
}
|
||||
|
||||
if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
// Needs a byte based off of Java's boolean
|
||||
metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class PaintingEntity extends Entity {
|
|||
addPaintingPacket.setName(paintingName.getBedrockName());
|
||||
addPaintingPacket.setPosition(fixOffset(true));
|
||||
addPaintingPacket.setDirection(direction);
|
||||
session.getUpstream().sendPacket(addPaintingPacket);
|
||||
session.sendUpstreamPacket(addPaintingPacket);
|
||||
|
||||
valid = true;
|
||||
|
||||
|
@ -67,7 +67,7 @@ public class PaintingEntity extends Entity {
|
|||
Vector3f position = super.position;
|
||||
position = position.add(0.5, 0.5, 0.5);
|
||||
double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 ? 0.5 : 0;
|
||||
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
|
||||
|
||||
switch (direction) {
|
||||
case 0: return position.add(widthOffset, heightOffset, OFFSET);
|
||||
|
|
|
@ -26,15 +26,13 @@
|
|||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.CommandPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerListPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
@ -47,7 +45,10 @@ import org.geysermc.connector.utils.MessageUtils;
|
|||
import org.geysermc.connector.network.session.cache.EntityEffectCache;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Getter @Setter
|
||||
public class PlayerEntity extends LivingEntity {
|
||||
|
@ -56,8 +57,12 @@ public class PlayerEntity extends LivingEntity {
|
|||
private String username;
|
||||
private long lastSkinUpdate = -1;
|
||||
private boolean playerList = true;
|
||||
private boolean onGround;
|
||||
private final EntityEffectCache effectCache;
|
||||
|
||||
private Entity leftParrot;
|
||||
private Entity rightParrot;
|
||||
|
||||
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
|
||||
|
||||
|
@ -93,8 +98,13 @@ public class PlayerEntity extends LivingEntity {
|
|||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.getMetadata().putAll(metadata);
|
||||
|
||||
long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId);
|
||||
if (linkedEntityId != -1) {
|
||||
addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false));
|
||||
}
|
||||
|
||||
valid = true;
|
||||
session.getUpstream().sendPacket(addPlayerPacket);
|
||||
session.sendUpstreamPacket(addPlayerPacket);
|
||||
|
||||
updateEquipment(session);
|
||||
updateBedrockAttributes(session);
|
||||
|
@ -108,7 +118,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
PlayerListPacket playerList = new PlayerListPacket();
|
||||
playerList.setAction(PlayerListPacket.Action.ADD);
|
||||
playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId));
|
||||
session.getUpstream().sendPacket(playerList);
|
||||
session.sendUpstreamPacket(playerList);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +134,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
PlayerListPacket playerList = new PlayerListPacket();
|
||||
playerList.setAction(PlayerListPacket.Action.REMOVE);
|
||||
playerList.getEntries().add(new PlayerListPacket.Entry(uuid));
|
||||
session.getUpstream().sendPacket(playerList);
|
||||
session.sendUpstreamPacket(playerList);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +144,8 @@ public class PlayerEntity extends LivingEntity {
|
|||
setPosition(position);
|
||||
setRotation(rotation);
|
||||
|
||||
this.onGround = isOnGround;
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(this.position);
|
||||
|
@ -145,7 +157,13 @@ public class PlayerEntity extends LivingEntity {
|
|||
movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN);
|
||||
}
|
||||
|
||||
session.getUpstream().sendPacket(movePlayerPacket);
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
if (leftParrot != null) {
|
||||
leftParrot.moveAbsolute(session, position, rotation, true, teleported);
|
||||
}
|
||||
if (rightParrot != null) {
|
||||
rightParrot.moveAbsolute(session, position, rotation, true, teleported);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,13 +171,21 @@ public class PlayerEntity extends LivingEntity {
|
|||
setRotation(rotation);
|
||||
this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ);
|
||||
|
||||
this.onGround = isOnGround;
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(geyserId);
|
||||
movePlayerPacket.setPosition(position);
|
||||
movePlayerPacket.setRotation(getBedrockRotation());
|
||||
movePlayerPacket.setOnGround(isOnGround);
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL);
|
||||
session.getUpstream().sendPacket(movePlayerPacket);
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
if (leftParrot != null) {
|
||||
leftParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||
}
|
||||
if (rightParrot != null) {
|
||||
rightParrot.moveRelative(session, relX, relY, relZ, rotation, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,5 +214,54 @@ public class PlayerEntity extends LivingEntity {
|
|||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||
}
|
||||
}
|
||||
|
||||
// Extra hearts - is not metadata but an attribute on Bedrock
|
||||
if (entityMetadata.getId() == 14) {
|
||||
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||
attributesPacket.setRuntimeEntityId(geyserId);
|
||||
List<Attribute> attributes = new ArrayList<>();
|
||||
// Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit
|
||||
attributes.add(new Attribute("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f));
|
||||
attributesPacket.setAttributes(attributes);
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
}
|
||||
|
||||
// Parrot occupying shoulder
|
||||
if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) {
|
||||
CompoundTag tag = (CompoundTag) entityMetadata.getValue();
|
||||
if (tag != null && !tag.isEmpty()) {
|
||||
// The parrot is a separate entity in Bedrock, but part of the player entity in Java
|
||||
Entity parrot = new Entity(0, session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||
EntityType.PARROT, position, motion, rotation);
|
||||
parrot.spawnEntity(session);
|
||||
parrot.getMetadata().put(EntityData.VARIANT, tag.get("Variant").getValue());
|
||||
// Different position whether the parrot is left or right
|
||||
float offset = (entityMetadata.getId() == 18) ? 0.4f : -0.4f;
|
||||
parrot.getMetadata().put(EntityData.RIDER_SEAT_POSITION, Vector3f.from(offset, -0.22, -0.1));
|
||||
parrot.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, 1);
|
||||
parrot.updateBedrockMetadata(session);
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
EntityLink.Type type = (entityMetadata.getId() == 18) ? EntityLink.Type.RIDER : EntityLink.Type.PASSENGER;
|
||||
linkPacket.setEntityLink(new EntityLink(geyserId, parrot.getGeyserId(), type, false));
|
||||
// Delay, or else spawned-in players won't get the link
|
||||
// TODO: Find a better solution. This problem also exists with item frames
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS);
|
||||
if (entityMetadata.getId() == 18) {
|
||||
leftParrot = parrot;
|
||||
} else {
|
||||
rightParrot = parrot;
|
||||
}
|
||||
} else {
|
||||
Entity parrot = (entityMetadata.getId() == 18 ? leftParrot : rightParrot);
|
||||
if (parrot != null) {
|
||||
parrot.despawnEntity(session);
|
||||
if (entityMetadata.getId() == 18) {
|
||||
leftParrot = null;
|
||||
} else {
|
||||
rightParrot = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
|
||||
|
||||
public SpawnerMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultBlockMetadata() {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID));
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, 6);
|
||||
}
|
||||
}
|
|
@ -23,23 +23,14 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators;
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class NbtItemStackTranslator {
|
||||
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
public class TippedArrowEntity extends AbstractArrowEntity {
|
||||
|
||||
public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class TridentEntity extends AbstractArrowEntity {
|
||||
|
||||
public TridentEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ public enum AttributeType {
|
|||
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||
HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||
|
||||
// Java Attributes
|
||||
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
||||
|
|
|
@ -25,28 +25,18 @@
|
|||
|
||||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class AbstractFishEntity extends WaterEntity {
|
||||
|
||||
public AbstractFishEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
metadata.getFlags().setFlag(EntityFlag.CAN_SWIM, true);
|
||||
metadata.getFlags().setFlag(EntityFlag.BREATHING, true);
|
||||
metadata.getFlags().setFlag(EntityFlag.CAN_CLIMB, false);
|
||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, false);
|
||||
|
||||
metadata.put(EntityData.AIR, (short) 400);
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ public class AgeableEntity extends CreatureEntity {
|
|||
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||
metadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
|
||||
metadata.getFlags().setFlag(EntityFlag.BABY, isBaby);
|
||||
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight() * (isBaby ? 0.55f : 1f));
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth() * (isBaby ? 0.55f : 1f));
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -35,16 +35,60 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
|
||||
public class ArmorStandEntity extends LivingEntity {
|
||||
|
||||
// These are used to store the state of the armour stand for use when handling invisibility
|
||||
private boolean isMarker = false;
|
||||
private boolean isInvisible = false;
|
||||
private boolean isSmall = false;
|
||||
|
||||
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 (!isMarker && isInvisible) {
|
||||
position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
|
||||
}
|
||||
|
||||
super.moveAbsolute(session, position, rotation, isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getType() == MetadataType.BYTE) {
|
||||
if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
if ((xd & 0x01) == 0x01 && (metadata.get(EntityData.SCALE) != null && !metadata.get(EntityData.SCALE).equals(0.0f))) {
|
||||
metadata.put(EntityData.SCALE, .55f);
|
||||
|
||||
// Check if the armour stand is invisible and store accordingly
|
||||
if ((xd & 0x20) == 0x20) {
|
||||
metadata.put(EntityData.SCALE, 0.0f);
|
||||
isInvisible = true;
|
||||
}
|
||||
} else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
||||
// isSmall
|
||||
if ((xd & 0x01) == 0x01) {
|
||||
isSmall = true;
|
||||
|
||||
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
||||
metadata.put(EntityData.SCALE, 0.55f);
|
||||
}
|
||||
|
||||
if (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.5f)) {
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.25f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.9875f);
|
||||
}
|
||||
} 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
|
||||
if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) == null || !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||
isMarker = true;
|
||||
}
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity.living;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class SlimeEntity extends InsentientEntity {
|
||||
|
||||
public SlimeEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
this.metadata.put(EntityData.SCALE, 0.10f + (int) entityMetadata.getValue());
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -23,14 +23,14 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class ArrowEntity extends Entity {
|
||||
public class SquidEntity extends WaterEntity {
|
||||
|
||||
public ArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
public SquidEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
}
|
|
@ -26,11 +26,14 @@
|
|||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class WaterEntity extends CreatureEntity {
|
||||
|
||||
public WaterEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
metadata.put(EntityData.AIR, (short) 400);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ package org.geysermc.connector.entity.living.animal;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.living.AbstractFishEntity;
|
||||
|
|
|
@ -27,25 +27,69 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.Attribute;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AbstractHorseEntity extends AnimalEntity {
|
||||
|
||||
// For updating the horse visual easier
|
||||
private float health = 20f;
|
||||
|
||||
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 8) {
|
||||
health = (float) entityMetadata.getValue();
|
||||
updateBedrockAttributes(session);
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||
}
|
||||
|
||||
// Needed to control horses
|
||||
metadata.getFlags().setFlag(EntityFlag.CAN_POWER_JUMP, true);
|
||||
metadata.getFlags().setFlag(EntityFlag.WASD_CONTROLLED, true);
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockAttributes(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f;
|
||||
|
||||
List<com.nukkitx.protocol.bedrock.data.Attribute> attributesLocal = new ArrayList<>();
|
||||
for (Map.Entry<AttributeType, org.geysermc.connector.entity.attribute.Attribute> entry : this.attributes.entrySet()) {
|
||||
if (!entry.getValue().getType().isBedrockAttribute())
|
||||
continue;
|
||||
|
||||
attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue()));
|
||||
}
|
||||
attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth));
|
||||
|
||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||
updateAttributesPacket.setAttributes(attributesLocal);
|
||||
session.sendUpstreamPacket(updateAttributesPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
|
@ -41,8 +42,9 @@ public class HorseEntity extends AbstractHorseEntity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
}
|
|
@ -65,7 +65,7 @@ public class LlamaEntity extends ChestedHorseEntity {
|
|||
equipmentPacket.setHelmet(ItemData.AIR);
|
||||
equipmentPacket.setLeggings(ItemData.AIR);
|
||||
|
||||
session.getUpstream().sendPacket(equipmentPacket);
|
||||
session.sendUpstreamPacket(equipmentPacket);
|
||||
}
|
||||
// Color of the llama
|
||||
if (entityMetadata.getId() == 21) {
|
||||
|
|
|
@ -26,11 +26,19 @@
|
|||
package org.geysermc.connector.entity.living.animal.horse;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class TraderLlamaEntity extends LlamaEntity {
|
||||
|
||||
public TraderLlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
this.metadata.put(EntityData.MARK_VARIANT, 1);
|
||||
super.spawnEntity(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ public class CreeperEntity extends MonsterEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15 && (int) entityMetadata.getValue() > 0) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
|
||||
if (entityMetadata.getId() == 15) {
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1);
|
||||
}
|
||||
if (entityMetadata.getId() == 16) {
|
||||
metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue());
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity.living.monster;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class ElderGuardianEntity extends GuardianEntity {
|
||||
|
||||
public ElderGuardianEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
// Otherwise it just looks like a normal guardian but bigger
|
||||
metadata.getFlags().setFlag(EntityFlag.ELDER, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -53,7 +53,7 @@ public class EnderDragonEntity extends InsentientEntity {
|
|||
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
|
||||
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||
entityEventPacket.setData(0);
|
||||
session.getUpstream().sendPacket(entityEventPacket);
|
||||
session.sendUpstreamPacket(entityEventPacket);
|
||||
case 6:
|
||||
case 7:
|
||||
metadata.getFlags().setFlag(EntityFlag.SITTING, true);
|
||||
|
@ -79,7 +79,7 @@ public class EnderDragonEntity extends InsentientEntity {
|
|||
addEntityPacket.getAttributes().add(new Attribute("minecraft:health", 0.0f, 200f, 200f, 200f));
|
||||
|
||||
valid = true;
|
||||
session.getUpstream().sendPacket(addEntityPacket);
|
||||
session.sendUpstreamPacket(addEntityPacket);
|
||||
|
||||
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity.living.monster;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class GiantEntity extends MonsterEntity {
|
||||
|
||||
public GiantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
metadata.put(EntityData.SCALE, 6f);
|
||||
}
|
||||
}
|
|
@ -42,8 +42,14 @@ public class GuardianEntity extends MonsterEntity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId((int) entityMetadata.getValue());
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
metadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
||||
} else {
|
||||
metadata.put(EntityData.TARGET_EID, (long) 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.entity.living.monster;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class WitherEntity extends MonsterEntity {
|
||||
|
||||
public WitherEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
||||
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
long targetID = 0;
|
||||
|
||||
if (entityMetadata.getId() >= 15 && entityMetadata.getId() <= 17) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId((int) entityMetadata.getValue());
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == (Integer) entityMetadata.getValue()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
targetID = entity.getGeyserId();
|
||||
}
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 15) {
|
||||
metadata.put(EntityData.WITHER_TARGET_1, targetID);
|
||||
} else if (entityMetadata.getId() == 16) {
|
||||
metadata.put(EntityData.WITHER_TARGET_2, targetID);
|
||||
} else if (entityMetadata.getId() == 17) {
|
||||
metadata.put(EntityData.WITHER_TARGET_3, targetID);
|
||||
} else if (entityMetadata.getId() == 18) {
|
||||
metadata.put(EntityData.WITHER_INVULNERABLE_TICKS, (int) entityMetadata.getValue());
|
||||
|
||||
// Show the shield for the first few seconds of spawning (like Java)
|
||||
if ((int) entityMetadata.getValue() >= 165) {
|
||||
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 0);
|
||||
} else {
|
||||
metadata.put(EntityData.WITHER_AERIAL_ATTACK, (short) 1);
|
||||
}
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ public enum EntityType {
|
|||
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
||||
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:villager_v2"),
|
||||
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
||||
SQUID(WaterEntity.class, 17, 0.8f),
|
||||
SQUID(SquidEntity.class, 17, 0.8f),
|
||||
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
||||
BAT(AmbientEntity.class, 19, 0.9f, 0.5f),
|
||||
IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f),
|
||||
|
@ -64,16 +64,17 @@ public enum EntityType {
|
|||
PARROT(ParrotEntity.class, 30, 0.9f, 0.5f),
|
||||
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
||||
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
GIANT(GiantEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie"),
|
||||
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
||||
SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
|
||||
ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
SLIME(InsentientEntity.class, 37, 0.51f),
|
||||
SLIME(SlimeEntity.class, 37, 0.51f),
|
||||
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
|
||||
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
|
||||
CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f),
|
||||
GHAST(FlyingEntity.class, 41, 4.0f),
|
||||
MAGMA_CUBE(InsentientEntity.class, 42, 0.51f),
|
||||
MAGMA_CUBE(SlimeEntity.class, 42, 0.51f),
|
||||
BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f),
|
||||
ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
|
@ -81,9 +82,9 @@ public enum EntityType {
|
|||
HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WITHER_SKELETON(AbstractSkeletonEntity.class, 48, 2.4f, 0.7f),
|
||||
GUARDIAN(GuardianEntity.class, 49, 0.85f),
|
||||
ELDER_GUARDIAN(GuardianEntity.class, 50, 1.9975f),
|
||||
ELDER_GUARDIAN(ElderGuardianEntity.class, 50, 1.9975f),
|
||||
NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
WITHER(MonsterEntity.class, 52, 3.5f, 0.9f),
|
||||
WITHER(WitherEntity.class, 52, 3.5f, 0.9f),
|
||||
ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f),
|
||||
SHULKER(ShulkerEntity.class, 54, 1f, 1f),
|
||||
ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f),
|
||||
|
@ -94,50 +95,52 @@ public enum EntityType {
|
|||
PHANTOM(FlyingEntity.class, 58, 0.5f, 0.9f, 0.9f, 0.6f),
|
||||
RAVAGER(RaidParticipantEntity.class, 59, 1.9f, 1.2f),
|
||||
|
||||
ARMOR_STAND(ArmorStandEntity.class, 61, 0f),
|
||||
ARMOR_STAND(ArmorStandEntity.class, 61, 1.975f, 0.5f),
|
||||
TRIPOD_CAMERA(Entity.class, 62, 0f),
|
||||
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
||||
TNT(TNTEntity.class, 65, 0.98f, 0.98f),
|
||||
PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"),
|
||||
FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f),
|
||||
MOVING_BLOCK(Entity.class, 67, 0f),
|
||||
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
||||
THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
||||
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"),
|
||||
EYE_OF_ENDER(Entity.class, 70, 0f),
|
||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"),
|
||||
FIREWORK_ROCKET(Entity.class, 72, 0f),
|
||||
TRIDENT(ArrowEntity.class, 73, 0f),
|
||||
EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"),
|
||||
END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
|
||||
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
|
||||
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
||||
CAT(CatEntity.class, 75, 0.35f, 0.3f),
|
||||
SHULKER_BULLET(Entity.class, 76, 0f),
|
||||
SHULKER_BULLET(Entity.class, 76, 0.3125f),
|
||||
FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"),
|
||||
CHALKBOARD(Entity.class, 78, 0f),
|
||||
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 0f),
|
||||
ARROW(ArrowEntity.class, 80, 0.25f, 0.25f),
|
||||
SNOWBALL(ThrowableEntity.class, 81, 0f),
|
||||
EGG(ThrowableEntity.class, 82, 0f),
|
||||
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 1.0f),
|
||||
ARROW(TippedArrowEntity.class, 80, 0.25f, 0.25f),
|
||||
SPECTRAL_ARROW(AbstractArrowEntity.class, 80, 0.25f, 0.25f, 0.25f, 0f, "minecraft:arrow"),
|
||||
SNOWBALL(ThrowableEntity.class, 81, 0.25f),
|
||||
THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"),
|
||||
PAINTING(PaintingEntity.class, 83, 0f),
|
||||
MINECART(MinecartEntity.class, 84, 0f),
|
||||
FIREBALL(ItemedFireballEntity.class, 85, 0f),
|
||||
POTION(ThrowableEntity.class, 86, 0f),
|
||||
ENDER_PEARL(ThrowableEntity.class, 87, 0f),
|
||||
LEASH_KNOT(Entity.class, 88, 0f),
|
||||
WITHER_SKULL(Entity.class, 89, 0f),
|
||||
BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
|
||||
FIREBALL(ItemedFireballEntity.class, 85, 1.0f),
|
||||
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
||||
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
||||
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
||||
BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0f),
|
||||
AREA_EFFECT_CLOUD(Entity.class, 95, 0f),
|
||||
HOPPER_MINECART(MinecartEntity.class, 96, 0f),
|
||||
TNT_MINECART(MinecartEntity.class, 97, 0f),
|
||||
CHEST_MINECART(MinecartEntity.class, 98, 0f),
|
||||
|
||||
COMMAND_BLOCK_MINECART(MinecartEntity.class, 100, 0f),
|
||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"),
|
||||
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"),
|
||||
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"),
|
||||
MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
|
||||
MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
|
||||
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
|
||||
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
||||
LLAMA_SPIT(Entity.class, 102, 0f),
|
||||
EVOKER_FANGS(Entity.class, 103, 0f),
|
||||
EVOKER(SpellcasterIllagerEntity.class, 104, 0f),
|
||||
VEX(MonsterEntity.class, 105, 0f),
|
||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
|
||||
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
|
||||
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
||||
ICE_BOMB(Entity.class, 106, 0f),
|
||||
BALLOON(Entity.class, 107, 0f), //TODO
|
||||
PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f),
|
||||
|
@ -152,7 +155,14 @@ public enum EntityType {
|
|||
/**
|
||||
* Item frames are handled differently since they are a block in Bedrock.
|
||||
*/
|
||||
ITEM_FRAME(ItemFrameEntity.class, 0, 0, 0);
|
||||
ITEM_FRAME(ItemFrameEntity.class, 0, 0, 0),
|
||||
|
||||
/**
|
||||
* Not an entity in Bedrock, so we replace it with a Pillager
|
||||
*/
|
||||
ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager");
|
||||
|
||||
private static final EntityType[] VALUES = values();
|
||||
|
||||
private Class<? extends Entity> entityClass;
|
||||
private final int type;
|
||||
|
@ -163,7 +173,7 @@ public enum EntityType {
|
|||
private String identifier;
|
||||
|
||||
EntityType(Class<? extends Entity> entityClass, int type, float height) {
|
||||
this(entityClass, type, height, 0f);
|
||||
this(entityClass, type, height, height);
|
||||
}
|
||||
|
||||
EntityType(Class<? extends Entity> entityClass, int type, float height, float width) {
|
||||
|
@ -189,4 +199,14 @@ public enum EntityType {
|
|||
this.offset = offset + 0.00001f;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public static EntityType getFromIdentifier(String identifier) {
|
||||
for (EntityType type : VALUES) {
|
||||
if (type.identifier.equals(identifier)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
|
||||
package org.geysermc.connector.network;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.status.ServerStatusInfo;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.nukkitx.protocol.bedrock.*;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
@ -39,7 +40,7 @@ import java.net.InetSocketAddress;
|
|||
|
||||
public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
||||
|
||||
private GeyserConnector connector;
|
||||
private final GeyserConnector connector;
|
||||
|
||||
public ConnectorServerEventHandler(GeyserConnector connector) {
|
||||
this.connector = connector;
|
||||
|
@ -56,29 +57,39 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
connector.getLogger().debug(inetSocketAddress + " has pinged you!");
|
||||
|
||||
GeyserConfiguration config = connector.getConfig();
|
||||
ServerStatusInfo serverInfo = connector.getPassthroughThread().getInfo();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) {
|
||||
IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough();
|
||||
pingInfo = pingPassthrough.getPingInformation();
|
||||
}
|
||||
|
||||
BedrockPong pong = new BedrockPong();
|
||||
pong.setEdition("MCPE");
|
||||
pong.setGameType("Default");
|
||||
pong.setNintendoLimited(false);
|
||||
pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion());
|
||||
pong.setVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
||||
pong.setVersion(null); // Server tries to connect either way and it looks better
|
||||
pong.setIpv4Port(config.getBedrock().getPort());
|
||||
if (connector.getConfig().isPingPassthrough() && serverInfo != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(serverInfo.getDescription()).split("\n");
|
||||
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||
String mainMotd = motd[0]; // First line of the motd.
|
||||
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
||||
|
||||
pong.setMotd(mainMotd.trim());
|
||||
pong.setSubMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
|
||||
pong.setPlayerCount(serverInfo.getPlayerInfo().getOnlinePlayers());
|
||||
pong.setMaximumPlayerCount(serverInfo.getPlayerInfo().getMaxPlayers());
|
||||
} else {
|
||||
pong.setMotd(config.getBedrock().getMotd1());
|
||||
pong.setSubMotd(config.getBedrock().getMotd2());
|
||||
}
|
||||
|
||||
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
pong.setPlayerCount(pingInfo.currentPlayerCount);
|
||||
pong.setMaximumPlayerCount(pingInfo.maxPlayerCount);
|
||||
} else {
|
||||
pong.setPlayerCount(connector.getPlayers().size());
|
||||
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
||||
pong.setMotd(config.getBedrock().getMotd1());
|
||||
pong.setMotd(config.getBedrock().getMotd2());
|
||||
}
|
||||
|
||||
//Bedrock will not even attempt a connection if the client thinks the server is full
|
||||
|
@ -105,4 +116,9 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
});
|
||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnhandledDatagram(ChannelHandlerContext ctx, DatagramPacket packet) {
|
||||
new QueryPacketHandler(connector, packet.sender(), packet.content());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.geysermc.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class QueryPacketHandler {
|
||||
|
||||
public static final byte HANDSHAKE = 0x09;
|
||||
public static final byte STATISTICS = 0x00;
|
||||
|
||||
private GeyserConnector connector;
|
||||
private InetSocketAddress sender;
|
||||
private byte type;
|
||||
private int sessionId;
|
||||
private byte[] token;
|
||||
|
||||
/**
|
||||
* The Query packet handler instance
|
||||
* @param connector Geyser Connector
|
||||
* @param sender The Sender IP/Port for the Query
|
||||
* @param buffer The Query data
|
||||
*/
|
||||
public QueryPacketHandler(GeyserConnector connector, InetSocketAddress sender, ByteBuf buffer) {
|
||||
if(!isQueryPacket(buffer))
|
||||
return;
|
||||
|
||||
this.connector = connector;
|
||||
this.sender = sender;
|
||||
this.type = buffer.readByte();
|
||||
this.sessionId = buffer.readInt();
|
||||
|
||||
regenerateToken();
|
||||
handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the packet is in fact a query packet
|
||||
* @param buffer Query data
|
||||
* @return if the packet is a query packet
|
||||
*/
|
||||
private boolean isQueryPacket(ByteBuf buffer) {
|
||||
return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the query
|
||||
*/
|
||||
private void handle() {
|
||||
switch (type) {
|
||||
case HANDSHAKE:
|
||||
sendToken();
|
||||
case STATISTICS:
|
||||
sendQueryData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the token to the sender
|
||||
*/
|
||||
private void sendToken() {
|
||||
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(10);
|
||||
reply.writeByte(HANDSHAKE);
|
||||
reply.writeInt(sessionId);
|
||||
reply.writeBytes(getTokenString(this.token, this.sender.getAddress()));
|
||||
reply.writeByte(0);
|
||||
|
||||
sendPacket(reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the query data to the sender
|
||||
*/
|
||||
private void sendQueryData() {
|
||||
ByteBuf reply = ByteBufAllocator.DEFAULT.ioBuffer(64);
|
||||
reply.writeByte(STATISTICS);
|
||||
reply.writeInt(sessionId);
|
||||
|
||||
// Game Info
|
||||
reply.writeBytes(getGameData());
|
||||
|
||||
// Players
|
||||
reply.writeBytes(getPlayers());
|
||||
|
||||
sendPacket(reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the game data for the query
|
||||
* @return the game data for the query
|
||||
*/
|
||||
private byte[] getGameData() {
|
||||
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
String motd;
|
||||
String currentPlayerCount;
|
||||
String maxPlayerCount;
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||
}
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
||||
String[] javaMotd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n");
|
||||
motd = javaMotd[0].trim(); // First line of the motd.
|
||||
} else {
|
||||
motd = connector.getConfig().getBedrock().getMotd1();
|
||||
}
|
||||
|
||||
// If passthrough player counts is enabled lets get players from the server
|
||||
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount);
|
||||
maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount);
|
||||
} else {
|
||||
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
||||
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
||||
}
|
||||
|
||||
// Create a hashmap of all game data needed in the query
|
||||
Map<String, String> gameData = new HashMap<String, String>();
|
||||
gameData.put("hostname", motd);
|
||||
gameData.put("gametype", "SMP");
|
||||
gameData.put("game_id", "MINECRAFT");
|
||||
gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
|
||||
gameData.put("plugins", "");
|
||||
gameData.put("map", GeyserConnector.NAME);
|
||||
gameData.put("numplayers", currentPlayerCount);
|
||||
gameData.put("maxplayers", maxPlayerCount);
|
||||
gameData.put("hostport", String.valueOf(connector.getConfig().getBedrock().getPort()));
|
||||
gameData.put("hostip", connector.getConfig().getBedrock().getAddress());
|
||||
|
||||
try {
|
||||
// Blank Buffer Bytes
|
||||
query.write("GeyserMC".getBytes());
|
||||
query.write((byte) 0x00);
|
||||
query.write((byte) 128);
|
||||
query.write((byte) 0x00);
|
||||
|
||||
// Fills the game data
|
||||
for(Map.Entry<String, String> entry : gameData.entrySet()) {
|
||||
query.write(entry.getKey().getBytes());
|
||||
query.write((byte) 0x00);
|
||||
query.write(entry.getValue().getBytes());
|
||||
query.write((byte) 0x00);
|
||||
}
|
||||
|
||||
// Final byte to show the end of the game data
|
||||
query.write(new byte[]{0x00, 0x01});
|
||||
return query.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getPlayers() {
|
||||
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) {
|
||||
pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation();
|
||||
}
|
||||
|
||||
try {
|
||||
// Start the player section
|
||||
query.write("player_".getBytes());
|
||||
query.write(new byte[]{0x00, 0x00});
|
||||
|
||||
// Fill player names
|
||||
if(pingInfo != null) {
|
||||
for (String username : pingInfo.getPlayers()) {
|
||||
query.write(username.getBytes());
|
||||
query.write((byte) 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Final byte to show the end of the player data
|
||||
query.write((byte) 0x00);
|
||||
return query.toByteArray();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the sender
|
||||
* @param data packet data
|
||||
*/
|
||||
private void sendPacket(ByteBuf data) {
|
||||
connector.getBedrockServer().getRakNet().send(sender, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates a token
|
||||
*/
|
||||
public void regenerateToken() {
|
||||
byte[] token = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
token[i] = (byte) new Random().nextInt(255);
|
||||
}
|
||||
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an MD5 token for the current IP/Port.
|
||||
* This should reset every 30 seconds but a new one is generated per instance
|
||||
* Seems wasteful to code something in to clear it when it has no use.
|
||||
* @param token the token
|
||||
* @param address the address
|
||||
* @return an MD5 token for the current IP/Port
|
||||
*/
|
||||
public static byte[] getTokenString(byte[] token, InetAddress address) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(token);
|
||||
return Arrays.copyOf(digest.digest(), 4);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import org.geysermc.common.AuthType;
|
|||
import org.geysermc.connector.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Registry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
||||
|
||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
|
@ -41,7 +41,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
private boolean translateAndDefault(BedrockPacket packet) {
|
||||
return Registry.BEDROCK.translate(packet.getClass(), packet, session);
|
||||
return PacketTranslatorRegistry.BEDROCK_TRANSLATOR.translate(packet.getClass(), packet, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,10 +58,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
PlayStatusPacket playStatus = new PlayStatusPacket();
|
||||
playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS);
|
||||
session.getUpstream().sendPacket(playStatus);
|
||||
session.sendUpstreamPacket(playStatus);
|
||||
|
||||
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
||||
session.getUpstream().sendPacket(resourcePacksInfo);
|
||||
session.sendUpstreamPacket(resourcePacksInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
stack.setExperimental(false);
|
||||
stack.setForcedToAccept(false);
|
||||
stack.setGameVersion("*");
|
||||
session.getUpstream().sendPacket(stack);
|
||||
session.sendUpstreamPacket(stack);
|
||||
break;
|
||||
default:
|
||||
session.disconnect("disconnectionScreen.resourcePack");
|
||||
|
@ -110,15 +110,19 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MovePlayerPacket packet) {
|
||||
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
|
||||
if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) {
|
||||
// TODO it is safer to key authentication on something that won't change (UUID, not username)
|
||||
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
||||
LoginEncryptionUtils.showLoginWindow(session);
|
||||
}
|
||||
// else we were able to log the user in
|
||||
return true;
|
||||
}
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MovePlayerPacket packet) {
|
||||
if (session.isLoggingIn()) {
|
||||
session.sendMessage("Please wait until you are logged in...");
|
||||
}
|
||||
|
|
|
@ -29,11 +29,13 @@ import com.github.steveice10.mc.auth.data.GameProfile;
|
|||
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
|
||||
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket;
|
||||
import com.github.steveice10.packetlib.Client;
|
||||
import com.github.steveice10.packetlib.event.session.*;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
|
@ -41,6 +43,7 @@ import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
|||
import com.nukkitx.math.GenericMath;
|
||||
import com.nukkitx.math.TrigMath;
|
||||
import com.nukkitx.math.vector.*;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
||||
|
@ -55,18 +58,22 @@ import org.geysermc.common.AuthType;
|
|||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
import org.geysermc.connector.network.session.auth.AuthData;
|
||||
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
||||
import org.geysermc.connector.network.session.cache.*;
|
||||
import org.geysermc.connector.network.translators.Registry;
|
||||
import org.geysermc.connector.network.translators.world.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.BiomeTranslator;
|
||||
import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
|
||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.ChunkUtils;
|
||||
import org.geysermc.connector.utils.LocaleUtils;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.world.WorldBorder;
|
||||
import org.geysermc.connector.utils.SkinUtils;
|
||||
import org.geysermc.floodgate.util.BedrockData;
|
||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||
|
||||
|
@ -154,11 +161,18 @@ public class GeyserSession implements CommandSender {
|
|||
private boolean manyDimPackets = false;
|
||||
private ServerRespawnPacket lastDimPacket = null;
|
||||
|
||||
@Setter
|
||||
private Entity ridingVehicleEntity;
|
||||
|
||||
@Setter
|
||||
private int craftSlot = 0;
|
||||
|
||||
@Setter
|
||||
private WorldBorder worldBorder; // Im just going to shove this here until i move some stuff around
|
||||
private WorldBorder worldBorder;
|
||||
@Setter
|
||||
private long lastWindowCloseTime = 0;
|
||||
|
||||
private MinecraftProtocol protocol;
|
||||
|
||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||
this.connector = connector;
|
||||
|
@ -188,16 +202,16 @@ public class GeyserSession implements CommandSender {
|
|||
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
||||
|
||||
BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket();
|
||||
biomeDefinitionListPacket.setTag(Toolbox.BIOMES);
|
||||
biomeDefinitionListPacket.setTag(BiomeTranslator.BIOMES);
|
||||
upstream.sendPacket(biomeDefinitionListPacket);
|
||||
|
||||
AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
|
||||
entityPacket.setTag(Toolbox.ENTITY_IDENTIFIERS);
|
||||
entityPacket.setTag(EntityIdentifierRegistry.ENTITY_IDENTIFIERS);
|
||||
upstream.sendPacket(entityPacket);
|
||||
|
||||
InventoryContentPacket creativePacket = new InventoryContentPacket();
|
||||
creativePacket.setContainerId(ContainerId.CREATIVE);
|
||||
creativePacket.setContents(Toolbox.CREATIVE_ITEMS);
|
||||
creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS);
|
||||
upstream.sendPacket(creativePacket);
|
||||
|
||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||
|
@ -205,6 +219,17 @@ public class GeyserSession implements CommandSender {
|
|||
upstream.sendPacket(playStatusPacket);
|
||||
}
|
||||
|
||||
public void fetchOurSkin(PlayerListPacket.Entry entry) {
|
||||
PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket();
|
||||
playerSkinPacket.setUuid(authData.getUUID());
|
||||
playerSkinPacket.setSkin(entry.getSkin());
|
||||
playerSkinPacket.setOldSkinName("OldName");
|
||||
playerSkinPacket.setNewSkinName("NewName");
|
||||
playerSkinPacket.setTrustedSkin(true);
|
||||
upstream.sendPacket(playerSkinPacket);
|
||||
getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID());
|
||||
}
|
||||
|
||||
public void login() {
|
||||
if (connector.getAuthType() != AuthType.ONLINE) {
|
||||
connector.getLogger().info(
|
||||
|
@ -231,7 +256,6 @@ public class GeyserSession implements CommandSender {
|
|||
// new thread so clients don't timeout
|
||||
new Thread(() -> {
|
||||
try {
|
||||
MinecraftProtocol protocol;
|
||||
if (password != null && !password.isEmpty()) {
|
||||
protocol = new MinecraftProtocol(username, password);
|
||||
} else {
|
||||
|
@ -329,13 +353,33 @@ public class GeyserSession implements CommandSender {
|
|||
lastDimPacket = event.getPacket();
|
||||
return;
|
||||
} else if (lastDimPacket != null) {
|
||||
Registry.JAVA.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this);
|
||||
lastDimPacket = null;
|
||||
}
|
||||
|
||||
Registry.JAVA.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
// Required, or else Floodgate players break with Bukkit chunk caching
|
||||
if (event.getPacket() instanceof LoginSuccessPacket) {
|
||||
GameProfile profile = ((LoginSuccessPacket) event.getPacket()).getProfile();
|
||||
playerEntity.setUsername(profile.getName());
|
||||
playerEntity.setUuid(profile.getId());
|
||||
|
||||
// Check if they are not using a linked account
|
||||
if (connector.getAuthType() == AuthType.OFFLINE || playerEntity.getUuid().getMostSignificantBits() == 0) {
|
||||
SkinUtils.handleBedrockSkin(playerEntity, clientData);
|
||||
}
|
||||
}
|
||||
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetError(PacketErrorEvent event) {
|
||||
connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage());
|
||||
if (connector.getConfig().isDebugMode())
|
||||
event.getCause().printStackTrace();
|
||||
event.setSuppress(true);
|
||||
}
|
||||
});
|
||||
|
||||
downstream.getSession().connect();
|
||||
|
@ -480,7 +524,7 @@ public class GeyserSession implements CommandSender {
|
|||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
startGamePacket.setBlockPalette(BlockTranslator.BLOCKS);
|
||||
startGamePacket.setItemEntries(Toolbox.ITEMS);
|
||||
startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||
startGamePacket.setVanillaVersion("*");
|
||||
// startGamePacket.setMovementServerAuthoritative(true);
|
||||
upstream.sendPacket(startGamePacket);
|
||||
|
@ -496,8 +540,47 @@ public class GeyserSession implements CommandSender {
|
|||
int teleportId = teleportCache.getTeleportConfirmId();
|
||||
teleportCache = null;
|
||||
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(teleportId);
|
||||
getDownstream().getSession().send(teleportConfirmPacket);
|
||||
sendDownstreamPacket(teleportConfirmPacket);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a packet to be sent to player.
|
||||
*
|
||||
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||
*/
|
||||
public void sendUpstreamPacket(BedrockPacket packet) {
|
||||
if (upstream != null && !upstream.isClosed()) {
|
||||
upstream.sendPacket(packet);
|
||||
} else {
|
||||
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " but the session was null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet immediately to the player.
|
||||
*
|
||||
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||
*/
|
||||
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
|
||||
if (upstream != null && !upstream.isClosed()) {
|
||||
upstream.sendPacketImmediately(packet);
|
||||
} else {
|
||||
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " immediately but the session was null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to the remote server.
|
||||
*
|
||||
* @param packet the java edition packet from MCProtocolLib
|
||||
*/
|
||||
public void sendDownstreamPacket(Packet packet) {
|
||||
if (downstream != null && downstream.getSession() != null && protocol.getSubProtocol().equals(SubProtocol.GAME)) {
|
||||
downstream.getSession().send(packet);
|
||||
} else {
|
||||
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,16 +24,26 @@ public class BedrockClientData {
|
|||
private String skinId;
|
||||
@JsonProperty(value = "SkinData")
|
||||
private String skinData;
|
||||
@JsonProperty(value = "SkinImageHeight")
|
||||
private int skinImageHeight;
|
||||
@JsonProperty(value = "SkinImageWidth")
|
||||
private int skinImageWidth;
|
||||
@JsonProperty(value = "CapeId")
|
||||
private String capeId;
|
||||
@JsonProperty(value = "CapeData")
|
||||
private byte[] capeData;
|
||||
@JsonProperty(value = "CapeImageHeight")
|
||||
private int capeImageHeight;
|
||||
@JsonProperty(value = "CapeImageWidth")
|
||||
private int capeImageWidth;
|
||||
@JsonProperty(value = "CapeOnClassicSkin")
|
||||
private boolean capeOnClassicSkin;
|
||||
@JsonProperty(value = "SkinResourcePatch")
|
||||
private String geometryName;
|
||||
@JsonProperty(value = "SkinGeometryData")
|
||||
private String geometryData;
|
||||
@JsonProperty(value = "PersonaSkin")
|
||||
private boolean personaSkin;
|
||||
@JsonProperty(value = "PremiumSkin")
|
||||
private boolean premiumSkin;
|
||||
|
||||
|
@ -60,6 +70,15 @@ public class BedrockClientData {
|
|||
@JsonProperty(value = "ClientRandomId")
|
||||
private long clientRandomId;
|
||||
|
||||
@JsonProperty(value = "ArmSize")
|
||||
private String armSize;
|
||||
@JsonProperty(value = "SkinAnimationData")
|
||||
private String skinAnimationData;
|
||||
@JsonProperty(value = "SkinColor")
|
||||
private String skinColor;
|
||||
@JsonProperty(value = "ThirdPartyNameOnly")
|
||||
private boolean thirdPartyNameOnly;
|
||||
|
||||
public enum UIProfile {
|
||||
@JsonEnumDefaultValue
|
||||
CLASSIC,
|
||||
|
|
|
@ -62,7 +62,7 @@ public class BossBar {
|
|||
bossEventPacket.setOverlay(overlay);
|
||||
bossEventPacket.setDarkenSky(darkenSky);
|
||||
|
||||
session.getUpstream().sendPacket(bossEventPacket);
|
||||
session.sendUpstreamPacket(bossEventPacket);
|
||||
}
|
||||
|
||||
public void updateTitle(Message title) {
|
||||
|
@ -72,7 +72,7 @@ public class BossBar {
|
|||
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
|
||||
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode()));
|
||||
|
||||
session.getUpstream().sendPacket(bossEventPacket);
|
||||
session.sendUpstreamPacket(bossEventPacket);
|
||||
}
|
||||
|
||||
public void updateHealth(float health) {
|
||||
|
@ -82,7 +82,7 @@ public class BossBar {
|
|||
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
|
||||
bossEventPacket.setHealthPercentage(health);
|
||||
|
||||
session.getUpstream().sendPacket(bossEventPacket);
|
||||
session.sendUpstreamPacket(bossEventPacket);
|
||||
}
|
||||
|
||||
public void removeBossBar() {
|
||||
|
@ -90,7 +90,7 @@ public class BossBar {
|
|||
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||
bossEventPacket.setAction(BossEventPacket.Action.HIDE);
|
||||
|
||||
session.getUpstream().sendPacket(bossEventPacket);
|
||||
session.sendUpstreamPacket(bossEventPacket);
|
||||
removeBossEntity();
|
||||
}
|
||||
|
||||
|
@ -104,18 +104,21 @@ public class BossBar {
|
|||
addEntityPacket.setRuntimeEntityId(entityId);
|
||||
addEntityPacket.setIdentifier("minecraft:creeper");
|
||||
addEntityPacket.setEntityType(33);
|
||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition());
|
||||
addEntityPacket.setPosition(session.getPlayerEntity().getPosition().sub(0D, -10D, 0D));
|
||||
addEntityPacket.setRotation(Vector3f.ZERO);
|
||||
addEntityPacket.setMotion(Vector3f.ZERO);
|
||||
addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work?
|
||||
addEntityPacket.getMetadata()
|
||||
.putFloat(EntityData.SCALE, 0F)
|
||||
.putFloat(EntityData.BOUNDING_BOX_WIDTH, 0F)
|
||||
.putFloat(EntityData.BOUNDING_BOX_HEIGHT, 0F);
|
||||
|
||||
session.getUpstream().sendPacket(addEntityPacket);
|
||||
session.sendUpstreamPacket(addEntityPacket);
|
||||
}
|
||||
|
||||
private void removeBossEntity() {
|
||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||
removeEntityPacket.setUniqueEntityId(entityId);
|
||||
|
||||
session.getUpstream().sendPacket(removeEntityPacket);
|
||||
session.sendUpstreamPacket(removeEntityPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.*;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
@ -49,6 +47,7 @@ public class EntityCache {
|
|||
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
|
||||
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
|
||||
private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
|
||||
@Getter
|
||||
private AtomicLong nextEntityId = new AtomicLong(2L);
|
||||
|
@ -148,4 +147,12 @@ public class EntityCache {
|
|||
playerEntities = null;
|
||||
bossBars = null;
|
||||
}
|
||||
|
||||
public long getCachedPlayerEntityLink(long playerId) {
|
||||
return cachedPlayerEntityLinks.getOrDefault(playerId, -1);
|
||||
}
|
||||
|
||||
public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) {
|
||||
cachedPlayerEntityLinks.put(playerId, linkedEntityId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class WindowCache {
|
|||
formRequestPacket.setFormId(id);
|
||||
formRequestPacket.setFormData(windows.get(id).getJSONData());
|
||||
|
||||
session.getUpstream().sendPacket(formRequestPacket);
|
||||
session.sendUpstreamPacket(formRequestPacket);
|
||||
}
|
||||
|
||||
public void showWindow(FormWindow window, int id) {
|
||||
|
@ -74,7 +74,7 @@ public class WindowCache {
|
|||
formRequestPacket.setFormId(id);
|
||||
formRequestPacket.setFormData(window.getJSONData());
|
||||
|
||||
session.getUpstream().sendPacket(formRequestPacket);
|
||||
session.sendUpstreamPacket(formRequestPacket);
|
||||
|
||||
addWindow(window, id);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
//Based off of ProtocolSupport's LegacyBiomeData.java https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java
|
||||
//Array index formula by https://wiki.vg/Chunk_Format
|
||||
|
||||
// Based off of ProtocolSupport's LegacyBiomeData.java:
|
||||
// https://github.com/ProtocolSupport/ProtocolSupport/blob/b2cad35977f3fcb65bee57b9e14fc9c975f71d32/src/protocolsupport/protocol/typeremapper/legacy/LegacyBiomeData.java
|
||||
// Array index formula by https://wiki.vg/Chunk_Format
|
||||
public class BiomeTranslator {
|
||||
|
||||
public static final CompoundTag BIOMES;
|
||||
|
||||
private BiomeTranslator() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load biomes */
|
||||
InputStream stream = FileUtils.getResource("bedrock/biome_definitions.dat");
|
||||
|
||||
CompoundTag biomesTag;
|
||||
|
||||
try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)){
|
||||
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
||||
BIOMES = biomesTag;
|
||||
} catch (Exception ex) {
|
||||
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toBedrockBiome(int[] biomeData) {
|
||||
byte[] bedrockData = new byte[256];
|
||||
if(biomeData == null) {
|
||||
if (biomeData == null) {
|
||||
return bedrockData;
|
||||
}
|
||||
|
||||
|
@ -24,12 +82,12 @@ public class BiomeTranslator {
|
|||
return bedrockData;
|
||||
}
|
||||
|
||||
protected static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) {
|
||||
private static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) {
|
||||
int offset = (z << 4) | x;
|
||||
Arrays.fill(legacyBiomeData, offset, offset + 4, (byte) biomeId);
|
||||
}
|
||||
|
||||
protected static byte biomeID(int[] biomeData, int x, int z) {
|
||||
private static byte biomeID(int[] biomeData, int x, int z) {
|
||||
return (byte) biomeData[((z >> 2) & 3) << 2 | ((x >> 2) & 3)];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Registry for entity identifiers.
|
||||
*/
|
||||
public class EntityIdentifierRegistry {
|
||||
|
||||
public static CompoundTag ENTITY_IDENTIFIERS;
|
||||
|
||||
private EntityIdentifierRegistry() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load entity identifiers */
|
||||
InputStream stream = FileUtils.getResource("bedrock/entity_identifiers.dat");
|
||||
|
||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
||||
ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to get entities from entity identifiers", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class ItemStackTranslator {
|
||||
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
if (itemStack.getNbt() == null) {
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount());
|
||||
}
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt()));
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData == null) return null;
|
||||
if (itemData.getTag() == null) {
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""));
|
||||
}
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag()));
|
||||
}
|
||||
|
||||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Tag<?>> javaValue = new HashMap<String, Tag<?>>();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue);
|
||||
return bedrockTag;
|
||||
}
|
||||
|
||||
private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) {
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
ByteArrayTag byteArrayTag = (ByteArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ByteTag) {
|
||||
ByteTag byteTag = (ByteTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof DoubleTag) {
|
||||
DoubleTag doubleTag = (DoubleTag) tag;
|
||||
return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof FloatTag) {
|
||||
FloatTag floatTag = (FloatTag) tag;
|
||||
return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntArrayTag) {
|
||||
IntArrayTag intArrayTag = (IntArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntTag) {
|
||||
IntTag intTag = (IntTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongArrayTag) {
|
||||
LongArrayTag longArrayTag = (LongArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongTag) {
|
||||
LongTag longTag = (LongTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ShortTag) {
|
||||
ShortTag shortTag = (ShortTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof StringTag) {
|
||||
StringTag stringTag = (StringTag) tag;
|
||||
return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
|
||||
List<Tag> tagList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) {
|
||||
tagList.add(translateToBedrockNBT(value));
|
||||
}
|
||||
Class clazz = CompoundTag.class;
|
||||
if (!tagList.isEmpty()) {
|
||||
clazz = tagList.get(0).getClass();
|
||||
}
|
||||
return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList);
|
||||
}
|
||||
|
||||
if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag;
|
||||
|
||||
return translateNbtToBedrock(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName());
|
||||
Map<String, com.github.steveice10.opennbt.tag.builtin.Tag> javaValue = javaTag.getValue();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str);
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
javaTag.setValue(javaValue);
|
||||
return javaTag;
|
||||
}
|
||||
|
||||
private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) {
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) {
|
||||
com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag;
|
||||
return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteTag) {
|
||||
com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag;
|
||||
return new ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) {
|
||||
com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag;
|
||||
return new DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.FloatTag) {
|
||||
com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag;
|
||||
return new FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) {
|
||||
com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag;
|
||||
return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntTag) {
|
||||
com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag;
|
||||
return new IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) {
|
||||
com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag;
|
||||
return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongTag) {
|
||||
com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag;
|
||||
return new LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ShortTag) {
|
||||
com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag;
|
||||
return new ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.StringTag) {
|
||||
com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag;
|
||||
return new StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ListTag) {
|
||||
com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag;
|
||||
|
||||
List<com.github.steveice10.opennbt.tag.builtin.Tag> tags = new ArrayList<>();
|
||||
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
|
||||
continue;
|
||||
|
||||
com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value;
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue);
|
||||
if (javaTag != null)
|
||||
tags.add(javaTag);
|
||||
}
|
||||
return new ListTag(listTag.getName(), tags);
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) {
|
||||
com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag;
|
||||
return translateToJavaNBT(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket;
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketTranslatorRegistry<T> {
|
||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> translators = new HashMap<>();
|
||||
|
||||
public static final PacketTranslatorRegistry<Packet> JAVA_TRANSLATOR = new PacketTranslatorRegistry<>();
|
||||
public static final PacketTranslatorRegistry<BedrockPacket> BEDROCK_TRANSLATOR = new PacketTranslatorRegistry<>();
|
||||
|
||||
private static final ObjectArrayList<Class<?>> IGNORED_PACKETS = new ObjectArrayList<>();
|
||||
|
||||
static {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(Translator.class)) {
|
||||
Class<?> packet = clazz.getAnnotation(Translator.class).packet();
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName());
|
||||
|
||||
try {
|
||||
if (Packet.class.isAssignableFrom(packet)) {
|
||||
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
|
||||
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
|
||||
|
||||
JAVA_TRANSLATOR.translators.put(targetPacket, translator);
|
||||
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
|
||||
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
|
||||
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
|
||||
|
||||
BEDROCK_TRANSLATOR.translators.put(targetPacket, translator);
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
IGNORED_PACKETS.add(ServerKeepAlivePacket.class); // Handled by MCProtocolLib
|
||||
IGNORED_PACKETS.add(ServerUpdateLightPacket.class); // Light is handled on Bedrock for us
|
||||
}
|
||||
|
||||
private PacketTranslatorRegistry() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
if (translators.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) translators.get(clazz)).translate(packet, session);
|
||||
return true;
|
||||
} else {
|
||||
if (!IGNORED_PACKETS.contains(clazz))
|
||||
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
|
||||
public class Registry<T> {
|
||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> MAP = new HashMap<>();
|
||||
|
||||
public static final Registry<Packet> JAVA = new Registry<>();
|
||||
public static final Registry<BedrockPacket> BEDROCK = new Registry<>();
|
||||
|
||||
public static void registerJava(Class<? extends Packet> targetPacket, PacketTranslator<? extends Packet> translator) {
|
||||
JAVA.MAP.put(targetPacket, translator);
|
||||
}
|
||||
|
||||
public static void registerBedrock(Class<? extends BedrockPacket> targetPacket, PacketTranslator<? extends BedrockPacket> translator) {
|
||||
BEDROCK.MAP.put(targetPacket, translator);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
if (MAP.containsKey(clazz)) {
|
||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||
return true;
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.*;
|
||||
import org.geysermc.connector.network.translators.inventory.*;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import com.github.steveice10.packetlib.packet.Packet;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTOutputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class Translators {
|
||||
|
||||
@Getter
|
||||
private static ItemTranslator itemTranslator;
|
||||
|
||||
@Getter
|
||||
private static Map<WindowType, InventoryTranslator> inventoryTranslators = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private static Map<String, BlockEntityTranslator> blockEntityTranslators = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private static ObjectArrayList<RequiresBlockState> requiresBlockStateMap = new ObjectArrayList<>();
|
||||
|
||||
private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag();
|
||||
public static final byte[] EMPTY_LEVEL_CHUNK_DATA;
|
||||
|
||||
static {
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size
|
||||
|
||||
try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) {
|
||||
stream.write(EMPTY_TAG);
|
||||
}
|
||||
|
||||
EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray();
|
||||
}catch (IOException e) {
|
||||
throw new AssertionError("Unable to generate empty level chunk data");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void start() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(Translator.class)) {
|
||||
Class<?> packet = clazz.getAnnotation(Translator.class).packet();
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName());
|
||||
|
||||
try {
|
||||
if (Packet.class.isAssignableFrom(packet)) {
|
||||
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
|
||||
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
|
||||
|
||||
Registry.registerJava(targetPacket, translator);
|
||||
|
||||
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
|
||||
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
|
||||
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
|
||||
|
||||
Registry.registerBedrock(targetPacket, translator);
|
||||
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
itemTranslator = new ItemTranslator();
|
||||
itemTranslator.init();
|
||||
BlockTranslator.init();
|
||||
|
||||
registerBlockEntityTranslators();
|
||||
registerInventoryTranslators();
|
||||
}
|
||||
|
||||
private static void registerBlockEntityTranslators() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity");
|
||||
|
||||
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
blockEntityTranslators.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance());
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
for (Class<?> clazz : ref.getSubTypesOf(RequiresBlockState.class)) {
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
requiresBlockStateMap.add((RequiresBlockState) clazz.newInstance());
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerInventoryTranslators() {
|
||||
inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||
inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
||||
inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
//inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
inventoryTranslators.put(WindowType.FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace);
|
||||
inventoryTranslators.put(WindowType.SMOKER, furnace);
|
||||
|
||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
||||
inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
|
||||
inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
|
||||
//inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
|
||||
}
|
||||
}
|
|
@ -64,44 +64,44 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
break;
|
||||
case START_SWIMMING:
|
||||
ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.getDownstream().getSession().send(startSwimPacket);
|
||||
session.sendDownstreamPacket(startSwimPacket);
|
||||
break;
|
||||
case STOP_SWIMMING:
|
||||
ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.getDownstream().getSession().send(stopSwimPacket);
|
||||
session.sendDownstreamPacket(stopSwimPacket);
|
||||
break;
|
||||
case START_GLIDE:
|
||||
case STOP_GLIDE:
|
||||
ClientPlayerStatePacket glidePacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_ELYTRA_FLYING);
|
||||
session.getDownstream().getSession().send(glidePacket);
|
||||
session.sendDownstreamPacket(glidePacket);
|
||||
break;
|
||||
case START_SNEAK:
|
||||
ClientPlayerStatePacket startSneakPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SNEAKING);
|
||||
session.getDownstream().getSession().send(startSneakPacket);
|
||||
session.sendDownstreamPacket(startSneakPacket);
|
||||
session.setSneaking(true);
|
||||
break;
|
||||
case STOP_SNEAK:
|
||||
ClientPlayerStatePacket stopSneakPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SNEAKING);
|
||||
session.getDownstream().getSession().send(stopSneakPacket);
|
||||
session.sendDownstreamPacket(stopSneakPacket);
|
||||
session.setSneaking(false);
|
||||
break;
|
||||
case START_SPRINT:
|
||||
ClientPlayerStatePacket startSprintPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.getDownstream().getSession().send(startSprintPacket);
|
||||
session.sendDownstreamPacket(startSprintPacket);
|
||||
session.setSprinting(true);
|
||||
break;
|
||||
case STOP_SPRINT:
|
||||
ClientPlayerStatePacket stopSprintPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.getDownstream().getSession().send(stopSprintPacket);
|
||||
session.sendDownstreamPacket(stopSprintPacket);
|
||||
session.setSprinting(false);
|
||||
break;
|
||||
case DROP_ITEM:
|
||||
ClientPlayerActionPacket dropItemPacket = new ClientPlayerActionPacket(PlayerAction.DROP_ITEM, position, BlockFace.values()[packet.getFace()]);
|
||||
session.getDownstream().getSession().send(dropItemPacket);
|
||||
session.sendDownstreamPacket(dropItemPacket);
|
||||
break;
|
||||
case STOP_SLEEP:
|
||||
ClientPlayerStatePacket stopSleepingPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.LEAVE_BED);
|
||||
session.getDownstream().getSession().send(stopSleepingPacket);
|
||||
session.sendDownstreamPacket(stopSleepingPacket);
|
||||
break;
|
||||
case BLOCK_INTERACT:
|
||||
// Handled in BedrockInventoryTransactionTranslator
|
||||
|
@ -109,19 +109,19 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
case START_BREAK:
|
||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(),
|
||||
packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]);
|
||||
session.getDownstream().getSession().send(startBreakingPacket);
|
||||
session.sendDownstreamPacket(startBreakingPacket);
|
||||
break;
|
||||
case CONTINUE_BREAK:
|
||||
LevelEventPacket continueBreakPacket = new LevelEventPacket();
|
||||
continueBreakPacket.setType(LevelEventType.PUNCH_BLOCK);
|
||||
continueBreakPacket.setData(BlockTranslator.getBedrockBlockId(session.getBreakingBlock() == null ? BlockTranslator.AIR : session.getBreakingBlock()));
|
||||
continueBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
||||
session.getUpstream().sendPacket(continueBreakPacket);
|
||||
session.sendUpstreamPacket(continueBreakPacket);
|
||||
break;
|
||||
case ABORT_BREAK:
|
||||
ClientPlayerActionPacket abortBreakingPacket = new ClientPlayerActionPacket(PlayerAction.CANCEL_DIGGING, new Position(packet.getBlockPosition().getX(),
|
||||
packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(abortBreakingPacket);
|
||||
session.sendDownstreamPacket(abortBreakingPacket);
|
||||
break;
|
||||
case STOP_BREAK:
|
||||
// Handled in BedrockInventoryTransactionTranslator
|
||||
|
@ -131,7 +131,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||
//sometimes the client doesn't feel like loading
|
||||
PlayStatusPacket spawnPacket = new PlayStatusPacket();
|
||||
spawnPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||
session.getUpstream().sendPacket(spawnPacket);
|
||||
session.sendUpstreamPacket(spawnPacket);
|
||||
entity.updateBedrockAttributes(session);
|
||||
session.getEntityCache().updateBossBars();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = AdventureSettingsPacket.class)
|
||||
public class BedrockAdventureSettingsTranslator extends PacketTranslator<AdventureSettingsPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(AdventureSettingsPacket packet, GeyserSession session) {
|
||||
// Only canFly and flying are used by the server
|
||||
// https://wiki.vg/Protocol#Player_Abilities_.28serverbound.29
|
||||
boolean canFly = packet.getFlags().contains(AdventureSettingsPacket.Flag.MAY_FLY);
|
||||
boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING);
|
||||
boolean creative = session.getGameMode() == GameMode.CREATIVE;
|
||||
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(
|
||||
false, canFly, flying, creative, 0.05f, 0.1f
|
||||
);
|
||||
session.sendDownstreamPacket(abilitiesPacket);
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerSwingArmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -38,6 +39,9 @@ import java.util.concurrent.TimeUnit;
|
|||
@Translator(packet = AnimatePacket.class)
|
||||
public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||
|
||||
private boolean isSteeringLeft;
|
||||
private boolean isSteeringRight;
|
||||
|
||||
@Override
|
||||
public void translate(AnimatePacket packet, GeyserSession session) {
|
||||
// Stop the player sending animations before they have fully spawned into the server
|
||||
|
@ -49,11 +53,23 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
|||
case SWING_ARM:
|
||||
// Delay so entity damage can be processed first
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
session.getDownstream().getSession().send(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
|
||||
session.sendDownstreamPacket(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
|
||||
25,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
break;
|
||||
// These two might need to be flipped, but my recommendation is getting moving working first
|
||||
case ROW_LEFT:
|
||||
// Packet value is a float of how long one has been rowing, so we convert that into a boolean
|
||||
isSteeringLeft = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerLeftPacket);
|
||||
break;
|
||||
case ROW_RIGHT:
|
||||
isSteeringRight = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerRightPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
|
|||
// Put the final line on since it isn't done in the for loop
|
||||
if (iterator < lines.length) lines[iterator] = newMessage.toString();
|
||||
ClientUpdateSignPacket clientUpdateSignPacket = new ClientUpdateSignPacket(pos, lines);
|
||||
session.getDownstream().getSession().send(clientUpdateSignPacket);
|
||||
session.sendDownstreamPacket(clientUpdateSignPacket);
|
||||
//TODO (potentially): originally I was going to update the sign blocks so Bedrock and Java users would match visually
|
||||
// However Java can still store a lot per-line and visuals are still messed up so that doesn't work
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientMoveItemToHotbarPacket;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
@Translator(packet = BlockPickRequestPacket.class)
|
||||
public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator<BlockPickRequestPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(BlockPickRequestPacket packet, GeyserSession session) {
|
||||
Vector3i vector = packet.getBlockPosition();
|
||||
BlockState blockToPick = session.getConnector().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ());
|
||||
|
||||
// Block is air - chunk caching is probably off
|
||||
if (blockToPick.getId() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the inventory to choose a slot to pick
|
||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
||||
if (inventory == null) {
|
||||
inventory = session.getInventory();
|
||||
}
|
||||
|
||||
String targetIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockToPick).split("\\[")[0];
|
||||
|
||||
// Check hotbar for item
|
||||
for (int i = 36; i < 45; i++) {
|
||||
if (inventory.getItem(i) == null) {
|
||||
continue;
|
||||
}
|
||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
||||
// If this isn't the item we're looking for
|
||||
if (!item.getJavaIdentifier().equals(targetIdentifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket();
|
||||
hotbarPacket.setContainerId(0);
|
||||
// Java inventory slot to hotbar slot ID
|
||||
hotbarPacket.setSelectedHotbarSlot(i - 36);
|
||||
hotbarPacket.setSelectHotbarSlot(true);
|
||||
session.sendUpstreamPacket(hotbarPacket);
|
||||
session.getInventory().setHeldItemSlot(i - 36);
|
||||
// Don't check inventory if item was in hotbar
|
||||
return;
|
||||
}
|
||||
|
||||
// Check inventory for item
|
||||
for (int i = 9; i < 36; i++) {
|
||||
if (inventory.getItem(i) == null) {
|
||||
continue;
|
||||
}
|
||||
ItemEntry item = ItemRegistry.getItem(inventory.getItem(i));
|
||||
// If this isn't the item we're looking for
|
||||
if (!item.getJavaIdentifier().equals(targetIdentifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClientMoveItemToHotbarPacket packetToSend = new ClientMoveItemToHotbarPacket(i); // https://wiki.vg/Protocol#Pick_Item
|
||||
session.sendDownstreamPacket(packetToSend);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
|||
}
|
||||
|
||||
ClientChatPacket chatPacket = new ClientChatPacket(message);
|
||||
session.getDownstream().getSession().send(chatPacket);
|
||||
session.sendDownstreamPacket(chatPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,17 +38,21 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
|||
|
||||
@Override
|
||||
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
||||
session.setLastWindowCloseTime(0);
|
||||
byte windowId = packet.getWindowId();
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (windowId == -1) { //player inventory or crafting table
|
||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||
if (openInventory != null) {
|
||||
windowId = (byte) openInventory.getId();
|
||||
} else {
|
||||
windowId = 0;
|
||||
}
|
||||
}
|
||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||
session.getDownstream().getSession().send(closeWindowPacket);
|
||||
InventoryUtils.closeInventory(session, windowId);
|
||||
|
||||
if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) {
|
||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||
session.getDownstream().getSession().send(closeWindowPacket);
|
||||
InventoryUtils.closeInventory(session, windowId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
|
|||
switch (packet.getType()) {
|
||||
// Resend the packet so we get the eating sounds
|
||||
case EATING_ITEM:
|
||||
session.getUpstream().sendPacket(packet);
|
||||
session.sendUpstreamPacket(packet);
|
||||
return;
|
||||
}
|
||||
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -32,9 +34,11 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
@Translator(packet = InteractPacket.class)
|
||||
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
||||
|
@ -47,17 +51,69 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||
|
||||
switch (packet.getAction()) {
|
||||
case INTERACT:
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD) {
|
||||
break;
|
||||
}
|
||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(interactPacket);
|
||||
session.sendDownstreamPacket(interactPacket);
|
||||
break;
|
||||
case DAMAGE:
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(attackPacket);
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
case LEAVE_VEHICLE:
|
||||
ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SNEAKING);
|
||||
session.sendDownstreamPacket(sneakPacket);
|
||||
session.setRidingVehicleEntity(null);
|
||||
break;
|
||||
case MOUSEOVER:
|
||||
// Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc
|
||||
if (packet.getRuntimeEntityId() != 0) {
|
||||
Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
||||
if (interactEntity == null)
|
||||
return;
|
||||
|
||||
String interactiveTag;
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case PIG:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = "action.interact.mount";
|
||||
} else interactiveTag = "";
|
||||
break;
|
||||
case HORSE:
|
||||
case SKELETON_HORSE:
|
||||
case ZOMBIE_HORSE:
|
||||
case DONKEY:
|
||||
case MULE:
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
interactiveTag = "action.interact.ride.horse";
|
||||
} else {
|
||||
interactiveTag = "action.interact.mount";
|
||||
}
|
||||
break;
|
||||
case BOAT:
|
||||
interactiveTag = "action.interact.ride.boat";
|
||||
break;
|
||||
case MINECART:
|
||||
interactiveTag = "action.interact.ride.minecart";
|
||||
break;
|
||||
default:
|
||||
return; // No need to process any further since there is no interactive tag
|
||||
}
|
||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
} else {
|
||||
if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) ||
|
||||
!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) {
|
||||
// No interactive tag should be sent
|
||||
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
|
@ -48,9 +49,9 @@ import org.geysermc.connector.inventory.Inventory;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
@ -64,12 +65,12 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
case NORMAL:
|
||||
Inventory inventory = session.getInventoryCache().getOpenInventory();
|
||||
if (inventory == null) inventory = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
|
||||
break;
|
||||
case INVENTORY_MISMATCH:
|
||||
Inventory inv = session.getInventoryCache().getOpenInventory();
|
||||
if (inv == null) inv = session.getInventory();
|
||||
Translators.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv);
|
||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(inv.getWindowType()).updateInventory(session, inv);
|
||||
InventoryUtils.updateCursor(session);
|
||||
break;
|
||||
case ITEM_USE:
|
||||
|
@ -84,8 +85,8 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
||||
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(interactPacket);
|
||||
session.getDownstream().getSession().send(interactAtPacket);
|
||||
session.sendDownstreamPacket(interactPacket);
|
||||
session.sendDownstreamPacket(interactAtPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
Hand.MAIN_HAND,
|
||||
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
|
||||
false);
|
||||
session.getDownstream().getSession().send(blockPacket);
|
||||
session.sendDownstreamPacket(blockPacket);
|
||||
|
||||
// Otherwise boats will not be able to be placed in survival
|
||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BOAT) {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
Vector3i blockPos = packet.getBlockPosition();
|
||||
// TODO: Find a better way to do this?
|
||||
switch (packet.getFace()) {
|
||||
|
@ -118,7 +126,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
blockPos = blockPos.add(1, 0, 0);
|
||||
break;
|
||||
}
|
||||
ItemEntry handItem = Translators.getItemTranslator().getItem(packet.getItemInHand());
|
||||
ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand());
|
||||
if (handItem.isBlock()) {
|
||||
session.setLastBlockPlacePosition(blockPos);
|
||||
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
||||
|
@ -127,11 +135,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
session.setInteracting(true);
|
||||
break;
|
||||
case 1:
|
||||
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
|
||||
ItemStack shieldSlot = session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36);
|
||||
if (shieldSlot != null && shieldSlot.getId() == ItemRegistry.SHIELD) {
|
||||
break;
|
||||
} // Handled in Entity.java
|
||||
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(useItemPacket);
|
||||
session.sendDownstreamPacket(useItemPacket);
|
||||
// Used for sleeping in beds
|
||||
session.setLastInteractionPosition(packet.getBlockPosition());
|
||||
break;
|
||||
case 2:
|
||||
BlockState blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
||||
|
@ -144,21 +155,21 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
blockBreakPacket.setType(LevelEventType.DESTROY);
|
||||
blockBreakPacket.setPosition(packet.getBlockPosition().toFloat());
|
||||
blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState));
|
||||
session.getUpstream().sendPacket(blockBreakPacket);
|
||||
session.sendUpstreamPacket(blockBreakPacket);
|
||||
}
|
||||
|
||||
if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) &&
|
||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||
InteractAction.ATTACK);
|
||||
session.getDownstream().getSession().send(attackPacket);
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
}
|
||||
|
||||
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
|
||||
Position pos = new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
||||
ClientPlayerActionPacket breakPacket = new ClientPlayerActionPacket(action, pos, BlockFace.values()[packet.getFace()]);
|
||||
session.getDownstream().getSession().send(breakPacket);
|
||||
session.sendDownstreamPacket(breakPacket);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -167,7 +178,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
// Followed to the Minecraft Protocol specification outlined at wiki.vg
|
||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0,0,0),
|
||||
BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(releaseItemPacket);
|
||||
session.sendDownstreamPacket(releaseItemPacket);
|
||||
}
|
||||
break;
|
||||
case ITEM_USE_ON_ENTITY:
|
||||
|
@ -183,15 +194,15 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
InteractAction.INTERACT, Hand.MAIN_HAND);
|
||||
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(interactPacket);
|
||||
session.getDownstream().getSession().send(interactAtPacket);
|
||||
session.sendDownstreamPacket(interactPacket);
|
||||
session.sendDownstreamPacket(interactAtPacket);
|
||||
|
||||
EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity);
|
||||
break;
|
||||
case 1: //Attack
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||
InteractAction.ATTACK);
|
||||
session.getDownstream().getSession().send(attackPacket);
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator<ItemFra
|
|||
Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), y, packet.getBlockPosition().getZ());
|
||||
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, position),
|
||||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
||||
session.getDownstream().getSession().send(interactPacket);
|
||||
session.sendDownstreamPacket(interactPacket);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,6 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator<LevelSoun
|
|||
@Override
|
||||
public void translate(LevelSoundEventPacket packet, GeyserSession session) {
|
||||
// lol what even :thinking:
|
||||
session.getUpstream().sendPacket(packet);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,6 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||
session.getInventory().setHeldItemSlot(packet.getHotbarSlot());
|
||||
|
||||
ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot());
|
||||
session.getDownstream().getSession().send(changeHeldItemPacket);
|
||||
session.sendDownstreamPacket(changeHeldItemPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Used for horses
|
||||
@Translator(packet = MoveEntityAbsolutePacket.class)
|
||||
public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEntityAbsolutePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(MoveEntityAbsolutePacket packet, GeyserSession session) {
|
||||
|
||||
ClientVehicleMovePacket clientVehicleMovePacket = new ClientVehicleMovePacket(
|
||||
packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(),
|
||||
packet.getRotation().getY() - 90, packet.getRotation().getX()
|
||||
);
|
||||
session.sendDownstreamPacket(clientVehicleMovePacket);
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
moveEntityBack.setRotation(entity.getBedrockRotation());
|
||||
moveEntityBack.setTeleported(true);
|
||||
moveEntityBack.setOnGround(true);
|
||||
session.getUpstream().sendPacketImmediately(moveEntityBack);
|
||||
session.sendUpstreamPacketImmediately(moveEntityBack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY());
|
||||
entity.setPosition(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0));
|
||||
entity.setRotation(rotation);
|
||||
entity.setOnGround(packet.isOnGround());
|
||||
|
||||
/*
|
||||
boolean colliding = false;
|
||||
|
@ -97,7 +98,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
|
||||
if (!colliding)
|
||||
*/
|
||||
session.getDownstream().getSession().send(playerPositionRotationPacket);
|
||||
session.sendDownstreamPacket(playerPositionRotationPacket);
|
||||
}
|
||||
|
||||
public boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) {
|
||||
|
@ -130,13 +131,13 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
|
||||
entityDataPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
entityDataPacket.getMetadata().putAll(entity.getMetadata());
|
||||
session.getUpstream().sendPacket(entityDataPacket);
|
||||
session.sendUpstreamPacket(entityDataPacket);
|
||||
|
||||
MovePlayerPacket movePlayerPacket = new MovePlayerPacket();
|
||||
movePlayerPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
movePlayerPacket.setPosition(entity.getPosition());
|
||||
movePlayerPacket.setRotation(entity.getBedrockRotation());
|
||||
movePlayerPacket.setMode(MovePlayerPacket.Mode.RESET);
|
||||
session.getUpstream().sendPacket(movePlayerPacket);
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerVehiclePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerInputPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Makes minecarts respond to player input
|
||||
@Translator(packet = PlayerInputPacket.class)
|
||||
public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(PlayerInputPacket packet, GeyserSession session) {
|
||||
ClientSteerVehiclePacket clientSteerVehiclePacket = new ClientSteerVehiclePacket(
|
||||
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
|
||||
);
|
||||
|
||||
session.sendDownstreamPacket(clientSteerVehiclePacket);
|
||||
}
|
||||
}
|
|
@ -44,10 +44,10 @@ public class BedrockRespawnTranslator extends PacketTranslator<RespawnPacket> {
|
|||
respawnPacket.setRuntimeEntityId(0);
|
||||
respawnPacket.setPosition(Vector3f.ZERO);
|
||||
respawnPacket.setState(RespawnPacket.State.SERVER_SEARCHING);
|
||||
session.getUpstream().sendPacket(respawnPacket);
|
||||
session.sendUpstreamPacket(respawnPacket);
|
||||
|
||||
ClientRequestPacket javaRespawnPacket = new ClientRequestPacket(ClientRequest.RESPAWN);
|
||||
session.getDownstream().getSession().send(javaRespawnPacket);
|
||||
session.sendDownstreamPacket(javaRespawnPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class BedrockShowCreditsTranslator extends PacketTranslator<ShowCreditsPa
|
|||
public void translate(ShowCreditsPacket packet, GeyserSession session) {
|
||||
if (packet.getStatus() == ShowCreditsPacket.Status.END_CREDITS) {
|
||||
ClientRequestPacket javaRespawnPacket = new ClientRequestPacket(ClientRequest.RESPAWN);
|
||||
session.getDownstream().getSession().send(javaRespawnPacket);
|
||||
session.sendDownstreamPacket(javaRespawnPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,6 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
|
|||
}
|
||||
|
||||
ClientChatPacket chatPacket = new ClientChatPacket(message);
|
||||
session.getDownstream().getSession().send(chatPacket);
|
||||
session.sendDownstreamPacket(chatPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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:
|
||||
* 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 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.
|
||||
* 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
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
package org.geysermc.connector.network.translators.effect;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.effect.Effect;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class EffectUtils {
|
||||
/**
|
||||
* Registry for particles and effects.
|
||||
*/
|
||||
public class EffectRegistry {
|
||||
|
||||
public static final Map<String, Effect> EFFECTS = new HashMap<>();
|
||||
public static final Int2ObjectMap<SoundEvent> RECORDS = new Int2ObjectOpenHashMap<>();
|
||||
|
@ -57,10 +58,10 @@ public class EffectUtils {
|
|||
|
||||
static {
|
||||
/* Load particles */
|
||||
InputStream particleStream = Toolbox.getResource("mappings/particles.json");
|
||||
InputStream particleStream = FileUtils.getResource("mappings/particles.json");
|
||||
JsonNode particleEntries;
|
||||
try {
|
||||
particleEntries = Toolbox.JSON_MAPPER.readTree(particleStream);
|
||||
particleEntries = GeyserConnector.JSON_MAPPER.readTree(particleStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load particle map", e);
|
||||
}
|
||||
|
@ -69,10 +70,10 @@ public class EffectUtils {
|
|||
while (particlesIterator.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = particlesIterator.next();
|
||||
try {
|
||||
setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase()));
|
||||
particleTypeMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase()));
|
||||
} catch (IllegalArgumentException e1) {
|
||||
try {
|
||||
setIdentifier(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText());
|
||||
particleStringMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText());
|
||||
GeyserConnector.getInstance().getLogger().debug("Force to map particle "
|
||||
+ entry.getKey()
|
||||
+ "=>"
|
||||
|
@ -85,10 +86,10 @@ public class EffectUtils {
|
|||
}
|
||||
|
||||
/* Load effects */
|
||||
InputStream effectsStream = Toolbox.getResource("mappings/effects.json");
|
||||
InputStream effectsStream = FileUtils.getResource("mappings/effects.json");
|
||||
JsonNode effects;
|
||||
try {
|
||||
effects = Toolbox.JSON_MAPPER.readTree(effectsStream);
|
||||
effects = GeyserConnector.JSON_MAPPER.readTree(effectsStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load effects mappings", e);
|
||||
}
|
||||
|
@ -112,14 +113,6 @@ public class EffectUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void setIdentifier(ParticleType type, LevelEventType identifier) {
|
||||
particleTypeMap.put(type, identifier);
|
||||
}
|
||||
|
||||
public static void setIdentifier(ParticleType type, String identifier) {
|
||||
particleStringMap.put(type, identifier);
|
||||
}
|
||||
|
||||
public static LevelEventType getParticleLevelEventType(@NonNull ParticleType type) {
|
||||
return particleTypeMap.getOrDefault(type, null);
|
||||
}
|
||||
|
@ -127,5 +120,4 @@ public class EffectUtils {
|
|||
public static String getParticleString(@NonNull ParticleType type){
|
||||
return particleStringMap.getOrDefault(type, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -108,7 +108,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator {
|
|||
rename = "";
|
||||
}
|
||||
ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
|
||||
session.getDownstream().getSession().send(renameItemPacket);
|
||||
session.sendDownstreamPacket(renameItemPacket);
|
||||
}
|
||||
if (anvilResult != null) {
|
||||
//client will send another packet to grab anvil output
|
||||
|
@ -138,7 +138,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator {
|
|||
rename = "";
|
||||
}
|
||||
ClientRenameItemPacket renameItemPacket = new ClientRenameItemPacket(rename);
|
||||
session.getDownstream().getSession().send(renameItemPacket);
|
||||
session.sendDownstreamPacket(renameItemPacket);
|
||||
}
|
||||
}
|
||||
super.updateSlot(session, inventory, slot);
|
||||
|
|
|
@ -44,7 +44,7 @@ public class BrewingInventoryTranslator extends BlockInventoryTranslator {
|
|||
dataPacket.setWindowId((byte) inventory.getId());
|
||||
dataPacket.setProperty(ContainerSetDataPacket.BREWING_STAND_FUEL_TOTAL);
|
||||
dataPacket.setValue(20);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +62,7 @@ public class BrewingInventoryTranslator extends BlockInventoryTranslator {
|
|||
return;
|
||||
}
|
||||
dataPacket.setValue(value);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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.inventory;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public ChestInventoryTranslator(int size, int paddedSize) {
|
||||
super(size);
|
||||
this.updater = new ChestInventoryUpdater(paddedSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateActions(GeyserSession session, Inventory inventory, List<InventoryActionData> actions) {
|
||||
for (InventoryActionData action : actions) {
|
||||
if (action.getSource().getContainerId() == inventory.getId()) {
|
||||
if (action.getSlot() >= size) {
|
||||
updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.translateActions(session, inventory, actions);
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator {
|
|||
containerOpenPacket.setType((byte) ContainerType.WORKBENCH.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
session.sendUpstreamPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,7 +92,10 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator {
|
|||
|
||||
@Override
|
||||
public int javaSlotToBedrock(int slot) {
|
||||
return slot == 0 ? 50 : slot + 31;
|
||||
if (slot < size) {
|
||||
return slot == 0 ? 50 : slot + 31;
|
||||
}
|
||||
return super.javaSlotToBedrock(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,15 +39,13 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
||||
public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
private final int blockId;
|
||||
private final InventoryUpdater updater;
|
||||
|
||||
public DoubleChestInventoryTranslator(int size) {
|
||||
super(size);
|
||||
super(size, 54);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
||||
this.updater = new ChestInventoryUpdater(54);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,7 +58,7 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
blockPacket.setBlockPosition(position);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
CompoundTag tag = CompoundTag.builder()
|
||||
.stringTag("id", "Chest")
|
||||
|
@ -73,14 +71,14 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(position);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
|
||||
blockPacket = new UpdateBlockPacket();
|
||||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(pairPosition);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
tag = CompoundTag.builder()
|
||||
.stringTag("id", "Chest")
|
||||
|
@ -93,7 +91,7 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(pairPosition);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
|
||||
inventory.setHolderPosition(position);
|
||||
}
|
||||
|
@ -105,7 +103,7 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
containerOpenPacket.setType((byte) ContainerType.CONTAINER.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
session.sendUpstreamPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,7 +115,7 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
|
||||
holderPos = holderPos.add(Vector3i.UNIT_X);
|
||||
pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ());
|
||||
|
@ -126,16 +124,6 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
|||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory(GeyserSession session, Inventory inventory) {
|
||||
updater.updateInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
|
||||
updater.updateSlot(this, session, inventory, slot);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class FurnaceInventoryTranslator extends BlockInventoryTranslator {
|
|||
return;
|
||||
}
|
||||
dataPacket.setValue(value);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,15 +25,50 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.InventoryActionData;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@AllArgsConstructor
|
||||
public abstract class InventoryTranslator {
|
||||
|
||||
public static final Map<WindowType, InventoryTranslator> INVENTORY_TRANSLATORS = new HashMap<WindowType, InventoryTranslator>() {
|
||||
{
|
||||
put(null, new PlayerInventoryTranslator()); //player inventory
|
||||
put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
|
||||
put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
|
||||
put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
|
||||
put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
|
||||
put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
|
||||
put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
|
||||
put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
|
||||
put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||
|
||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||
put(WindowType.FURNACE, furnace);
|
||||
put(WindowType.BLAST_FURNACE, furnace);
|
||||
put(WindowType.SMOKER, furnace);
|
||||
|
||||
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
|
||||
put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
|
||||
put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
|
||||
put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
|
||||
//put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
|
||||
}
|
||||
};
|
||||
|
||||
public final int size;
|
||||
|
||||
public abstract void prepareInventory(GeyserSession session, Inventory inventory);
|
||||
|
|
|
@ -34,17 +34,17 @@ import com.nukkitx.protocol.bedrock.data.InventorySource;
|
|||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||
private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(
|
||||
"The creative crafting grid is\nunavailable in Java Edition");
|
||||
|
||||
public PlayerInventoryTranslator() {
|
||||
super(46);
|
||||
|
@ -59,30 +59,30 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
ItemData[] contents = new ItemData[36];
|
||||
// Inventory
|
||||
for (int i = 9; i < 36; i++) {
|
||||
contents[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
// Hotbar
|
||||
for (int i = 36; i < 45; i++) {
|
||||
contents[i - 36] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
inventoryContentPacket.setContents(contents);
|
||||
session.getUpstream().sendPacket(inventoryContentPacket);
|
||||
session.sendUpstreamPacket(inventoryContentPacket);
|
||||
|
||||
// Armor
|
||||
InventoryContentPacket armorContentPacket = new InventoryContentPacket();
|
||||
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
||||
contents = new ItemData[4];
|
||||
for (int i = 5; i < 9; i++) {
|
||||
contents[i - 5] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
armorContentPacket.setContents(contents);
|
||||
session.getUpstream().sendPacket(armorContentPacket);
|
||||
session.sendUpstreamPacket(armorContentPacket);
|
||||
|
||||
// Offhand
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(45))});
|
||||
session.getUpstream().sendPacket(offhandPacket);
|
||||
offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))});
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,12 +98,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
slotPacket.setSlot(i + 27);
|
||||
|
||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, new ItemStack(Toolbox.BARRIER_INDEX)));
|
||||
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
||||
}else{
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)));
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||
}
|
||||
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,13 +125,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(slot + 27);
|
||||
}
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
} else if (slot == 45) {
|
||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
||||
offhandPacket.setContents(new ItemData[]{Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(slot))});
|
||||
session.getUpstream().sendPacket(offhandPacket);
|
||||
offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))});
|
||||
session.sendUpstreamPacket(offhandPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,23 +201,23 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
|||
if (action.getToItem().getId() == 0) {
|
||||
javaItem = new ItemStack(-1, 0, null);
|
||||
} else {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem());
|
||||
javaItem = ItemTranslator.translateToJava(action.getToItem());
|
||||
}
|
||||
ClientCreativeInventoryActionPacket creativePacket = new ClientCreativeInventoryActionPacket(javaSlot, javaItem);
|
||||
session.getDownstream().getSession().send(creativePacket);
|
||||
session.sendDownstreamPacket(creativePacket);
|
||||
inventory.setItem(javaSlot, javaItem);
|
||||
break;
|
||||
case ContainerId.CURSOR:
|
||||
if (action.getSlot() == 0) {
|
||||
session.getInventory().setCursor(Translators.getItemTranslator().translateToJava(session, action.getToItem()));
|
||||
session.getInventory().setCursor(ItemTranslator.translateToJava(action.getToItem()));
|
||||
}
|
||||
break;
|
||||
case ContainerId.NONE:
|
||||
if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION
|
||||
&& action.getSource().getFlag() == InventorySource.Flag.DROP_ITEM) {
|
||||
javaItem = Translators.getItemTranslator().translateToJava(session, action.getToItem());
|
||||
javaItem = ItemTranslator.translateToJava(action.getToItem());
|
||||
ClientCreativeInventoryActionPacket creativeDropPacket = new ClientCreativeInventoryActionPacket(-1, javaItem);
|
||||
session.getDownstream().getSession().send(creativeDropPacket);
|
||||
session.sendDownstreamPacket(creativeDropPacket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,35 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||
import com.nukkitx.protocol.bedrock.data.ContainerType;
|
||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder;
|
||||
import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
||||
public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
|
||||
private final InventoryHolder holder;
|
||||
|
||||
public class SingleChestInventoryTranslator extends BlockInventoryTranslator {
|
||||
public SingleChestInventoryTranslator(int size) {
|
||||
super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27));
|
||||
super(size, 27);
|
||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||
this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.prepareInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.openInventory(this, session, inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInventory(GeyserSession session, Inventory inventory) {
|
||||
holder.closeInventory(this, session, inventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,8 +104,8 @@ class ClickPlan {
|
|||
break;
|
||||
}
|
||||
}
|
||||
session.getDownstream().getSession().send(clickPacket);
|
||||
session.getDownstream().getSession().send(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true));
|
||||
session.sendDownstreamPacket(clickPacket);
|
||||
session.sendDownstreamPacket(new ClientConfirmTransactionPacket(inventory.getId(), actionId, true));
|
||||
}
|
||||
|
||||
/*if (refresh) {
|
||||
|
|
|
@ -38,9 +38,9 @@ import com.nukkitx.protocol.bedrock.data.InventorySource;
|
|||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.inventory.SlotType;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -61,13 +61,13 @@ public class InventoryActionDataTranslator {
|
|||
worldAction = action;
|
||||
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
|
||||
cursorAction = action;
|
||||
ItemData translatedCursor = Translators.getItemTranslator().translateToBedrock(session, session.getInventory().getCursor());
|
||||
ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor());
|
||||
if (!translatedCursor.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
} else {
|
||||
containerAction = action;
|
||||
ItemData translatedItem = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
|
||||
ItemData translatedItem = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
|
||||
if (!translatedItem.equals(action.getFromItem())) {
|
||||
refresh = true;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class InventoryActionDataTranslator {
|
|||
ClientPlayerActionPacket actionPacket = new ClientPlayerActionPacket(
|
||||
sourceAction.getToItem().getCount() == 0 ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM,
|
||||
new Position(0, 0, 0), BlockFace.DOWN);
|
||||
session.getDownstream().getSession().send(actionPacket);
|
||||
session.sendDownstreamPacket(actionPacket);
|
||||
ItemStack item = session.getInventory().getItem(heldSlot);
|
||||
if (item != null) {
|
||||
session.getInventory().setItem(heldSlot, new ItemStack(item.getId(), item.getAmount() - 1, item.getNbt()));
|
||||
|
@ -110,14 +110,14 @@ public class InventoryActionDataTranslator {
|
|||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, null, WindowAction.DROP_ITEM,
|
||||
DropItemParam.DROP_SELECTED_STACK);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
session.sendDownstreamPacket(dropPacket);
|
||||
} else {
|
||||
for (int i = 0; i < dropAmount; i++) {
|
||||
ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(),
|
||||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, null, WindowAction.DROP_ITEM,
|
||||
DropItemParam.DROP_FROM_SELECTED);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
session.sendDownstreamPacket(dropPacket);
|
||||
}
|
||||
}
|
||||
ItemStack item = session.getInventory().getItem(javaSlot);
|
||||
|
@ -129,7 +129,7 @@ public class InventoryActionDataTranslator {
|
|||
ClientWindowActionPacket dropPacket = new ClientWindowActionPacket(inventory.getId(), inventory.getTransactionId().getAndIncrement(),
|
||||
-999, null, WindowAction.CLICK_ITEM,
|
||||
dropAmount > 1 ? ClickItemParam.LEFT_CLICK : ClickItemParam.RIGHT_CLICK);
|
||||
session.getDownstream().getSession().send(dropPacket);
|
||||
session.sendDownstreamPacket(dropPacket);
|
||||
ItemStack cursor = session.getInventory().getCursor();
|
||||
if (cursor != null) {
|
||||
session.getInventory().setCursor(new ItemStack(cursor.getId(), dropAmount > 1 ? 0 : cursor.getAmount() - 1, cursor.getNbt()));
|
||||
|
@ -180,18 +180,19 @@ public class InventoryActionDataTranslator {
|
|||
inventory.getTransactionId().getAndIncrement(),
|
||||
javaSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
|
||||
ShiftClickItemParam.LEFT_CLICK);
|
||||
session.getDownstream().getSession().send(shiftClickPacket);
|
||||
session.sendDownstreamPacket(shiftClickPacket);
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
}
|
||||
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
} else {
|
||||
int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot));
|
||||
int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false);
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
plan.add(Click.LEFT, javaSlot);
|
||||
|
@ -245,11 +246,15 @@ public class InventoryActionDataTranslator {
|
|||
|
||||
int cursorSlot = -1;
|
||||
if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
|
||||
cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot));
|
||||
cursorSlot = findTempSlot(inventory,
|
||||
session.getInventory().getCursor(),
|
||||
Arrays.asList(fromSlot, toSlot),
|
||||
translator.getSlotType(fromSlot) == SlotType.OUTPUT);
|
||||
if (cursorSlot != -1) {
|
||||
plan.add(Click.LEFT, cursorSlot);
|
||||
} else {
|
||||
translator.updateInventory(session, inventory);
|
||||
InventoryUtils.updateCursor(session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +271,7 @@ public class InventoryActionDataTranslator {
|
|||
inventory.getTransactionId().getAndIncrement(),
|
||||
fromSlot, InventoryUtils.REFRESH_ITEM, WindowAction.SHIFT_CLICK_ITEM,
|
||||
ShiftClickItemParam.LEFT_CLICK);
|
||||
session.getDownstream().getSession().send(shiftClickPacket);
|
||||
session.sendDownstreamPacket(shiftClickPacket);
|
||||
translator.updateInventory(session, inventory);
|
||||
return;
|
||||
} else if (translator.getSlotType(fromSlot) == SlotType.OUTPUT) {
|
||||
|
@ -298,7 +303,7 @@ public class InventoryActionDataTranslator {
|
|||
InventoryUtils.updateCursor(session);
|
||||
}
|
||||
|
||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist) {
|
||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist, boolean emptyOnly) {
|
||||
/*try and find a slot that can temporarily store the given item
|
||||
only look in the main inventory and hotbar
|
||||
only slots that are empty or contain a different type of item are valid*/
|
||||
|
@ -314,6 +319,9 @@ public class InventoryActionDataTranslator {
|
|||
ItemStack testItem = inventory.getItem(i);
|
||||
boolean acceptable = true;
|
||||
if (testItem != null) {
|
||||
if (emptyOnly) {
|
||||
continue;
|
||||
}
|
||||
for (ItemStack blacklistItem : itemBlacklist) {
|
||||
if (InventoryUtils.canStack(testItem, blacklistItem)) {
|
||||
acceptable = false;
|
||||
|
|
|
@ -54,7 +54,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
blockPacket.setBlockPosition(position);
|
||||
blockPacket.setRuntimeId(blockId);
|
||||
blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY);
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
inventory.setHolderPosition(position);
|
||||
|
||||
CompoundTag tag = CompoundTag.builder()
|
||||
|
@ -65,7 +65,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
BlockEntityDataPacket dataPacket = new BlockEntityDataPacket();
|
||||
dataPacket.setData(tag);
|
||||
dataPacket.setBlockPosition(position);
|
||||
session.getUpstream().sendPacket(dataPacket);
|
||||
session.sendUpstreamPacket(dataPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,7 +75,7 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
containerOpenPacket.setType((byte) containerType.id());
|
||||
containerOpenPacket.setBlockPosition(inventory.getHolderPosition());
|
||||
containerOpenPacket.setUniqueEntityId(inventory.getHolderId());
|
||||
session.getUpstream().sendPacket(containerOpenPacket);
|
||||
session.sendUpstreamPacket(containerOpenPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,6 +87,6 @@ public class BlockInventoryHolder extends InventoryHolder {
|
|||
blockPacket.setDataLayer(0);
|
||||
blockPacket.setBlockPosition(holderPos);
|
||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||
session.getUpstream().sendPacket(blockPacket);
|
||||
session.sendUpstreamPacket(blockPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,15 @@ import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
|||
import lombok.AllArgsConstructor;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.utils.InventoryUtils;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class ChestInventoryUpdater extends InventoryUpdater {
|
||||
private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(
|
||||
"This slot does not exist in the inventory\non Java Edition, as there is less\nrows than possible in Bedrock");
|
||||
|
||||
private final int paddedSize;
|
||||
|
||||
@Override
|
||||
|
@ -44,17 +48,17 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
|
||||
ItemData[] bedrockItems = new ItemData[paddedSize];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
if (i <= translator.size) {
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
if (i < translator.size) {
|
||||
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
} else {
|
||||
bedrockItems[i] = ItemData.AIR;
|
||||
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getId());
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,8 +69,8 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class ContainerInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
|
@ -40,13 +40,13 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
|
||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||
for (int i = 0; i < bedrockItems.length; i++) {
|
||||
bedrockItems[translator.javaSlotToBedrock(i)] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i));
|
||||
bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||
}
|
||||
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(inventory.getId());
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,8 +57,8 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(inventory.getId());
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ import com.nukkitx.protocol.bedrock.data.ContainerId;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public class CursorInventoryUpdater extends InventoryUpdater {
|
||||
@Override
|
||||
|
@ -44,8 +44,8 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(bedrockSlot);
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(i)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,20 +31,20 @@ import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket;
|
|||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||
import org.geysermc.connector.inventory.Inventory;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.Translators;
|
||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
public abstract class InventoryUpdater {
|
||||
public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
|
||||
ItemData[] bedrockItems = new ItemData[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
final int offset = i < 9 ? 27 : -9;
|
||||
bedrockItems[i] = Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(translator.size + i + offset));
|
||||
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.size + i + offset));
|
||||
}
|
||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||
contentPacket.setContents(bedrockItems);
|
||||
session.getUpstream().sendPacket(contentPacket);
|
||||
session.sendUpstreamPacket(contentPacket);
|
||||
}
|
||||
|
||||
public boolean updateSlot(InventoryTranslator translator, GeyserSession session, Inventory inventory, int javaSlot) {
|
||||
|
@ -52,8 +52,8 @@ public abstract class InventoryUpdater {
|
|||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||
slotPacket.setItem(Translators.getItemTranslator().translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.getUpstream().sendPacket(slotPacket);
|
||||
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||
session.sendUpstreamPacket(slotPacket);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,91 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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:
|
||||
* 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 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.
|
||||
* 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
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.nukkitx.nbt.NbtUtils;
|
||||
import com.nukkitx.nbt.stream.NBTInputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.StartGamePacket;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ToolItemEntry;
|
||||
import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Toolbox {
|
||||
/**
|
||||
* Registry for anything item related.
|
||||
*/
|
||||
public class ItemRegistry {
|
||||
|
||||
private static final Map<String, ItemEntry> JAVA_IDENTIFIER_MAP = new HashMap<>();
|
||||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
|
||||
public static final CompoundTag BIOMES;
|
||||
public static final ItemData[] CREATIVE_ITEMS;
|
||||
|
||||
public static final List<StartGamePacket.ItemEntry> ITEMS = new ArrayList<>();
|
||||
|
||||
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public static CompoundTag ENTITY_IDENTIFIERS;
|
||||
// Shield ID, used in Entity.java
|
||||
public static final int SHIELD = 829;
|
||||
// Boat ID, used in BedrockInventoryTransactionTranslator.java
|
||||
public static final int BOAT = 333;
|
||||
|
||||
public static int BARRIER_INDEX = 0;
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load biomes */
|
||||
InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat");
|
||||
if (biomestream == null) {
|
||||
throw new AssertionError("Unable to find bedrock/biome_definitions.dat");
|
||||
}
|
||||
|
||||
CompoundTag biomesTag;
|
||||
|
||||
try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(biomestream)){
|
||||
biomesTag = (CompoundTag) biomenbtInputStream.readTag();
|
||||
BIOMES = biomesTag;
|
||||
} catch (Exception ex) {
|
||||
GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?");
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
|
||||
/* Load item palette */
|
||||
InputStream stream = getResource("bedrock/items.json");
|
||||
InputStream stream = FileUtils.getResource("bedrock/items.json");
|
||||
|
||||
TypeReference<List<JsonNode>> itemEntriesType = new TypeReference<List<JsonNode>>() {
|
||||
};
|
||||
|
||||
List<JsonNode> itemEntries;
|
||||
try {
|
||||
itemEntries = JSON_MAPPER.readValue(stream, itemEntriesType);
|
||||
itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load Bedrock runtime item IDs", e);
|
||||
}
|
||||
|
@ -94,11 +88,11 @@ public class Toolbox {
|
|||
ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue()));
|
||||
}
|
||||
|
||||
stream = getResource("mappings/items.json");
|
||||
stream = FileUtils.getResource("mappings/items.json");
|
||||
|
||||
JsonNode items;
|
||||
try {
|
||||
items = JSON_MAPPER.readTree(stream);
|
||||
items = GeyserConnector.JSON_MAPPER.readTree(stream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load Java runtime item IDs", e);
|
||||
}
|
||||
|
@ -139,22 +133,12 @@ public class Toolbox {
|
|||
itemIndex++;
|
||||
}
|
||||
|
||||
// Load particle/effect mappings
|
||||
EffectUtils.init();
|
||||
// Load sound mappings
|
||||
SoundUtils.init();
|
||||
// Load the locale data
|
||||
LocaleUtils.init();
|
||||
|
||||
// Load sound handlers
|
||||
SoundHandlerRegistry.init();
|
||||
|
||||
/* Load creative items */
|
||||
stream = getResource("bedrock/creative_items.json");
|
||||
stream = FileUtils.getResource("bedrock/creative_items.json");
|
||||
|
||||
JsonNode creativeItemEntries;
|
||||
try {
|
||||
creativeItemEntries = JSON_MAPPER.readTree(stream).get("items");
|
||||
creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items");
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to load creative items", e);
|
||||
}
|
||||
|
@ -179,33 +163,51 @@ public class Toolbox {
|
|||
}
|
||||
}
|
||||
CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]);
|
||||
|
||||
|
||||
/* Load entity identifiers */
|
||||
stream = Toolbox.getResource("bedrock/entity_identifiers.dat");
|
||||
|
||||
try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) {
|
||||
ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag();
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError("Unable to get entities from entity identifiers", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an InputStream for the given resource path, throws AssertionError if resource is not found
|
||||
* Gets an {@link ItemEntry} from the given {@link ItemStack}.
|
||||
*
|
||||
* @param resource Resource to get
|
||||
* @return InputStream of the given resource
|
||||
* @param stack the item stack
|
||||
* @return an item entry from the given item stack
|
||||
*/
|
||||
public static InputStream getResource(String resource) {
|
||||
InputStream stream = Toolbox.class.getClassLoader().getResourceAsStream(resource);
|
||||
if (stream == null) {
|
||||
throw new AssertionError("Unable to find resource: " + resource);
|
||||
}
|
||||
return stream;
|
||||
public static ItemEntry getItem(ItemStack stack) {
|
||||
return ITEM_ENTRIES.get(stack.getId());
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
/**
|
||||
* Gets an {@link ItemEntry} from the given {@link ItemData}.
|
||||
*
|
||||
* @param data the item data
|
||||
* @return an item entry from the given item data
|
||||
*/
|
||||
public static ItemEntry getItem(ItemData data) {
|
||||
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
// If item find was unsuccessful first time, we try again while ignoring damage
|
||||
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
||||
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId()) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
||||
return ItemEntry.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link ItemEntry} from the given Minecraft: Java Edition
|
||||
* block state identifier.
|
||||
*
|
||||
* @param javaIdentifier the block state identifier
|
||||
* @return an item entry from the given java edition identifier
|
||||
*/
|
||||
public static ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
}
|
||||
}
|
|
@ -1,55 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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:
|
||||
* 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 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.
|
||||
* 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
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.item;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.*;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemTranslator {
|
||||
public abstract class ItemTranslator {
|
||||
|
||||
private Int2ObjectMap<ItemStackTranslator> itemTranslators = new Int2ObjectOpenHashMap();
|
||||
private List<NbtItemStackTranslator> nbtItemTranslators;
|
||||
private Map<String, ItemEntry> javaIdentifierMap = new HashMap<>();
|
||||
private static final Int2ObjectMap<ItemTranslator> ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>();
|
||||
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
|
||||
|
||||
// Shield ID, used in Entity.java
|
||||
public static final int SHIELD = 829;
|
||||
protected ItemTranslator() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
static {
|
||||
/* Load item translators */
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.item");
|
||||
|
||||
Map<NbtItemStackTranslator, Integer> loadedNbtItemTranslators = new HashMap<>();
|
||||
|
@ -64,34 +76,33 @@ public class ItemTranslator {
|
|||
loadedNbtItemTranslators.put(nbtItemTranslator, priority);
|
||||
continue;
|
||||
}
|
||||
ItemStackTranslator itemStackTranslator = (ItemStackTranslator) clazz.newInstance();
|
||||
ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance();
|
||||
List<ItemEntry> appliedItems = itemStackTranslator.getAppliedItems();
|
||||
for (ItemEntry item : appliedItems) {
|
||||
ItemStackTranslator registered = itemTranslators.get(item.getJavaId());
|
||||
ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId());
|
||||
if (registered != null) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." +
|
||||
" Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier());
|
||||
continue;
|
||||
}
|
||||
itemTranslators.put(item.getJavaId(), itemStackTranslator);
|
||||
ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator);
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
nbtItemTranslators = loadedNbtItemTranslators.keySet().stream()
|
||||
.sorted(Comparator.comparingInt(value -> loadedNbtItemTranslators.get(value))).collect(Collectors.toList());
|
||||
NBT_TRANSLATORS = loadedNbtItemTranslators.keySet().stream().sorted(Comparator.comparingInt(loadedNbtItemTranslators::get)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(GeyserSession session, ItemData data) {
|
||||
public static ItemStack translateToJava(ItemData data) {
|
||||
if (data == null) {
|
||||
return new ItemStack(0);
|
||||
}
|
||||
ItemEntry javaItem = getItem(data);
|
||||
ItemEntry javaItem = ItemRegistry.getItem(data);
|
||||
|
||||
ItemStack itemStack;
|
||||
ItemStackTranslator itemStackTranslator = itemTranslators.get(javaItem.getJavaId());
|
||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(javaItem.getJavaId());
|
||||
if (itemStackTranslator != null) {
|
||||
itemStack = itemStackTranslator.translateToJava(data, javaItem);
|
||||
} else {
|
||||
|
@ -99,7 +110,7 @@ public class ItemTranslator {
|
|||
}
|
||||
|
||||
if (itemStack != null && itemStack.getNbt() != null) {
|
||||
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
||||
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
|
||||
if (translator.acceptItem(javaItem)) {
|
||||
translator.translateToJava(itemStack.getNbt(), javaItem);
|
||||
}
|
||||
|
@ -108,62 +119,271 @@ public class ItemTranslator {
|
|||
return itemStack;
|
||||
}
|
||||
|
||||
public ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
||||
public static ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
||||
if (stack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
|
||||
ItemEntry bedrockItem = getItem(stack);
|
||||
ItemEntry bedrockItem = ItemRegistry.getItem(stack);
|
||||
|
||||
ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() != null ? stack.getNbt().clone() : null);
|
||||
|
||||
if (itemStack.getNbt() != null) {
|
||||
for (NbtItemStackTranslator translator : nbtItemTranslators) {
|
||||
for (NbtItemStackTranslator translator : NBT_TRANSLATORS) {
|
||||
if (translator.acceptItem(bedrockItem)) {
|
||||
translator.translateToBedrock(itemStack.getNbt(), bedrockItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemStackTranslator itemStackTranslator = itemTranslators.get(bedrockItem.getJavaId());
|
||||
ItemData itemData;
|
||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId());
|
||||
if (itemStackTranslator != null) {
|
||||
return itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
||||
itemData = itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
||||
} else {
|
||||
return DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||
itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||
}
|
||||
}
|
||||
|
||||
public ItemEntry getItem(ItemStack stack) {
|
||||
return Toolbox.ITEM_ENTRIES.get(stack.getId());
|
||||
}
|
||||
|
||||
public ItemEntry getItem(ItemData data) {
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) {
|
||||
return itemEntry;
|
||||
}
|
||||
}
|
||||
// If item find was unsuccessful first time, we try again while ignoring damage
|
||||
// Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory
|
||||
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.values()) {
|
||||
if (itemEntry.getBedrockId() == data.getId()) {
|
||||
return itemEntry;
|
||||
// Get the display name of the item
|
||||
CompoundTag tag = itemData.getTag();
|
||||
if (tag != null) {
|
||||
CompoundTag display = tag.getCompound("display");
|
||||
if (display != null) {
|
||||
String name = display.getString("Name");
|
||||
|
||||
// Check if its a message to translate
|
||||
if (MessageUtils.isMessage(name)) {
|
||||
// Get the translated name
|
||||
name = MessageUtils.getTranslatedBedrockMessage(Message.fromString(name), session.getClientData().getLanguageCode());
|
||||
|
||||
// Build the new display tag
|
||||
CompoundTagBuilder displayBuilder = display.toBuilder();
|
||||
displayBuilder.stringTag("Name", name);
|
||||
|
||||
// Build the new root tag
|
||||
CompoundTagBuilder builder = tag.toBuilder();
|
||||
builder.tag(displayBuilder.build("display"));
|
||||
|
||||
// Create a new item with the original data + updated name
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage());
|
||||
return ItemEntry.AIR;
|
||||
return itemData;
|
||||
}
|
||||
|
||||
public ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return javaIdentifierMap.computeIfAbsent(javaIdentifier, key -> Toolbox.ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
}
|
||||
|
||||
private static final ItemStackTranslator DEFAULT_TRANSLATOR = new ItemStackTranslator() {
|
||||
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack == null) {
|
||||
return ItemData.AIR;
|
||||
}
|
||||
if (itemStack.getNbt() == null) {
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount());
|
||||
}
|
||||
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt()));
|
||||
}
|
||||
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData == null) return null;
|
||||
if (itemData.getTag() == null) {
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""));
|
||||
}
|
||||
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag()));
|
||||
}
|
||||
|
||||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Tag<?>> javaValue = new HashMap<>();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
com.nukkitx.nbt.tag.Tag<?> translatedTag = translateToBedrockNBT(javaTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
return new CompoundTag(tag.getName(), javaValue);
|
||||
}
|
||||
|
||||
private Tag<?> translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) {
|
||||
if (tag instanceof ByteArrayTag) {
|
||||
ByteArrayTag byteArrayTag = (ByteArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ByteTag) {
|
||||
ByteTag byteTag = (ByteTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof DoubleTag) {
|
||||
DoubleTag doubleTag = (DoubleTag) tag;
|
||||
return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof FloatTag) {
|
||||
FloatTag floatTag = (FloatTag) tag;
|
||||
return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntArrayTag) {
|
||||
IntArrayTag intArrayTag = (IntArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof IntTag) {
|
||||
IntTag intTag = (IntTag) tag;
|
||||
return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongArrayTag) {
|
||||
LongArrayTag longArrayTag = (LongArrayTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof LongTag) {
|
||||
LongTag longTag = (LongTag) tag;
|
||||
return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ShortTag) {
|
||||
ShortTag shortTag = (ShortTag) tag;
|
||||
return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof StringTag) {
|
||||
StringTag stringTag = (StringTag) tag;
|
||||
return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof ListTag) {
|
||||
ListTag listTag = (ListTag) tag;
|
||||
|
||||
List<Tag<?>> tagList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) {
|
||||
tagList.add(translateToBedrockNBT(value));
|
||||
}
|
||||
Class<?> clazz = CompoundTag.class;
|
||||
if (!tagList.isEmpty()) {
|
||||
clazz = tagList.get(0).getClass();
|
||||
}
|
||||
return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList);
|
||||
}
|
||||
|
||||
if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag;
|
||||
|
||||
return translateNbtToBedrock(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
|
||||
com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName());
|
||||
Map<String, com.github.steveice10.opennbt.tag.builtin.Tag> javaValue = javaTag.getValue();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
Tag<?> bedrockTag = tag.get(str);
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag);
|
||||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(translatedTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
|
||||
javaTag.setValue(javaValue);
|
||||
return javaTag;
|
||||
}
|
||||
|
||||
private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag<?> tag) {
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) {
|
||||
com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag;
|
||||
return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ByteTag) {
|
||||
com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag;
|
||||
return new ByteTag(byteTag.getName(), byteTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) {
|
||||
com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag;
|
||||
return new DoubleTag(doubleTag.getName(), doubleTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.FloatTag) {
|
||||
com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag;
|
||||
return new FloatTag(floatTag.getName(), floatTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) {
|
||||
com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag;
|
||||
return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.IntTag) {
|
||||
com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag;
|
||||
return new IntTag(intTag.getName(), intTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) {
|
||||
com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag;
|
||||
return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.LongTag) {
|
||||
com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag;
|
||||
return new LongTag(longTag.getName(), longTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ShortTag) {
|
||||
com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag;
|
||||
return new ShortTag(shortTag.getName(), shortTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.StringTag) {
|
||||
com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag;
|
||||
return new StringTag(stringTag.getName(), stringTag.getValue());
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.ListTag) {
|
||||
com.nukkitx.nbt.tag.ListTag<?> listTag = (com.nukkitx.nbt.tag.ListTag<?>) tag;
|
||||
|
||||
List<com.github.steveice10.opennbt.tag.builtin.Tag> tags = new ArrayList<>();
|
||||
|
||||
for (Object value : listTag.getValue()) {
|
||||
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
|
||||
continue;
|
||||
|
||||
com.nukkitx.nbt.tag.Tag<?> tagValue = (com.nukkitx.nbt.tag.Tag<?>) value;
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue);
|
||||
if (javaTag != null)
|
||||
tags.add(javaTag);
|
||||
}
|
||||
return new ListTag(listTag.getName(), tags);
|
||||
}
|
||||
|
||||
if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) {
|
||||
com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag;
|
||||
return translateToJavaNBT(compoundTag);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
|
||||
public class NbtItemStackTranslator {
|
||||
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
|
||||
}
|
||||
|
||||
public boolean acceptItem(ItemEntry itemEntry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 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;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ItemRemapper
|
||||
public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
private List<ItemEntry> appliedItems;
|
||||
|
||||
public BannerTranslator() {
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
CompoundTagBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.tag(convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry);
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
com.nukkitx.nbt.tag.CompoundTag nbtTag = itemData.getTag();
|
||||
if (nbtTag.contains("Patterns")) {
|
||||
com.nukkitx.nbt.tag.ListTag<?> patterns = nbtTag.get("Patterns");
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of patterns from Java nbt to Bedrock nbt
|
||||
*
|
||||
* @param patterns The patterns to convert
|
||||
* @return The new converted patterns
|
||||
*/
|
||||
public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) {
|
||||
List<com.nukkitx.nbt.tag.CompoundTag> tagsList = new ArrayList<>();
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) {
|
||||
com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag);
|
||||
if (newPatternTag != null) {
|
||||
tagsList.add(newPatternTag);
|
||||
}
|
||||
}
|
||||
|
||||
return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist
|
||||
*
|
||||
* @param pattern Java edition pattern nbt
|
||||
* @return The Bedrock edition format pattern nbt
|
||||
*/
|
||||
public static com.nukkitx.nbt.tag.CompoundTag getBedrockBannerPattern(CompoundTag pattern) {
|
||||
String patternName = (String) pattern.get("Pattern").getValue();
|
||||
|
||||
// Return null if its the globe pattern as it doesn't exist on bedrock
|
||||
if (patternName.equals("glb")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CompoundTagBuilder.builder()
|
||||
.intTag("Color", 15 - (int) pattern.get("Color").getValue())
|
||||
.stringTag("Pattern", (String) pattern.get("Pattern").getValue())
|
||||
.stringTag("Pattern", patternName)
|
||||
.buildRootTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of patterns from Bedrock nbt to Java nbt
|
||||
*
|
||||
* @param patterns The patterns to convert
|
||||
* @return The new converted patterns
|
||||
*/
|
||||
public static ListTag convertBannerPattern(com.nukkitx.nbt.tag.ListTag<?> patterns) {
|
||||
List<Tag> tagsList = new ArrayList<>();
|
||||
for (Object patternTag : patterns.getValue()) {
|
||||
CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag);
|
||||
tagsList.add(newPatternTag);
|
||||
}
|
||||
|
||||
return new ListTag("Patterns", tagsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Bedrock edition banner pattern nbt to Java edition
|
||||
*
|
||||
* @param pattern Bedorck edition pattern nbt
|
||||
* @return The Java edition format pattern nbt
|
||||
*/
|
||||
public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) {
|
||||
Map<String, Tag> tags = new HashMap<>();
|
||||
tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color")));
|
||||
tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern")));
|
||||
|
||||
return new CompoundTag("", tags);
|
||||
}
|
||||
}
|
|
@ -30,22 +30,22 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
|||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.translators.ItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.Potion;
|
||||
import org.geysermc.connector.utils.Toolbox;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ItemRemapper
|
||||
public class PotionTranslator extends ItemStackTranslator {
|
||||
public class PotionTranslator extends ItemTranslator {
|
||||
|
||||
private List<ItemEntry> appliedItems;
|
||||
|
||||
public PotionTranslator() {
|
||||
appliedItems = Toolbox.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList());
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,7 +34,7 @@ import net.kyori.text.TextComponent;
|
|||
import net.kyori.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
|
@ -46,49 +46,51 @@ public class BasicItemTranslator extends NbtItemStackTranslator {
|
|||
|
||||
@Override
|
||||
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("display")) {
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
if (!itemTag.contains("display")) {
|
||||
return;
|
||||
}
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
try {
|
||||
displayTag.put(new StringTag("Name", toBedrockMessage(nameTag)));
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
if (displayTag.contains("Lore")) {
|
||||
ListTag loreTag = displayTag.get("Lore");
|
||||
List<Tag> lore = new ArrayList<>();
|
||||
for (Tag tag : loreTag.getValue()) {
|
||||
if (!(tag instanceof StringTag)) return;
|
||||
try {
|
||||
displayTag.put(new StringTag("Name", toBedrockMessage(nameTag)));
|
||||
lore.add(new StringTag("", toBedrockMessage((StringTag) tag)));
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
if (displayTag.contains("Lore")) {
|
||||
ListTag loreTag = displayTag.get("Lore");
|
||||
List<Tag> lore = new ArrayList<>();
|
||||
for (Tag tag : loreTag.getValue()) {
|
||||
if (!(tag instanceof StringTag)) return;
|
||||
try {
|
||||
lore.add(new StringTag("", toBedrockMessage((StringTag) tag)));
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||
if (itemTag.contains("display")) {
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
displayTag.put(new StringTag("Name", toJavaMessage(nameTag)));
|
||||
}
|
||||
if (!itemTag.contains("display")) {
|
||||
return;
|
||||
}
|
||||
CompoundTag displayTag = itemTag.get("display");
|
||||
if (displayTag.contains("Name")) {
|
||||
StringTag nameTag = displayTag.get("Name");
|
||||
displayTag.put(new StringTag("Name", toJavaMessage(nameTag)));
|
||||
}
|
||||
|
||||
if (displayTag.contains("Lore")) {
|
||||
ListTag loreTag = displayTag.get("Lore");
|
||||
List<Tag> lore = new ArrayList<>();
|
||||
for (Tag tag : loreTag.getValue()) {
|
||||
if (!(tag instanceof StringTag)) return;
|
||||
lore.add(new StringTag("", "§r" + toJavaMessage((StringTag) tag)));
|
||||
}
|
||||
displayTag.put(new ListTag("Lore", lore));
|
||||
if (displayTag.contains("Lore")) {
|
||||
ListTag loreTag = displayTag.get("Lore");
|
||||
List<Tag> lore = new ArrayList<>();
|
||||
for (Tag tag : loreTag.getValue()) {
|
||||
if (!(tag instanceof StringTag)) return;
|
||||
lore.add(new StringTag("", "§r" + toJavaMessage((StringTag) tag)));
|
||||
}
|
||||
displayTag.put(new ListTag("Lore", lore));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue