forked from GeyserMC/Geyser
Merge branch 'master' of https://github.com/GeyserMC/Geyser
This commit is contained in:
commit
b92450ede6
60 changed files with 1537 additions and 189 deletions
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -7,30 +7,34 @@ assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!--- Please follow this format COMPLETELY and make sure the bug you are reporting has not been reported yet. Reports should contain as much information or context as possible to help us find the problem. Simply creating an issue on a vague topic will not help us at all, and if you are unsure if something should belong here, please contact us on [Discord](http://discord.geysermc.org).-->
|
||||||
|
|
||||||
|
<!--- Issues pertaining to connection problem, or anything of that covered on the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues) do not belong here and only clutter this issue tracker. -->
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
<!--- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
Steps to reproduce the behavior:
|
<!--- Steps to reproduce the behavior: -->
|
||||||
1. Go to '...'
|
<!--- 1. Go to '...' -->
|
||||||
2. Click on '....'
|
<!--- 2. Click on '....' -->
|
||||||
3. Scroll down to '....'
|
<!--- 3. Scroll down to '....' -->
|
||||||
4. See error
|
<!--- 4. See error -->
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
A clear and concise description of what you expected to happen.
|
<!--- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots / Videos**
|
||||||
If applicable, add screenshots to help explain your problem.
|
<!--- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
**Server version**
|
**Server Version**
|
||||||
run /version
|
<!--- Give us the exact output from /version. Saying "latest" does not help us at all. -->
|
||||||
|
|
||||||
**Geyser version**
|
**Geyser Version**
|
||||||
Jenkins
|
<!--- Give us the exact build number as well as branch if applicable. Saying "latest" does not help us at all. -->
|
||||||
|
|
||||||
**Bedrock version**
|
**Minecraft: Bedrock Edition Version**
|
||||||
The version of your Minecraft pe
|
<!-- The version of your Minecraft: Bedrock Edition client you tested with. -->
|
||||||
|
|
||||||
**Additional context**
|
**Additional Context**
|
||||||
Add any other context about the problem here.
|
<!--- Add any other context about the problem here. --->
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -225,3 +225,4 @@ nbdist/
|
||||||
config.yml
|
config.yml
|
||||||
logs/
|
logs/
|
||||||
public-key.pem
|
public-key.pem
|
||||||
|
locales/
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
<shadedPattern>org.geysermc.platform.bukkit.shaded.fastutil</shadedPattern>
|
<shadedPattern>org.geysermc.platform.bukkit.shaded.fastutil</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<minimizeJar>true</minimizeJar>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -101,6 +101,11 @@ public class GeyserBukkitConfiguration implements IGeyserConfiguration {
|
||||||
return config.getBoolean("allow-third-party-capes", true);
|
return config.getBoolean("allow-third-party-capes", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultLocale() {
|
||||||
|
return config.getString("default-locale", "en_us");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
<shadedPattern>org.geysermc.platform.bungeecord.shaded.netty</shadedPattern>
|
<shadedPattern>org.geysermc.platform.bungeecord.shaded.netty</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<minimizeJar>true</minimizeJar>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -102,6 +102,11 @@ public class GeyserBungeeConfiguration implements IGeyserConfiguration {
|
||||||
return config.getBoolean("allow-third-party-capes", true);
|
return config.getBoolean("allow-third-party-capes", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultLocale() {
|
||||||
|
return config.getString("default-locale", "en_us");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
return Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem"));
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
<shadedPattern>org.geysermc.platform.sponge.shaded.fastutil</shadedPattern>
|
<shadedPattern>org.geysermc.platform.sponge.shaded.fastutil</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<minimizeJar>true</minimizeJar>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -105,6 +105,11 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
|
||||||
return node.getNode("allow-third-party-capes").getBoolean(true);
|
return node.getNode("allow-third-party-capes").getBoolean(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultLocale() {
|
||||||
|
return node.getNode("default-locale").getString("en_us");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem"));
|
return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem"));
|
||||||
|
|
|
@ -120,6 +120,9 @@
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
<mainClass>org.geysermc.platform.standalone.GeyserBootstrap</mainClass>
|
<mainClass>org.geysermc.platform.standalone.GeyserBootstrap</mainClass>
|
||||||
|
<manifestEntries>
|
||||||
|
<Multi-Release>true</Multi-Release>
|
||||||
|
</manifestEntries>
|
||||||
</transformer>
|
</transformer>
|
||||||
<transformer
|
<transformer
|
||||||
implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
|
implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
|
||||||
|
|
|
@ -63,6 +63,9 @@ public class GeyserConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes;
|
private boolean allowThirdPartyCapes;
|
||||||
|
|
||||||
|
@JsonProperty("default-locale")
|
||||||
|
private String defaultLocale;
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
private MetricsInfo metrics;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class GeyserLogger extends SimpleTerminalConsole implements IGeyserLogger
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void shutdown() {
|
protected void shutdown() {
|
||||||
GeyserConnector.getInstance().shutdown();
|
GeyserConnector.getInstance().getBootstrap().onDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,7 +44,12 @@
|
||||||
<goal>shade</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<minimizeJar>true</minimizeJar>
|
<relocations>
|
||||||
|
<relocation>
|
||||||
|
<pattern>it.unimi.dsi.fastutil</pattern>
|
||||||
|
<shadedPattern>org.geysermc.platform.velocity.shaded.fastutil</shadedPattern>
|
||||||
|
</relocation>
|
||||||
|
</relocations>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -63,6 +63,9 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration {
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes;
|
private boolean allowThirdPartyCapes;
|
||||||
|
|
||||||
|
@JsonProperty("default-locale")
|
||||||
|
private String defaultLocale;
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
private MetricsInfo metrics;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,6 +46,8 @@ public interface IGeyserConfiguration {
|
||||||
|
|
||||||
boolean isAllowThirdPartyCapes();
|
boolean isAllowThirdPartyCapes();
|
||||||
|
|
||||||
|
String getDefaultLocale();
|
||||||
|
|
||||||
Path getFloodgateKeyFile();
|
Path getFloodgateKeyFile();
|
||||||
|
|
||||||
IMetricsInfo getMetrics();
|
IMetricsInfo getMetrics();
|
||||||
|
|
|
@ -50,6 +50,8 @@ import java.net.InetSocketAddress;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -64,7 +66,7 @@ public class GeyserConnector {
|
||||||
//Change this on every game version
|
//Change this on every game version
|
||||||
public static final String GAME_VERSION = "1.14.0";
|
public static final String GAME_VERSION = "1.14.0";
|
||||||
|
|
||||||
private final Map<Object, GeyserSession> players = new HashMap<>();
|
private final Map<InetSocketAddress, GeyserSession> players = new HashMap<>();
|
||||||
|
|
||||||
private static GeyserConnector instance;
|
private static GeyserConnector instance;
|
||||||
|
|
||||||
|
@ -145,6 +147,40 @@ public class GeyserConnector {
|
||||||
bootstrap.getGeyserLogger().info("Shutting down Geyser.");
|
bootstrap.getGeyserLogger().info("Shutting down Geyser.");
|
||||||
shuttingDown = true;
|
shuttingDown = true;
|
||||||
|
|
||||||
|
if (players.size() >= 1) {
|
||||||
|
bootstrap.getGeyserLogger().info("Kicking " + players.size() + " player(s)");
|
||||||
|
|
||||||
|
for (GeyserSession playerSession : players.values()) {
|
||||||
|
playerSession.disconnect("Geyser Proxy shutting down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Simulate a long-running Job
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
if (players.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeUnit.MILLISECONDS.sleep(100);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Block and wait for the future to complete
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
bootstrap.getGeyserLogger().info("Kicked all players");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Quietly fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generalThreadPool.shutdown();
|
generalThreadPool.shutdown();
|
||||||
bedrockServer.close();
|
bedrockServer.close();
|
||||||
players.clear();
|
players.clear();
|
||||||
|
@ -152,17 +188,15 @@ public class GeyserConnector {
|
||||||
authType = null;
|
authType = null;
|
||||||
commandMap.getCommands().clear();
|
commandMap.getCommands().clear();
|
||||||
commandMap = null;
|
commandMap = null;
|
||||||
|
|
||||||
|
bootstrap.getGeyserLogger().info("Geyser shutdown successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPlayer(GeyserSession player) {
|
public void addPlayer(GeyserSession player) {
|
||||||
players.put(player.getAuthData().getName(), player);
|
|
||||||
players.put(player.getAuthData().getUUID(), player);
|
|
||||||
players.put(player.getSocketAddress(), player);
|
players.put(player.getSocketAddress(), player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayer(GeyserSession player) {
|
public void removePlayer(GeyserSession player) {
|
||||||
players.remove(player.getAuthData().getName());
|
|
||||||
players.remove(player.getAuthData().getUUID());
|
|
||||||
players.remove(player.getSocketAddress());
|
players.remove(player.getSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,11 @@ public class StopCommand extends GeyserCommand {
|
||||||
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
|
if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connector.shutdown();
|
connector.shutdown();
|
||||||
|
|
||||||
|
if (connector.getPlatformType() == PlatformType.STANDALONE) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.block.BlockTranslator;
|
||||||
|
|
||||||
|
public class FallingBlockEntity extends Entity {
|
||||||
|
|
||||||
|
public FallingBlockEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, int javaId) {
|
||||||
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
|
|
||||||
|
this.metadata.put(EntityData.VARIANT, BlockTranslator.getBedrockBlockId(javaId));
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,8 +26,11 @@
|
||||||
package org.geysermc.connector.entity;
|
package org.geysermc.connector.entity;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.CommandPermission;
|
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.data.PlayerPermission;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
|
@ -39,6 +42,8 @@ import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.scoreboard.Team;
|
||||||
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
import org.geysermc.connector.utils.SkinUtils;
|
import org.geysermc.connector.utils.SkinUtils;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -152,4 +157,27 @@ public class PlayerEntity extends LivingEntity {
|
||||||
public void setPosition(Vector3f position) {
|
public void setPosition(Vector3f position) {
|
||||||
this.position = position.add(0, entityType.getOffset(), 0);
|
this.position = position.add(0, entityType.getOffset(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
||||||
|
if (entityMetadata.getId() == 2) {
|
||||||
|
// System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet());
|
||||||
|
for (Team team : session.getScoreboardCache().getScoreboard().getTeams().values()) {
|
||||||
|
// session.getConnector().getLogger().info("team name " + team.getName());
|
||||||
|
// session.getConnector().getLogger().info("team entities " + team.getEntities());
|
||||||
|
}
|
||||||
|
String username = this.username;
|
||||||
|
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||||
|
if (name != null) {
|
||||||
|
username = MessageUtils.getBedrockMessage(name);
|
||||||
|
}
|
||||||
|
Team team = session.getScoreboardCache().getScoreboard().getTeamFor(username);
|
||||||
|
if (team != null) {
|
||||||
|
// session.getConnector().getLogger().info("team name es " + team.getName() + " with prefix " + team.getPrefix() + " and suffix " + team.getSuffix());
|
||||||
|
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ public class BeeEntity extends AnimalEntity {
|
||||||
if (entityMetadata.getId() == 16) {
|
if (entityMetadata.getId() == 16) {
|
||||||
byte xd = (byte) entityMetadata.getValue();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||||
|
// If the bee has nectar or not
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,52 @@
|
||||||
|
|
||||||
package org.geysermc.connector.entity.living.animal.horse;
|
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.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||||
|
|
||||||
public class LlamaEntity extends ChestedHorseEntity {
|
public class LlamaEntity extends ChestedHorseEntity {
|
||||||
|
|
||||||
public LlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
public LlamaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
// Strength
|
||||||
|
if (entityMetadata.getId() == 19) {
|
||||||
|
metadata.put(EntityData.STRENGTH, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
// Color equipped on the llama
|
||||||
|
if (entityMetadata.getId() == 20) {
|
||||||
|
// Bedrock treats llama decoration as armor
|
||||||
|
MobArmorEquipmentPacket equipmentPacket = new MobArmorEquipmentPacket();
|
||||||
|
equipmentPacket.setRuntimeEntityId(getGeyserId());
|
||||||
|
// -1 means no armor
|
||||||
|
if ((int) entityMetadata.getValue() != -1) {
|
||||||
|
// The damage value is the dye color that Java sends us
|
||||||
|
// Always going to be a carpet so we can hardcode 171 in BlockTranslator
|
||||||
|
// The int then short conversion is required or we get a ClassCastException
|
||||||
|
equipmentPacket.setChestplate(ItemData.of(BlockTranslator.CARPET, (short)((int) entityMetadata.getValue()), 1));
|
||||||
|
} else {
|
||||||
|
equipmentPacket.setChestplate(ItemData.AIR);
|
||||||
|
}
|
||||||
|
// Required to fill out the rest of the equipment or Bedrock ignores it, including above else statement if removing armor
|
||||||
|
equipmentPacket.setBoots(ItemData.AIR);
|
||||||
|
equipmentPacket.setHelmet(ItemData.AIR);
|
||||||
|
equipmentPacket.setLeggings(ItemData.AIR);
|
||||||
|
|
||||||
|
session.getUpstream().sendPacket(equipmentPacket);
|
||||||
|
}
|
||||||
|
// Color of the llama
|
||||||
|
if (entityMetadata.getId() == 21) {
|
||||||
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
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.living.animal.horse;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||||
|
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) {
|
||||||
|
// The trader llama is a separate entity from the llama in Java but a normal llama with extra metadata in Bedrock.
|
||||||
|
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||||
|
addEntityPacket.setIdentifier("minecraft:llama");
|
||||||
|
addEntityPacket.setRuntimeEntityId(geyserId);
|
||||||
|
addEntityPacket.setUniqueEntityId(geyserId);
|
||||||
|
addEntityPacket.setPosition(position);
|
||||||
|
addEntityPacket.setMotion(motion);
|
||||||
|
addEntityPacket.setRotation(getBedrockRotation());
|
||||||
|
addEntityPacket.setEntityType(entityType.getType());
|
||||||
|
addEntityPacket.getMetadata().putAll(metadata);
|
||||||
|
// Here's the difference
|
||||||
|
addEntityPacket.getMetadata().put(EntityData.MARK_VARIANT, 1);
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
session.getUpstream().sendPacket(addEntityPacket);
|
||||||
|
|
||||||
|
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.tameable;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
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.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -40,12 +41,32 @@ public class CatEntity extends TameableEntity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 18) {
|
if (entityMetadata.getId() == 18) {
|
||||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
// Different colors in Java and Bedrock for some reason
|
||||||
|
int variantColor;
|
||||||
|
switch ((int) entityMetadata.getValue()) {
|
||||||
|
case 0:
|
||||||
|
variantColor = 8;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
variantColor = 0;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
variantColor = 10;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
variantColor = 9;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
variantColor = (int) entityMetadata.getValue();
|
||||||
|
}
|
||||||
|
metadata.put(EntityData.VARIANT, variantColor);
|
||||||
}
|
}
|
||||||
if (entityMetadata.getId() == 21) {
|
if (entityMetadata.getId() == 21) {
|
||||||
// FIXME: Colors the whole animal instead of just collar
|
// Needed or else wild cats are a red color
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
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.animal.tameable;
|
||||||
|
|
||||||
|
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 ParrotEntity extends TameableEntity {
|
||||||
|
|
||||||
|
public ParrotEntity(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) {
|
||||||
|
// Parrot color
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ package org.geysermc.connector.entity.living.animal.tameable;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
@ -45,6 +46,11 @@ public class TameableEntity extends AnimalEntity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01);
|
||||||
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04);
|
||||||
|
// Must be set for wolf collar color to work
|
||||||
|
// Extending it to all entities to prevent future bugs
|
||||||
|
if (metadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId());
|
||||||
|
} // Can't de-tame an entity so no resetting the owner ID
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.tameable;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
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.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -39,9 +40,14 @@ public class WolfEntity extends TameableEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
// "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head
|
||||||
|
if (entityMetadata.getId() == 18) {
|
||||||
|
metadata.getFlags().setFlag(EntityFlag.INTERESTED, (boolean) entityMetadata.getValue());
|
||||||
|
}
|
||||||
|
// Wolf collar color
|
||||||
|
// Relies on EntityData.OWNER_EID being set in TameableEntity.java
|
||||||
if (entityMetadata.getId() == 19) {
|
if (entityMetadata.getId() == 19) {
|
||||||
// FIXME: Colors the whole animal instead of just collar
|
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
||||||
// metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
|
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,10 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.connector.entity.living;
|
package org.geysermc.connector.entity.living.merchant;
|
||||||
|
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import org.geysermc.connector.entity.living.AgeableEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
|
||||||
public class AbstractMerchantEntity extends AgeableEntity {
|
public class AbstractMerchantEntity extends AgeableEntity {
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* 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.merchant;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
|
||||||
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
|
public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
|
|
||||||
|
private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap();
|
||||||
|
private static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Java villager profession IDs -> Bedrock
|
||||||
|
VILLAGER_VARIANTS.put(0, 0);
|
||||||
|
VILLAGER_VARIANTS.put(1, 8);
|
||||||
|
VILLAGER_VARIANTS.put(2, 11);
|
||||||
|
VILLAGER_VARIANTS.put(3, 6);
|
||||||
|
VILLAGER_VARIANTS.put(4, 7);
|
||||||
|
VILLAGER_VARIANTS.put(5, 1);
|
||||||
|
VILLAGER_VARIANTS.put(6, 2);
|
||||||
|
VILLAGER_VARIANTS.put(7, 4);
|
||||||
|
VILLAGER_VARIANTS.put(8, 12);
|
||||||
|
VILLAGER_VARIANTS.put(9, 5);
|
||||||
|
VILLAGER_VARIANTS.put(10, 13);
|
||||||
|
VILLAGER_VARIANTS.put(11, 14);
|
||||||
|
VILLAGER_VARIANTS.put(12, 3);
|
||||||
|
VILLAGER_VARIANTS.put(13, 10);
|
||||||
|
VILLAGER_VARIANTS.put(14, 9);
|
||||||
|
|
||||||
|
VILLAGER_REGIONS.put(0, 1);
|
||||||
|
VILLAGER_REGIONS.put(1, 2);
|
||||||
|
VILLAGER_REGIONS.put(2, 0);
|
||||||
|
VILLAGER_REGIONS.put(3, 3);
|
||||||
|
VILLAGER_REGIONS.put(4, 4);
|
||||||
|
VILLAGER_REGIONS.put(5, 5);
|
||||||
|
VILLAGER_REGIONS.put(6, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VillagerEntity(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() == 17) {
|
||||||
|
VillagerData villagerData = (VillagerData) entityMetadata.getValue();
|
||||||
|
// Profession
|
||||||
|
metadata.put(EntityData.VARIANT, VILLAGER_VARIANTS.get(villagerData.getProfession()));
|
||||||
|
//metadata.put(EntityData.SKIN_ID, villagerData.getType()); Looks like this is modified but for any reason?
|
||||||
|
// Region
|
||||||
|
metadata.put(EntityData.MARK_VARIANT, VILLAGER_REGIONS.get(villagerData.getType()));
|
||||||
|
// Trade tier - different indexing in Bedrock
|
||||||
|
metadata.put(EntityData.TRADE_TIER, villagerData.getLevel() - 1);
|
||||||
|
}
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawnEntity(GeyserSession session) {
|
||||||
|
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||||
|
// "v2" or else it's the legacy villager
|
||||||
|
addEntityPacket.setIdentifier("minecraft:villager_v2");
|
||||||
|
addEntityPacket.setRuntimeEntityId(geyserId);
|
||||||
|
addEntityPacket.setUniqueEntityId(geyserId);
|
||||||
|
addEntityPacket.setPosition(position);
|
||||||
|
addEntityPacket.setMotion(motion);
|
||||||
|
addEntityPacket.setRotation(getBedrockRotation());
|
||||||
|
addEntityPacket.setEntityType(entityType.getType());
|
||||||
|
addEntityPacket.getMetadata().putAll(metadata);
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
session.getUpstream().sendPacket(addEntityPacket);
|
||||||
|
|
||||||
|
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,13 +29,9 @@ import lombok.Getter;
|
||||||
import org.geysermc.connector.entity.*;
|
import org.geysermc.connector.entity.*;
|
||||||
import org.geysermc.connector.entity.living.*;
|
import org.geysermc.connector.entity.living.*;
|
||||||
import org.geysermc.connector.entity.living.animal.*;
|
import org.geysermc.connector.entity.living.animal.*;
|
||||||
import org.geysermc.connector.entity.living.animal.tameable.CatEntity;
|
import org.geysermc.connector.entity.living.animal.horse.*;
|
||||||
import org.geysermc.connector.entity.living.animal.tameable.TameableEntity;
|
import org.geysermc.connector.entity.living.animal.tameable.*;
|
||||||
import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity;
|
import org.geysermc.connector.entity.living.merchant.*;
|
||||||
import org.geysermc.connector.entity.living.animal.horse.ChestedHorseEntity;
|
|
||||||
import org.geysermc.connector.entity.living.animal.horse.HorseEntity;
|
|
||||||
import org.geysermc.connector.entity.living.animal.horse.LlamaEntity;
|
|
||||||
import org.geysermc.connector.entity.living.animal.tameable.WolfEntity;
|
|
||||||
import org.geysermc.connector.entity.living.monster.*;
|
import org.geysermc.connector.entity.living.monster.*;
|
||||||
import org.geysermc.connector.entity.living.monster.raid.AbstractIllagerEntity;
|
import org.geysermc.connector.entity.living.monster.raid.AbstractIllagerEntity;
|
||||||
import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity;
|
import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity;
|
||||||
|
@ -49,7 +45,7 @@ public enum EntityType {
|
||||||
PIG(PigEntity.class, 12, 0.9f),
|
PIG(PigEntity.class, 12, 0.9f),
|
||||||
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
SHEEP(SheepEntity.class, 13, 1.3f, 0.9f),
|
||||||
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
WOLF(WolfEntity.class, 14, 0.85f, 0.6f),
|
||||||
VILLAGER(AbstractMerchantEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f),
|
VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f),
|
||||||
SQUID(WaterEntity.class, 17, 0.8f),
|
SQUID(WaterEntity.class, 17, 0.8f),
|
||||||
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f),
|
||||||
|
@ -64,8 +60,8 @@ public enum EntityType {
|
||||||
ZOMBIE_HORSE(AbstractHorseEntity.class, 27, 1.6f, 1.3965f),
|
ZOMBIE_HORSE(AbstractHorseEntity.class, 27, 1.6f, 1.3965f),
|
||||||
POLAR_BEAR(PolarBearEntity.class, 28, 1.4f, 1.3f),
|
POLAR_BEAR(PolarBearEntity.class, 28, 1.4f, 1.3f),
|
||||||
LLAMA(LlamaEntity.class, 29, 1.87f, 0.9f),
|
LLAMA(LlamaEntity.class, 29, 1.87f, 0.9f),
|
||||||
TRADER_LLAMA(LlamaEntity.class, 29, 1.187f, 0.9f),
|
TRADER_LLAMA(TraderLlamaEntity.class, 29, 1.187f, 0.9f),
|
||||||
PARROT(TameableEntity.class, 30, 0.9f, 0.5f),
|
PARROT(ParrotEntity.class, 30, 0.9f, 0.5f),
|
||||||
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
DOLPHIN(WaterEntity.class, 31, 0.6f, 0.9f),
|
||||||
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
ZOMBIE(ZombieEntity.class, 32, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f),
|
||||||
|
@ -103,7 +99,7 @@ public enum EntityType {
|
||||||
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f),
|
||||||
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
ITEM(ItemEntity.class, 64, 0.25f, 0.25f),
|
||||||
TNT(Entity.class, 65, 0.98f, 0.98f),
|
TNT(Entity.class, 65, 0.98f, 0.98f),
|
||||||
FALLING_BLOCK(Entity.class, 66, 0.98f, 0.98f),
|
FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f),
|
||||||
MOVING_BLOCK(Entity.class, 67, 0f),
|
MOVING_BLOCK(Entity.class, 67, 0f),
|
||||||
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f),
|
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f),
|
||||||
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f),
|
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f),
|
||||||
|
@ -123,7 +119,7 @@ public enum EntityType {
|
||||||
PAINTING(PaintingEntity.class, 83, 0f),
|
PAINTING(PaintingEntity.class, 83, 0f),
|
||||||
MINECART(MinecartEntity.class, 84, 0f),
|
MINECART(MinecartEntity.class, 84, 0f),
|
||||||
FIREBALL(ItemedFireballEntity.class, 85, 0f),
|
FIREBALL(ItemedFireballEntity.class, 85, 0f),
|
||||||
SPLASH_POTION(ThrowableEntity.class, 86, 0f),
|
POTION(ThrowableEntity.class, 86, 0f),
|
||||||
ENDER_PEARL(ThrowableEntity.class, 87, 0f),
|
ENDER_PEARL(ThrowableEntity.class, 87, 0f),
|
||||||
LEASH_KNOT(Entity.class, 88, 0f),
|
LEASH_KNOT(Entity.class, 88, 0f),
|
||||||
WITHER_SKULL(Entity.class, 89, 0f),
|
WITHER_SKULL(Entity.class, 89, 0f),
|
||||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.connector.network;
|
||||||
|
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
import org.geysermc.common.AuthType;
|
||||||
import org.geysermc.common.IGeyserConfiguration;
|
import org.geysermc.common.IGeyserConfiguration;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
@ -142,7 +143,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MovePlayerPacket packet) {
|
public boolean handle(MovePlayerPacket packet) {
|
||||||
if (!session.isLoggedIn() && !session.isLoggingIn()) {
|
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)
|
// TODO it is safer to key authentication on something that won't change (UUID, not username)
|
||||||
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
if (!couldLoginUserByName(session.getAuthData().getName())) {
|
||||||
LoginEncryptionUtils.showLoginWindow(session);
|
LoginEncryptionUtils.showLoginWindow(session);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
package org.geysermc.connector.network.session;
|
package org.geysermc.connector.network.session;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
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.auth.exception.request.RequestException;
|
||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
|
@ -38,6 +39,7 @@ import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||||
import com.nukkitx.math.GenericMath;
|
import com.nukkitx.math.GenericMath;
|
||||||
import com.nukkitx.math.TrigMath;
|
import com.nukkitx.math.TrigMath;
|
||||||
import com.nukkitx.math.vector.Vector2f;
|
import com.nukkitx.math.vector.Vector2f;
|
||||||
|
import com.nukkitx.math.vector.Vector2i;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.nbt.tag.CompoundTag;
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
|
@ -63,6 +65,7 @@ import org.geysermc.connector.network.session.cache.*;
|
||||||
import org.geysermc.connector.network.translators.Registry;
|
import org.geysermc.connector.network.translators.Registry;
|
||||||
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
import org.geysermc.connector.utils.Toolbox;
|
import org.geysermc.connector.utils.Toolbox;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||||
|
@ -96,6 +99,8 @@ public class GeyserSession implements CommandSender {
|
||||||
|
|
||||||
private DataCache<Packet> javaPacketCache;
|
private DataCache<Packet> javaPacketCache;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private Vector2i lastChunkPosition = null;
|
||||||
private int renderDistance;
|
private int renderDistance;
|
||||||
|
|
||||||
private boolean loggedIn;
|
private boolean loggedIn;
|
||||||
|
@ -144,15 +149,6 @@ public class GeyserSession implements CommandSender {
|
||||||
public void connect(RemoteServer remoteServer) {
|
public void connect(RemoteServer remoteServer) {
|
||||||
startGame();
|
startGame();
|
||||||
this.remoteServer = remoteServer;
|
this.remoteServer = remoteServer;
|
||||||
if (connector.getAuthType() != AuthType.ONLINE) {
|
|
||||||
connector.getLogger().info(
|
|
||||||
"Attempting to login using " + connector.getAuthType().name().toLowerCase() + " mode... " +
|
|
||||||
(connector.getAuthType() == AuthType.OFFLINE ?
|
|
||||||
"authentication is disabled." : "authentication will be encrypted"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
authenticate(authData.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false);
|
||||||
|
|
||||||
|
@ -169,6 +165,18 @@ public class GeyserSession implements CommandSender {
|
||||||
upstream.sendPacket(playStatusPacket);
|
upstream.sendPacket(playStatusPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void login() {
|
||||||
|
if (connector.getAuthType() != AuthType.ONLINE) {
|
||||||
|
connector.getLogger().info(
|
||||||
|
"Attempting to login using " + connector.getAuthType().name().toLowerCase() + " mode... " +
|
||||||
|
(connector.getAuthType() == AuthType.OFFLINE ?
|
||||||
|
"authentication is disabled." : "authentication will be encrypted"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
authenticate(authData.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void authenticate(String username) {
|
public void authenticate(String username) {
|
||||||
authenticate(username, "");
|
authenticate(username, "");
|
||||||
}
|
}
|
||||||
|
@ -179,7 +187,7 @@ public class GeyserSession implements CommandSender {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loggedIn = true;
|
loggingIn = true;
|
||||||
// new thread so clients don't timeout
|
// new thread so clients don't timeout
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -248,6 +256,17 @@ public class GeyserSession implements CommandSender {
|
||||||
connector.getLogger().info(authData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
|
connector.getLogger().info(authData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress());
|
||||||
playerEntity.setUuid(protocol.getProfile().getId());
|
playerEntity.setUuid(protocol.getProfile().getId());
|
||||||
playerEntity.setUsername(protocol.getProfile().getName());
|
playerEntity.setUsername(protocol.getProfile().getName());
|
||||||
|
|
||||||
|
String locale = clientData.getLanguageCode();
|
||||||
|
|
||||||
|
// Let the user know there locale may take some time to download
|
||||||
|
// as it has to be extracted from a JAR
|
||||||
|
if (locale.toLowerCase().equals("en_us") && !LocaleUtils.LOCALE_MAPPINGS.containsKey("en_us")) {
|
||||||
|
sendMessage("Downloading your locale (en_us) this may take some time");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download and load the language for the player
|
||||||
|
LocaleUtils.downloadAndLoadLocale(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -278,6 +297,9 @@ public class GeyserSession implements CommandSender {
|
||||||
|
|
||||||
downstream.getSession().connect();
|
downstream.getSession().connect();
|
||||||
connector.addPlayer(this);
|
connector.addPlayer(this);
|
||||||
|
} catch (InvalidCredentialsException e) {
|
||||||
|
connector.getLogger().info("User '" + username + "' entered invalid login info, kicking.");
|
||||||
|
disconnect("Invalid/incorrect login info");
|
||||||
} catch (RequestException ex) {
|
} catch (RequestException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -381,7 +403,7 @@ public class GeyserSession implements CommandSender {
|
||||||
startGamePacket.setBonusChestEnabled(false);
|
startGamePacket.setBonusChestEnabled(false);
|
||||||
startGamePacket.setStartingWithMap(false);
|
startGamePacket.setStartingWithMap(false);
|
||||||
startGamePacket.setTrustingPlayers(true);
|
startGamePacket.setTrustingPlayers(true);
|
||||||
startGamePacket.setDefaultPlayerPermission(PlayerPermission.OPERATOR);
|
startGamePacket.setDefaultPlayerPermission(PlayerPermission.MEMBER);
|
||||||
startGamePacket.setServerChunkTickRange(4);
|
startGamePacket.setServerChunkTickRange(4);
|
||||||
startGamePacket.setBehaviorPackLocked(false);
|
startGamePacket.setBehaviorPackLocked(false);
|
||||||
startGamePacket.setResourcePackLocked(false);
|
startGamePacket.setResourcePackLocked(false);
|
||||||
|
|
|
@ -55,6 +55,8 @@ public class Registry<T> {
|
||||||
if (MAP.containsKey(clazz)) {
|
if (MAP.containsKey(clazz)) {
|
||||||
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
((PacketTranslator<P>) MAP.get(clazz)).translate(packet, session);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex);
|
||||||
|
|
|
@ -33,12 +33,10 @@ import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
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.entity.player.PlayerAction;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
|
import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket;
|
||||||
|
@ -101,10 +99,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||||
session.getDownstream().getSession().send(stopSleepingPacket);
|
session.getDownstream().getSession().send(stopSleepingPacket);
|
||||||
break;
|
break;
|
||||||
case BLOCK_INTERACT:
|
case BLOCK_INTERACT:
|
||||||
ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket(position,
|
// Handled in BedrockInventoryTransactionTranslator
|
||||||
BlockFace.values()[packet.getFace()],
|
|
||||||
Hand.MAIN_HAND, 0, 0, 0, false);
|
|
||||||
session.getDownstream().getSession().send(blockPacket);
|
|
||||||
break;
|
break;
|
||||||
case START_BREAK:
|
case START_BREAK:
|
||||||
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(),
|
ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(),
|
||||||
|
|
|
@ -33,6 +33,8 @@ 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.player.ClientPlayerSwingArmPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Translator(packet = AnimatePacket.class)
|
@Translator(packet = AnimatePacket.class)
|
||||||
public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||||
|
|
||||||
|
@ -40,8 +42,12 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||||
public void translate(AnimatePacket packet, GeyserSession session) {
|
public void translate(AnimatePacket packet, GeyserSession session) {
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case SWING_ARM:
|
case SWING_ARM:
|
||||||
ClientPlayerSwingArmPacket swingArmPacket = new ClientPlayerSwingArmPacket(Hand.MAIN_HAND);
|
// Delay so entity damage can be processed first
|
||||||
session.getDownstream().getSession().send(swingArmPacket);
|
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||||
|
session.getDownstream().getSession().send(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
|
||||||
|
25,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.bedrock;
|
package org.geysermc.connector.network.translators.bedrock;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
@ -49,19 +50,33 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
|
||||||
switch (packet.getTransactionType()) {
|
switch (packet.getTransactionType()) {
|
||||||
case ITEM_USE:
|
case ITEM_USE:
|
||||||
if (packet.getActionType() == 1) {
|
switch (packet.getActionType()) {
|
||||||
|
case 0:
|
||||||
|
ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket(
|
||||||
|
new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()),
|
||||||
|
BlockFace.values()[packet.getFace()],
|
||||||
|
Hand.MAIN_HAND,
|
||||||
|
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
|
||||||
|
false);
|
||||||
|
session.getDownstream().getSession().send(blockPacket);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
session.getDownstream().getSession().send(useItemPacket);
|
session.getDownstream().getSession().send(useItemPacket);
|
||||||
} else if (packet.getActionType() == 2) {
|
break;
|
||||||
|
case 2:
|
||||||
PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING;
|
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());
|
Position pos = new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
||||||
ClientPlayerActionPacket breakPacket = new ClientPlayerActionPacket(action, pos, BlockFace.values()[packet.getFace()]);
|
ClientPlayerActionPacket breakPacket = new ClientPlayerActionPacket(action, pos, BlockFace.values()[packet.getFace()]);
|
||||||
session.getDownstream().getSession().send(breakPacket);
|
session.getDownstream().getSession().send(breakPacket);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ITEM_RELEASE:
|
case ITEM_RELEASE:
|
||||||
if (packet.getActionType() == 0) {
|
if (packet.getActionType() == 0) {
|
||||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0, 0, 0), BlockFace.DOWN);
|
// 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.getDownstream().getSession().send(releaseItemPacket);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,12 +34,13 @@ import org.geysermc.connector.utils.SkinUtils;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||||
|
|
||||||
@Translator(packet = SetLocalPlayerAsInitializedPacket.class)
|
@Translator(packet = SetLocalPlayerAsInitializedPacket.class)
|
||||||
public class BedrockPlayerInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
|
public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
|
||||||
@Override
|
@Override
|
||||||
public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession session) {
|
public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession session) {
|
||||||
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
|
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
|
||||||
if (!session.getUpstream().isInitialized()) {
|
if (!session.getUpstream().isInitialized()) {
|
||||||
session.getUpstream().setInitialized(true);
|
session.getUpstream().setInitialized(true);
|
||||||
|
session.login();
|
||||||
|
|
||||||
for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) {
|
for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) {
|
||||||
if (!entity.isValid()) {
|
if (!entity.isValid()) {
|
|
@ -57,6 +57,9 @@ public class BlockTranslator {
|
||||||
private static final Int2ObjectMap<BlockState> BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<BlockState> BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>();
|
||||||
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
private static final IntSet WATERLOGGED = new IntOpenHashSet();
|
||||||
|
|
||||||
|
// Bedrock carpet ID, used in LlamaEntity.java for decoration
|
||||||
|
public static final int CARPET = 171;
|
||||||
|
|
||||||
private static final int BLOCK_STATE_VERSION = 17760256;
|
private static final int BLOCK_STATE_VERSION = 17760256;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -103,7 +106,8 @@ public class BlockTranslator {
|
||||||
if ("minecraft:water[level=0]".equals(javaId)) {
|
if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
waterRuntimeId = bedrockRuntimeId;
|
waterRuntimeId = bedrockRuntimeId;
|
||||||
}
|
}
|
||||||
boolean waterlogged = entry.getValue().has("waterlogged") && entry.getValue().get("waterlogged").booleanValue();
|
boolean waterlogged = entry.getKey().contains("waterlogged=true")
|
||||||
|
|| javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass");
|
||||||
|
|
||||||
if (waterlogged) {
|
if (waterlogged) {
|
||||||
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, new BlockState(javaRuntimeId));
|
BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, new BlockState(javaRuntimeId));
|
||||||
|
@ -180,6 +184,10 @@ public class BlockTranslator {
|
||||||
return JAVA_TO_BEDROCK_BLOCK_MAP.get(state.getId());
|
return JAVA_TO_BEDROCK_BLOCK_MAP.get(state.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getBedrockBlockId(int javaId) {
|
||||||
|
return JAVA_TO_BEDROCK_BLOCK_MAP.get(javaId);
|
||||||
|
}
|
||||||
|
|
||||||
public static BlockState getJavaBlockState(int bedrockId) {
|
public static BlockState getJavaBlockState(int bedrockId) {
|
||||||
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,18 @@ public class ItemTranslator {
|
||||||
if (stack.getNbt() == null) {
|
if (stack.getNbt() == null) {
|
||||||
return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount());
|
return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount());
|
||||||
}
|
}
|
||||||
return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount(), translateToBedrockNBT(stack.getNbt()));
|
|
||||||
|
// TODO: Create proper transformers instead of shoving everything here
|
||||||
|
CompoundTag tag = stack.getNbt();
|
||||||
|
IntTag mapId = tag.get("map");
|
||||||
|
|
||||||
|
if (mapId != null) {
|
||||||
|
tag.put(new StringTag("map_uuid", mapId.getValue().toString()));
|
||||||
|
tag.put(new IntTag("map_name_index", mapId.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ItemData.of(bedrockItem.getBedrockId(), (short) bedrockItem.getBedrockData(), stack.getAmount(), translateToBedrockNBT(tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemEntry getItem(ItemStack stack) {
|
public ItemEntry getItem(ItemStack stack) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class JavaBossBarTranslator extends PacketTranslator<ServerBossBarPacket>
|
||||||
|
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.SHOW);
|
bossEventPacket.setAction(BossEventPacket.Action.SHOW);
|
||||||
bossEventPacket.setBossUniqueEntityId(entityId);
|
bossEventPacket.setBossUniqueEntityId(entityId);
|
||||||
bossEventPacket.setTitle(MessageUtils.getBedrockMessage(packet.getTitle()));
|
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), session.getClientData().getLanguageCode()));
|
||||||
bossEventPacket.setHealthPercentage(packet.getHealth());
|
bossEventPacket.setHealthPercentage(packet.getHealth());
|
||||||
bossEventPacket.setColor(0); //ignored by client
|
bossEventPacket.setColor(0); //ignored by client
|
||||||
bossEventPacket.setOverlay(1);
|
bossEventPacket.setOverlay(1);
|
||||||
|
@ -59,7 +59,7 @@ public class JavaBossBarTranslator extends PacketTranslator<ServerBossBarPacket>
|
||||||
break;
|
break;
|
||||||
case UPDATE_TITLE:
|
case UPDATE_TITLE:
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
|
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
|
||||||
bossEventPacket.setTitle(MessageUtils.getBedrockMessage(packet.getTitle()));
|
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), session.getClientData().getLanguageCode()));
|
||||||
break;
|
break;
|
||||||
case UPDATE_HEALTH:
|
case UPDATE_HEALTH:
|
||||||
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
|
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
|
||||||
|
|
|
@ -34,6 +34,8 @@ import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.TextPacket;
|
import com.nukkitx.protocol.bedrock.packet.TextPacket;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Translator(packet = ServerChatPacket.class)
|
@Translator(packet = ServerChatPacket.class)
|
||||||
public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
||||||
|
|
||||||
|
@ -58,14 +60,20 @@ public class JavaChatTranslator extends PacketTranslator<ServerChatPacket> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String locale = session.getClientData().getLanguageCode();
|
||||||
|
|
||||||
if (packet.getMessage() instanceof TranslationMessage) {
|
if (packet.getMessage() instanceof TranslationMessage) {
|
||||||
textPacket.setType(TextPacket.Type.TRANSLATION);
|
textPacket.setType(TextPacket.Type.TRANSLATION);
|
||||||
textPacket.setNeedsTranslation(true);
|
textPacket.setNeedsTranslation(true);
|
||||||
textPacket.setParameters(MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams()));
|
|
||||||
textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage()));
|
List<String> paramsTranslated = MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams(), locale);
|
||||||
|
textPacket.setParameters(paramsTranslated);
|
||||||
|
|
||||||
|
textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, true), paramsTranslated));
|
||||||
} else {
|
} else {
|
||||||
textPacket.setNeedsTranslation(false);
|
textPacket.setNeedsTranslation(false);
|
||||||
textPacket.setMessage(MessageUtils.getBedrockMessage(packet.getMessage()));
|
|
||||||
|
textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getUpstream().sendPacket(textPacket);
|
session.getUpstream().sendPacket(textPacket);
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.geysermc.connector.entity.PlayerEntity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
|
||||||
import org.geysermc.connector.utils.DimensionUtils;
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
|
||||||
|
@ -49,7 +48,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||||
|
|
||||||
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
|
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
|
||||||
bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
|
bedrockPacket.setUniqueEntityId(session.getPlayerEntity().getGeyserId());
|
||||||
bedrockPacket.setPlayerPermission(PlayerPermission.OPERATOR);
|
bedrockPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||||
session.getUpstream().sendPacket(bedrockPacket);
|
session.getUpstream().sendPacket(bedrockPacket);
|
||||||
|
|
||||||
PlayStatusPacket playStatus = new PlayStatusPacket();
|
PlayStatusPacket playStatus = new PlayStatusPacket();
|
||||||
|
@ -69,7 +68,6 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||||
session.setRenderDistance(packet.getViewDistance());
|
session.setRenderDistance(packet.getViewDistance());
|
||||||
|
|
||||||
if (DimensionUtils.javaToBedrock(packet.getDimension()) != entity.getDimension()) {
|
if (DimensionUtils.javaToBedrock(packet.getDimension()) != entity.getDimension()) {
|
||||||
ChunkUtils.sendEmptyChunks(session, entity.getPosition().toInt(), 3, true);
|
|
||||||
DimensionUtils.switchDimension(session, packet.getDimension());
|
DimensionUtils.switchDimension(session, packet.getDimension());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator<ServerPlayer
|
||||||
playerFlags.add(AdventureSettingsPacket.Flag.FLYING);
|
playerFlags.add(AdventureSettingsPacket.Flag.FLYING);
|
||||||
|
|
||||||
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
||||||
adventureSettingsPacket.setPlayerPermission(PlayerPermission.OPERATOR);
|
adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||||
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
||||||
adventureSettingsPacket.getFlags().addAll(playerFlags);
|
adventureSettingsPacket.getFlags().addAll(playerFlags);
|
||||||
session.getUpstream().sendPacket(adventureSettingsPacket);
|
session.getUpstream().sendPacket(adventureSettingsPacket);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
|
||||||
|
@ -86,6 +87,8 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
||||||
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
|
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
|
||||||
session.getDownstream().getSession().send(teleportConfirmPacket);
|
session.getDownstream().getSession().send(teleportConfirmPacket);
|
||||||
|
|
||||||
|
ChunkUtils.updateChunkPosition(session, pos.toInt());
|
||||||
|
|
||||||
session.getConnector().getLogger().info("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
|
session.getConnector().getLogger().info("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,9 @@ package org.geysermc.connector.network.translators.java.entity.spawn;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.type.object.FallingBlockData;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.FallingBlockEntity;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
@ -59,12 +61,18 @@ public class JavaSpawnObjectTranslator extends PacketTranslator<ServerSpawnObjec
|
||||||
|
|
||||||
Class<? extends Entity> entityClass = type.getEntityClass();
|
Class<? extends Entity> entityClass = type.getEntityClass();
|
||||||
try {
|
try {
|
||||||
|
Entity entity;
|
||||||
|
if (packet.getType() == ObjectType.FALLING_BLOCK) {
|
||||||
|
entity = new FallingBlockEntity(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
|
type, position, motion, rotation, ((FallingBlockData) packet.getData()).getId());
|
||||||
|
} else {
|
||||||
Constructor<? extends Entity> entityConstructor = entityClass.getConstructor(long.class, long.class, EntityType.class,
|
Constructor<? extends Entity> entityConstructor = entityClass.getConstructor(long.class, long.class, EntityType.class,
|
||||||
Vector3f.class, Vector3f.class, Vector3f.class);
|
Vector3f.class, Vector3f.class, Vector3f.class);
|
||||||
|
|
||||||
Entity entity = entityConstructor.newInstance(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
entity = entityConstructor.newInstance(packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
|
||||||
type, position, motion, rotation
|
type, position, motion, rotation
|
||||||
);
|
);
|
||||||
|
}
|
||||||
session.getEntityCache().spawnEntity(entity);
|
session.getEntityCache().spawnEntity(entity);
|
||||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
|
|
@ -52,12 +52,14 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
scoreboard.registerNewTeam(packet.getTeamName(), toPlayerSet(packet.getPlayers()))
|
scoreboard.registerNewTeam(packet.getTeamName(), toPlayerSet(packet.getPlayers()))
|
||||||
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||||
|
.setColor(packet.getColor())
|
||||||
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
||||||
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()));
|
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()));
|
||||||
break;
|
break;
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
scoreboard.getTeam(packet.getTeamName())
|
scoreboard.getTeam(packet.getTeamName())
|
||||||
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||||
|
.setColor(packet.getColor())
|
||||||
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
.setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix()))
|
||||||
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()))
|
.setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix()))
|
||||||
.setUpdateType(UpdateType.UPDATE);
|
.setUpdateType(UpdateType.UPDATE);
|
||||||
|
|
|
@ -36,7 +36,6 @@ import org.geysermc.connector.world.chunk.ChunkSection;
|
||||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
|
||||||
import com.nukkitx.network.VarInts;
|
import com.nukkitx.network.VarInts;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||||
|
|
||||||
|
@ -48,10 +47,16 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerChunkDataPacket packet, GeyserSession session) {
|
public void translate(ServerChunkDataPacket packet, GeyserSession session) {
|
||||||
|
if (session.isSpawned()) {
|
||||||
|
ChunkUtils.updateChunkPosition(session, session.getPlayerEntity().getPosition().toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet.getColumn().getBiomeData() == null) //Non-full chunk
|
||||||
|
return;
|
||||||
|
|
||||||
// Not sure if this is safe or not, however without this the client usually times out
|
// Not sure if this is safe or not, however without this the client usually times out
|
||||||
GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> {
|
GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> {
|
||||||
try {
|
try {
|
||||||
if (packet.getColumn().getBiomeData() != null) { //Full chunk
|
|
||||||
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn());
|
ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn());
|
||||||
ByteBuf byteBuf = Unpooled.buffer(32);
|
ByteBuf byteBuf = Unpooled.buffer(32);
|
||||||
ChunkSection[] sections = chunkData.sections;
|
ChunkSection[] sections = chunkData.sections;
|
||||||
|
@ -83,28 +88,6 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
||||||
levelChunkPacket.setChunkZ(packet.getColumn().getZ());
|
levelChunkPacket.setChunkZ(packet.getColumn().getZ());
|
||||||
levelChunkPacket.setData(payload);
|
levelChunkPacket.setData(payload);
|
||||||
session.getUpstream().sendPacket(levelChunkPacket);
|
session.getUpstream().sendPacket(levelChunkPacket);
|
||||||
} else {
|
|
||||||
final int xOffset = packet.getColumn().getX() << 4;
|
|
||||||
final int zOffset = packet.getColumn().getZ() << 4;
|
|
||||||
Chunk[] chunks = packet.getColumn().getChunks();
|
|
||||||
for (int i = 0; i < chunks.length; i++) {
|
|
||||||
Chunk chunk = chunks[i];
|
|
||||||
if (chunk == null) continue;
|
|
||||||
final int yOffset = i * 16;
|
|
||||||
for (int x = 0; x < 16; x++) {
|
|
||||||
for (int y = 0; y < 16; y++) {
|
|
||||||
for (int z = 0; z < 16; z++) {
|
|
||||||
BlockState blockState = chunk.get(x, y, z);
|
|
||||||
Vector3i pos = Vector3i.from(
|
|
||||||
x + xOffset,
|
|
||||||
y + yOffset,
|
|
||||||
z + zOffset);
|
|
||||||
ChunkUtils.updateBlock(session, blockState, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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.java.world;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityCollectItemPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.TakeItemEntityPacket;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
|
||||||
|
@Translator(packet = ServerEntityCollectItemPacket.class)
|
||||||
|
public class JavaCollectItemTranslator extends PacketTranslator<ServerEntityCollectItemPacket> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translate(ServerEntityCollectItemPacket packet, GeyserSession session) {
|
||||||
|
// This is the definition of translating - both packets take the same values
|
||||||
|
TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket();
|
||||||
|
// Collected entity is the item
|
||||||
|
Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId());
|
||||||
|
// Collector is the entity picking up the item
|
||||||
|
Entity collectorEntity;
|
||||||
|
if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||||
|
collectorEntity = session.getPlayerEntity();
|
||||||
|
} else {
|
||||||
|
collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId());
|
||||||
|
}
|
||||||
|
takeItemEntityPacket.setRuntimeEntityId(collectorEntity.getGeyserId());
|
||||||
|
takeItemEntityPacket.setItemRuntimeEntityId(collectedEntity.getGeyserId());
|
||||||
|
session.getUpstream().sendPacket(takeItemEntityPacket);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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.java.world;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.world.map.MapData;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerMapDataPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket;
|
||||||
|
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.utils.MapColor;
|
||||||
|
|
||||||
|
@Translator(packet = ServerMapDataPacket.class)
|
||||||
|
public class JavaMapDataTranslator extends PacketTranslator<ServerMapDataPacket> {
|
||||||
|
@Override
|
||||||
|
public void translate(ServerMapDataPacket packet, GeyserSession session) {
|
||||||
|
ClientboundMapItemDataPacket mapItemDataPacket = new ClientboundMapItemDataPacket();
|
||||||
|
|
||||||
|
mapItemDataPacket.setUniqueMapId(packet.getMapId());
|
||||||
|
mapItemDataPacket.setDimensionId(session.getPlayerEntity().getDimension());
|
||||||
|
mapItemDataPacket.setLocked(packet.isLocked());
|
||||||
|
mapItemDataPacket.setScale(packet.getScale());
|
||||||
|
|
||||||
|
MapData data = packet.getData();
|
||||||
|
if (data != null) {
|
||||||
|
mapItemDataPacket.setXOffset(data.getX());
|
||||||
|
mapItemDataPacket.setYOffset(data.getY());
|
||||||
|
mapItemDataPacket.setWidth(data.getColumns());
|
||||||
|
mapItemDataPacket.setHeight(data.getRows());
|
||||||
|
|
||||||
|
// Every int entry is an ARGB color
|
||||||
|
int[] colors = new int[data.getData().length];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (byte colorId : data.getData()) {
|
||||||
|
colors[idx] = MapColor.fromId(colorId).toARGB();
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapItemDataPacket.setColors(colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
session.getUpstream().getSession().sendPacket(mapItemDataPacket);
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,7 +98,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
|
||||||
session.setGameMode(gameMode);
|
session.setGameMode(gameMode);
|
||||||
|
|
||||||
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
||||||
adventureSettingsPacket.setPlayerPermission(PlayerPermission.OPERATOR);
|
adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||||
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
||||||
adventureSettingsPacket.getFlags().addAll(playerFlags);
|
adventureSettingsPacket.getFlags().addAll(playerFlags);
|
||||||
session.getUpstream().sendPacket(adventureSettingsPacket);
|
session.getUpstream().sendPacket(adventureSettingsPacket);
|
||||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java.world;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateViewPositionPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateViewPositionPacket;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
@ -38,9 +39,8 @@ public class JavaUpdateViewPositionTranslator extends PacketTranslator<ServerUpd
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerUpdateViewPositionPacket packet, GeyserSession session) {
|
public void translate(ServerUpdateViewPositionPacket packet, GeyserSession session) {
|
||||||
NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket();
|
if (!session.isSpawned() && session.getLastChunkPosition() == null) {
|
||||||
chunkPublisherUpdatePacket.setPosition(Vector3i.from(packet.getChunkX() << 4, 0, packet.getChunkZ() << 4));
|
ChunkUtils.updateChunkPosition(session, Vector3i.from(packet.getChunkX() << 4, 64, packet.getChunkZ() << 4));
|
||||||
chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4);
|
}
|
||||||
session.getUpstream().sendPacket(chunkPublisherUpdatePacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.scoreboard;
|
package org.geysermc.connector.scoreboard;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
@ -44,10 +45,10 @@ public class Team {
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
private UpdateType updateType = UpdateType.ADD;
|
||||||
private String name;
|
private String name;
|
||||||
private String prefix;
|
private String prefix;
|
||||||
|
private TeamColor color;
|
||||||
private String suffix;
|
private String suffix;
|
||||||
private Set<String> entities = new ObjectOpenHashSet<>();
|
private Set<String> entities = new ObjectOpenHashSet<>();
|
||||||
|
|
||||||
|
|
||||||
public Team(Scoreboard scoreboard, String id) {
|
public Team(Scoreboard scoreboard, String id) {
|
||||||
this.scoreboard = scoreboard;
|
this.scoreboard = scoreboard;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
|
@ -29,8 +29,10 @@ import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||||
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
|
||||||
|
import com.nukkitx.math.vector.Vector2i;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.Translators;
|
import org.geysermc.connector.network.translators.Translators;
|
||||||
|
@ -74,6 +76,20 @@ public class ChunkUtils {
|
||||||
return chunkData;
|
return chunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateChunkPosition(GeyserSession session, Vector3i position) {
|
||||||
|
Vector2i chunkPos = session.getLastChunkPosition();
|
||||||
|
Vector2i newChunkPos = Vector2i.from(position.getX() >> 4, position.getZ() >> 4);
|
||||||
|
|
||||||
|
if (chunkPos == null || !chunkPos.equals(newChunkPos)) {
|
||||||
|
NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket();
|
||||||
|
chunkPublisherUpdatePacket.setPosition(position);
|
||||||
|
chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4);
|
||||||
|
session.getUpstream().sendPacket(chunkPublisherUpdatePacket);
|
||||||
|
|
||||||
|
session.setLastChunkPosition(newChunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void updateBlock(GeyserSession session, BlockState blockState, Position position) {
|
public static void updateBlock(GeyserSession session, BlockState blockState, Position position) {
|
||||||
Vector3i pos = Vector3i.from(position.getX(), position.getY(), position.getZ());
|
Vector3i pos = Vector3i.from(position.getX(), position.getY(), position.getZ());
|
||||||
updateBlock(session, blockState, pos);
|
updateBlock(session, blockState, pos);
|
||||||
|
|
|
@ -52,6 +52,7 @@ public class DimensionUtils {
|
||||||
player.setDimension(bedrockDimension);
|
player.setDimension(bedrockDimension);
|
||||||
player.setPosition(pos.toFloat());
|
player.setPosition(pos.toFloat());
|
||||||
session.setSpawned(false);
|
session.setSpawned(false);
|
||||||
|
session.setLastChunkPosition(null);
|
||||||
|
|
||||||
//let java server handle portal travel sound
|
//let java server handle portal travel sound
|
||||||
StopSoundPacket stopSoundPacket = new StopSoundPacket();
|
StopSoundPacket stopSoundPacket = new StopSoundPacket();
|
||||||
|
|
|
@ -72,4 +72,23 @@ public class FileUtils {
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void writeFile(File file, char[] data) throws IOException {
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
|
||||||
|
for (char c : data) {
|
||||||
|
fos.write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fos.flush();
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeFile(String name, char[] data) throws IOException {
|
||||||
|
writeFile(new File(name), data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class LocaleUtils {
|
||||||
|
|
||||||
|
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
||||||
|
|
||||||
|
private static final Map<String, Asset> ASSET_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
private static final String DEFAULT_LOCALE = (GeyserConnector.getInstance().getConfig().getDefaultLocale() != null ? GeyserConnector.getInstance().getConfig().getDefaultLocale() : "en_us");
|
||||||
|
|
||||||
|
private static String smallestURL = "";
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Create the locales folder
|
||||||
|
File localesFolder = new File("locales/");
|
||||||
|
localesFolder.mkdir();
|
||||||
|
|
||||||
|
// Download the latest asset list and cache it
|
||||||
|
generateAssetCache();
|
||||||
|
downloadAndLoadLocale(DEFAULT_LOCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generateAssetCache() {
|
||||||
|
try {
|
||||||
|
VersionManifest versionManifest = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class);
|
||||||
|
String latestInfoURL = "";
|
||||||
|
for (Version version : versionManifest.getVersions()) {
|
||||||
|
if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) {
|
||||||
|
latestInfoURL = version.getUrl();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latestInfoURL.isEmpty()) {
|
||||||
|
throw new Exception("Unable to get latest Minecraft version");
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionInfo versionInfo = Toolbox.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class);
|
||||||
|
|
||||||
|
int currentSize = Integer.MAX_VALUE;
|
||||||
|
for (VersionDownload download : versionInfo.getDownloads().values()) {
|
||||||
|
if (download.getUrl().endsWith(".jar") && download.getSize() < currentSize) {
|
||||||
|
smallestURL = download.getUrl();
|
||||||
|
currentSize = download.getSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode assets = Toolbox.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects");
|
||||||
|
|
||||||
|
Iterator<Map.Entry<String, JsonNode>> assetIterator = assets.fields();
|
||||||
|
while (assetIterator.hasNext()) {
|
||||||
|
Map.Entry<String, JsonNode> entry = assetIterator.next();
|
||||||
|
Asset asset = Toolbox.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class);
|
||||||
|
ASSET_MAP.put(entry.getKey(), asset);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
GeyserConnector.getInstance().getLogger().info("Failed to load locale asset cache: " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void downloadAndLoadLocale(String locale) {
|
||||||
|
locale = locale.toLowerCase();
|
||||||
|
if (!ASSET_MAP.containsKey("minecraft/lang/" + locale + ".json") && !locale.equals("en_us")) {
|
||||||
|
GeyserConnector.getInstance().getLogger().warning("Invalid locale requested to download and load: " + locale);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Downloading and loading locale: " + locale);
|
||||||
|
|
||||||
|
downloadLocale(locale);
|
||||||
|
loadLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void downloadLocale(String locale) {
|
||||||
|
File localeFile = new File("locales/" + locale + ".json");
|
||||||
|
|
||||||
|
if (localeFile.exists()) {
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Locale already downloaded: " + locale);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the en_us locale
|
||||||
|
if (locale.equals("en_us")) {
|
||||||
|
downloadEN_US(localeFile);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the hash and download the locale
|
||||||
|
String hash = ASSET_MAP.get("minecraft/lang/" + locale + ".json").getHash();
|
||||||
|
WebUtils.downloadFile("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash, "locales/" + locale + ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadLocale(String locale) {
|
||||||
|
File localeFile = new File("locales/" + locale + ".json");
|
||||||
|
|
||||||
|
// Load the locale
|
||||||
|
if (localeFile.exists()) {
|
||||||
|
// Read the localefile
|
||||||
|
InputStream localeStream;
|
||||||
|
try {
|
||||||
|
localeStream = new FileInputStream(localeFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new AssertionError("Unable to load locale: " + locale + " (" + e.getMessage() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the file as json
|
||||||
|
JsonNode localeObj;
|
||||||
|
try {
|
||||||
|
localeObj = Toolbox.JSON_MAPPER.readTree(localeStream);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError("Unable to load Java lang map for " + locale, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse all the locale fields
|
||||||
|
Iterator<Map.Entry<String, JsonNode>> localeIterator = localeObj.fields();
|
||||||
|
Map<String, String> langMap = new HashMap<>();
|
||||||
|
while (localeIterator.hasNext()) {
|
||||||
|
Map.Entry<String, JsonNode> entry = localeIterator.next();
|
||||||
|
langMap.put(entry.getKey(), entry.getValue().asText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the locale into the mappings
|
||||||
|
LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap);
|
||||||
|
} else {
|
||||||
|
GeyserConnector.getInstance().getLogger().warning("Missing locale file: " + locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void downloadEN_US(File localeFile) {
|
||||||
|
try {
|
||||||
|
// Let the user know we are downloading the JAR
|
||||||
|
GeyserConnector.getInstance().getLogger().info("Downloading Minecraft JAR to extract en_us locale, please wait... (this may take some time depending on the speed of your internet connection)");
|
||||||
|
GeyserConnector.getInstance().getLogger().debug("Download URL: " + smallestURL);
|
||||||
|
|
||||||
|
// Download the smallest JAR (client or server)
|
||||||
|
WebUtils.downloadFile(smallestURL, "tmp_locale.jar");
|
||||||
|
|
||||||
|
// Load in the JAR as a zip and extract the file
|
||||||
|
ZipFile localeJar = new ZipFile("tmp_locale.jar");
|
||||||
|
InputStream inputStream = localeJar.getInputStream(localeJar.getEntry("assets/minecraft/lang/en_us.json"));
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(localeFile);
|
||||||
|
|
||||||
|
// Write the file to the locale dir
|
||||||
|
int data = inputStream.read();
|
||||||
|
while(data != -1){
|
||||||
|
outputStream.write(data);
|
||||||
|
data = inputStream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush all changes to disk and cleanup
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
inputStream.close();
|
||||||
|
localeJar.close();
|
||||||
|
|
||||||
|
// Delete the nolonger needed client/server jar
|
||||||
|
Files.delete(Paths.get("tmp_locale.jar"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError("Unable to download and extract en_us locale!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLocaleString(String messageText, String locale) {
|
||||||
|
Map<String, String> localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase());
|
||||||
|
if (localeStrings == null)
|
||||||
|
localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(DEFAULT_LOCALE);
|
||||||
|
|
||||||
|
return localeStrings.getOrDefault(messageText, messageText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class VersionManifest {
|
||||||
|
@JsonProperty("latest")
|
||||||
|
private LatestVersion latestVersion;
|
||||||
|
|
||||||
|
@JsonProperty("versions")
|
||||||
|
private List<Version> versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class LatestVersion {
|
||||||
|
@JsonProperty("release")
|
||||||
|
private String release;
|
||||||
|
|
||||||
|
@JsonProperty("snapshot")
|
||||||
|
private String snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class Version {
|
||||||
|
@JsonProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@JsonProperty("type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@JsonProperty("url")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@JsonProperty("time")
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
@JsonProperty("releaseTime")
|
||||||
|
private String releaseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class VersionInfo {
|
||||||
|
@JsonProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@JsonProperty("type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@JsonProperty("time")
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
@JsonProperty("releaseTime")
|
||||||
|
private String releaseTime;
|
||||||
|
|
||||||
|
@JsonProperty("assetIndex")
|
||||||
|
private AssetIndex assetIndex;
|
||||||
|
|
||||||
|
@JsonProperty("downloads")
|
||||||
|
private Map<String, VersionDownload> downloads;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class VersionDownload {
|
||||||
|
@JsonProperty("sha1")
|
||||||
|
private String sha1;
|
||||||
|
|
||||||
|
@JsonProperty("size")
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
@JsonProperty("url")
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class AssetIndex {
|
||||||
|
@JsonProperty("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@JsonProperty("sha1")
|
||||||
|
private String sha1;
|
||||||
|
|
||||||
|
@JsonProperty("size")
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
@JsonProperty("totalSize")
|
||||||
|
private int totalSize;
|
||||||
|
|
||||||
|
@JsonProperty("url")
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@Getter
|
||||||
|
class Asset {
|
||||||
|
@JsonProperty("hash")
|
||||||
|
private String hash;
|
||||||
|
|
||||||
|
@JsonProperty("size")
|
||||||
|
private int size;
|
||||||
|
}
|
|
@ -0,0 +1,244 @@
|
||||||
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public enum MapColor {
|
||||||
|
COLOR_0(-1, -1, -1),
|
||||||
|
COLOR_1(-1, -1, -1),
|
||||||
|
COLOR_2(-1, -1, -1),
|
||||||
|
COLOR_3(-1, -1, -1),
|
||||||
|
COLOR_4(89, 125, 39),
|
||||||
|
COLOR_5(109, 153, 48),
|
||||||
|
COLOR_6(127, 178, 56),
|
||||||
|
COLOR_7(67, 94, 29),
|
||||||
|
COLOR_8(174, 164, 115),
|
||||||
|
COLOR_9(213, 201, 140),
|
||||||
|
COLOR_10(247, 233, 163),
|
||||||
|
COLOR_11(130, 123, 86),
|
||||||
|
COLOR_12(140, 140, 140),
|
||||||
|
COLOR_13(171, 171, 171),
|
||||||
|
COLOR_14(199, 199, 199),
|
||||||
|
COLOR_15(105, 105, 105),
|
||||||
|
COLOR_16(180, 0, 0),
|
||||||
|
COLOR_17(220, 0, 0),
|
||||||
|
COLOR_18(255, 0, 0),
|
||||||
|
COLOR_19(135, 0, 0),
|
||||||
|
COLOR_20(112, 112, 180),
|
||||||
|
COLOR_21(138, 138, 220),
|
||||||
|
COLOR_22(160, 160, 255),
|
||||||
|
COLOR_23(84, 84, 135),
|
||||||
|
COLOR_24(117, 117, 117),
|
||||||
|
COLOR_25(144, 144, 144),
|
||||||
|
COLOR_26(167, 167, 167),
|
||||||
|
COLOR_27(88, 88, 88),
|
||||||
|
COLOR_28(0, 87, 0),
|
||||||
|
COLOR_29(0, 106, 0),
|
||||||
|
COLOR_30(0, 124, 0),
|
||||||
|
COLOR_31(0, 65, 0),
|
||||||
|
COLOR_32(180, 180, 180),
|
||||||
|
COLOR_33(220, 220, 220),
|
||||||
|
COLOR_34(255, 255, 255),
|
||||||
|
COLOR_35(135, 135, 135),
|
||||||
|
COLOR_36(115, 118, 129),
|
||||||
|
COLOR_37(141, 144, 158),
|
||||||
|
COLOR_38(164, 168, 184),
|
||||||
|
COLOR_39(86, 88, 97),
|
||||||
|
COLOR_40(106, 76, 54),
|
||||||
|
COLOR_41(130, 94, 66),
|
||||||
|
COLOR_42(151, 109, 77),
|
||||||
|
COLOR_43(79, 57, 40),
|
||||||
|
COLOR_44(79, 79, 79),
|
||||||
|
COLOR_45(96, 96, 96),
|
||||||
|
COLOR_46(112, 112, 112),
|
||||||
|
COLOR_47(59, 59, 59),
|
||||||
|
COLOR_48(45, 45, 180),
|
||||||
|
COLOR_49(55, 55, 220),
|
||||||
|
COLOR_50(64, 64, 255),
|
||||||
|
COLOR_51(33, 33, 135),
|
||||||
|
COLOR_52(100, 84, 50),
|
||||||
|
COLOR_53(123, 102, 62),
|
||||||
|
COLOR_54(143, 119, 72),
|
||||||
|
COLOR_55(75, 63, 38),
|
||||||
|
COLOR_56(180, 177, 172),
|
||||||
|
COLOR_57(220, 217, 211),
|
||||||
|
COLOR_58(255, 252, 245),
|
||||||
|
COLOR_59(135, 133, 129),
|
||||||
|
COLOR_60(152, 89, 36),
|
||||||
|
COLOR_61(186, 109, 44),
|
||||||
|
COLOR_62(216, 127, 51),
|
||||||
|
COLOR_63(114, 67, 27),
|
||||||
|
COLOR_64(125, 53, 152),
|
||||||
|
COLOR_65(153, 65, 186),
|
||||||
|
COLOR_66(178, 76, 216),
|
||||||
|
COLOR_67(94, 40, 114),
|
||||||
|
COLOR_68(72, 108, 152),
|
||||||
|
COLOR_69(88, 132, 186),
|
||||||
|
COLOR_70(102, 153, 216),
|
||||||
|
COLOR_71(54, 81, 114),
|
||||||
|
COLOR_72(161, 161, 36),
|
||||||
|
COLOR_73(197, 197, 44),
|
||||||
|
COLOR_74(229, 229, 51),
|
||||||
|
COLOR_75(121, 121, 27),
|
||||||
|
COLOR_76(89, 144, 17),
|
||||||
|
COLOR_77(109, 176, 21),
|
||||||
|
COLOR_78(127, 204, 25),
|
||||||
|
COLOR_79(67, 108, 13),
|
||||||
|
COLOR_80(170, 89, 116),
|
||||||
|
COLOR_81(208, 109, 142),
|
||||||
|
COLOR_82(242, 127, 165),
|
||||||
|
COLOR_83(128, 67, 87),
|
||||||
|
COLOR_84(53, 53, 53),
|
||||||
|
COLOR_85(65, 65, 65),
|
||||||
|
COLOR_86(76, 76, 76),
|
||||||
|
COLOR_87(40, 40, 40),
|
||||||
|
COLOR_88(108, 108, 108),
|
||||||
|
COLOR_89(132, 132, 132),
|
||||||
|
COLOR_90(153, 153, 153),
|
||||||
|
COLOR_91(81, 81, 81),
|
||||||
|
COLOR_92(53, 89, 108),
|
||||||
|
COLOR_93(65, 109, 132),
|
||||||
|
COLOR_94(76, 127, 153),
|
||||||
|
COLOR_95(40, 67, 81),
|
||||||
|
COLOR_96(89, 44, 125),
|
||||||
|
COLOR_97(109, 54, 153),
|
||||||
|
COLOR_98(127, 63, 178),
|
||||||
|
COLOR_99(67, 33, 94),
|
||||||
|
COLOR_100(36, 53, 125),
|
||||||
|
COLOR_101(44, 65, 153),
|
||||||
|
COLOR_102(51, 76, 178),
|
||||||
|
COLOR_103(27, 40, 94),
|
||||||
|
COLOR_104(72, 53, 36),
|
||||||
|
COLOR_105(88, 65, 44),
|
||||||
|
COLOR_106(102, 76, 51),
|
||||||
|
COLOR_107(54, 40, 27),
|
||||||
|
COLOR_108(72, 89, 36),
|
||||||
|
COLOR_109(88, 109, 44),
|
||||||
|
COLOR_110(102, 127, 51),
|
||||||
|
COLOR_111(54, 67, 27),
|
||||||
|
COLOR_112(108, 36, 36),
|
||||||
|
COLOR_113(132, 44, 44),
|
||||||
|
COLOR_114(153, 51, 51),
|
||||||
|
COLOR_115(81, 27, 27),
|
||||||
|
COLOR_116(17, 17, 17),
|
||||||
|
COLOR_117(21, 21, 21),
|
||||||
|
COLOR_118(25, 25, 25),
|
||||||
|
COLOR_119(13, 13, 13),
|
||||||
|
COLOR_120(176, 168, 54),
|
||||||
|
COLOR_121(215, 205, 66),
|
||||||
|
COLOR_122(250, 238, 77),
|
||||||
|
COLOR_123(132, 126, 40),
|
||||||
|
COLOR_124(64, 154, 150),
|
||||||
|
COLOR_125(79, 188, 183),
|
||||||
|
COLOR_126(92, 219, 213),
|
||||||
|
COLOR_127(48, 115, 112),
|
||||||
|
COLOR_128(52, 90, 180),
|
||||||
|
COLOR_129(63, 110, 220),
|
||||||
|
COLOR_130(74, 128, 255),
|
||||||
|
COLOR_131(39, 67, 135),
|
||||||
|
COLOR_132(0, 153, 40),
|
||||||
|
COLOR_133(0, 187, 50),
|
||||||
|
COLOR_134(0, 217, 58),
|
||||||
|
COLOR_135(0, 114, 30),
|
||||||
|
COLOR_136(91, 60, 34),
|
||||||
|
COLOR_137(111, 74, 42),
|
||||||
|
COLOR_138(129, 86, 49),
|
||||||
|
COLOR_139(68, 45, 25),
|
||||||
|
COLOR_140(79, 1, 0),
|
||||||
|
COLOR_141(96, 1, 0),
|
||||||
|
COLOR_142(112, 2, 0),
|
||||||
|
COLOR_143(59, 1, 0),
|
||||||
|
COLOR_144(147, 124, 113),
|
||||||
|
COLOR_145(180, 152, 138),
|
||||||
|
COLOR_146(209, 177, 161),
|
||||||
|
COLOR_147(110, 93, 85),
|
||||||
|
COLOR_148(112, 57, 25),
|
||||||
|
COLOR_149(137, 70, 31),
|
||||||
|
COLOR_150(159, 82, 36),
|
||||||
|
COLOR_151(84, 43, 19),
|
||||||
|
COLOR_152(105, 61, 76),
|
||||||
|
COLOR_153(128, 75, 93),
|
||||||
|
COLOR_154(149, 87, 108),
|
||||||
|
COLOR_155(78, 46, 57),
|
||||||
|
COLOR_156(79, 76, 97),
|
||||||
|
COLOR_157(96, 93, 119),
|
||||||
|
COLOR_158(112, 108, 138),
|
||||||
|
COLOR_159(59, 57, 73),
|
||||||
|
COLOR_160(131, 93, 25),
|
||||||
|
COLOR_161(160, 114, 31),
|
||||||
|
COLOR_162(186, 133, 36),
|
||||||
|
COLOR_163(98, 70, 19),
|
||||||
|
COLOR_164(72, 82, 37),
|
||||||
|
COLOR_165(88, 100, 45),
|
||||||
|
COLOR_166(103, 117, 53),
|
||||||
|
COLOR_167(54, 61, 28),
|
||||||
|
COLOR_168(112, 54, 55),
|
||||||
|
COLOR_169(138, 66, 67),
|
||||||
|
COLOR_170(160, 77, 78),
|
||||||
|
COLOR_171(84, 40, 41),
|
||||||
|
COLOR_172(40, 28, 24),
|
||||||
|
COLOR_173(49, 35, 30),
|
||||||
|
COLOR_174(57, 41, 35),
|
||||||
|
COLOR_175(30, 21, 18),
|
||||||
|
COLOR_176(95, 75, 69),
|
||||||
|
COLOR_177(116, 92, 84),
|
||||||
|
COLOR_178(135, 107, 98),
|
||||||
|
COLOR_179(71, 56, 51),
|
||||||
|
COLOR_180(61, 64, 64),
|
||||||
|
COLOR_181(75, 79, 79),
|
||||||
|
COLOR_182(87, 92, 92),
|
||||||
|
COLOR_183(46, 48, 48),
|
||||||
|
COLOR_184(86, 51, 62),
|
||||||
|
COLOR_185(105, 62, 75),
|
||||||
|
COLOR_186(122, 73, 88),
|
||||||
|
COLOR_187(64, 38, 46),
|
||||||
|
COLOR_188(53, 43, 64),
|
||||||
|
COLOR_189(65, 53, 79),
|
||||||
|
COLOR_190(76, 62, 92),
|
||||||
|
COLOR_191(40, 32, 48),
|
||||||
|
COLOR_192(53, 35, 24),
|
||||||
|
COLOR_193(65, 43, 30),
|
||||||
|
COLOR_194(76, 50, 35),
|
||||||
|
COLOR_195(40, 26, 18),
|
||||||
|
COLOR_196(53, 57, 29),
|
||||||
|
COLOR_197(65, 70, 36),
|
||||||
|
COLOR_198(76, 82, 42),
|
||||||
|
COLOR_199(40, 43, 22),
|
||||||
|
COLOR_200(100, 42, 32),
|
||||||
|
COLOR_201(122, 51, 39),
|
||||||
|
COLOR_202(142, 60, 46),
|
||||||
|
COLOR_203(75, 31, 24),
|
||||||
|
COLOR_204(26, 15, 11),
|
||||||
|
COLOR_205(31, 18, 13),
|
||||||
|
COLOR_206(37, 22, 16),
|
||||||
|
COLOR_207(19, 11, 8);
|
||||||
|
|
||||||
|
private final int red;
|
||||||
|
private final int green;
|
||||||
|
private final int blue;
|
||||||
|
|
||||||
|
MapColor(int red, int green, int blue) {
|
||||||
|
this.red = red;
|
||||||
|
this.green = green;
|
||||||
|
this.blue = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getId() {
|
||||||
|
return ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MapColor fromId(int id) {
|
||||||
|
return Arrays.stream(values()).filter(color -> color.getId() == id).findFirst().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int toARGB() {
|
||||||
|
int alpha = 255;
|
||||||
|
if (red == -1 && green == -1 && blue == -1)
|
||||||
|
alpha = 0; // transparent
|
||||||
|
|
||||||
|
long result = red & 0xff;
|
||||||
|
result |= (green & 0xff) << 8;
|
||||||
|
result |= (blue & 0xff) << 16;
|
||||||
|
result |= (alpha & 0xff) << 24;
|
||||||
|
return (int) (result & 0xFFFFFFFFL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,31 +25,30 @@
|
||||||
|
|
||||||
package org.geysermc.connector.utils;
|
package org.geysermc.connector.utils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.message.ChatColor;
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
||||||
import com.github.steveice10.mc.protocol.data.message.ChatFormat;
|
import com.github.steveice10.mc.protocol.data.message.*;
|
||||||
import com.github.steveice10.mc.protocol.data.message.Message;
|
|
||||||
import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class MessageUtils {
|
public class MessageUtils {
|
||||||
|
|
||||||
public static List<String> getTranslationParams(Message[] messages) {
|
public static List<String> getTranslationParams(Message[] messages, String locale) {
|
||||||
List<String> strings = new ArrayList<String>();
|
List<String> strings = new ArrayList<>();
|
||||||
for (int i = 0; i < messages.length; i++) {
|
for (Message message : messages) {
|
||||||
if (messages[i] instanceof TranslationMessage) {
|
if (message instanceof TranslationMessage) {
|
||||||
TranslationMessage translation = (TranslationMessage) messages[i];
|
TranslationMessage translation = (TranslationMessage) message;
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder("");
|
if (locale == null) {
|
||||||
builder.append("%");
|
String builder = "%" + translation.getTranslationKey();
|
||||||
builder.append(translation.getTranslationKey());
|
strings.add(builder);
|
||||||
strings.add(builder.toString());
|
}
|
||||||
|
|
||||||
if (translation.getTranslationKey().equals("commands.gamemode.success.other")) {
|
if (translation.getTranslationKey().equals("commands.gamemode.success.other")) {
|
||||||
strings.add("");
|
strings.add("");
|
||||||
|
@ -59,47 +58,92 @@ public class MessageUtils {
|
||||||
strings.add(" - no permission or invalid command!");
|
strings.add(" - no permission or invalid command!");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < getTranslationParams(translation.getTranslationParams()).size(); j++) {
|
List<String> furtherParams = getTranslationParams(translation.getTranslationParams());
|
||||||
strings.add(getTranslationParams(translation.getTranslationParams()).get(j));
|
if (locale != null) {
|
||||||
|
strings.add(insertParams(LocaleUtils.getLocaleString(translation.getTranslationKey(), locale), furtherParams));
|
||||||
|
}else{
|
||||||
|
strings.addAll(furtherParams);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
StringBuilder builder = new StringBuilder("");
|
String builder = getFormat(message.getStyle().getFormats()) +
|
||||||
builder.append(getFormat(messages[i].getStyle().getFormats()));
|
getColorOrParent(message.getStyle());
|
||||||
builder.append(getColor(messages[i].getStyle().getColor()));
|
builder += getTranslatedBedrockMessage(message, locale, false);
|
||||||
builder.append(getBedrockMessage(messages[i]));
|
strings.add(builder);
|
||||||
strings.add(builder.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings;
|
return strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTranslationText(TranslationMessage message) {
|
public static List<String> getTranslationParams(Message[] messages) {
|
||||||
StringBuilder builder = new StringBuilder("");
|
return getTranslationParams(messages, null);
|
||||||
builder.append(getFormat(message.getStyle().getFormats()));
|
|
||||||
builder.append(getColor(message.getStyle().getColor()));
|
|
||||||
builder.append("%");
|
|
||||||
builder.append(message.getTranslationKey());
|
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBedrockMessage(Message message) {
|
public static String getTranslationText(TranslationMessage message) {
|
||||||
|
return getFormat(message.getStyle().getFormats()) + getColorOrParent(message.getStyle())
|
||||||
|
+ "%" + message.getTranslationKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate) {
|
||||||
JsonParser parser = new JsonParser();
|
JsonParser parser = new JsonParser();
|
||||||
if (isMessage(message.getText())) {
|
if (isMessage(message.getText())) {
|
||||||
JsonObject object = parser.parse(message.getText()).getAsJsonObject();
|
JsonObject object = parser.parse(message.getText()).getAsJsonObject();
|
||||||
message = Message.fromJson(formatJson(object));
|
message = Message.fromJson(formatJson(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder(message.getText());
|
String messageText = message.getText();
|
||||||
|
if (locale != null && shouldTranslate) {
|
||||||
|
messageText = LocaleUtils.getLocaleString(messageText, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder(messageText);
|
||||||
for (Message msg : message.getExtra()) {
|
for (Message msg : message.getExtra()) {
|
||||||
builder.append(getFormat(msg.getStyle().getFormats()));
|
builder.append(getFormat(msg.getStyle().getFormats()));
|
||||||
builder.append(getColor(msg.getStyle().getColor()));
|
builder.append(getColorOrParent(msg.getStyle()));
|
||||||
if (!(msg.getText() == null)) {
|
if (!(msg.getText() == null)) {
|
||||||
builder.append(getBedrockMessage(msg));
|
boolean isTranslationMessage = (msg instanceof TranslationMessage);
|
||||||
|
builder.append(getTranslatedBedrockMessage(msg, locale, isTranslationMessage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTranslatedBedrockMessage(Message message, String locale) {
|
||||||
|
return getTranslatedBedrockMessage(message, locale, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getBedrockMessage(Message message) {
|
||||||
|
return getTranslatedBedrockMessage(message, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String insertParams(String message, List<String> params) {
|
||||||
|
String newMessage = message;
|
||||||
|
|
||||||
|
Pattern p = Pattern.compile("%([1-9])\\$s");
|
||||||
|
Matcher m = p.matcher(message);
|
||||||
|
while (m.find()) {
|
||||||
|
try {
|
||||||
|
newMessage = newMessage.replaceFirst("%" + m.group(1) + "\\$s" , params.get(Integer.parseInt(m.group(1)) - 1));
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Couldnt find the param to replace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.toString();
|
for (String text : params) {
|
||||||
|
newMessage = newMessage.replaceFirst("%s", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getColorOrParent(MessageStyle style) {
|
||||||
|
ChatColor chatColor = style.getColor();
|
||||||
|
|
||||||
|
if (chatColor == ChatColor.NONE) {
|
||||||
|
return getColor(style.getParent().getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
return getColor(chatColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getColor(ChatColor color) {
|
private static String getColor(ChatColor color) {
|
||||||
|
@ -206,7 +250,6 @@ public class MessageUtils {
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +274,20 @@ public class MessageUtils {
|
||||||
formatJson((JsonObject) a.get(i));
|
formatJson((JsonObject) a.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toChatColor(TeamColor teamColor) {
|
||||||
|
for (ChatColor color : ChatColor.values()) {
|
||||||
|
if (color.name().equals(teamColor.name())) {
|
||||||
|
return getColor(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ChatFormat format : ChatFormat.values()) {
|
||||||
|
if (format.name().equals(teamColor.name())) {
|
||||||
|
return getFormat(Collections.singletonList(format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Toolbox {
|
public class Toolbox {
|
||||||
|
@ -52,6 +52,8 @@ public class Toolbox {
|
||||||
|
|
||||||
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
public static final Int2ObjectMap<ItemEntry> ITEM_ENTRIES = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/* Load biomes */
|
/* Load biomes */
|
||||||
InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat");
|
InputStream biomestream = GeyserConnector.class.getClassLoader().getResourceAsStream("bedrock/biome_definitions.dat");
|
||||||
|
@ -104,6 +106,9 @@ public class Toolbox {
|
||||||
entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue()));
|
entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue()));
|
||||||
itemIndex++;
|
itemIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the locale data
|
||||||
|
LocaleUtils.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputStream getResource(String resource) {
|
public static InputStream getResource(String resource) {
|
||||||
|
|
|
@ -0,0 +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.utils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
public class WebUtils {
|
||||||
|
|
||||||
|
public static String getBody(String reqURL) {
|
||||||
|
URL url = null;
|
||||||
|
try {
|
||||||
|
url = new URL(reqURL);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||||
|
con.setRequestMethod("GET");
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||||
|
String inputLine;
|
||||||
|
StringBuffer content = new StringBuffer();
|
||||||
|
|
||||||
|
while ((inputLine = in.readLine()) != null) {
|
||||||
|
content.append(inputLine);
|
||||||
|
content.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
in.close();
|
||||||
|
con.disconnect();
|
||||||
|
|
||||||
|
return content.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void downloadFile(String reqURL, String fileLocation) {
|
||||||
|
try {
|
||||||
|
InputStream in = new URL(reqURL).openStream();
|
||||||
|
Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,9 @@ general-thread-pool: 32
|
||||||
# OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes
|
# OptiFine capes, LabyMod capes, 5Zig capes and MinecraftCapes
|
||||||
allow-third-party-capes: true
|
allow-third-party-capes: true
|
||||||
|
|
||||||
|
# The default locale if we dont have the one the client requested
|
||||||
|
default-locale: en_us
|
||||||
|
|
||||||
# bStats is a stat tracker that is entirely anonymous and tracks only basic information
|
# bStats is a stat tracker that is entirely anonymous and tracks only basic information
|
||||||
# about Geyser, such as how many people are online, how many servers are using Geyser,
|
# about Geyser, such as how many people are online, how many servers are using Geyser,
|
||||||
# what OS is being used, etc. You can learn more about bStats here: https://bstats.org/.
|
# what OS is being used, etc. You can learn more about bStats here: https://bstats.org/.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 278c73449aeeb4064c7513a68f98a49a5f463f0a
|
Subproject commit efc9db6b7d51bdf145230933ac23b321ac1c132d
|
Loading…
Reference in a new issue