mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Add support for client side settings (#1035)
* Port code from #486 Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com> * Fix and clean code and add default gamemode changing * Clean copyright * Remove direct modification of server, clean up code and add player list xuid fetching. * Move to custom settings menu * Move sendAdventureSettings to GeyserSession * Add javadoc comments * Add translation support * Remove updated copyright * Clean up * Clarify some javadoc comments * Remove obsolete code * Update languages submodule * Fix javadoc comments * Fix compile Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com> Co-authored-by: Redned <redned235@gmail.com>
This commit is contained in:
parent
0fde30fc78
commit
0a5048232f
29 changed files with 668 additions and 83 deletions
|
@ -25,17 +25,19 @@
|
|||
|
||||
package org.geysermc.platform.spigot.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
import org.geysermc.connector.network.translators.world.GeyserWorldManager;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
|
||||
import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class GeyserSpigotWorldManager extends WorldManager {
|
||||
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
|
||||
private final boolean isLegacy;
|
||||
// You need ViaVersion to connect to an older server with Geyser.
|
||||
|
@ -69,4 +71,19 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
|||
return BlockTranslator.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
||||
return Boolean.parseBoolean(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGameRuleInt(GeyserSession session, GameRule gameRule) {
|
||||
return Integer.parseInt(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(GeyserSession session, String permission) {
|
||||
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,12 @@
|
|||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nukkitx.fastutil</groupId>
|
||||
<artifactId>fastutil-object-object-maps</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
|
|
@ -30,14 +30,14 @@ import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
|||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.network.translators.world.CachedChunkManager;
|
||||
import org.geysermc.connector.network.translators.world.GeyserWorldManager;
|
||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface GeyserBootstrap {
|
||||
|
||||
CachedChunkManager DEFAULT_CHUNK_MANAGER = new CachedChunkManager();
|
||||
GeyserWorldManager DEFAULT_CHUNK_MANAGER = new GeyserWorldManager();
|
||||
|
||||
/**
|
||||
* Called when the GeyserBootstrap is enabled
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
|||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.AdventureSetting;
|
||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||
|
@ -47,10 +48,7 @@ import org.geysermc.connector.scoreboard.Team;
|
|||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Getter @Setter
|
||||
|
@ -95,7 +93,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
addPlayerPacket.setMotion(motion);
|
||||
addPlayerPacket.setHand(hand);
|
||||
addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.NORMAL);
|
||||
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.VISITOR);
|
||||
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER);
|
||||
addPlayerPacket.setDeviceId("");
|
||||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.getMetadata().putAll(metadata);
|
||||
|
@ -212,7 +210,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
|
||||
if (entityMetadata.getId() == 2) {
|
||||
// System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet());
|
||||
for (Team team : session.getScoreboardCache().getScoreboard().getTeams().values()) {
|
||||
for (Team team : session.getWorldCache().getScoreboard().getTeams().values()) {
|
||||
// session.getConnector().getLogger().info("team name " + team.getName());
|
||||
// session.getConnector().getLogger().info("team entities " + team.getEntities());
|
||||
}
|
||||
|
@ -221,7 +219,7 @@ public class PlayerEntity extends LivingEntity {
|
|||
if (name != null) {
|
||||
username = MessageUtils.getBedrockMessage(name);
|
||||
}
|
||||
Team team = session.getScoreboardCache().getScoreboard().getTeamFor(username);
|
||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||
if (team != null) {
|
||||
// session.getConnector().getLogger().info("team name es " + team.getName() + " with prefix " + team.getPrefix() + " and suffix " + team.getSuffix());
|
||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||
import org.geysermc.connector.utils.LoginEncryptionUtils;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import org.geysermc.connector.utils.SettingsUtils;
|
||||
|
||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
|
||||
|
@ -91,6 +92,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public boolean handle(ModalFormResponsePacket packet) {
|
||||
if (packet.getFormId() == SettingsUtils.SETTINGS_FORM_ID) {
|
||||
return SettingsUtils.handleSettingsForm(session, packet.getFormData());
|
||||
}
|
||||
|
||||
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData());
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.nukkitx.math.vector.*;
|
|||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
||||
|
@ -54,6 +55,7 @@ import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
|||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.CustomFormWindow;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
|
@ -79,9 +81,7 @@ import java.net.InetSocketAddress;
|
|||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Getter
|
||||
|
@ -102,7 +102,7 @@ public class GeyserSession implements CommandSender {
|
|||
private ChunkCache chunkCache;
|
||||
private EntityCache entityCache;
|
||||
private InventoryCache inventoryCache;
|
||||
private ScoreboardCache scoreboardCache;
|
||||
private WorldCache worldCache;
|
||||
private WindowCache windowCache;
|
||||
@Setter
|
||||
private TeleportCache teleportCache;
|
||||
|
@ -191,6 +191,41 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
private MinecraftProtocol protocol;
|
||||
|
||||
private boolean reducedDebugInfo = false;
|
||||
|
||||
@Setter
|
||||
private CustomFormWindow settingsForm;
|
||||
|
||||
/**
|
||||
* The op permission level set by the server
|
||||
*/
|
||||
@Setter
|
||||
private int opPermissionLevel = 0;
|
||||
|
||||
/**
|
||||
* If the current player can fly
|
||||
*/
|
||||
@Setter
|
||||
private boolean canFly = false;
|
||||
|
||||
/**
|
||||
* If the current player is flying
|
||||
*/
|
||||
@Setter
|
||||
private boolean flying = false;
|
||||
|
||||
/**
|
||||
* If the current player is in noclip
|
||||
*/
|
||||
@Setter
|
||||
private boolean noClip = false;
|
||||
|
||||
/**
|
||||
* If the current player can not interact with the world
|
||||
*/
|
||||
@Setter
|
||||
private boolean worldImmutable = false;
|
||||
|
||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||
this.connector = connector;
|
||||
this.upstream = new UpstreamSession(bedrockServerSession);
|
||||
|
@ -198,7 +233,7 @@ public class GeyserSession implements CommandSender {
|
|||
this.chunkCache = new ChunkCache(this);
|
||||
this.entityCache = new EntityCache(this);
|
||||
this.inventoryCache = new InventoryCache(this);
|
||||
this.scoreboardCache = new ScoreboardCache(this);
|
||||
this.worldCache = new WorldCache(this);
|
||||
this.windowCache = new WindowCache(this);
|
||||
|
||||
this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO);
|
||||
|
@ -440,7 +475,7 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
this.chunkCache = null;
|
||||
this.entityCache = null;
|
||||
this.scoreboardCache = null;
|
||||
this.worldCache = null;
|
||||
this.inventoryCache = null;
|
||||
this.windowCache = null;
|
||||
|
||||
|
@ -605,4 +640,66 @@ public class GeyserSession implements CommandSender {
|
|||
connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the cached value for the reduced debug info gamerule.
|
||||
* This also toggles the coordinates display
|
||||
*
|
||||
* @param value The new value for reducedDebugInfo
|
||||
*/
|
||||
public void setReducedDebugInfo(boolean value) {
|
||||
worldCache.setShowCoordinates(!value);
|
||||
reducedDebugInfo = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a gamerule value to the client
|
||||
*
|
||||
* @param gameRule The gamerule to send
|
||||
* @param value The value of the gamerule
|
||||
*/
|
||||
public void sendGameRule(String gameRule, Object value) {
|
||||
GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket();
|
||||
gameRulesChangedPacket.getGameRules().add(new GameRuleData<>(gameRule, value));
|
||||
upstream.sendPacket(gameRulesChangedPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.geysermc.connector.network.translators.world.WorldManager#hasPermission(GeyserSession, String)
|
||||
*/
|
||||
public Boolean hasPermission(String permission) {
|
||||
return connector.getWorldManager().hasPermission(this, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an AdventureSettingsPacket to the client with the latest flags
|
||||
*/
|
||||
public void sendAdventureSettings() {
|
||||
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
||||
adventureSettingsPacket.setUniqueEntityId(playerEntity.getGeyserId());
|
||||
adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL);
|
||||
adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||
|
||||
Set<AdventureSetting> flags = new HashSet<>();
|
||||
if (canFly) {
|
||||
flags.add(AdventureSetting.MAY_FLY);
|
||||
}
|
||||
|
||||
if (flying) {
|
||||
flags.add(AdventureSetting.FLYING);
|
||||
}
|
||||
|
||||
if (worldImmutable) {
|
||||
flags.add(AdventureSetting.WORLD_IMMUTABLE);
|
||||
}
|
||||
|
||||
if (noClip) {
|
||||
flags.add(AdventureSetting.NO_CLIP);
|
||||
}
|
||||
|
||||
flags.add(AdventureSetting.AUTO_JUMP);
|
||||
|
||||
adventureSettingsPacket.getSettings().addAll(flags);
|
||||
sendUpstreamPacket(adventureSettingsPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
|
@ -33,11 +35,18 @@ import org.geysermc.connector.scoreboard.Scoreboard;
|
|||
import java.util.Collection;
|
||||
|
||||
@Getter
|
||||
public class ScoreboardCache {
|
||||
public class WorldCache {
|
||||
|
||||
private GeyserSession session;
|
||||
|
||||
@Setter
|
||||
private Difficulty difficulty = Difficulty.EASY;
|
||||
|
||||
private boolean showCoordinates = true;
|
||||
|
||||
private Scoreboard scoreboard;
|
||||
|
||||
public ScoreboardCache(GeyserSession session) {
|
||||
public WorldCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
this.scoreboard = new Scoreboard(session);
|
||||
}
|
||||
|
@ -52,4 +61,14 @@ public class ScoreboardCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the client to hide or show the coordinates
|
||||
*
|
||||
* @param value True to show, false to hide
|
||||
*/
|
||||
public void setShowCoordinates(boolean value) {
|
||||
showCoordinates = value;
|
||||
session.sendGameRule("showcoordinates", value);
|
||||
}
|
||||
}
|
|
@ -23,15 +23,25 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.world;
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.nukkitx.protocol.bedrock.packet.ServerSettingsRequestPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.ServerSettingsResponsePacket;
|
||||
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.SettingsUtils;
|
||||
|
||||
public class CachedChunkManager extends WorldManager {
|
||||
@Translator(packet = ServerSettingsRequestPacket.class)
|
||||
public class BedrockServerSettingsRequestTranslator extends PacketTranslator<ServerSettingsRequestPacket> {
|
||||
|
||||
@Override
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
return session.getChunkCache().getBlockAt(new Position(x, y, z));
|
||||
public void translate(ServerSettingsRequestPacket packet, GeyserSession session) {
|
||||
SettingsUtils.buildForm(session);
|
||||
|
||||
ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket();
|
||||
serverSettingsResponsePacket.setFormData(session.getSettingsForm().getJSONData());
|
||||
serverSettingsResponsePacket.setFormId(SettingsUtils.SETTINGS_FORM_ID);
|
||||
session.sendUpstreamPacket(serverSettingsResponsePacket);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.EmotePacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.entity.player;
|
||||
|
||||
import com.nukkitx.math.vector.Vector3d;
|
||||
import org.geysermc.connector.common.ChatColor;
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
package org.geysermc.connector.network.translators.bedrock.world;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.SoundEvent;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket;
|
|
@ -40,5 +40,7 @@ public class JavaDifficultyTranslator extends PacketTranslator<ServerDifficultyP
|
|||
SetDifficultyPacket setDifficultyPacket = new SetDifficultyPacket();
|
||||
setDifficultyPacket.setDifficulty(packet.getDifficulty().ordinal());
|
||||
session.sendUpstreamPacket(setDifficultyPacket);
|
||||
|
||||
session.getWorldCache().setDifficulty(packet.getDifficulty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
|||
DimensionUtils.switchDimension(session, fakeDim);
|
||||
DimensionUtils.switchDimension(session, packet.getDimension());
|
||||
|
||||
session.getScoreboardCache().removeScoreboard();
|
||||
session.getWorldCache().removeScoreboard();
|
||||
}
|
||||
|
||||
AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket();
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
|||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -51,6 +52,33 @@ public class JavaEntityStatusTranslator extends PacketTranslator<ServerEntitySta
|
|||
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||
entityEventPacket.setRuntimeEntityId(entity.getGeyserId());
|
||||
switch (packet.getStatus()) {
|
||||
case PLAYER_ENABLE_REDUCED_DEBUG:
|
||||
session.setReducedDebugInfo(true);
|
||||
return;
|
||||
case PLAYER_DISABLE_REDUCED_DEBUG:
|
||||
session.setReducedDebugInfo(false);
|
||||
return;
|
||||
case PLAYER_OP_PERMISSION_LEVEL_0:
|
||||
session.setOpPermissionLevel(0);
|
||||
session.sendAdventureSettings();
|
||||
return;
|
||||
case PLAYER_OP_PERMISSION_LEVEL_1:
|
||||
session.setOpPermissionLevel(1);
|
||||
session.sendAdventureSettings();
|
||||
return;
|
||||
case PLAYER_OP_PERMISSION_LEVEL_2:
|
||||
session.setOpPermissionLevel(2);
|
||||
session.sendAdventureSettings();
|
||||
return;
|
||||
case PLAYER_OP_PERMISSION_LEVEL_3:
|
||||
session.setOpPermissionLevel(3);
|
||||
session.sendAdventureSettings();
|
||||
return;
|
||||
case PLAYER_OP_PERMISSION_LEVEL_4:
|
||||
session.setOpPermissionLevel(4);
|
||||
session.sendAdventureSettings();
|
||||
return;
|
||||
|
||||
// EntityEventType.HURT sends extra data depending on the type of damage. However this appears to have no visual changes
|
||||
case LIVING_BURN:
|
||||
case LIVING_DROWN:
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
|||
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -43,24 +44,12 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator<ServerPlayer
|
|||
|
||||
@Override
|
||||
public void translate(ServerPlayerAbilitiesPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getPlayerEntity();
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
Set<AdventureSetting> playerFlags = new ObjectOpenHashSet<>();
|
||||
playerFlags.add(AdventureSetting.AUTO_JUMP);
|
||||
if (packet.isCanFly())
|
||||
playerFlags.add(AdventureSetting.MAY_FLY);
|
||||
|
||||
if (packet.isFlying())
|
||||
playerFlags.add(AdventureSetting.FLYING);
|
||||
|
||||
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
||||
adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||
// Required or the packet simply is not sent
|
||||
adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL);
|
||||
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
||||
adventureSettingsPacket.getSettings().addAll(playerFlags);
|
||||
session.sendUpstreamPacket(adventureSettingsPacket);
|
||||
session.setCanFly(packet.isCanFly());
|
||||
session.setFlying(packet.isFlying());
|
||||
session.sendAdventureSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisp
|
|||
|
||||
@Override
|
||||
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
||||
session.getScoreboardCache().getScoreboard().registerNewObjective(
|
||||
session.getWorldCache().getScoreboard().registerNewObjective(
|
||||
packet.getName(), packet.getPosition()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.scoreboard;
|
||||
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.ScoreboardCache;
|
||||
import org.geysermc.connector.network.session.cache.WorldCache;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
|
@ -41,7 +41,7 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
|||
|
||||
@Override
|
||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
||||
ScoreboardCache cache = session.getScoreboardCache();
|
||||
WorldCache cache = session.getWorldCache();
|
||||
Scoreboard scoreboard = cache.getScoreboard();
|
||||
|
||||
Objective objective = scoreboard.getObjective(packet.getName());
|
||||
|
|
|
@ -47,7 +47,7 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
|||
public void translate(ServerTeamPacket packet, GeyserSession session) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers()));
|
||||
|
||||
Scoreboard scoreboard = session.getScoreboardCache().getScoreboard();
|
||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||
Team team = scoreboard.getTeam(packet.getTeamName());
|
||||
switch (packet.getAction()) {
|
||||
case CREATE:
|
||||
|
|
|
@ -42,7 +42,7 @@ public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScor
|
|||
@Override
|
||||
public void translate(ServerUpdateScorePacket packet, GeyserSession session) {
|
||||
try {
|
||||
Scoreboard scoreboard = session.getScoreboardCache().getScoreboard();
|
||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||
|
||||
Objective objective = scoreboard.getObjective(packet.getObjective());
|
||||
if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) {
|
||||
|
|
|
@ -41,6 +41,7 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityEventType;
|
|||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -55,7 +56,7 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
|
|||
|
||||
@Override
|
||||
public void translate(ServerNotifyClientPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getPlayerEntity();
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
|
@ -75,39 +76,17 @@ public class JavaNotifyClientTranslator extends PacketTranslator<ServerNotifyCli
|
|||
session.sendUpstreamPacket(stopRainPacket);
|
||||
break;
|
||||
case CHANGE_GAMEMODE:
|
||||
Set<AdventureSetting> playerFlags = new ObjectOpenHashSet<>();
|
||||
GameMode gameMode = (GameMode) packet.getValue();
|
||||
if (gameMode == GameMode.ADVENTURE)
|
||||
playerFlags.add(AdventureSetting.WORLD_IMMUTABLE);
|
||||
|
||||
if (gameMode == GameMode.CREATIVE)
|
||||
playerFlags.add(AdventureSetting.MAY_FLY);
|
||||
|
||||
if (gameMode == GameMode.SPECTATOR) {
|
||||
playerFlags.add(AdventureSetting.MAY_FLY);
|
||||
playerFlags.add(AdventureSetting.NO_CLIP);
|
||||
playerFlags.add(AdventureSetting.FLYING);
|
||||
playerFlags.add(AdventureSetting.WORLD_IMMUTABLE);
|
||||
gameMode = GameMode.CREATIVE; // spectator doesnt exist on bedrock
|
||||
}
|
||||
|
||||
playerFlags.add(AdventureSetting.AUTO_JUMP);
|
||||
session.setNoClip(gameMode == GameMode.SPECTATOR);
|
||||
session.setWorldImmutable(gameMode == GameMode.ADVENTURE || gameMode == GameMode.SPECTATOR);
|
||||
session.sendAdventureSettings();
|
||||
|
||||
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
|
||||
playerGameTypePacket.setGamemode(gameMode.ordinal());
|
||||
session.sendUpstreamPacket(playerGameTypePacket);
|
||||
session.setGameMode(gameMode);
|
||||
|
||||
// We need to delay this because otherwise it's overridden by the adventure settings from the abilities packet
|
||||
session.getConnector().getGeneralThreadPool().schedule(() -> {
|
||||
AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket();
|
||||
adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER);
|
||||
adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL);
|
||||
adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId());
|
||||
adventureSettingsPacket.getSettings().addAll(playerFlags);
|
||||
session.sendUpstreamPacket(adventureSettingsPacket);
|
||||
}, 50, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Update the crafting grid to add/remove barriers for creative inventory
|
||||
PlayerInventoryTranslator.updateCraftingGrid(session, session.getInventory());
|
||||
break;
|
||||
|
|
|
@ -67,9 +67,7 @@ public class JavaUpdateTimeTranslator extends PacketTranslator<ServerUpdateTimeP
|
|||
}
|
||||
|
||||
private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) {
|
||||
GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket();
|
||||
gameRulesChangedPacket.getGameRules().add(new GameRuleData<>("dodaylightcycle", doCycle));
|
||||
session.sendUpstreamPacket(gameRulesChangedPacket);
|
||||
session.sendGameRule("dodaylightcycle", doCycle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.network.translators.world;
|
||||
|
||||
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.setting.Difficulty;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
|
||||
public class GeyserWorldManager extends WorldManager {
|
||||
|
||||
private static final Object2ObjectMap<String, String> gameruleCache = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
@Override
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
return session.getChunkCache().getBlockAt(new Position(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameRule(GeyserSession session, String name, Object value) {
|
||||
session.sendDownstreamPacket(new ClientChatPacket("/gamerule " + name + " " + value));
|
||||
gameruleCache.put(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
||||
String value = gameruleCache.get(gameRule.getJavaID());
|
||||
if (value != null) {
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
return gameRule.getDefaultValue() != null ? (Boolean) gameRule.getDefaultValue() : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGameRuleInt(GeyserSession session, GameRule gameRule) {
|
||||
String value = gameruleCache.get(gameRule.getJavaID());
|
||||
if (value != null) {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
return gameRule.getDefaultValue() != null ? (int) gameRule.getDefaultValue() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerGameMode(GeyserSession session, GameMode gameMode) {
|
||||
session.sendDownstreamPacket(new ClientChatPacket("/gamemode " + gameMode.name().toLowerCase()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDifficulty(GeyserSession session, Difficulty difficulty) {
|
||||
session.sendDownstreamPacket(new ClientChatPacket("/difficulty " + difficulty.name().toLowerCase()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(GeyserSession session, String permission) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -26,8 +26,11 @@
|
|||
package org.geysermc.connector.network.translators.world;
|
||||
|
||||
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.setting.Difficulty;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
|
||||
/**
|
||||
* Class that manages or retrieves various information
|
||||
|
@ -70,4 +73,56 @@ public abstract class WorldManager {
|
|||
* @return the block state at the specified location
|
||||
*/
|
||||
public abstract int getBlockAt(GeyserSession session, int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Updates a gamerule value on the Java server
|
||||
*
|
||||
* @param session The session of the user that requested the change
|
||||
* @param name The gamerule to change
|
||||
* @param value The new value for the gamerule
|
||||
*/
|
||||
public abstract void setGameRule(GeyserSession session, String name, Object value);
|
||||
|
||||
/**
|
||||
* Get a gamerule value as a boolean
|
||||
*
|
||||
* @param session The session of the user that requested the value
|
||||
* @param gameRule The gamerule to fetch the value of
|
||||
* @return The boolean representation of the value
|
||||
*/
|
||||
public abstract Boolean getGameRuleBool(GeyserSession session, GameRule gameRule);
|
||||
|
||||
/**
|
||||
* Get a gamerule value as an integer
|
||||
*
|
||||
* @param session The session of the user that requested the value
|
||||
* @param gameRule The gamerule to fetch the value of
|
||||
* @return The integer representation of the value
|
||||
*/
|
||||
public abstract int getGameRuleInt(GeyserSession session, GameRule gameRule);
|
||||
|
||||
/**
|
||||
* Change the game mode of the given session
|
||||
*
|
||||
* @param session The session of the player to change the game mode of
|
||||
* @param gameMode The game mode to change the player to
|
||||
*/
|
||||
public abstract void setPlayerGameMode(GeyserSession session, GameMode gameMode);
|
||||
|
||||
/**
|
||||
* Change the difficulty of the Java server
|
||||
*
|
||||
* @param session The session of the user that requested the change
|
||||
* @param difficulty The difficulty to change to
|
||||
*/
|
||||
public abstract void setDifficulty(GeyserSession session, Difficulty difficulty);
|
||||
|
||||
/**
|
||||
* Checks if the given session's player has a permission
|
||||
*
|
||||
* @param session The session of the player to check the permission of
|
||||
* @param permission The permission node to check
|
||||
* @return True if the player has the requested permission, false if not
|
||||
*/
|
||||
public abstract boolean hasPermission(GeyserSession session, String permission);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* This enum stores each gamerule along with the value type and the default.
|
||||
* It is used to construct the list for the settings menu
|
||||
*/
|
||||
public enum GameRule {
|
||||
ANNOUNCEADVANCEMENTS("announceAdvancements", Boolean.class, true), // JE only
|
||||
COMMANDBLOCKOUTPUT("commandBlockOutput", Boolean.class, true),
|
||||
DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", Boolean.class, false), // JE only
|
||||
DISABLERAIDS("disableRaids", Boolean.class, false), // JE only
|
||||
DODAYLIGHTCYCLE("doDaylightCycle", Boolean.class, true),
|
||||
DOENTITYDROPS("doEntityDrops", Boolean.class, true),
|
||||
DOFIRETICK("doFireTick", Boolean.class, true),
|
||||
DOIMMEDIATERESPAWN("doImmediateRespawn", Boolean.class, false),
|
||||
DOINSOMNIA("doInsomnia", Boolean.class, true),
|
||||
DOLIMITEDCRAFTING("doLimitedCrafting", Boolean.class, false), // JE only
|
||||
DOMOBLOOT("doMobLoot", Boolean.class, true),
|
||||
DOMOBSPAWNING("doMobSpawning", Boolean.class, true),
|
||||
DOPATROLSPAWNING("doPatrolSpawning", Boolean.class, true), // JE only
|
||||
DOTILEDROPS("doTileDrops", Boolean.class, true),
|
||||
DOTRADERSPAWNING("doTraderSpawning", Boolean.class, true), // JE only
|
||||
DOWEATHERCYCLE("doWeatherCycle", Boolean.class, true),
|
||||
DROWNINGDAMAGE("drowningDamage", Boolean.class, true),
|
||||
FALLDAMAGE("fallDamage", Boolean.class, true),
|
||||
FIREDAMAGE("fireDamage", Boolean.class, true),
|
||||
FORGIVEDEADPLAYERS("forgiveDeadPlayers", Boolean.class, true), // JE only
|
||||
KEEPINVENTORY("keepInventory", Boolean.class, false),
|
||||
LOGADMINCOMMANDS("logAdminCommands", Boolean.class, true), // JE only
|
||||
MAXCOMMANDCHAINLENGTH("maxCommandChainLength", Integer.class, 65536),
|
||||
MAXENTITYCRAMMING("maxEntityCramming", Integer.class, 24), // JE only
|
||||
MOBGRIEFING("mobGriefing", Boolean.class, true),
|
||||
NATURALREGENERATION("naturalRegeneration", Boolean.class, true),
|
||||
RANDOMTICKSPEED("randomTickSpeed", Integer.class, 3),
|
||||
REDUCEDDEBUGINFO("reducedDebugInfo", Boolean.class, false), // JE only
|
||||
SENDCOMMANDFEEDBACK("sendCommandFeedback", Boolean.class, true),
|
||||
SHOWDEATHMESSAGES("showDeathMessages", Boolean.class, true),
|
||||
SPAWNRADIUS("spawnRadius", Integer.class, 10),
|
||||
SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", Boolean.class, true), // JE only
|
||||
UNIVERSALANGER("universalAnger", Boolean.class, false), // JE only
|
||||
|
||||
UNKNOWN("unknown", Object.class);
|
||||
|
||||
private static final GameRule[] VALUES = values();
|
||||
|
||||
@Getter
|
||||
private String javaID;
|
||||
|
||||
@Getter
|
||||
private Class<?> type;
|
||||
|
||||
@Getter
|
||||
private Object defaultValue;
|
||||
|
||||
GameRule(String javaID, Class<?> type) {
|
||||
this(javaID, type, null);
|
||||
}
|
||||
|
||||
GameRule(String javaID, Class<?> type, Object defaultValue) {
|
||||
this.javaID = javaID;
|
||||
this.type = type;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to an object of the correct type for the current gamerule
|
||||
*
|
||||
* @param value The string value to convert
|
||||
* @return The converted and formatted value
|
||||
*/
|
||||
public Object convertValue(String value) {
|
||||
if (type.equals(Boolean.class)) {
|
||||
return Boolean.parseBoolean(value);
|
||||
} else if (type.equals(Integer.class)) {
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a game rule by the given Java ID
|
||||
*
|
||||
* @param id The ID of the gamerule
|
||||
* @return A {@link GameRule} object representing the requested ID or {@link GameRule.UNKNOWN}
|
||||
*/
|
||||
public static GameRule fromJavaID(String id) {
|
||||
for (GameRule gamerule : VALUES) {
|
||||
if (gamerule.javaID.equals(id)) {
|
||||
return gamerule;
|
||||
}
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.utils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.setting.Difficulty;
|
||||
import org.geysermc.common.window.CustomFormBuilder;
|
||||
import org.geysermc.common.window.CustomFormWindow;
|
||||
import org.geysermc.common.window.button.FormImage;
|
||||
import org.geysermc.common.window.component.DropdownComponent;
|
||||
import org.geysermc.common.window.component.InputComponent;
|
||||
import org.geysermc.common.window.component.LabelComponent;
|
||||
import org.geysermc.common.window.component.ToggleComponent;
|
||||
import org.geysermc.common.window.response.CustomFormResponse;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SettingsUtils {
|
||||
|
||||
// Used in UpstreamPacketHandler.java
|
||||
public static final int SETTINGS_FORM_ID = 1338;
|
||||
|
||||
/**
|
||||
* Build a settings form for the given session and store it for later
|
||||
*
|
||||
* @param session The session to build the form for
|
||||
*/
|
||||
public static void buildForm(GeyserSession session) {
|
||||
// Cache the language for cleaner access
|
||||
String language = session.getClientData().getLanguageCode();
|
||||
|
||||
CustomFormBuilder builder = new CustomFormBuilder(LanguageUtils.getPlayerLocaleString("geyser.settings.title.main", language));
|
||||
builder.setIcon(new FormImage(FormImage.FormImageType.PATH, "textures/ui/settings_glyph_color_2x.png"));
|
||||
|
||||
builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.client", language)));
|
||||
builder.addComponent(new ToggleComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.option.coordinates", language, session.getWorldCache().isShowCoordinates())));
|
||||
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) {
|
||||
builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.server", language)));
|
||||
|
||||
DropdownComponent gamemodeDropdown = new DropdownComponent();
|
||||
gamemodeDropdown.setText("%createWorldScreen.gameMode.personal");
|
||||
gamemodeDropdown.setOptions(new ArrayList<>());
|
||||
for (GameMode gamemode : GameMode.values()) {
|
||||
gamemodeDropdown.addOption(LocaleUtils.getLocaleString("selectWorld.gameMode." + gamemode.name().toLowerCase(), language), session.getGameMode() == gamemode);
|
||||
}
|
||||
builder.addComponent(gamemodeDropdown);
|
||||
|
||||
DropdownComponent difficultyDropdown = new DropdownComponent();
|
||||
difficultyDropdown.setText("%options.difficulty");
|
||||
difficultyDropdown.setOptions(new ArrayList<>());
|
||||
for (Difficulty difficulty : Difficulty.values()) {
|
||||
difficultyDropdown.addOption("%options.difficulty." + difficulty.name().toLowerCase(), session.getWorldCache().getDifficulty() == difficulty);
|
||||
}
|
||||
builder.addComponent(difficultyDropdown);
|
||||
}
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) {
|
||||
builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.game_rules", language)));
|
||||
for (GameRule gamerule : GameRule.values()) {
|
||||
if (gamerule.equals(GameRule.UNKNOWN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the relevant form item based on the gamerule type
|
||||
if (Boolean.class.equals(gamerule.getType())) {
|
||||
builder.addComponent(new ToggleComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), GeyserConnector.getInstance().getWorldManager().getGameRuleBool(session, gamerule)));
|
||||
} else if (Integer.class.equals(gamerule.getType())) {
|
||||
builder.addComponent(new InputComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), "", String.valueOf(GeyserConnector.getInstance().getWorldManager().getGameRuleInt(session, gamerule))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session.setSettingsForm(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the settings form response
|
||||
*
|
||||
* @param session The session that sent the response
|
||||
* @param response The response string to parse
|
||||
* @return True if the form was parsed correctly, false if not
|
||||
*/
|
||||
public static boolean handleSettingsForm(GeyserSession session, String response) {
|
||||
CustomFormWindow settingsForm = session.getSettingsForm();
|
||||
settingsForm.setResponse(response);
|
||||
|
||||
CustomFormResponse settingsResponse = (CustomFormResponse) settingsForm.getResponse();
|
||||
int offset = 0;
|
||||
|
||||
offset++; // Client settings title
|
||||
|
||||
session.getWorldCache().setShowCoordinates(settingsResponse.getToggleResponses().get(offset));
|
||||
offset++;
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) {
|
||||
offset++; // Server settings title
|
||||
|
||||
GameMode gameMode = GameMode.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()];
|
||||
if (gameMode != null && gameMode != session.getGameMode()) {
|
||||
session.getConnector().getWorldManager().setPlayerGameMode(session, gameMode);
|
||||
}
|
||||
offset++;
|
||||
|
||||
Difficulty difficulty = Difficulty.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()];
|
||||
if (difficulty != null && difficulty != session.getWorldCache().getDifficulty()) {
|
||||
session.getConnector().getWorldManager().setDifficulty(session, difficulty);
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) {
|
||||
offset++; // Game rule title
|
||||
|
||||
for (GameRule gamerule : GameRule.values()) {
|
||||
if (gamerule.equals(GameRule.UNKNOWN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Boolean.class.equals(gamerule.getType())) {
|
||||
Boolean value = settingsResponse.getToggleResponses().get(offset).booleanValue();
|
||||
if (value != session.getConnector().getWorldManager().getGameRuleBool(session, gamerule)) {
|
||||
session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value);
|
||||
}
|
||||
} else if (Integer.class.equals(gamerule.getType())) {
|
||||
int value = Integer.parseInt(settingsResponse.getInputResponses().get(offset));
|
||||
if (value != session.getConnector().getWorldManager().getGameRuleInt(session, gamerule)) {
|
||||
session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value);
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ import lombok.AllArgsConstructor;
|
|||
import lombok.Getter;
|
||||
import org.geysermc.connector.common.AuthType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.auth.BedrockClientData;
|
||||
|
@ -93,6 +94,15 @@ public class SkinUtils {
|
|||
ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId
|
||||
);
|
||||
|
||||
// This attempts to find the xuid of the player so profile images show up for xbox accounts
|
||||
String xuid = "";
|
||||
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
|
||||
if (player.getPlayerEntity().getUuid().equals(uuid)) {
|
||||
xuid = player.getAuthData().getXboxUUID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerListPacket.Entry entry;
|
||||
|
||||
// If we are building a PlayerListEntry for our own session we use our AuthData UUID instead of the Java UUID
|
||||
|
@ -102,11 +112,11 @@ public class SkinUtils {
|
|||
} else {
|
||||
entry = new PlayerListPacket.Entry(uuid);
|
||||
}
|
||||
|
||||
|
||||
entry.setName(username);
|
||||
entry.setEntityId(geyserId);
|
||||
entry.setSkin(serializedSkin);
|
||||
entry.setXuid("");
|
||||
entry.setXuid(xuid);
|
||||
entry.setPlatformChatId("");
|
||||
entry.setTeacher(false);
|
||||
entry.setTrustedSkin(true);
|
||||
|
|
Loading…
Reference in a new issue