Merge branch 'master' into resources

This commit is contained in:
rtm516 2020-04-28 20:43:25 +01:00
commit 9a250c6687
190 changed files with 7789 additions and 1319 deletions

View File

@ -31,10 +31,10 @@ assignees: ''
<!--- Give us the exact output from /version. Saying "latest" does not help us at all. -->
**Geyser Version**
<!--- Give us the exact build number as well as branch if applicable. Saying "latest" does not help us at all. -->
<!--- Give us the exact build number as well as branch if applicable. Saying "latest" does not help us at all. Please also include if you are running the standalone version, or specify which plugin version you are using. If your issue is a connection problem, please specify if you are using the Floodgate plugin. -->
**Minecraft: Bedrock Edition Version**
<!-- The version of your Minecraft: Bedrock Edition client you tested with. -->
**Additional Context**
<!--- Add any other context about the problem here. --->
<!--- Add any other context about the problem here. Include any plugins on the Minecraft server that may cause problems. --->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: GeyserMC Discord
url: http://discord.geysermc.org/
about: If your issue seems like it could possibly be an easy fix due to configuration, please hop on our Discord.

View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) 2019-&amp;#36;today.year GeyserMC. http://geysermc.org&#10; &#10; Permission is hereby granted, free of charge, to any person obtaining a copy&#10; of this software and associated documentation files (the &quot;Software&quot;), to deal&#10; in the Software without restriction, including without limitation the rights&#10; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10; copies of the Software, and to permit persons to whom the Software is&#10; furnished to do so, subject to the following conditions:&#10; &#10; The above copyright notice and this permission notice shall be included in&#10; all copies or substantial portions of the Software.&#10; &#10; THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10; THE SOFTWARE.&#10; &#10; @author GeyserMC&#10; @link https://github.com/GeyserMC/Geyser&#10; " />
<option name="myName" value="Geyser" />
</copyright>
</component>

View File

@ -0,0 +1,7 @@
<component name="CopyrightManager">
<settings>
<module2copyright>
<element module="All" copyright="Geyser" />
</module2copyright>
</settings>
</component>

View File

