forked from GeyserMC/Geyser
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement book editing (GeyserMC#1117)
* Implement book editing Updates the PR created by @ForceUpdate1 for 1.16 support. Seems to work fine now that hand support is in MCProtocolLib. Co-authored-by: Camotoy <[email protected]> * Remove debug line * Simplify code Currently still borked for creative mode. * Fix books on creative * Bug fixes * Fix NPE? * Blind fixes * Send Book update before any player actions * Remove debug prints * Fix out of bounds for page replace and add * Fix editing desync and remove empty pages from the end * Send edit packet after signing * Refactor * Clean up and fix creative * Apply suggestions from code review Co-authored-by: rtm516 <[email protected]> Co-authored-by: ForceUpdate1 <[email protected]> Co-authored-by: Camotoy <[email protected]> Co-authored-by: David Choo <[email protected]> Co-authored-by: rtm516 <[email protected]>
- Loading branch information
1 parent
7cefb57
commit fe23c79
Showing
9 changed files
with
223 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* 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.entity.metadata.ItemStack; | ||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientEditBookPacket; | ||
import lombok.Setter; | ||
import org.geysermc.connector.network.session.GeyserSession; | ||
import org.geysermc.connector.network.translators.item.ItemRegistry; | ||
|
||
/** | ||
* Manages updating the current writable book. | ||
* | ||
* Java sends book updates less frequently than Bedrock, and this can cause issues with servers that rate limit | ||
* book packets. Because of this, we need to ensure packets are only send every second or so at maximum. | ||
*/ | ||
public class BookEditCache { | ||
private final GeyserSession session; | ||
@Setter | ||
private ClientEditBookPacket packet; | ||
/** | ||
* Stores the last time a book update packet was sent to the server. | ||
*/ | ||
private long lastBookUpdate; | ||
|
||
public BookEditCache(GeyserSession session) { | ||
this.session = session; | ||
} | ||
|
||
/** | ||
* Check to see if there is a book edit update to send, and if so, send it. | ||
*/ | ||
public void checkForSend() { | ||
if (packet == null) { | ||
// No new packet has to be sent | ||
return; | ||
} | ||
// Prevent kicks due to rate limiting - specifically on Spigot servers | ||
if ((System.currentTimeMillis() - lastBookUpdate) < 1000) { | ||
return; | ||
} | ||
// Don't send the update if the player isn't not holding a book, shouldn't happen if we catch all interactions | ||
ItemStack itemStack = session.getInventory().getItemInHand(); | ||
if (itemStack == null || itemStack.getId() != ItemRegistry.WRITABLE_BOOK.getJavaId()) { | ||
packet = null; | ||
return; | ||
} | ||
session.getDownstream().getSession().send(packet); | ||
packet = null; | ||
lastBookUpdate = System.currentTimeMillis(); | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
...in/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* 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.bedrock; | ||
|
||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; | ||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; | ||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientEditBookPacket; | ||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; | ||
import com.github.steveice10.opennbt.tag.builtin.ListTag; | ||
import com.github.steveice10.opennbt.tag.builtin.StringTag; | ||
import com.github.steveice10.opennbt.tag.builtin.Tag; | ||
import com.nukkitx.protocol.bedrock.packet.BookEditPacket; | ||
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.inventory.InventoryTranslator; | ||
|
||
import java.util.Collections; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
|
||
@Translator(packet = BookEditPacket.class) | ||
public class BedrockBookEditTranslator extends PacketTranslator<BookEditPacket> { | ||
|
||
@Override | ||
public void translate(BookEditPacket packet, GeyserSession session) { | ||
ItemStack itemStack = session.getInventory().getItemInHand(); | ||
if (itemStack != null) { | ||
CompoundTag tag = itemStack.getNbt() != null ? itemStack.getNbt() : new CompoundTag(""); | ||
ItemStack bookItem = new ItemStack(itemStack.getId(), itemStack.getAmount(), tag); | ||
List<Tag> pages = tag.contains("pages") ? new LinkedList<>(((ListTag) tag.get("pages")).getValue()) : new LinkedList<>(); | ||
|
||
int page = packet.getPageNumber(); | ||
// Creative edits the NBT for us | ||
if (session.getGameMode() != GameMode.CREATIVE) { | ||
switch (packet.getAction()) { | ||
case ADD_PAGE: { | ||
// Add empty pages in between | ||
for (int i = pages.size(); i < page; i++) { | ||
pages.add(i, new StringTag("", "")); | ||
} | ||
pages.add(page, new StringTag("", packet.getText())); | ||
break; | ||
} | ||
// Called whenever a page is modified | ||
case REPLACE_PAGE: { | ||
if (page < pages.size()) { | ||
pages.set(page, new StringTag("", packet.getText())); | ||
} else { | ||
// Add empty pages in between | ||
for (int i = pages.size(); i < page; i++) { | ||
pages.add(i, new StringTag("", "")); | ||
} | ||
pages.add(page, new StringTag("", packet.getText())); | ||
} | ||
break; | ||
} | ||
case DELETE_PAGE: { | ||
if (page < pages.size()) { | ||
pages.remove(page); | ||
} | ||
break; | ||
} | ||
case SWAP_PAGES: { | ||
int page2 = packet.getSecondaryPageNumber(); | ||
if (page < pages.size() && page2 < pages.size()) { | ||
Collections.swap(pages, page, page2); | ||
} | ||
break; | ||
} | ||
case SIGN_BOOK: { | ||
tag.put(new StringTag("author", packet.getAuthor())); | ||
tag.put(new StringTag("title", packet.getTitle())); | ||
break; | ||
} | ||
default: | ||
return; | ||
} | ||
} | ||
// Remove empty pages at the end | ||
while (pages.size() > 0) { | ||
StringTag currentPage = (StringTag) pages.get(pages.size() - 1); | ||
if (currentPage.getValue() == null || currentPage.getValue().isEmpty()) { | ||
pages.remove(pages.size() - 1); | ||
} else { | ||
break; | ||
} | ||
} | ||
tag.put(new ListTag("pages", pages)); | ||
session.getInventory().setItem(36 + session.getInventory().getHeldItemSlot(), bookItem); | ||
InventoryTranslator.INVENTORY_TRANSLATORS.get(null).updateInventory(session, session.getInventory()); | ||
|
||
session.getBookEditCache().setPacket(new ClientEditBookPacket(bookItem, packet.getAction() == BookEditPacket.Action.SIGN_BOOK, session.getInventory().getHeldItemSlot())); | ||
// There won't be any more book updates after this, so we can try sending the edit packet immediately | ||
if (packet.getAction() == BookEditPacket.Action.SIGN_BOOK) { | ||
session.getBookEditCache().checkForSend(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters