3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-09-08 20:43:04 +02:00

Merge remote-tracking branch 'remotes/upstream/master' into server-inventory-upstream

# Conflicts:
#	connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
Dieser Commit ist enthalten in:
AJ Ferguson 2021-01-13 18:49:20 -09:00
Commit e87ae8f0dd
15 geänderte Dateien mit 680 neuen und 24 gelöschten Zeilen

5
Jenkinsfile vendored
Datei anzeigen

@ -92,8 +92,9 @@ pipeline {
success { success {
script { script {
if (env.BRANCH_NAME == 'master') { if (env.BRANCH_NAME == 'master') {
build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.16' build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.16', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
build propagate: false, wait: false, job: 'GeyserMC/GeyserAndroid/master' build propagate: false, wait: false, job: 'GeyserMC/GeyserAndroid/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
build propagate: false, wait: false, job: 'GeyserMC/GeyserConnect/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
} }
} }
} }

Datei anzeigen

@ -47,6 +47,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
- Horse Inventory - Horse Inventory
- Loom - Loom
- Smithing Table - Smithing Table
- Grindstone
## What can't be fixed ## What can't be fixed
The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now.

Datei anzeigen

@ -52,6 +52,7 @@ public abstract class CommandManager {
registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version")); registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version"));
registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings"));
registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics"));
registerCommand(new AdvancementsCommand(connector, "advancements", "geyser.commands.advancements.desc", "geyser.command.advancements"));
} }
public void registerCommand(GeyserCommand command) { public void registerCommand(GeyserCommand command) {

Datei anzeigen

@ -0,0 +1,74 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.command.defaults;
import org.geysermc.common.window.SimpleFormWindow;
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 org.geysermc.connector.network.session.cache.AdvancementsCache;
public class AdvancementsCommand extends GeyserCommand {
private final GeyserConnector connector;
public AdvancementsCommand(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
GeyserSession session = null;
if (sender instanceof GeyserSession) {
session = (GeyserSession) sender;
} else {
// Needed for Spigot - sender is not an instance of GeyserSession
for (GeyserSession otherSession : connector.getPlayers()) {
if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) {
session = otherSession;
break;
}
}
}
if (session == null) return;
SimpleFormWindow window = session.getAdvancementsCache().buildMenuForm();
session.sendForm(window, AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID);
}
@Override
public boolean isExecutableOnConsole() {
return false;
}
}

Datei anzeigen

@ -40,7 +40,9 @@ public class BedrockProtocol {
* Default Bedrock codec that should act as a fallback. Should represent the latest available * Default Bedrock codec that should act as a fallback. Should represent the latest available
* release of the game that Geyser supports. * release of the game that Geyser supports.
*/ */
public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v422.V422_CODEC; public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v422.V422_CODEC.toBuilder()
.minecraftVersion("1.16.201")
.build();
/** /**
* A list of all supported Bedrock versions that can join Geyser * A list of all supported Bedrock versions that can join Geyser
*/ */
@ -50,7 +52,9 @@ public class BedrockProtocol {
SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder() SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder()
.minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 is a beta .minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 is a beta
.build()); .build());
SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder()
.minecraftVersion("1.16.200/1.16.201")
.build());
} }
/** /**

Datei anzeigen

@ -33,14 +33,9 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.common.AuthType; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.session.cache.AdvancementsCache;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.*;
import org.geysermc.connector.utils.LoginEncryptionUtils;
import org.geysermc.connector.utils.MathUtils;
import org.geysermc.connector.utils.ResourcePack;
import org.geysermc.connector.utils.ResourcePackManifest;
import org.geysermc.connector.utils.SettingsUtils;
import org.geysermc.connector.utils.StatisticsUtils;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
@ -144,12 +139,19 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override @Override
public boolean handle(ModalFormResponsePacket packet) { public boolean handle(ModalFormResponsePacket packet) {
if (packet.getFormId() == SettingsUtils.SETTINGS_FORM_ID) { switch (packet.getFormId()) {
return SettingsUtils.handleSettingsForm(session, packet.getFormData()); case AdvancementsCache.ADVANCEMENT_INFO_FORM_ID:
} else if (packet.getFormId() == StatisticsUtils.STATISTICS_MENU_FORM_ID) { return session.getAdvancementsCache().handleInfoForm(packet.getFormData());
return StatisticsUtils.handleMenuForm(session, packet.getFormData()); case AdvancementsCache.ADVANCEMENTS_LIST_FORM_ID:
} else if (packet.getFormId() == StatisticsUtils.STATISTICS_LIST_FORM_ID) { return session.getAdvancementsCache().handleListForm(packet.getFormData());
return StatisticsUtils.handleListForm(session, packet.getFormData()); case AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID:
return session.getAdvancementsCache().handleMenuForm(packet.getFormData());
case SettingsUtils.SETTINGS_FORM_ID:
return SettingsUtils.handleSettingsForm(session, packet.getFormData());
case StatisticsUtils.STATISTICS_LIST_FORM_ID:
return StatisticsUtils.handleListForm(session, packet.getFormData());
case StatisticsUtils.STATISTICS_MENU_FORM_ID:
return StatisticsUtils.handleMenuForm(session, packet.getFormData());
} }
return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData()); return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData());

Datei anzeigen

@ -124,6 +124,7 @@ public class GeyserSession implements CommandSender {
private final SessionPlayerEntity playerEntity; private final SessionPlayerEntity playerEntity;
private AdvancementsCache advancementsCache;
private BookEditCache bookEditCache; private BookEditCache bookEditCache;
private ChunkCache chunkCache; private ChunkCache chunkCache;
private EntityCache entityCache; private EntityCache entityCache;
@ -384,6 +385,7 @@ public class GeyserSession implements CommandSender {
this.connector = connector; this.connector = connector;
this.upstream = new UpstreamSession(bedrockServerSession); this.upstream = new UpstreamSession(bedrockServerSession);
this.advancementsCache = new AdvancementsCache(this);
this.bookEditCache = new BookEditCache(this); this.bookEditCache = new BookEditCache(this);
this.chunkCache = new ChunkCache(this); this.chunkCache = new ChunkCache(this);
this.entityCache = new EntityCache(this); this.entityCache = new EntityCache(this);
@ -409,6 +411,10 @@ public class GeyserSession implements CommandSender {
connector.getPlayers().forEach(player -> this.emotes.addAll(player.getEmotes())); connector.getPlayers().forEach(player -> this.emotes.addAll(player.getEmotes()));
// Make a copy to prevent ConcurrentModificationException
final List<GeyserSession> tmpPlayers = new ArrayList<>(connector.getPlayers());
tmpPlayers.forEach(player -> this.emotes.addAll(player.getEmotes()));
bedrockServerSession.addDisconnectHandler(disconnectReason -> { bedrockServerSession.addDisconnectHandler(disconnectReason -> {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason)); connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason));
@ -723,6 +729,7 @@ public class GeyserSession implements CommandSender {
tickThread.cancel(true); tickThread.cancel(true);
} }
this.advancementsCache = null;
this.bookEditCache = null; this.bookEditCache = null;
this.chunkCache = null; this.chunkCache = null;
this.entityCache = null; this.entityCache = null;
@ -862,6 +869,7 @@ public class GeyserSession implements CommandSender {
startGamePacket.setLevelName(serverName); startGamePacket.setLevelName(serverName);
startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000"); startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000");
// startGamePacket.setCurrentTick(0);
startGamePacket.setEnchantmentSeed(0); startGamePacket.setEnchantmentSeed(0);
startGamePacket.setMultiplayerCorrelationId(""); startGamePacket.setMultiplayerCorrelationId("");
startGamePacket.setItemEntries(ItemRegistry.ITEMS); startGamePacket.setItemEntries(ItemRegistry.ITEMS);

Datei anzeigen

@ -0,0 +1,321 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.session.cache;
import com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientAdvancementTabPacket;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.window.SimpleFormWindow;
import org.geysermc.common.window.button.FormButton;
import org.geysermc.common.window.response.SimpleFormResponse;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.chat.MessageTranslator;
import org.geysermc.connector.utils.GeyserAdvancement;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.LocaleUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AdvancementsCache {
// Different form IDs
public static final int ADVANCEMENTS_MENU_FORM_ID = 1341;
public static final int ADVANCEMENTS_LIST_FORM_ID = 1342;
public static final int ADVANCEMENT_INFO_FORM_ID = 1343;
/**
* Stores the player's advancement progress
*/
@Getter
private final Map<String, Map<String, Long>> storedAdvancementProgress = new HashMap<>();
/**
* Stores advancements for the player.
*/
@Getter
private final Map<String, GeyserAdvancement> storedAdvancements = new HashMap<>();
/**
* Stores player's chosen advancement's ID and title for use in form creators.
*/
@Setter
private String currentAdvancementCategoryId = null;
private final GeyserSession session;
public AdvancementsCache(GeyserSession session) {
this.session = session;
}
/**
* Build a form with all advancement categories
*
* @return The built advancement category menu
*/
public SimpleFormWindow buildMenuForm() {
// Cache the language for cleaner access
String language = session.getClientData().getLanguageCode();
// Created menu window for advancement categories
SimpleFormWindow window = new SimpleFormWindow(LocaleUtils.getLocaleString("gui.advancements", language), "");
for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) {
if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement
window.getButtons().add(new FormButton(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), language)));
}
}
if (window.getButtons().isEmpty()) {
window.setContent(LocaleUtils.getLocaleString("advancements.empty", language));
}
return window;
}
/**
* Builds the list of advancements
*
* @return The built list form
*/
public SimpleFormWindow buildListForm() {
// Cache the language for easier access
String language = session.getLocale();
String id = currentAdvancementCategoryId;
GeyserAdvancement categoryAdvancement = storedAdvancements.get(currentAdvancementCategoryId);
// Create the window
SimpleFormWindow window = new SimpleFormWindow(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language),
MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language));
if (id != null) {
for (Map.Entry<String, GeyserAdvancement> advancementEntry : storedAdvancements.entrySet()) {
GeyserAdvancement advancement = advancementEntry.getValue();
if (advancement != null) {
if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) {
boolean earned = isEarned(advancement);
if (earned || !advancement.getDisplayData().isShowToast()) {
window.getButtons().add(new FormButton("§6" + MessageTranslator.convertMessage(advancementEntry.getValue().getDisplayData().getTitle()) + "\n"));
} else {
window.getButtons().add(new FormButton(MessageTranslator.convertMessage(advancementEntry.getValue().getDisplayData().getTitle()) + "\n"));
}
}
}
}
}
window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("gui.back", language)));
return window;
}
/**
* Builds the advancement display info based on the chosen category
*
* @param advancement The advancement used to create the info display
* @return The information for the chosen advancement
*/
public SimpleFormWindow buildInfoForm(GeyserAdvancement advancement) {
// Cache language for easier access
String language = session.getLocale();
String earned = isEarned(advancement) ? "yes" : "no";
String description = getColorFromAdvancementFrameType(advancement) + MessageTranslator.convertMessage(advancement.getDisplayData().getDescription(), language);
String earnedString = LanguageUtils.getPlayerLocaleString("geyser.advancements.earned", language, LocaleUtils.getLocaleString("gui." + earned, language));
/*
Layout will look like:
(Form title) Stone Age
(Description) Mine stone with your new pickaxe
Earned: Yes
Parent Advancement: Minecraft // If relevant
*/
String content = description + "\n\n§f" +
earnedString + "\n";
if (!currentAdvancementCategoryId.equals(advancement.getParentId())) {
// Only display the parent if it is not the category
content += LanguageUtils.getPlayerLocaleString("geyser.advancements.parentid", language, MessageTranslator.convertMessage(storedAdvancements.get(advancement.getParentId()).getDisplayData().getTitle(), language));
}
SimpleFormWindow window = new SimpleFormWindow(MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()), content);
window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("gui.back", language)));
return window;
}
/**
* Determine if this advancement has been earned.
*
* @param advancement the advancement to determine
* @return true if the advancement has been earned.
*/
public boolean isEarned(GeyserAdvancement advancement) {
boolean earned = false;
if (advancement.getRequirements().size() == 0) {
// Minecraft handles this case, so we better as well
return false;
}
Map<String, Long> progress = storedAdvancementProgress.get(advancement.getId());
if (progress != null) {
// Each advancement's requirement must be fulfilled
// For example, [[zombie, blaze, skeleton]] means that one of those three categories must be achieved
// But [[zombie], [blaze], [skeleton]] means that all three requirements must be completed
for (List<String> requirements : advancement.getRequirements()) {
boolean requirementsDone = false;
for (String requirement : requirements) {
Long obtained = progress.get(requirement);
// -1 means that this particular component required for completing the advancement
// has yet to be fulfilled
if (obtained != null && !obtained.equals(-1L)) {
requirementsDone = true;
break;
}
}
if (!requirementsDone) {
return false;
}
}
earned = true;
}
return earned;
}
/**
* Handle the menu form response
*
* @param response The response string to parse
* @return True if the form was parsed correctly, false if not
*/
public boolean handleMenuForm(String response) {
SimpleFormWindow menuForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENTS_MENU_FORM_ID);
menuForm.setResponse(response);
SimpleFormResponse formResponse = (SimpleFormResponse) menuForm.getResponse();
String id = "";
if (formResponse != null && formResponse.getClickedButton() != null) {
int advancementIndex = 0;
for (Map.Entry<String, GeyserAdvancement> advancement : storedAdvancements.entrySet()) {
if (advancement.getValue().getParentId() == null) { // Root advancement
if (advancementIndex == formResponse.getClickedButtonId()) {
id = advancement.getKey();
break;
} else {
advancementIndex++;
}
}
}
}
if (!id.equals("")) {
if (id.equals(currentAdvancementCategoryId)) {
// The server thinks we are already on this tab
session.sendForm(buildListForm(), ADVANCEMENTS_LIST_FORM_ID);
} else {
// Send a packet indicating that we intend to open this particular advancement window
ClientAdvancementTabPacket packet = new ClientAdvancementTabPacket(id);
session.sendDownstreamPacket(packet);
// Wait for a response there
}
}
return true;
}
/**
* Handle the list form response (Advancement category choice)
*
* @param response The response string to parse
* @return True if the form was parsed correctly, false if not
*/
public boolean handleListForm(String response) {
SimpleFormWindow listForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENTS_LIST_FORM_ID);
listForm.setResponse(response);
SimpleFormResponse formResponse = (SimpleFormResponse) listForm.getResponse();
if (!listForm.isClosed() && formResponse != null && formResponse.getClickedButton() != null) {
GeyserAdvancement advancement = null;
int advancementIndex = 0;
// Loop around to find the advancement that the client pressed
for (GeyserAdvancement advancementEntry : storedAdvancements.values()) {
if (advancementEntry.getParentId() != null &&
currentAdvancementCategoryId.equals(advancementEntry.getRootId(this))) {
if (advancementIndex == formResponse.getClickedButtonId()) {
advancement = advancementEntry;
break;
} else {
advancementIndex++;
}
}
}
if (advancement != null) {
session.sendForm(buildInfoForm(advancement), ADVANCEMENT_INFO_FORM_ID);
} else {
session.sendForm(buildMenuForm(), ADVANCEMENTS_MENU_FORM_ID);
// Indicate that we have closed the current advancement tab
session.sendDownstreamPacket(new ClientAdvancementTabPacket());
}
} else {
// Indicate that we have closed the current advancement tab
session.sendDownstreamPacket(new ClientAdvancementTabPacket());
}
return true;
}
/**
* Handle the info form response
*
* @param response The response string to parse
* @return True if the form was parsed correctly, false if not
*/
public boolean handleInfoForm(String response) {
SimpleFormWindow listForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENT_INFO_FORM_ID);
listForm.setResponse(response);
SimpleFormResponse formResponse = (SimpleFormResponse) listForm.getResponse();
if (!listForm.isClosed() && formResponse != null && formResponse.getClickedButton() != null) {
session.sendForm(buildListForm(), ADVANCEMENTS_LIST_FORM_ID);
}
return true;
}
public String getColorFromAdvancementFrameType(GeyserAdvancement advancement) {
String base = "\u00a7";
if (advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE) {
return base + "5";
}
return base + "a"; // Used for types TASK and GOAL
}
}