@ -13,7 +13,7 @@ Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Editio
Geyser is a proxy, bridging the gap between Minecraft: Bedrock Edition and Minecraft: Java Edition servers.
The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible. **Please note, this project is still a work in progress and should not be used on production. Expect bugs!**
### Currently supporting Minecraft Bedrock v1.14.X and Minecraft Java v1.15.2.
### Currently supporting Minecraft Bedrock v1.14.6(0) and Minecraft Java v1.15.2.
## Setting Up
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
@ -28,12 +28,14 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
- Donate: https://patreon.com/GeyserMC
## What's Left to be Added/Fixed
- Inventories ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
- Crafting ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
- Creative Mode ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
- The Following Inventories
- [ ] Enchantment Table
- [ ] Beacon
- [ ] Cartography Table
- [ ] Stonecutter
- [ ] Villager Trading
- Sounds
- Block Particles
- Block Entities ([`inventory`](https://github.com/GeyserMC/Geyser/tree/inventory))
- Some Entity Flags
## Compiling

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,16 +25,20 @@
package org.geysermc.platform.bukkit;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
import java.util.UUID;
public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
private GeyserBukkitCommandManager geyserCommandManager;
private GeyserBukkitConfiguration geyserConfig;
private GeyserBukkitLogger geyserLogger;
@ -50,9 +54,20 @@ public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
saveConfig();
}
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!Bukkit.getIp().equals("0.0.0.0")) {
getConfig().set("remote.address", Bukkit.getIp());
}
getConfig().set("remote.port", Bukkit.getPort());
saveConfig();
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
this.connector = GeyserConnector.start(PlatformType.BUKKIT, this);
this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector);
this.getCommand("geyser").setExecutor(new GeyserBukkitCommandExecutor(connector));
}
@ -70,4 +85,9 @@ public class GeyserBukkitPlugin extends JavaPlugin implements IGeyserBootstrap {
public GeyserBukkitLogger getGeyserLogger() {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
}

View File

@ -70,6 +70,6 @@ public class GeyserBukkitCommandExecutor implements TabExecutor {
}
private GeyserCommand getCommand(String label) {
return connector.getCommandMap().getCommands().get(label);
return connector.getCommandManager().getCommands().get(label);
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.platform.bukkit.command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.platform.bukkit.GeyserBukkitPlugin;
import java.lang.reflect.Field;
public class GeyserBukkitCommandManager extends CommandManager {
private static CommandMap COMMAND_MAP;
static {
try {
Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
cmdMapField.setAccessible(true);
COMMAND_MAP = (CommandMap) cmdMapField.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
}
}
private GeyserBukkitPlugin plugin;
public GeyserBukkitCommandManager(GeyserBukkitPlugin plugin, GeyserConnector connector) {
super(connector);
this.plugin = plugin;
}
@Override
public String getDescription(String command) {
Command cmd = COMMAND_MAP.getCommand(command.replace("/", ""));
return cmd != null ? cmd.getDescription() : "";
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,25 +25,29 @@
package org.geysermc.platform.bungeecord;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.util.UUID;
import java.util.logging.Level;
public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
private GeyserBungeeCommandManager geyserCommandManager;
private GeyserBungeeConfiguration geyserConfig;
private GeyserBungeeLogger geyserLogger;
@ -78,8 +82,31 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
this.geyserConfig = new GeyserBungeeConfiguration(getDataFolder(), configuration);
boolean configHasChanged = false;
if (getProxy().getConfig().getListeners().size() == 1) {
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
InetSocketAddress javaAddr = listener.getHost();
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
configuration.set("remote.address", javaAddr.getHostString());
}
configuration.set("remote.port", javaAddr.getPort());
configHasChanged = true;
}
if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
configuration.set("metrics.uuid", UUID.randomUUID().toString());
configHasChanged = true;
}
if (configHasChanged) {
try {
ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, new File(getDataFolder(), "config.yml"));
} catch (IOException ex) {
@ -91,6 +118,8 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
this.geyserCommandManager = new GeyserBungeeCommandManager(connector);
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(connector));
}
@ -108,4 +137,9 @@ public class GeyserBungeePlugin extends Plugin implements IGeyserBootstrap {
public GeyserBungeeLogger getGeyserLogger() {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
}

View File

@ -71,6 +71,6 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
}
private GeyserCommand getCommand(String label) {
return connector.getCommandMap().getCommands().get(label);
return connector.getCommandManager().getCommands().get(label);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.bungeecord.command;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
public class GeyserBungeeCommandManager extends CommandManager {
public GeyserBungeeCommandManager(GeyserConnector connector) {
super(connector);
}
@Override
public String getDescription(String command) {
return ""; // no support for command descriptions in bungee
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -26,17 +26,13 @@
package org.geysermc.platform.sponge;
import lombok.AllArgsConstructor;
import ninja.leaping.configurate.ConfigurationNode;
import org.geysermc.common.IGeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class GeyserSpongeConfiguration implements IGeyserConfiguration {
@ -60,7 +56,8 @@ public class GeyserSpongeConfiguration implements IGeyserConfiguration {
if (node.getNode("userAuths").getValue() == null)
return;
for (String key : (List<String>) node.getNode("userAuths").getValue()) {
List<String> userAuths = new ArrayList<String>(((LinkedHashMap)node.getNode("userAuths").getValue()).keySet());
for (String key : userAuths) {
userAuthInfo.put(key, new SpongeUserAuthenticationInfo(key));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -26,15 +26,16 @@
package org.geysermc.platform.sponge;
import com.google.inject.Inject;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.geysermc.common.PlatformType;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor;
import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager;
import org.slf4j.Logger;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.config.ConfigDir;
@ -45,6 +46,7 @@ import org.spongepowered.api.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.UUID;
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Sponge", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
@ -57,6 +59,7 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
@ConfigDir(sharedRoot = false)
private File configDir;
private GeyserSpongeCommandManager geyserCommandManager;
private GeyserSpongeConfiguration geyserConfig;
private GeyserSpongeLogger geyserLogger;
@ -76,16 +79,34 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
}
ConfigurationLoader loader = YAMLConfigurationLoader.builder().setPath(configFile.toPath()).build();
ConfigurationNode config;
try {
this.geyserConfig = new GeyserSpongeConfiguration(configDir, loader.load());
config = loader.load();
this.geyserConfig = new GeyserSpongeConfiguration(configDir, config);
} catch (IOException ex) {
logger.warn("Failed to load config.yml!");
ex.printStackTrace();
return;
}
ConfigurationNode serverIP = config.getNode("remote").getNode("address");
ConfigurationNode serverPort = config.getNode("remote").getNode("port");
if (Sponge.getServer().getBoundAddress().isPresent()) {
InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get();
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
serverIP.setValue("127.0.0.1");
}
serverPort.setValue(javaAddr.getPort());
}
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
this.connector = GeyserConnector.start(PlatformType.SPONGE, this);
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), connector);
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(connector), "geyser");
}
@ -105,6 +126,11 @@ public class GeyserSpongePlugin implements IGeyserBootstrap {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
@Listener
public void onServerStart(GameStartedServerEvent event) {
onEnable();

View File

@ -95,6 +95,6 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
}
private GeyserCommand getCommand(String label) {
return connector.getCommandMap().getCommands().get(label);
return connector.getCommandManager().getCommands().get(label);
}
}

View File

@ -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.platform.sponge.command;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandMapping;
import org.spongepowered.api.text.Text;
public class GeyserSpongeCommandManager extends CommandManager {
private org.spongepowered.api.command.CommandManager handle;
public GeyserSpongeCommandManager(org.spongepowered.api.command.CommandManager handle, GeyserConnector connector) {
super(connector);
this.handle = handle;
}
@Override
public String getDescription(String command) {
return handle.get(command).map(CommandMapping::getCallable).map(callable -> callable.getShortDescription(Sponge.getServer().getConsole()).orElse(Text.EMPTY)).orElse(Text.EMPTY).toPlain();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,18 +25,21 @@
package org.geysermc.platform.standalone;
import org.geysermc.common.PlatformType;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
import org.geysermc.platform.standalone.console.GeyserLogger;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.geysermc.common.PlatformType;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.standalone.console.GeyserLogger;
public class GeyserBootstrap implements IGeyserBootstrap {
private GeyserCommandManager geyserCommandManager;
private GeyserConfiguration geyserConfig;
private GeyserLogger geyserLogger;
@ -49,7 +52,7 @@ public class GeyserBootstrap implements IGeyserBootstrap {
@Override
public void onEnable() {
geyserLogger = new GeyserLogger();
LoopbackUtil.checkLoopback(geyserLogger);
try {
@ -61,6 +64,7 @@ public class GeyserBootstrap implements IGeyserBootstrap {
}
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
geyserCommandManager = new GeyserCommandManager(connector);
geyserLogger.start();
}
@ -79,4 +83,9 @@ public class GeyserBootstrap implements IGeyserBootstrap {
public GeyserLogger getGeyserLogger() {
return geyserLogger;
}
@Override
public CommandManager getGeyserCommandManager() {
return geyserCommandManager;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.standalone.command;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
public class GeyserCommandManager extends CommandManager {
public GeyserCommandManager(GeyserConnector connector) {
super(connector);
}
@Override
public String getDescription(String command) {
return ""; // this is not sent over the protocol, so we return none
}
}

View File

@ -47,7 +47,7 @@ public class GeyserLogger extends SimpleTerminalConsole implements IGeyserLogger
@Override
protected void runCommand(String line) {
GeyserConnector.getInstance().getCommandMap().runCommand(this, line);
GeyserConnector.getInstance().getCommandManager().runCommand(this, line);
}
@Override

View File

@ -27,9 +27,8 @@ package org.geysermc.platform.velocity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.IGeyserConfiguration;
import java.nio.file.Path;
@ -86,7 +85,10 @@ public class GeyserVelocityConfiguration implements IGeyserConfiguration {
@Getter
public static class RemoteConfiguration implements IRemoteConfiguration {
@Setter
private String address;
@Setter
private int port;
private String motd1;

View File

@ -33,15 +33,18 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import org.geysermc.common.PlatformType;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor;
import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.UUID;
@Plugin(id = "geyser", name = GeyserConnector.NAME + "-Velocity", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
@ -50,9 +53,13 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
@Inject
private Logger logger;
@Inject
private ProxyServer server;
@Inject
private CommandManager commandManager;
private GeyserVelocityCommandManager geyserCommandManager;
private GeyserVelocityConfiguration geyserConfig;
private GeyserVelocityLogger geyserLogger;
@ -71,9 +78,20 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
ex.printStackTrace();
}
InetSocketAddress javaAddr = server.getBoundAddress();
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0")) {
geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
geyserConfig.getRemote().setPort(javaAddr.getPort());
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser");
}
@ -92,6 +110,11 @@ public class GeyserVelocityPlugin implements IGeyserBootstrap {
return geyserLogger;
}
@Override
public org.geysermc.connector.command.CommandManager getGeyserCommandManager() {
return this.geyserCommandManager;
}
@Subscribe
public void onInit(ProxyInitializeEvent event) {
onEnable();

View File

@ -57,6 +57,6 @@ public class GeyserVelocityCommandExecutor implements Command {
}
private GeyserCommand getCommand(String label) {
return connector.getCommandMap().getCommands().get(label);
return connector.getCommandManager().getCommands().get(label);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.velocity.command;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandManager;
public class GeyserVelocityCommandManager extends CommandManager {
public GeyserVelocityCommandManager(GeyserConnector connector) {
super(connector);
}
@Override
public String getDescription(String command) {
return ""; // no support for command descriptions in velocity
}
}

View File

@ -14,6 +14,13 @@ public enum AuthType {
return id < VALUES.length ? VALUES[id] : OFFLINE;
}
/**
* Convert the AuthType string (from config) to the enum, OFFLINE on fail
*
* @param name AuthType string
*
* @return The converted AuthType
*/
public static AuthType getByName(String name) {
String upperCase = name.toUpperCase();
for (AuthType type : VALUES) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -51,6 +51,13 @@ public class ChatColor {
public static final String ITALIC = ESCAPE + "o";
public static final String RESET = ESCAPE + "r";
/**
* Convert chat colour codes to terminal colours
*
* @param string The text to replace colours for
*
* @return A string ready for terminal printing
*/
public static String toANSI(String string) {
string = string.replace(BOLD, (char) 0x1b + "[1m");
string = string.replace(OBFUSCATED, (char) 0x1b + "[5m");
@ -81,6 +88,13 @@ public class ChatColor {
return message.replace(color, ESCAPE);
}
/**
* Remove all colour formatting tags from a message
*
* @param message Message to remove colour tags from
*
* @return The sanitised message
*/
public static String stripColors(String message) {
return message = message.replaceAll("(&([a-fk-or0-9]))","").replaceAll("(§([a-fk-or0-9]))","").replaceAll("s/\\x1b\\[[0-9;]*[a-zA-Z]//g","");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -26,15 +26,39 @@
package org.geysermc.common.bootstrap;
import org.geysermc.common.IGeyserConfiguration;
import org.geysermc.common.command.ICommandManager;
import org.geysermc.common.logger.IGeyserLogger;
public interface IGeyserBootstrap {
/**
* Called when the GeyserBootstrap is enabled
*/
void onEnable();
/**
* Called when the GeyserBootstrap is disabled
*/
void onDisable();
/**
* Returns the current GeyserConfig
*
* @return The current GeyserConfig
*/
IGeyserConfiguration getGeyserConfig();
/**
* Returns the current GeyserLogger
*
* @return The current GeyserLogger
*/
IGeyserLogger getGeyserLogger();
/**
* Returns the current GeyserCommandManager
*
* @return The current GeyserCommandManager
*/
ICommandManager getGeyserCommandManager();
}

View File

@ -0,0 +1,38 @@
/*
* 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.common.command;
public interface ICommandManager {
/**
* Returns the description of the given command
*
* @param command Command to get the description for
*
* @return Command description
*/
String getDescription(String command);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,8 +25,9 @@
package org.geysermc.common.window;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.window.button.FormImage;
@ -34,6 +35,7 @@ import org.geysermc.common.window.component.*;
import org.geysermc.common.window.response.CustomFormResponse;
import org.geysermc.common.window.response.FormResponseData;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -77,7 +79,11 @@ public class CustomFormWindow extends FormWindow {
}
public String getJSONData() {
String toModify = new Gson().toJson(this);
String toModify = "";
try {
toModify = new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) { }
//We need to replace this due to Java not supporting declaring class field 'default'
return toModify.replace("defaultOptionIndex", "default")
.replace("defaultText", "default")
@ -100,7 +106,11 @@ public class CustomFormWindow extends FormWindow {
Map<Integer, Object> responses = new HashMap<Integer, Object>();
Map<Integer, String> labelResponses = new HashMap<Integer, String>();
List<String> componentResponses = new Gson().fromJson(data, new TypeToken<List<String>>() { }.getType());
List<String> componentResponses = new ArrayList<>();
try {
componentResponses = new ObjectMapper().readValue(data, new TypeReference<List<String>>(){});
} catch (IOException e) { }
for (String response : componentResponses) {
if (i >= content.size()) {
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,6 +25,7 @@
package org.geysermc.common.window;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.window.response.FormResponse;
@ -50,6 +51,7 @@ public abstract class FormWindow {
this.response = response;
}
@JsonIgnore
public abstract String getJSONData();
public abstract void setResponse(String response);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,7 +25,8 @@
package org.geysermc.common.window;
import com.google.gson.Gson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.window.response.ModalFormResponse;
@ -59,7 +60,11 @@ public class ModalFormWindow extends FormWindow {
@Override
public String getJSONData() {
return new Gson().toJson(this);
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
return "";
}
}
public void setResponse(String data) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -25,7 +25,8 @@
package org.geysermc.common.window;
import com.google.gson.Gson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.window.button.FormButton;
@ -63,7 +64,11 @@ public class SimpleFormWindow extends FormWindow {
@Override
public String getJSONData() {
return new Gson().toJson(this);
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
return "";
}
}
public void setResponse(String data) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -37,6 +37,10 @@ public class FormButton {
@Getter
private FormImage image;
public FormButton(String text) {
this.text = text;
}
public FormButton(String text, FormImage image) {
this.text = text;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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

View File

@ -30,16 +30,10 @@
<version>2.9.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry</artifactId>
<version>1.7.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v389</artifactId>
<version>2.5.4</version>
<artifactId>bedrock-v390</artifactId>
<version>2.5.6-SNAPSHOT</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@ -72,10 +66,34 @@
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-int-double-maps</artifactId>
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-int-boolean-maps</artifactId>
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-object-int-maps</artifactId>
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-object-byte-maps</artifactId>
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.steveice10</groupId>
<artifactId>opennbt</artifactId>
<version>1.3-SNAPSHOT</version>
<version>1.4-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -93,7 +111,7 @@
<dependency>
<groupId>com.github.steveice10</groupId>
<artifactId>mcauthlib</artifactId>
<version>1.1-SNAPSHOT</version>
<version>1.3-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -121,5 +139,23 @@
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>text-api</artifactId>
<version>3.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>text-serializer-gson</artifactId>
<version>3.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>text-serializer-legacy</artifactId>
<version>3.0.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -27,15 +27,16 @@ package org.geysermc.connector;
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
import com.nukkitx.protocol.bedrock.BedrockServer;
import com.nukkitx.protocol.bedrock.v389.Bedrock_v389;
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
import lombok.Getter;
import org.geysermc.common.AuthType;
import org.geysermc.common.IGeyserConfiguration;
import org.geysermc.common.PlatformType;
import org.geysermc.common.bootstrap.IGeyserBootstrap;
import org.geysermc.common.logger.IGeyserLogger;
import org.geysermc.connector.command.GeyserCommandMap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler;
import org.geysermc.connector.network.remote.RemoteServer;
@ -44,14 +45,12 @@ import org.geysermc.connector.network.translators.Translators;
import org.geysermc.connector.thread.PingPassthroughThread;
import org.geysermc.connector.utils.ResourcePack;
import org.geysermc.connector.utils.Toolbox;
import org.geysermc.common.IGeyserConfiguration;
import java.net.InetSocketAddress;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -59,7 +58,7 @@ import java.util.concurrent.TimeUnit;
@Getter
public class GeyserConnector {
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v389.V389_CODEC;
public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC;
public static final String NAME = "Geyser";
public static final String VERSION = "1.0-SNAPSHOT";
@ -71,8 +70,6 @@ public class GeyserConnector {
private RemoteServer remoteServer;
private AuthType authType;
private GeyserCommandMap commandMap;
private boolean shuttingDown = false;
private final ScheduledExecutorService generalThreadPool;
@ -110,7 +107,6 @@ public class GeyserConnector {
Toolbox.init();
ResourcePack.loadPacks();
commandMap = new GeyserCommandMap(this);
remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort());
authType = AuthType.getByName(config.getRemote().getAuthType());
@ -184,8 +180,7 @@ public class GeyserConnector {
players.clear();
remoteServer = null;
authType = null;
commandMap.getCommands().clear();
commandMap = null;
this.getCommandManager().getCommands().clear();
bootstrap.getGeyserLogger().info("Geyser shutdown successfully.");
}
@ -215,6 +210,10 @@ public class GeyserConnector {
return bootstrap.getGeyserConfig();
}
public CommandManager getCommandManager() {
return (CommandManager) bootstrap.getGeyserCommandManager();
}
public static GeyserConnector getInstance() {
return instance;
}

View File

@ -26,28 +26,29 @@
package org.geysermc.connector.command;
import lombok.Getter;
import org.geysermc.common.command.ICommandManager;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.defaults.HelpCommand;
import org.geysermc.connector.command.defaults.ReloadCommand;
import org.geysermc.connector.command.defaults.StopCommand;
import org.geysermc.connector.command.defaults.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GeyserCommandMap {
public abstract class CommandManager implements ICommandManager {
@Getter
private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>());
private GeyserConnector connector;
public GeyserCommandMap(GeyserConnector connector) {
public CommandManager(GeyserConnector connector) {
this.connector = connector;
registerCommand(new HelpCommand(connector, "help", "Shows help for all registered commands.", "geyser.command.help"));
registerCommand(new ListCommand(connector, "list", "List all players connected through Geyser.", "geyser.command.list"));
registerCommand(new ReloadCommand(connector, "reload", "Reloads the Geyser configurations. Kicks all players when used!", "geyser.command.reload"));
registerCommand(new StopCommand(connector, "stop", "Shuts down Geyser.", "geyser.command.stop"));
registerCommand(new OffhandCommand(connector, "offhand", "Puts an items in your offhand.", "geyser.command.offhand"));
}
public void registerCommand(GeyserCommand command) {

View File

@ -49,8 +49,8 @@ public class HelpCommand extends GeyserCommand {
@Override
public void execute(CommandSender sender, String[] args) {
sender.sendMessage("---- Showing Help For: Geyser (Page 1/1) ----");
Map<String, GeyserCommand> cmds = connector.getCommandMap().getCommands();
List<String> commands = connector.getCommandMap().getCommands().keySet().stream().sorted().collect(Collectors.toList());
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + cmds.get(cmd).getDescription()));
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.command.defaults;
import org.geysermc.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import java.util.stream.Collectors;
public class ListCommand extends GeyserCommand {
private GeyserConnector connector;
public ListCommand(GeyserConnector connector, String name, String description, String permission) {
super(name, description, permission);
this.connector = connector;
}
@Override
public void execute(CommandSender sender, String[] args) {
sender.sendMessage(ChatColor.YELLOW + "Online Players (" + connector.getPlayers().size() + "): " + ChatColor.WHITE + connector.getPlayers().values().stream().map(GeyserSession::getName).collect(Collectors.joining(" ")));
}
}

View File

@ -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.command.defaults;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
public class OffhandCommand extends GeyserCommand {
private GeyserConnector connector;
public OffhandCommand(GeyserConnector connector, String name, String description, String permission) {
super(name, description, permission);
this.connector = connector;
}
@Override
public void execute(CommandSender sender, String[] args) {
if (sender.isConsole()) {
return;
}
// Make sure the sender is a Bedrock edition client
if (sender instanceof GeyserSession) {
GeyserSession session = (GeyserSession) sender;
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0),
BlockFace.DOWN);
session.getDownstream().getSession().send(releaseItemPacket);
}
}
}

View File

@ -48,7 +48,7 @@ public class ReloadCommand extends GeyserCommand {
}
sender.sendMessage(ChatColor.YELLOW + "Reloading Geyser configurations... all connected bedrock clients will be kicked.");
for (GeyserSession session : connector.getPlayers().values()) {
session.getUpstream().disconnect("Geyser has been reloaded... sorry for the inconvenience!");
session.disconnect("Geyser has been reloaded... sorry for the inconvenience!");
}
connector.reload();
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.entity;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class EnderCrystalEntity extends Entity {
public EnderCrystalEntity(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) {
// Show beam
// Usually performed client-side on Bedrock except for Ender Dragon respawn event
if (entityMetadata.getId() == 7) {
if (entityMetadata.getValue() instanceof Position) {
Position pos = (Position) entityMetadata.getValue();
metadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ()));
} else {
metadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO);
}
}
// There is a base located on the ender crystal
if (entityMetadata.getId() == 8) {
metadata.getFlags().setFlag(EntityFlag.SHOW_BOTTOM, (boolean) entityMetadata.getValue());
}
super.updateBedrockMetadata(entityMetadata, session);
}
@Override
public void spawnEntity(GeyserSession session) {
AddEntityPacket addEntityPacket = new AddEntityPacket();
// Not end crystal but ender crystal
addEntityPacket.setIdentifier("minecraft:ender_crystal");
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 + ")");
}
}

View File

@ -27,12 +27,15 @@ package org.geysermc.connector.entity;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
import com.github.steveice10.mc.protocol.data.message.TextMessage;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityDataMap;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import com.nukkitx.protocol.bedrock.data.EntityFlags;
import com.nukkitx.protocol.bedrock.data.*;
import com.nukkitx.protocol.bedrock.packet.*;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
@ -45,6 +48,7 @@ import org.geysermc.connector.entity.attribute.Attribute;
import org.geysermc.connector.entity.attribute.AttributeType;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.utils.AttributeUtils;
import org.geysermc.connector.utils.MessageUtils;
@ -120,6 +124,9 @@ public class Entity {
}
/**
* Despawns the entity
*
* @param session The GeyserSession
* @return can be deleted
*/
public boolean despawnEntity(GeyserSession session) {
@ -196,6 +203,28 @@ public class Entity {
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10);
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
// Shield code
if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) {
if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) ||
(session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemTranslator.SHIELD)) {
ClientPlayerUseItemPacket useItemPacket;
metadata.getFlags().setFlag(EntityFlag.BLOCKING, true);
if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemTranslator.SHIELD) {
useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
}
// Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent
else {
useItemPacket = new ClientPlayerUseItemPacket(Hand.OFF_HAND);
}
session.getDownstream().getSession().send(useItemPacket);
}
} else if (session.getPlayerEntity().getEntityId() == entityId && !metadata.getFlags().getFlag(EntityFlag.SNEAKING) && metadata.getFlags().getFlag(EntityFlag.BLOCKING)) {
metadata.getFlags().setFlag(EntityFlag.BLOCKING, false);
metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true);
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0,0,0), BlockFace.DOWN);
session.getDownstream().getSession().send(releaseItemPacket);
}
// metadata.getFlags().setFlag(EntityFlag.INVISIBLE, (xd & 0x20) == 0x20);
if ((xd & 0x20) == 0x20)
metadata.put(EntityData.SCALE, 0.0f);
@ -218,6 +247,12 @@ public class Entity {
case 5: // no gravity
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
break;
case 7: // blocking
if (entityMetadata.getType() == MetadataType.BYTE) {
byte xd = (byte) entityMetadata.getValue();
metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01);
}
break;
}
updateBedrockMetadata(session);
@ -234,6 +269,7 @@ public class Entity {
/**
* x = Pitch, y = HeadYaw, z = Yaw
* @return the bedrock rotation
*/
public Vector3f getBedrockRotation() {
return Vector3f.from(rotation.getY(), rotation.getZ(), rotation.getX());

View File

@ -0,0 +1,56 @@
/*
* 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.packet.AddEntityPacket;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class FishingHookEntity extends Entity {
public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void spawnEntity(GeyserSession session) {
AddEntityPacket addEntityPacket = new AddEntityPacket();
// Different ID in Bedrock
addEntityPacket.setIdentifier("minecraft:fishing_hook");
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 + ")");
}
}

View File

@ -49,7 +49,7 @@ public class ItemEntity extends Entity {
itemPacket.setUniqueEntityId(geyserId);
itemPacket.setFromFishing(false);
itemPacket.getMetadata().putAll(metadata);
itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock((ItemStack) entityMetadata.getValue()));
itemPacket.setItemInHand(Translators.getItemTranslator().translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
session.getUpstream().sendPacket(itemPacket);
}

View File

@ -44,6 +44,7 @@ import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.scoreboard.Team;
import org.geysermc.connector.utils.MessageUtils;
import org.geysermc.connector.network.session.cache.EntityEffectCache;
import org.geysermc.connector.utils.SkinUtils;
import java.util.UUID;
@ -55,6 +56,7 @@ public class PlayerEntity extends LivingEntity {
private String username;
private long lastSkinUpdate = -1;
private boolean playerList = true;
private final EntityEffectCache effectCache;
public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation);
@ -62,6 +64,7 @@ public class PlayerEntity extends LivingEntity {
profile = gameProfile;
uuid = gameProfile.getId();
username = gameProfile.getName();
effectCache = new EntityEffectCache();
if (geyserId == 1) valid = true;
}

View File

@ -25,12 +25,28 @@
package org.geysermc.connector.entity.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class AbstractFishEntity extends WaterEntity {
public AbstractFishEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
metadata.getFlags().setFlag(EntityFlag.CAN_SWIM, true);
metadata.getFlags().setFlag(EntityFlag.BREATHING, true);
metadata.getFlags().setFlag(EntityFlag.CAN_CLIMB, false);
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, false);
metadata.put(EntityData.AIR, (short) 400);
super.updateBedrockMetadata(entityMetadata, session);
}
}

View File

@ -26,7 +26,6 @@
package org.geysermc.connector.entity.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
@ -43,10 +42,8 @@ public class AgeableEntity extends CreatureEntity {
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 15) {
boolean isBaby = (boolean) entityMetadata.getValue();
if (isBaby) {
metadata.put(EntityData.SCALE, .55f);
metadata.getFlags().setFlag(EntityFlag.BABY, true);
}
metadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
metadata.getFlags().setFlag(EntityFlag.BABY, isBaby);
}
super.updateBedrockMetadata(entityMetadata, session);

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.entity.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import org.geysermc.connector.entity.living.AbstractFishEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class PufferFishEntity extends AbstractFishEntity {
public PufferFishEntity(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() == 16) {
// Transfers correctly but doesn't apply on the client
int puffsize = (int) entityMetadata.getValue();
metadata.put(EntityData.PUFFERFISH_SIZE, puffsize);
metadata.put(EntityData.VARIANT, puffsize);
}
super.updateBedrockMetadata(entityMetadata, session);
}
}

View File

@ -0,0 +1,94 @@
/*
* 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;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.connector.entity.living.AbstractFishEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class TropicalFishEntity extends AbstractFishEntity {
public TropicalFishEntity(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() == 16) {
TropicalFishVariant variant = TropicalFishVariant.fromVariantNumber((int) entityMetadata.getValue());
metadata.put(EntityData.VARIANT, variant.getShape()); // Shape 0-1
metadata.put(EntityData.MARK_VARIANT, variant.getPattern()); // Pattern 0-5
metadata.put(EntityData.COLOR, variant.getBaseColor()); // Base color 0-15
metadata.put(EntityData.COLOR_2, variant.getPatternColor()); // Pattern color 0-15
}
super.updateBedrockMetadata(entityMetadata, session);
}
@Override
public void spawnEntity(GeyserSession session) {
AddEntityPacket addEntityPacket = new AddEntityPacket();
addEntityPacket.setIdentifier("minecraft:tropicalfish");
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 + ")");
}
@Getter
@AllArgsConstructor
private static class TropicalFishVariant {
private int shape;
private int pattern;
private byte baseColor;
private byte patternColor;
/**
* Convert the variant number from Java into separate values
*
* @param varNumber Variant number from Java edition
*
* @return The variant converted into TropicalFishVariant
*/
public static TropicalFishVariant fromVariantNumber(int varNumber) {
return new TropicalFishVariant((varNumber & 0xFF), ((varNumber >> 8) & 0xFF), (byte) ((varNumber >> 16) & 0xFF), (byte) ((varNumber >> 24) & 0xFF));
}
}
}

View File

@ -45,4 +45,4 @@ public class HorseEntity extends AbstractHorseEntity {
super.updateBedrockMetadata(entityMetadata, session);
}
}
}

View File

@ -44,9 +44,19 @@ public class WolfEntity extends TameableEntity {
if (entityMetadata.getId() == 18) {
metadata.getFlags().setFlag(EntityFlag.INTERESTED, (boolean) entityMetadata.getValue());
}
//Reset wolf color
if (entityMetadata.getId() == 16) {
byte xd = (byte) entityMetadata.getValue();
boolean angry = (xd & 0x02) == 0x02;
if (angry) {
metadata.put(EntityData.COLOR, (byte) 0);
}
}
// Wolf collar color
// Relies on EntityData.OWNER_EID being set in TameableEntity.java
if (entityMetadata.getId() == 19) {
if (entityMetadata.getId() == 19 && !metadata.getFlags().getFlag(EntityFlag.ANGRY)) {
metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue());
}
super.updateBedrockMetadata(entityMetadata, session);

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.entity.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.Attribute;
import com.nukkitx.protocol.bedrock.data.EntityEventType;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.connector.entity.living.InsentientEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class EnderDragonEntity extends InsentientEntity {
public EnderDragonEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 15) {
metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true);
switch ((int) entityMetadata.getValue()) {
// Performing breath attack
case 5:
EntityEventPacket entityEventPacket = new EntityEventPacket();
entityEventPacket.setType(EntityEventType.DRAGON_FLAMING);
entityEventPacket.setRuntimeEntityId(geyserId);
entityEventPacket.setData(0);
session.getUpstream().sendPacket(entityEventPacket);
case 6:
case 7:
metadata.getFlags().setFlag(EntityFlag.SITTING, true);
break;
}
}
super.updateBedrockMetadata(entityMetadata, session);
}
@Override
public void spawnEntity(GeyserSession session) {
AddEntityPacket addEntityPacket = new AddEntityPacket();
addEntityPacket.setIdentifier("minecraft:" + entityType.name().toLowerCase());
addEntityPacket.setRuntimeEntityId(geyserId);
addEntityPacket.setUniqueEntityId(geyserId);
addEntityPacket.setPosition(position);
addEntityPacket.setMotion(motion);
addEntityPacket.setRotation(getBedrockRotation());
addEntityPacket.setEntityType(entityType.getType());
addEntityPacket.getMetadata().putAll(metadata);
// Otherwise dragon is always 'dying'
addEntityPacket.getAttributes().add(new Attribute("minecraft:health", 0.0f, 200f, 200f, 200f));
valid = true;
session.getUpstream().sendPacket(addEntityPacket);
session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.entity.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.data.EntityFlag;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.block.BlockTranslator;
public class EndermanEntity extends MonsterEntity {
public EndermanEntity(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) {
// Held block
if (entityMetadata.getId() == 15) {
metadata.put(EntityData.ENDERMAN_HELD_ITEM_ID, BlockTranslator.getBedrockBlockId((BlockState) entityMetadata.getValue()));
}
// 'Angry' - mouth open
if (entityMetadata.getId() == 16) {
metadata.getFlags().setFlag(EntityFlag.ANGRY, (boolean) entityMetadata.getValue());
}
// TODO: ID 17 is stared at but I don't believe it's used - maybe only for the sound effect. Check after particle merge
super.updateBedrockMetadata(entityMetadata, session);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.entity.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.protocol.bedrock.data.EntityData;
import org.geysermc.connector.entity.living.GolemEntity;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
public class ShulkerEntity extends GolemEntity {
public ShulkerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 15) {
BlockFace blockFace = (BlockFace) entityMetadata.getValue();
metadata.put(EntityData.SHULKER_ATTACH_FACE, (byte) blockFace.ordinal());
}
if (entityMetadata.getId() == 16) {
Position position = (Position) entityMetadata.getValue();
if (position != null) {
metadata.put(EntityData.SHULKER_ATTACH_POS, Vector3i.from(position.getX(), position.getY(), position.getZ()));
}
}
//TODO Outdated metadata flag SHULKER_PEAK_HEIGHT
// if (entityMetadata.getId() == 17) {
// int height = (byte) entityMetadata.getValue();
// metadata.put(EntityData.SHULKER_PEAK_HEIGHT, height);
// }
if (entityMetadata.getId() == 18) {
int color = Math.abs((byte) entityMetadata.getValue() - 15);
metadata.put(EntityData.VARIANT, color);
}
super.updateBedrockMetadata(entityMetadata, session);
}
}

View File

@ -69,7 +69,7 @@ public enum EntityType {
SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f),
ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f),
SLIME(InsentientEntity.class, 37, 0.51f),
ENDERMAN(MonsterEntity.class, 38, 2.9f, 0.6f),
ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f),
SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f),
CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f),
GHAST(FlyingEntity.class, 41, 4.0f),
@ -84,8 +84,8 @@ public enum EntityType {
ELDER_GUARDIAN(GuardianEntity.class, 50, 1.9975f),
NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f),
WITHER(MonsterEntity.class, 52, 3.5f, 0.9f),
ENDER_DRAGON(InsentientEntity.class, 53, 4f, 13f),
SHULKER(GolemEntity.class, 54, 1f, 1f),
ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f),
SHULKER(ShulkerEntity.class, 54, 1f, 1f),
ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f),
AGENT(Entity.class, 56, 0f),
VINDICATOR(AbstractIllagerEntity.class, 57, 1.8f, 0.6f, 0.6f, 1.62f),
@ -104,13 +104,13 @@ public enum EntityType {
EXPERIENCE_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f),
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f),
EYE_OF_ENDER(Entity.class, 70, 0f),
END_CRYSTAL(Entity.class, 71, 0f),
END_CRYSTAL(EnderCrystalEntity.class, 71, 0f),
FIREWORK_ROCKET(Entity.class, 72, 0f),
TRIDENT(ArrowEntity.class, 73, 0f),
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
CAT(CatEntity.class, 75, 0.35f, 0.3f),
SHULKER_BULLET(Entity.class, 76, 0f),
FISHING_BOBBER(Entity.class, 77, 0f),
FISHING_BOBBER(FishingHookEntity.class, 77, 0f),
CHALKBOARD(Entity.class, 78, 0f),
DRAGON_FIREBALL(ItemedFireballEntity.class, 79, 0f),
ARROW(ArrowEntity.class, 80, 0.25f, 0.25f),
@ -140,10 +140,10 @@ public enum EntityType {
VEX(MonsterEntity.class, 105, 0f),
ICE_BOMB(Entity.class, 106, 0f),
BALLOON(Entity.class, 107, 0f), //TODO
PUFFERFISH(AbstractFishEntity.class, 108, 0.7f, 0.7f),
PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f),
SALMON(AbstractFishEntity.class, 109, 0.5f, 0.7f),
DROWNED(ZombieEntity.class, 110, 1.95f, 0.6f),
TROPICAL_FISH(AbstractFishEntity.class, 111, 0.6f, 0.6f),
TROPICAL_FISH(TropicalFishEntity.class, 111, 0.6f, 0.6f),
COD(AbstractFishEntity.class, 112, 0.25f, 0.5f),
PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f),
FOX(FoxEntity.class, 121, 0.5f, 1.25f),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -27,9 +27,12 @@ package org.geysermc.connector.inventory;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.math.vector.Vector3i;
import lombok.Getter;
import lombok.Setter;
import java.util.concurrent.atomic.AtomicInteger;
public class Inventory {
@Getter
@ -43,16 +46,26 @@ public class Inventory {
protected WindowType windowType;
@Getter
protected int size;
protected final int size;
@Getter
@Setter
protected String title;
@Getter
@Setter
protected ItemStack[] items;
@Getter
@Setter
protected Vector3i holderPosition = Vector3i.ZERO;
@Getter
@Setter
protected long holderId = -1;
@Getter
protected AtomicInteger transactionId = new AtomicInteger(1);
public Inventory(int id, WindowType windowType, int size) {
this("Inventory", id, windowType, size);
}
@ -62,11 +75,16 @@ public class Inventory {
this.id = id;
this.windowType = windowType;
this.size = size;
this.items = new ItemStack[size];
}
public ItemStack getItem(int slot) {
return items[slot];
}
public void setItem(int slot, ItemStack item) {
if (item != null && (item.getId() == 0 || item.getAmount() < 1))
item = null;
items[slot] = item;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 GeyserMC. http://geysermc.org
* 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
@ -35,13 +35,21 @@ public class PlayerInventory extends Inventory {
@Setter
private int heldItemSlot;
public PlayerInventory() {
super(0, null, 45);
@Getter
private ItemStack cursor;
public PlayerInventory() {
super(0, null, 46);
heldItemSlot = 0;
}
public void setCursor(ItemStack stack) {
if (stack != null && (stack.getId() == 0 || stack.getAmount() < 1))
stack = null;
cursor = stack;
}
public ItemStack getItemInHand() {
return items[heldItemSlot];
return items[36 + heldItemSlot];
}
}

View File

@ -25,8 +25,10 @@
package org.geysermc.connector.metrics;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.geysermc.connector.GeyserConnector;
import javax.net.ssl.HttpsURLConnection;
@ -71,6 +73,8 @@ public class Metrics {
// A list with all custom charts
private final List<CustomChart> charts = new ArrayList<>();
private final static ObjectMapper mapper = new ObjectMapper();
private GeyserConnector connector;
/**
@ -110,7 +114,7 @@ public class Metrics {
*/
private void startSubmitting() {
connector.getGeneralThreadPool().scheduleAtFixedRate(this::submitData, 1, 30, TimeUnit.MINUTES);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// Submit the data every 30 minutes, first time after 1 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
@ -120,22 +124,22 @@ public class Metrics {
*
* @return The plugin specific data.
*/
private JsonObject getPluginData() {
JsonObject data = new JsonObject();
private ObjectNode getPluginData() {
ObjectNode data = mapper.createObjectNode();
data.addProperty("pluginName", name); // Append the name of the server software
data.addProperty("pluginVersion", GeyserConnector.VERSION); // Append the name of the server software
data.put("pluginName", name); // Append the name of the server software
data.put("pluginVersion", GeyserConnector.VERSION); // Append the name of the server software
JsonArray customCharts = new JsonArray();
ArrayNode customCharts = mapper.createArrayNode();
for (CustomChart customChart : charts) {
// Add the data of the custom charts
JsonObject chart = customChart.getRequestJsonObject();
JsonNode chart = customChart.getRequestJsonNode();
if (chart == null) { // If the chart is null, we skip it
continue;
}
customCharts.add(chart);
}
data.add("customCharts", customCharts);
data.put("customCharts", customCharts);
return data;
}
@ -145,7 +149,7 @@ public class Metrics {
*
* @return The server specific data.
*/
private JsonObject getServerData() {
private ObjectNode getServerData() {
// OS specific data
int playerAmount = connector.getPlayers().size();
@ -154,15 +158,15 @@ public class Metrics {
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject();
ObjectNode data = mapper.createObjectNode();
data.addProperty("serverUUID", serverUUID);
data.put("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount);
data.addProperty("osName", osName);
data.addProperty("osArch", osArch);
data.addProperty("osVersion", osVersion);
data.addProperty("coreCount", coreCount);
data.put("playerAmount", playerAmount);
data.put("osName", osName);
data.put("osArch", osArch);
data.put("osVersion", osVersion);
data.put("coreCount", coreCount);
return data;
}
@ -171,11 +175,11 @@ public class Metrics {
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JsonObject data = getServerData();
final ObjectNode data = getServerData();
JsonArray pluginData = new JsonArray();
ArrayNode pluginData = mapper.createArrayNode();
pluginData.add(getPluginData());
data.add("plugins", pluginData);
data.putPOJO("plugins", pluginData);
new Thread(() -> {
try {
@ -196,7 +200,7 @@ public class Metrics {
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(JsonObject data) throws Exception {
private static void sendData(ObjectNode data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null!");
}
@ -262,16 +266,16 @@ public class Metrics {
this.chartId = chartId;
}
private JsonObject getRequestJsonObject() {
JsonObject chart = new JsonObject();
chart.addProperty("chartId", chartId);
private ObjectNode getRequestJsonNode() {
ObjectNode chart = new ObjectMapper().createObjectNode();
chart.put("chartId", chartId);
try {
JsonObject data = getChartData();
ObjectNode data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
chart.add("data", data);
chart.putPOJO("data", data);
} catch (Throwable t) {
if (logFailedRequests) {
logger.log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
@ -281,7 +285,9 @@ public class Metrics {
return chart;
}
protected abstract JsonObject getChartData() throws Exception;
protected abstract ObjectNode getChartData() throws Exception;
}
@ -304,14 +310,14 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
data.addProperty("value", value);
data.put("value", value);
return data;
}
}
@ -335,9 +341,9 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
ObjectNode values = mapper.createObjectNode();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
@ -349,13 +355,13 @@ public class Metrics {
continue; // Skip this invalid
}
allSkipped = false;
values.addProperty(entry.getKey(), entry.getValue());
values.put(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
data.putPOJO("values", values);
return data;
}
}
@ -379,9 +385,9 @@ public class Metrics {
}
@Override
public JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
public ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
ObjectNode values = mapper.createObjectNode();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
@ -389,22 +395,22 @@ public class Metrics {
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JsonObject value = new JsonObject();
ObjectNode value = mapper.createObjectNode();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
value.addProperty(valueEntry.getKey(), valueEntry.getValue());
value.put(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
values.add(entryValues.getKey(), value);
values.putPOJO(entryValues.getKey(), value);
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
data.putPOJO("values", values);
return data;
}
}
@ -428,14 +434,14 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
data.addProperty("value", value);
data.put("value", value);
return data;
}
@ -460,9 +466,9 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
ObjectNode values = mapper.createObjectNode();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
@ -474,13 +480,13 @@ public class Metrics {
continue; // Skip this invalid
}
allSkipped = false;
values.addProperty(entry.getKey(), entry.getValue());
values.put(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
data.putPOJO("values", values);
return data;
}
@ -505,20 +511,20 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
ObjectNode values = mapper.createObjectNode();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
JsonArray categoryValues = new JsonArray();
ArrayNode categoryValues = mapper.createArrayNode();
categoryValues.add(entry.getValue());
values.add(entry.getKey(), categoryValues);
values.putPOJO(entry.getKey(), categoryValues);
}
data.add("values", values);
data.putPOJO("values", values);
return data;
}
@ -543,9 +549,9 @@ public class Metrics {
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
protected ObjectNode getChartData() throws Exception {
ObjectNode data = mapper.createObjectNode();
ObjectNode values = mapper.createObjectNode();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
@ -557,17 +563,17 @@ public class Metrics {
continue; // Skip this invalid
}
allSkipped = false;
JsonArray categoryValues = new JsonArray();
ArrayNode categoryValues = mapper.createArrayNode();
for (int categoryValue : entry.getValue()) {
categoryValues.add(categoryValue);
}
values.add(entry.getKey(), categoryValues);
values.putPOJO(entry.getKey(), categoryValues);
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
data.putPOJO("values", values);
return data;
}

View File

@ -1,107 +0,0 @@
package org.geysermc.connector.metrics;
import io.sentry.Sentry;
import io.sentry.SentryClient;
import io.sentry.SentryClientFactory;
import io.sentry.context.Context;
import io.sentry.event.BreadcrumbBuilder;
import io.sentry.event.UserBuilder;
public class SentryMetrics {
private static SentryClient sentry;
public static void init() {
/*
It is recommended that you use the DSN detection system, which
will check the environment variable "SENTRY_DSN", the Java
System Property "sentry.dsn", or the "sentry.properties" file
in your classpath. This makes it easier to provide and adjust
your DSN without needing to change your code. See the configuration
page for more information.
*/
Sentry.init();
// You can also manually provide the DSN to the ``init`` method.
Sentry.init();
/*
It is possible to go around the static ``Sentry`` API, which means
you are responsible for making the SentryClient instance available
to your code.
*/
sentry = SentryClientFactory.sentryClient();
SentryMetrics metrics = new SentryMetrics();
metrics.logWithStaticAPI();
metrics.logWithInstanceAPI();
}
/**
* An example method that throws an exception.
*/
void unsafeMethod() {
throw new UnsupportedOperationException("You shouldn't call this!");
}
/**
* Examples using the (recommended) static API.
*/
void logWithStaticAPI() {
// Note that all fields set on the context are optional. Context data is copied onto
// all future events in the current context (until the context is cleared).
// Record a breadcrumb in the current context. By default the last 100 breadcrumbs are kept.
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage("User made an action").build()
);
// Set the user in the current context.
Sentry.getContext().setUser(
new UserBuilder().setEmail("hello@sentry.io").build()
);
// Add extra data to future events in this context.
Sentry.getContext().addExtra("extra", "thing");
// Add an additional tag to future events in this context.
Sentry.getContext().addTag("tagName", "tagValue");
/*
This sends a simple event to Sentry using the statically stored instance
that was created in the ``main`` method.
*/
Sentry.capture("This is a test");
try {
unsafeMethod();
} catch (Exception e) {
// This sends an exception event to Sentry using the statically stored instance
// that was created in the ``main`` method.
Sentry.capture(e);
}
}
/**
* Examples that use the SentryClient instance directly.
*/
void logWithInstanceAPI() {
// Retrieve the current context.
Context context = sentry.getContext();
// Record a breadcrumb in the current context. By default the last 100 breadcrumbs are kept.
context.recordBreadcrumb(new BreadcrumbBuilder().setMessage("User made an action").build());
// Set the user in the current context.
context.setUser(new UserBuilder().setEmail("geyser.project@gmail.com").build());
// This sends a simple event to Sentry.
sentry.sendMessage("This is a test");
try {
unsafeMethod();
} catch (Exception e) {
// This sends an exception event to Sentry.
sentry.sendException(e);
}
}
}

View File

@ -80,6 +80,13 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
pong.setMotd(config.getBedrock().getMotd1());
pong.setMotd(config.getBedrock().getMotd2());
}
//Bedrock will not even attempt a connection if the client thinks the server is full
//so we have to fake it not being full
if (pong.getPlayerCount() >= pong.getMaximumPlayerCount()) {
pong.setMaximumPlayerCount(pong.getPlayerCount() + 1);
}
return pong;
}

View File

@ -50,8 +50,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(LoginPacket loginPacket) {
if (loginPacket.getProtocolVersion() != GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) {
session.getUpstream().disconnect("Unsupported Bedrock version. Are you running an outdated version?");
if (loginPacket.getProtocolVersion() > GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) {
session.disconnect("Outdated Geyser proxy! I'm still on " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
return true;
} else if (loginPacket.getProtocolVersion() < GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) {
session.disconnect("Outdated Bedrock client! Please use " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion());
return true;
}
@ -111,7 +114,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
break;
default:
session.getUpstream().disconnect("disconnectionScreen.resourcePack");
session.disconnect("disconnectionScreen.resourcePack");
break;
}
@ -120,7 +123,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public boolean handle(ModalFormResponsePacket packet) {
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormData());
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData());
}
private boolean couldLoginUserByName(String bedrockUsername) {

View File

@ -30,8 +30,8 @@ import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsExcepti
import com.github.steveice10.mc.auth.exception.request.RequestException;
import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket;
import com.github.steveice10.packetlib.Client;
import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet;
@ -42,16 +42,14 @@ import com.nukkitx.math.vector.Vector2f;
import com.nukkitx.math.vector.Vector2i;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.tag.CompoundTag;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
import com.nukkitx.protocol.bedrock.data.ContainerId;
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
import com.nukkitx.protocol.bedrock.data.GameRuleData;
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
import com.nukkitx.protocol.bedrock.packet.*;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.AuthType;
import org.geysermc.common.window.FormWindow;
import org.geysermc.connector.GeyserConnector;
@ -125,6 +123,9 @@ public class GeyserSession implements CommandSender {
private boolean manyDimPackets = false;
private ServerRespawnPacket lastDimPacket = null;
@Setter
private int craftSlot = 0;
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
this.connector = connector;
this.upstream = new UpstreamSession(bedrockServerSession);
@ -157,9 +158,14 @@ public class GeyserSession implements CommandSender {
upstream.sendPacket(biomeDefinitionListPacket);
AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket();
entityPacket.setTag(CompoundTag.EMPTY);
entityPacket.setTag(Toolbox.ENTITY_IDENTIFIERS);
upstream.sendPacket(entityPacket);
InventoryContentPacket creativePacket = new InventoryContentPacket();
creativePacket.setContainerId(ContainerId.CREATIVE);
creativePacket.setContents(Toolbox.CREATIVE_ITEMS);
upstream.sendPacket(creativePacket);
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
upstream.sendPacket(playStatusPacket);
@ -274,6 +280,9 @@ public class GeyserSession implements CommandSender {
loggingIn = false;
loggedIn = false;
connector.getLogger().info(authData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason());
if (event.getCause() != null) {
event.getCause().printStackTrace();
}
upstream.disconnect(event.getReason());
}
@ -297,7 +306,7 @@ public class GeyserSession implements CommandSender {
downstream.getSession().connect();
connector.addPlayer(this);
} catch (InvalidCredentialsException e) {
} catch (InvalidCredentialsException | IllegalArgumentException e) {
connector.getLogger().info("User '" + username + "' entered invalid login info, kicking.");
disconnect("Invalid/incorrect login info");
} catch (RequestException ex) {
@ -313,10 +322,16 @@ public class GeyserSession implements CommandSender {
downstream.getSession().disconnect(reason);
}
if (upstream != null && !upstream.isClosed()) {
connector.getPlayers().remove(this.upstream.getAddress());
upstream.disconnect(reason);
}
}
this.entityCache.getEntities().clear();
this.scoreboardCache.removeScoreboard();
this.inventoryCache.getInventories().clear();
this.windowCache.getWindows().clear();
closed = true;
}

View File

@ -0,0 +1,121 @@
/*
* 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.session.cache;
import com.github.steveice10.mc.protocol.data.message.Message;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.data.EntityData;
import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
import com.nukkitx.protocol.bedrock.packet.BossEventPacket;
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
import lombok.AllArgsConstructor;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.MessageUtils;
@AllArgsConstructor
public class BossBar {
private GeyserSession session;
private long entityId;
private Message title;
private float health;
private int color;
private int overlay;
private int darkenSky;
public void addBossBar() {
addBossEntity();
updateBossBar();
}
public void updateBossBar() {
BossEventPacket bossEventPacket = new BossEventPacket();
bossEventPacket.setBossUniqueEntityId(entityId);
bossEventPacket.setAction(BossEventPacket.Action.SHOW);
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode()));
bossEventPacket.setHealthPercentage(health);
bossEventPacket.setColor(color); //ignored by client
bossEventPacket.setOverlay(overlay);
bossEventPacket.setDarkenSky(darkenSky);
session.getUpstream().sendPacket(bossEventPacket);
}
public void updateTitle(Message title) {
this.title = title;
BossEventPacket bossEventPacket = new BossEventPacket();
bossEventPacket.setBossUniqueEntityId(entityId);
bossEventPacket.setAction(BossEventPacket.Action.TITLE);
bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode()));
session.getUpstream().sendPacket(bossEventPacket);
}
public void updateHealth(float health) {
this.health = health;
BossEventPacket bossEventPacket = new BossEventPacket();
bossEventPacket.setBossUniqueEntityId(entityId);
bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE);
bossEventPacket.setHealthPercentage(health);
session.getUpstream().sendPacket(bossEventPacket);
}
public void removeBossBar() {
BossEventPacket bossEventPacket = new BossEventPacket();
bossEventPacket.setBossUniqueEntityId(entityId);
bossEventPacket.setAction(BossEventPacket.Action.HIDE);
session.getUpstream().sendPacket(bossEventPacket);
removeBossEntity();
}
/**
* Bedrock still needs an entity to display the BossBar.<br>
* Just like 1.8 but it doesn't care about which entity
*/
private void addBossEntity() {
AddEntityPacket addEntityPacket = new AddEntityPacket();
addEntityPacket.setUniqueEntityId(entityId);
addEntityPacket.setRuntimeEntityId(entityId);
addEntityPacket.setIdentifier("minecraft:creeper");
addEntityPacket.setEntityType(33);
addEntityPacket.setPosition(session.getPlayerEntity().getPosition());
addEntityPacket.setRotation(Vector3f.ZERO);
addEntityPacket.setMotion(Vector3f.ZERO);
addEntityPacket.getMetadata().put(EntityData.SCALE, 0.01F); // scale = 0 doesn't work?
session.getUpstream().sendPacket(addEntityPacket);
}
private void removeBossEntity() {
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
removeEntityPacket.setUniqueEntityId(entityId);
session.getUpstream().sendPacket(removeEntityPacket);
}
}

View File

@ -48,7 +48,7 @@ public class EntityCache {
private Long2ObjectMap<Entity> entities = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
private Object2LongMap<UUID> bossbars = new Object2LongOpenHashMap<>();
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
@Getter
private AtomicLong nextEntityId = new AtomicLong(2L);
@ -58,13 +58,19 @@ public class EntityCache {
}
public void spawnEntity(Entity entity) {
cacheEntity(entity);
entity.spawnEntity(session);
if (cacheEntity(entity)) {
entity.spawnEntity(session);
}
}
public void cacheEntity(Entity entity) {
entityIdTranslations.put(entity.getEntityId(), entity.getGeyserId());
entities.put(entity.getGeyserId(), entity);
public boolean cacheEntity(Entity entity) {
// Check to see if the entity exists, otherwise we can end up with duplicated mobs
if (!entityIdTranslations.containsKey(entity.getEntityId())) {
entityIdTranslations.put(entity.getEntityId(), entity.getGeyserId());
entities.put(entity.getGeyserId(), entity);
return true;
}
return false;
}
public boolean removeEntity(Entity entity, boolean force) {
@ -116,24 +122,30 @@ public class EntityCache {
playerEntities.remove(uuid);
}
public long addBossBar(UUID uuid) {
long entityId = getNextEntityId().incrementAndGet();
bossbars.put(uuid, entityId);
return entityId;
public void addBossBar(UUID uuid, BossBar bossBar) {
bossBars.put(uuid, bossBar);
bossBar.addBossBar();
}
public long getBossBar(UUID uuid) {
return bossbars.containsKey(uuid) ? bossbars.get(uuid) : -1;
public BossBar getBossBar(UUID uuid) {
return bossBars.get(uuid);
}
public long removeBossBar(UUID uuid) {
return bossbars.remove(uuid);
public void removeBossBar(UUID uuid) {
BossBar bossBar = bossBars.remove(uuid);
if (bossBar != null) {
bossBar.removeBossBar();
}
}
public void updateBossBars() {
bossBars.values().forEach(BossBar::updateBossBar);
}
public void clear() {
entities = null;
entityIdTranslations = null;
playerEntities = null;
bossbars = null;
bossBars = null;
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.session.cache;
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.Getter;
public class EntityEffectCache {
@Getter
private final Object2IntMap<Effect> entityEffects = new Object2IntOpenHashMap<>();
public void addEffect(Effect effect, int effectAmplifier) {
if (effect != null) {
entityEffects.putIfAbsent(effect, effectAmplifier + 1);
}
}
public void removeEffect(Effect effect) {
if (entityEffects.containsKey(effect)) {
int effectLevel = entityEffects.getInt(effect);
entityEffects.remove(effect, effectLevel);
}
}
public int getEffectLevel(Effect effect) {
return entityEffects.getOrDefault(effect, 0);
}
}

View File

@ -25,17 +25,13 @@
package org.geysermc.connector.network.session.cache;
import com.github.steveice10.packetlib.packet.Packet;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InventoryCache {
private GeyserSession session;
@ -45,10 +41,7 @@ public class InventoryCache {
private Inventory openInventory;
@Getter
private Map<Integer, Inventory> inventories = new HashMap<Integer, Inventory>();
@Getter
private Map<Integer, List<Packet>> cachedPackets = new HashMap<Integer, List<Packet>>();
private Int2ObjectMap<Inventory> inventories = new Int2ObjectOpenHashMap<>();
public InventoryCache(GeyserSession session) {
this.session = session;
@ -65,10 +58,4 @@ public class InventoryCache {
public void uncacheInventory(int id) {
inventories.remove(id);
}
public void cachePacket(int id, Packet packet) {
List<Packet> packets = cachedPackets.getOrDefault(id, new ArrayList<Packet>());
packets.add(packet);
cachedPackets.put(id, packets);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(value = RetentionPolicy.RUNTIME)
public @interface ItemRemapper {
int priority() default 0;
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.message.Message;
import com.github.steveice10.opennbt.tag.builtin.*;
import com.nukkitx.nbt.tag.CompoundTag;
import com.nukkitx.nbt.tag.Tag;
import com.nukkitx.protocol.bedrock.data.ItemData;
import org.geysermc.connector.network.translators.item.ItemEntry;
import org.geysermc.connector.utils.MessageUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ItemStackTranslator {
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
if (itemStack == null) {
return ItemData.AIR;
}
if (itemStack.getNbt() == null) {
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount());
}
return ItemData.of(itemEntry.getBedrockId(), (short) itemEntry.getBedrockData(), itemStack.getAmount(), this.translateNbtToBedrock(itemStack.getNbt()));
}
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
if (itemData == null) return null;
if (itemData.getTag() == null) {
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""));
}
return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag()));
}
public abstract List<ItemEntry> getAppliedItems();
public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
Map<String, Tag<?>> javaValue = new HashMap<String, Tag<?>>();
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
for (String str : tag.getValue().keySet()) {
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag);
if (translatedTag == null)
continue;
javaValue.put(translatedTag.getName(), translatedTag);
}
}
com.nukkitx.nbt.tag.CompoundTag bedrockTag = new com.nukkitx.nbt.tag.CompoundTag(tag.getName(), javaValue);
return bedrockTag;
}
private com.nukkitx.nbt.tag.Tag translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) {
if (tag instanceof ByteArrayTag) {
ByteArrayTag byteArrayTag = (ByteArrayTag) tag;
return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
}
if (tag instanceof ByteTag) {
ByteTag byteTag = (ByteTag) tag;
return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue());
}
if (tag instanceof DoubleTag) {
DoubleTag doubleTag = (DoubleTag) tag;
return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue());
}
if (tag instanceof FloatTag) {
FloatTag floatTag = (FloatTag) tag;
return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue());
}
if (tag instanceof IntArrayTag) {
IntArrayTag intArrayTag = (IntArrayTag) tag;
return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
}
if (tag instanceof IntTag) {
IntTag intTag = (IntTag) tag;
return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue());
}
if (tag instanceof LongArrayTag) {
LongArrayTag longArrayTag = (LongArrayTag) tag;
return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
}
if (tag instanceof LongTag) {
LongTag longTag = (LongTag) tag;
return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue());
}
if (tag instanceof ShortTag) {
ShortTag shortTag = (ShortTag) tag;
return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue());
}
if (tag instanceof StringTag) {
StringTag stringTag = (StringTag) tag;
return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), MessageUtils.getBedrockMessage(Message.fromString(stringTag.getValue())));
}
if (tag instanceof ListTag) {
ListTag listTag = (ListTag) tag;
List<Tag> tagList = new ArrayList<>();
for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) {
tagList.add(translateToBedrockNBT(value));
}
Class clazz = CompoundTag.class;
if (!tagList.isEmpty()) {
clazz = tagList.get(0).getClass();
}
return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList);
}
if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) {
com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag;
return translateNbtToBedrock(compoundTag);
}
return null;
}
public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) {
com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName());
Map<String, com.github.steveice10.opennbt.tag.builtin.Tag> javaValue = javaTag.getValue();
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
for (String str : tag.getValue().keySet()) {
com.nukkitx.nbt.tag.Tag bedrockTag = tag.get(str);
com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag);
if (translatedTag == null)
continue;
javaValue.put(translatedTag.getName(), translatedTag);
}
}
javaTag.setValue(javaValue);
return javaTag;
}
private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) {
if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) {
com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag;
return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.ByteTag) {
com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag;
return new ByteTag(byteTag.getName(), byteTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) {
com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag;
return new DoubleTag(doubleTag.getName(), doubleTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.FloatTag) {
com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag;
return new FloatTag(floatTag.getName(), floatTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) {
com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag;
return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.IntTag) {
com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag;
return new IntTag(intTag.getName(), intTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) {
com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag;
return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.LongTag) {
com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag;
return new LongTag(longTag.getName(), longTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.ShortTag) {
com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag;
return new ShortTag(shortTag.getName(), shortTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.StringTag) {
com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag;
return new StringTag(stringTag.getName(), stringTag.getValue());
}
if (tag instanceof com.nukkitx.nbt.tag.ListTag) {
com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag;
List<com.github.steveice10.opennbt.tag.builtin.Tag> tags = new ArrayList<>();
for (Object value : listTag.getValue()) {
if (!(value instanceof com.nukkitx.nbt.tag.Tag))
continue;
com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value;
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue);
if (javaTag != null)
tags.add(javaTag);
}
return new ListTag(listTag.getName(), tags);
}
if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) {
com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag;
return translateToJavaNBT(compoundTag);
}
return null;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.geysermc.connector.network.translators.item.ItemEntry;
public class NbtItemStackTranslator {
public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) {
}
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
}
public boolean acceptItem(ItemEntry itemEntry) {
return true;
}
}

View File

@ -27,11 +27,17 @@ package org.geysermc.connector.network.translators;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.nukkitx.protocol.bedrock.data.ContainerType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.translators.block.BlockTranslator;
import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator;
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
import org.geysermc.connector.network.translators.block.entity.*;
import org.geysermc.connector.network.translators.inventory.*;
import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.reflections.Reflections;
@ -50,7 +56,10 @@ public class Translators {
private static ItemTranslator itemTranslator;
@Getter
private static InventoryTranslator inventoryTranslator = new GenericInventoryTranslator();
private static Map<WindowType, InventoryTranslator> inventoryTranslators = new HashMap<>();
@Getter
private static Map<String, BlockEntityTranslator> blockEntityTranslators = new HashMap<>();
private static final CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag();
public static final byte[] EMPTY_LEVEL_CHUNK_DATA;
@ -82,15 +91,15 @@ public class Translators {
if (Packet.class.isAssignableFrom(packet)) {
Class<? extends Packet> targetPacket = (Class<? extends Packet>) packet;
PacketTranslator<? extends Packet> translator = (PacketTranslator<? extends Packet>) clazz.newInstance();
Registry.registerJava(targetPacket, translator);
} else if (BedrockPacket.class.isAssignableFrom(packet)) {
Class<? extends BedrockPacket> targetPacket = (Class<? extends BedrockPacket>) packet;
PacketTranslator<? extends BedrockPacket> translator = (PacketTranslator<? extends BedrockPacket>) clazz.newInstance();
Registry.registerBedrock(targetPacket, translator);
} else {
GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet.");
}
@ -100,17 +109,51 @@ public class Translators {
}
itemTranslator = new ItemTranslator();
itemTranslator.init();
BlockTranslator.init();
registerBlockEntityTranslators();
registerInventoryTranslators();
}
private static void registerBlockEntityTranslators() {
Reflections ref = new Reflections("org.geysermc.connector.network.translators.block.entity");
for (Class<?> clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) {
GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName());
try {
blockEntityTranslators.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + ".");
}
}
}
private static void registerInventoryTranslators() {
/*inventoryTranslators.put(WindowType.GENERIC_9X1, new GenericInventoryTranslator());
inventoryTranslators.put(WindowType.GENERIC_9X2, new GenericInventoryTranslator());
inventoryTranslators.put(WindowType.GENERIC_9X3, new GenericInventoryTranslator());
inventoryTranslators.put(WindowType.GENERIC_9X4, new GenericInventoryTranslator());
inventoryTranslators.put(WindowType.GENERIC_9X5, new GenericInventoryTranslator());
inventoryTranslators.put(WindowType.GENERIC_9X6, new GenericInventoryTranslator());*/
inventoryTranslators.put(null, new PlayerInventoryTranslator()); //player inventory
inventoryTranslators.put(WindowType.GENERIC_9X1, new SingleChestInventoryTranslator(9));
inventoryTranslators.put(WindowType.GENERIC_9X2, new SingleChestInventoryTranslator(18));
inventoryTranslators.put(WindowType.GENERIC_9X3, new SingleChestInventoryTranslator(27));
inventoryTranslators.put(WindowType.GENERIC_9X4, new DoubleChestInventoryTranslator(36));
inventoryTranslators.put(WindowType.GENERIC_9X5, new DoubleChestInventoryTranslator(45));
inventoryTranslators.put(WindowType.GENERIC_9X6, new DoubleChestInventoryTranslator(54));
inventoryTranslators.put(WindowType.BREWING_STAND, new BrewingInventoryTranslator());
inventoryTranslators.put(WindowType.ANVIL, new AnvilInventoryTranslator());
inventoryTranslators.put(WindowType.CRAFTING, new CraftingInventoryTranslator());
inventoryTranslators.put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
//inventoryTranslators.put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
InventoryTranslator furnace = new FurnaceInventoryTranslator();
inventoryTranslators.put(WindowType.FURNACE, furnace);
inventoryTranslators.put(WindowType.BLAST_FURNACE, furnace);
inventoryTranslators.put(WindowType.SMOKER, furnace);
InventoryUpdater containerUpdater = new ContainerInventoryUpdater();
inventoryTranslators.put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater));
inventoryTranslators.put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater));
inventoryTranslators.put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater));
//inventoryTranslators.put(WindowType.BEACON, new BlockInventoryTranslator(1, "minecraft:beacon", ContainerType.BEACON)); //TODO
}
}