Datei anzeigen

@ -37,10 +37,10 @@ import org.geysermc.connector.network.session.GeyserSession;
public class WindowCache { public class WindowCache {
private GeyserSession session; private final GeyserSession session;
@Getter @Getter
private Int2ObjectMap<FormWindow> windows = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<FormWindow> windows = new Int2ObjectOpenHashMap<>();
public WindowCache(GeyserSession session) { public WindowCache(GeyserSession session) {
this.session = session; this.session = session;

Datei anzeigen

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.java;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerAdvancementTabPacket;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.session.cache.AdvancementsCache;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
/**
* Indicates that the client should open a particular advancement tab
*/
@Translator(packet = ServerAdvancementTabPacket.class)
public class JavaAdvancementsTabTranslator extends PacketTranslator<ServerAdvancementTabPacket> {
@Override
public void translate(ServerAdvancementTabPacket packet, GeyserSession session) {
session.getAdvancementsCache().setCurrentAdvancementCategoryId(packet.getTabId());
session.sendForm(session.getAdvancementsCache().buildListForm(), AdvancementsCache.ADVANCEMENTS_LIST_FORM_ID);
}
}

Datei anzeigen

@ -0,0 +1,103 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.network.translators.java;
import com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerAdvancementsPacket;
import com.nukkitx.protocol.bedrock.packet.SetTitlePacket;
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.chat.MessageTranslator;
import org.geysermc.connector.network.session.cache.AdvancementsCache;
import org.geysermc.connector.utils.GeyserAdvancement;
import org.geysermc.connector.utils.LocaleUtils;
import java.util.Map;
@Translator(packet = ServerAdvancementsPacket.class)
public class JavaAdvancementsTranslator extends PacketTranslator<ServerAdvancementsPacket> {
@Override
public void translate(ServerAdvancementsPacket packet, GeyserSession session) {
AdvancementsCache advancementsCache = session.getAdvancementsCache();
if (packet.isReset()) {
advancementsCache.getStoredAdvancements().clear();
advancementsCache.getStoredAdvancementProgress().clear();
}
// Removes removed advancements from player's stored advancements
for (String removedAdvancement : packet.getRemovedAdvancements()) {
advancementsCache.getStoredAdvancements().remove(removedAdvancement);
}
advancementsCache.getStoredAdvancementProgress().putAll(packet.getProgress());
sendToolbarAdvancementUpdates(session, packet);
// Adds advancements to the player's stored advancements when advancements are sent
for (Advancement advancement : packet.getAdvancements()) {
if (advancement.getDisplayData() != null && !advancement.getDisplayData().isHidden()) {
GeyserAdvancement geyserAdvancement = GeyserAdvancement.from(advancement);
advancementsCache.getStoredAdvancements().put(advancement.getId(), geyserAdvancement);
} else {
advancementsCache.getStoredAdvancements().remove(advancement.getId());
}
}
}
/**
* Handle all advancements progress updates
*/
public void sendToolbarAdvancementUpdates(GeyserSession session, ServerAdvancementsPacket packet) {
if (packet.isReset()) {
// Advancements are being cleared, so they can't be granted
return;
}
for (Map.Entry<String, Map<String, Long>> progress : packet.getProgress().entrySet()) {
GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey());
if (advancement != null && advancement.getDisplayData() != null) {
if (session.getAdvancementsCache().isEarned(advancement)) {
// Java uses some pink color for toast challenge completes
String color = advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ?
"§d" : "§a";
String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale());
// Send an action bar message stating they earned an achievement
// Sent for instances where broadcasting advancements through chat are disabled
SetTitlePacket titlePacket = new SetTitlePacket();
titlePacket.setText(color + "[" + LocaleUtils.getLocaleString("advancements.toast." +
advancement.getDisplayData().getFrameType().toString().toLowerCase(), session.getLocale()) + "]§f " + advancementName);
titlePacket.setType(SetTitlePacket.Type.ACTIONBAR);
titlePacket.setFadeOutTime(3);
titlePacket.setFadeInTime(3);
titlePacket.setStayTime(3);
session.sendUpstreamPacket(titlePacket);
}
}
}
}
}

Datei anzeigen

@ -217,8 +217,8 @@ public class FileUtils {
* @return The byte array of the file * @return The byte array of the file
*/ */
public static byte[] readAllBytes(File file) { public static byte[] readAllBytes(File file) {
try { try (InputStream inputStream = new FileInputStream(file)) {
return readAllBytes(new FileInputStream(file)); return readAllBytes(inputStream);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Cannot read " + file); throw new RuntimeException("Cannot read " + file);
} }

Datei anzeigen

@ -0,0 +1,89 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.utils;
import com.github.steveice10.mc.protocol.data.game.advancement.Advancement;
import lombok.NonNull;
import org.geysermc.connector.network.session.cache.AdvancementsCache;
import java.util.List;
/**
* A wrapper around MCProtocolLib's {@link Advancement} class so we can control the parent of an advancement
*/
public class GeyserAdvancement {
private final Advancement advancement;
private String rootId = null;
public static GeyserAdvancement from(Advancement advancement) {
return new GeyserAdvancement(advancement);
}
private GeyserAdvancement(Advancement advancement) {
this.advancement = advancement;
}
@NonNull
public String getId() {
return this.advancement.getId();
}
@NonNull
public List<String> getCriteria() {
return this.advancement.getCriteria();
}
@NonNull
public List<List<String>> getRequirements() {
return this.advancement.getRequirements();
}
public String getParentId() {
return this.advancement.getParentId();
}
public Advancement.DisplayData getDisplayData() {
return this.advancement.getDisplayData();
}
public String getRootId(AdvancementsCache advancementsCache) {
if (rootId == null) {
if (this.advancement.getParentId() == null) {
// We are the root ID
this.rootId = this.advancement.getId();
} else {
// Go through our cache, and descend until we find the root ID
GeyserAdvancement advancement = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId());
if (advancement.getParentId() == null) {
this.rootId = advancement.getId();
} else {
this.rootId = advancement.getRootId(advancementsCache);
}
}
}
return rootId;
}
}

Datei anzeigen

@ -142,8 +142,9 @@ public class LocaleUtils {
try { try {
File hashFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/en_us.hash").toFile(); File hashFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/en_us.hash").toFile();
if (hashFile.exists()) { if (hashFile.exists()) {
BufferedReader br = new BufferedReader(new FileReader(hashFile)); try (BufferedReader br = new BufferedReader(new FileReader(hashFile))) {
curHash = br.readLine().trim(); curHash = br.readLine().trim();
}
} }
} catch (IOException ignored) { } } catch (IOException ignored) { }
targetHash = clientJarInfo.getSha1(); targetHash = clientJarInfo.getSha1();
@ -208,6 +209,12 @@ public class LocaleUtils {
// Insert the locale into the mappings // Insert the locale into the mappings
LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap); LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap);
try {
localeStream.close();
} catch (IOException e) {
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage()));
}
} else { } else {
GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.missing", locale)); GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.missing", locale));
} }

@ -1 +1 @@
Subproject commit 6f246c24ddbd543a359d651e706da470fe53ceeb Subproject commit 8141bc6aed878a95ed9ee3ca83a2381f9906c4b4