View File

@ -123,6 +123,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
spawnPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
session.getUpstream().sendPacket(spawnPacket);
entity.updateBedrockAttributes(session);
session.getEntityCache().updateBossBars();
}
break;
case JUMP:

View File

@ -40,6 +40,11 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
@Override
public void translate(AnimatePacket packet, GeyserSession session) {
// Stop the player sending animations before they have fully spawned into the server
if (!session.isSpawned()) {
return;
}
switch (packet.getAction()) {
case SWING_ARM:
// Delay so entity damage can be processed first

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientUpdateSignPacket;
import com.nukkitx.nbt.tag.CompoundTag;
import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import java.util.HashMap;
import java.util.Map;
@Translator(packet = BlockEntityDataPacket.class)
public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEntityDataPacket> {
// In case two people are editing signs at the same time this array holds the temporary messages to be sent
// Position -> Message being held
protected static Map<Position, String> lastMessages = new HashMap<>();
@Override
public void translate(BlockEntityDataPacket packet, GeyserSession session) {
if (packet.getData() instanceof CompoundTag) {
CompoundTag tag = (CompoundTag) packet.getData();
if (tag.getString("id").equals("Sign")) {
// This is the reason why this all works - Bedrock sends packets every time you update the sign, Java only wants the final packet
// But Bedrock sends one final packet when you're done editing the sign, which should be equal to the last message since there's no edits
// So if the latest update does not match the last cached update then it's still being edited
Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z"));
if (!tag.getString("Text").equals(lastMessages.get(pos))) {
lastMessages.put(pos, tag.getString("Text"));
return;
}
// Otherwise the two messages are identical and we can get to work deconstructing
StringBuilder newMessage = new StringBuilder();
// While Bedrock's sign lines are one string, Java's is an array of each line
// (Initialized all with empty strings because it complains about null)
String[] lines = new String[] {"", "", "", ""};
int iterator = 0;
// This converts the message into the array'd message Java wants
for (char character : tag.getString("Text").toCharArray()) {
// If we get a return in Bedrock, that signals to use the next line.
if (character == '\n') {
lines[iterator] = newMessage.toString();
iterator++;
// Bedrock, for whatever reason, can hold a message out of bounds
// We don't care about that so we discard that
if (iterator > lines.length - 1) {
break;
}
newMessage = new StringBuilder();
} else newMessage.append(character);
}
// Put the final line on since it isn't done in the for loop
if (iterator < lines.length) lines[iterator] = newMessage.toString();
ClientUpdateSignPacket clientUpdateSignPacket = new ClientUpdateSignPacket(pos, lines);
session.getDownstream().getSession().send(clientUpdateSignPacket);
//TODO (potentially): originally I was going to update the sign blocks so Bedrock and Java users would match visually
// However Java can still store a lot per-line and visuals are still messed up so that doesn't work
// We remove the sign position from map to indicate there is no work-in-progress sign
lastMessages.remove(pos);
}
}
}
}

View File

@ -27,13 +27,14 @@ package org.geysermc.connector.network.translators.bedrock;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommandMap;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket;
import org.geysermc.connector.utils.MessageUtils;
@Translator(packet = CommandRequestPacket.class)
public class BedrockCommandRequestTranslator extends PacketTranslator<CommandRequestPacket> {
@ -41,11 +42,17 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
@Override
public void translate(CommandRequestPacket packet, GeyserSession session) {
String command = packet.getCommand().replace("/", "");
GeyserCommandMap commandMap = GeyserConnector.getInstance().getCommandMap();
if (session.getConnector().getPlatformType() == PlatformType.STANDALONE && command.startsWith("geyser ") && commandMap.getCommands().containsKey(command.split(" ")[1])) {
commandMap.runCommand(session, command);
CommandManager commandManager = GeyserConnector.getInstance().getCommandManager();
if (session.getConnector().getPlatformType() == PlatformType.STANDALONE && command.startsWith("geyser ") && commandManager.getCommands().containsKey(command.split(" ")[1])) {
commandManager.runCommand(session, command);
} else {
ClientChatPacket chatPacket = new ClientChatPacket(packet.getCommand());
String message = packet.getCommand().trim();
if (MessageUtils.isTooLong(message, session)) {
return;
}
ClientChatPacket chatPacket = new ClientChatPacket(message);
session.getDownstream().getSession().send(chatPacket);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket;
import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.InventoryUtils;
@Translator(packet = ContainerClosePacket.class)
public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerClosePacket> {
@Override
public void translate(ContainerClosePacket packet, GeyserSession session) {
byte windowId = packet.getWindowId();
if (windowId == -1) { //player inventory or crafting table
Inventory openInventory = session.getInventoryCache().getOpenInventory();
if (openInventory != null) {
windowId = (byte) openInventory.getId();
} else {
windowId = 0;
}
}
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
session.getDownstream().getSession().send(closeWindowPacket);
InventoryUtils.closeInventory(session, windowId);
}
}

View File

@ -34,6 +34,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
import org.geysermc.connector.network.translators.item.ItemTranslator;
@Translator(packet = InteractPacket.class)
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
@ -46,6 +47,9 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
switch (packet.getAction()) {
case INTERACT:
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
break;
}
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
InteractAction.INTERACT, Hand.MAIN_HAND);
session.getDownstream().getSession().send(interactPacket);

View File

@ -27,10 +27,15 @@ 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.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.network.translators.Translators;
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.utils.InventoryUtils;
import com.nukkitx.math.vector.Vector3f;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
@ -40,7 +45,6 @@ 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.ClientPlayerInteractEntityPacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
import com.nukkitx.math.vector.Vector3f;
import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
@Translator(packet = InventoryTransactionPacket.class)
@ -49,6 +53,17 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
@Override
public void translate(InventoryTransactionPacket packet, GeyserSession session) {
switch (packet.getTransactionType()) {
case NORMAL:
Inventory inventory = session.getInventoryCache().getOpenInventory();
if (inventory == null) inventory = session.getInventory();
Translators.getInventoryTranslators().get(inventory.getWindowType()).translateActions(session, inventory, packet.getActions());
break;
case INVENTORY_MISMATCH:
Inventory inv = session.getInventoryCache().getOpenInventory();
if (inv == null) inv = session.getInventory();
Translators.getInventoryTranslators().get(inv.getWindowType()).updateInventory(session, inv);
InventoryUtils.updateCursor(session);
break;
case ITEM_USE:
switch (packet.getActionType()) {
case 0:
@ -61,6 +76,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
session.getDownstream().getSession().send(blockPacket);
break;
case 1:
if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemTranslator.SHIELD) {
break;
} // Handled in Entity.java
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
session.getDownstream().getSession().send(useItemPacket);
break;
@ -85,11 +103,23 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (entity == null)
return;
Vector3f vector = packet.getClickPosition();
ClientPlayerInteractEntityPacket entityPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
InteractAction.values()[packet.getActionType()], vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
session.getDownstream().getSession().send(entityPacket);
//https://wiki.vg/Protocol#Interact_Entity
switch (packet.getActionType()) {
case 0: //Interact
Vector3f vector = packet.getClickPosition();
ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
InteractAction.INTERACT, Hand.MAIN_HAND);
ClientPlayerInteractEntityPacket interactAtPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
InteractAction.INTERACT_AT, vector.getX(), vector.getY(), vector.getZ(), Hand.MAIN_HAND);
session.getDownstream().getSession().send(interactPacket);
session.getDownstream().getSession().send(interactAtPacket);
break;
case 1: //Attack
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
InteractAction.ATTACK);
session.getDownstream().getSession().send(attackPacket);
break;
}
break;
}
}

View File

@ -67,8 +67,10 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset();
if (packet.isOnGround()) javaY = Math.ceil(javaY * 2) / 2;
// We need to parse the float as a string since casting a float to a double causes us to
// lose precision and thus, causes players to get stuck when walking near walls
ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket(
packet.isOnGround(), GenericMath.round(packet.getPosition().getX(), 4), javaY, GenericMath.round(packet.getPosition().getZ(), 4), packet.getRotation().getY(), packet.getRotation().getX()
packet.isOnGround(), Double.parseDouble(Float.toString(packet.getPosition().getX())), javaY, Double.parseDouble(Float.toString(packet.getPosition().getZ())), packet.getRotation().getY(), packet.getRotation().getX()
);
// head yaw, pitch, head yaw

View File

@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.Translator;
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
import com.nukkitx.protocol.bedrock.packet.TextPacket;
import org.geysermc.connector.utils.MessageUtils;
@Translator(packet = TextPacket.class)
public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
@ -38,12 +39,24 @@ public class BedrockTextTranslator extends PacketTranslator<TextPacket> {
@Override
public void translate(TextPacket packet, GeyserSession session) {
if (packet.getMessage().charAt(0) == '.') {
ClientChatPacket chatPacket = new ClientChatPacket(packet.getMessage().replace(".", "/"));
String message = packet.getMessage().replace(".", "/").trim();
if (MessageUtils.isTooLong(message, session)) {
return;
}
ClientChatPacket chatPacket = new ClientChatPacket(message);
session.getDownstream().getSession().send(chatPacket);
return;
}
ClientChatPacket chatPacket = new ClientChatPacket(packet.getMessage());
String message = packet.getMessage().trim();
if (MessageUtils.isTooLong(message, session)) {
return;
}
ClientChatPacket chatPacket = new ClientChatPacket(message);
session.getDownstream().getSession().send(chatPacket);
}
}

View File

@ -0,0 +1,127 @@
/*
* 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.block;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.Map;
/**
* Used for block entities if the Java block state contains Bedrock block information.
*/
public class BlockStateValues {
private static final Object2IntMap<BlockState> BANNER_COLORS = new Object2IntOpenHashMap<>();
private static final Object2ByteMap<BlockState> BED_COLORS = new Object2ByteOpenHashMap<>();
private static final Object2ByteMap<BlockState> SKULL_VARIANTS = new Object2ByteOpenHashMap<>();
private static final Object2ByteMap<BlockState> SKULL_ROTATIONS = new Object2ByteOpenHashMap<>();
/**
* Determines if the block state contains Bedrock block information
* @param entry The String to JsonNode map used in BlockTranslator
* @param javaBlockState the Java Block State of the block
*/
public static void storeBlockStateValues(Map.Entry<String, JsonNode> entry, BlockState javaBlockState) {
JsonNode bannerColor = entry.getValue().get("banner_color");
if (bannerColor != null) {
BlockStateValues.BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue());
return; // There will never be a banner color and a skull variant
}
JsonNode bedColor = entry.getValue().get("bed_color");
if (bedColor != null) {
BlockStateValues.BED_COLORS.put(javaBlockState, (byte) bedColor.intValue());
return;
}
JsonNode skullVariation = entry.getValue().get("variation");
if(skullVariation != null) {
BlockStateValues.SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
}
JsonNode skullRotation = entry.getValue().get("skull_rotation");
if (skullRotation != null) {
BlockStateValues.SKULL_ROTATIONS.put(javaBlockState, (byte) skullRotation.intValue());
}
}
/**
* Banner colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
* This gives an integer color that Bedrock can use.
* @param state BlockState of the block
* @return banner color integer or -1 if no color
*/
public static int getBannerColor(BlockState state) {
if (BANNER_COLORS.containsKey(state)) {
return BANNER_COLORS.getInt(state);
}
return -1;
}
/**
* Bed colors are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
* This gives a byte color that Bedrock can use - Bedrock needs a byte in the final tag.
* @param state BlockState of the block
* @return bed color byte or -1 if no color
*/
public static byte getBedColor(BlockState state) {
if (BED_COLORS.containsKey(state)) {
return BED_COLORS.getByte(state);
}
return -1;
}
/**
* Skull variations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock.
* This gives a byte variant ID that Bedrock can use.
* @param state BlockState of the block
* @return skull variant byte or -1 if no variant
*/
public static byte getSkullVariant(BlockState state) {
if (SKULL_VARIANTS.containsKey(state)) {
return SKULL_VARIANTS.getByte(state);
}
return -1;
}
/**
*
* @param state BlockState of the block
* @return skull rotation value or -1 if no value
*/
public static byte getSkullRotation(BlockState state) {
if (SKULL_ROTATIONS.containsKey(state)) {
return SKULL_ROTATIONS.getByte(state);
}
return -1;
}
}

Some files were not shown because too many files have changed in this diff Show More