Skip to content
/ Geyser Public
forked from GeyserMC/Geyser
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from Camotoy:master #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.geysermc.connector.network.translators.item.ItemTranslator;
import org.geysermc.connector.registry.type.ItemMapping;

import javax.annotation.Nonnull;

@Data
public class GeyserItemStack {
public static final GeyserItemStack EMPTY = new GeyserItemStack(0, 0, null);
Expand All @@ -42,26 +44,18 @@ public class GeyserItemStack {
private CompoundTag nbt;
private int netId;

public GeyserItemStack(int javaId) {
this(javaId, 1);
}

public GeyserItemStack(int javaId, int amount) {
this(javaId, amount, null);
}

public GeyserItemStack(int javaId, int amount, CompoundTag nbt) {
private GeyserItemStack(int javaId, int amount, CompoundTag nbt) {
this(javaId, amount, nbt, 1);
}

public GeyserItemStack(int javaId, int amount, CompoundTag nbt, int netId) {
private GeyserItemStack(int javaId, int amount, CompoundTag nbt, int netId) {
this.javaId = javaId;
this.amount = amount;
this.nbt = nbt;
this.netId = netId;
}

public static GeyserItemStack from(ItemStack itemStack) {
public static @Nonnull GeyserItemStack from(ItemStack itemStack) {
return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
package org.geysermc.connector.inventory;

import com.github.steveice10.mc.protocol.data.game.window.WindowType;
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.math.vector.Vector3i;
import lombok.Getter;
import lombok.NonNull;
Expand Down Expand Up @@ -93,20 +96,31 @@ protected Inventory(String title, int id, int size, WindowType windowType) {

public GeyserItemStack getItem(int slot) {
if (slot > this.size) {
GeyserConnector.getInstance().getLogger().debug("Tried to get an item out of bounds! " + this.toString());
GeyserConnector.getInstance().getLogger().debug("Tried to get an item out of bounds! " + this);
return GeyserItemStack.EMPTY;
}
return items[slot];
}

public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
if (slot > this.size) {
session.getConnector().getLogger().debug("Tried to set an item out of bounds! " + this.toString());
session.getConnector().getLogger().debug("Tried to set an item out of bounds! " + this);
return;
}
GeyserItemStack oldItem = items[slot];
updateItemNetId(oldItem, newItem, session);
items[slot] = newItem;

// Lodestone caching
if (newItem.getJavaId() == session.getItemMappings().getStoredItems().compass().getJavaId()) {
CompoundTag nbt = newItem.getNbt();
if (nbt != null) {
Tag lodestoneTag = nbt.get("LodestoneTracked");
if (lodestoneTag instanceof ByteTag) {
session.getLodestoneCache().cacheInventoryItem(newItem);
}
}
}
}

protected static void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public class GeyserSession implements CommandSender {
private EntityCache entityCache;
private EntityEffectCache effectCache;
private final FormCache formCache;
private final LodestoneCache lodestoneCache;
private final PreferencesCache preferencesCache;
private final TagCache tagCache;
private WorldCache worldCache;
Expand Down Expand Up @@ -444,6 +445,7 @@ public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServ
this.entityCache = new EntityCache(this);
this.effectCache = new EntityEffectCache();
this.formCache = new FormCache(this);
this.lodestoneCache = new LodestoneCache();
this.preferencesCache = new PreferencesCache(this);
this.tagCache = new TagCache();
this.worldCache = new WorldCache(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void addToCache(Column chunk) {
chunks.put(chunkPosition, geyserColumn);
}

public GeyserColumn getChunk(int chunkX, int chunkZ) {
public GeyserColumn getChunk(int chunkX, int chunkZ) {
long chunkPosition = MathUtils.chunkPositionToLong(chunkX, chunkZ);
return chunks.getOrDefault(chunkPosition, null);
}
Expand Down Expand Up @@ -136,6 +136,19 @@ public void removeChunk(int chunkX, int chunkZ) {
chunks.remove(chunkPosition);
}

/**
* Manually clears all entries in the chunk cache.
* The server is responsible for clearing chunk entries if out of render distance (for example) or switching dimensions,
* but it is the client that must clear chunks in the event of proxy switches.
*/
public void clear() {
if (!cache) {
return;
}

chunks.clear();
}

public int getChunkMinY() {
return minY >> 4;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* 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.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.geysermc.connector.inventory.GeyserItemStack;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.WeakHashMap;

/**
* A temporary cache for lodestone information.
* Bedrock requests the lodestone position information separately from the item.
*/
public class LodestoneCache {
/**
* A list of any GeyserItemStacks that are lodestones. Used mainly to minimize Bedrock's "pop-in" effect
* when a new item has been created; instead we can re-use already existing IDs
*/
private final Map<GeyserItemStack, LodestonePos> activeLodestones = new WeakHashMap<>();
private final Int2ObjectMap<LodestonePos> lodestones = new Int2ObjectOpenHashMap<>();
/**
* An ID to increment for each lodestone
*/
private int id = 1;

public void cacheInventoryItem(GeyserItemStack itemStack) {
CompoundTag tag = itemStack.getNbt();
CompoundTag lodestonePos = tag.get("LodestonePos");
if (lodestonePos == null) {
// invalid
return;
}

// Get all info needed for tracking
int x = ((IntTag) lodestonePos.get("X")).getValue();
int y = ((IntTag) lodestonePos.get("Y")).getValue();
int z = ((IntTag) lodestonePos.get("Z")).getValue();
String dim = ((StringTag) tag.get("LodestoneDimension")).getValue();

for (LodestonePos pos : this.activeLodestones.values()) {
if (pos.equals(x, y, z, dim)) {
this.activeLodestones.put(itemStack, pos);
return;
}
}

for (Int2ObjectMap.Entry<LodestonePos> entry : this.lodestones.int2ObjectEntrySet()) {
LodestonePos pos = entry.getValue();
if (pos.equals(x, y, z, dim)) {
// Use this existing position instead
this.activeLodestones.put(itemStack, pos);
return;
}
}

this.activeLodestones.put(itemStack, new LodestonePos(id++, x, y, z, dim));
}

public int store(CompoundTag tag) {
CompoundTag lodestonePos = tag.get("LodestonePos");
if (lodestonePos == null) {
// invalid
return 0;
}

// Get all info needed for tracking
int x = ((IntTag) lodestonePos.get("X")).getValue();
int y = ((IntTag) lodestonePos.get("Y")).getValue();
int z = ((IntTag) lodestonePos.get("Z")).getValue();
String dim = ((StringTag) tag.get("LodestoneDimension")).getValue();

for (LodestonePos pos : this.activeLodestones.values()) {
if (pos.equals(x, y, z, dim)) {
// No need to add this into the lodestones map as it should not be re-requested
return pos.id;
}
}

for (Int2ObjectMap.Entry<LodestonePos> entry : this.lodestones.int2ObjectEntrySet()) {
if (entry.getValue().equals(x, y, z, dim)) {
// Use this existing position instead
return entry.getIntKey();
}
}

// Start at 1 as 0 does not work
this.lodestones.put(id, new LodestonePos(id, x, y, z, dim));
return id++;
}

public @Nullable LodestonePos getPos(int id) {
// We should not need to check the activeLodestones map as Bedrock should already be aware of this ID
return this.lodestones.remove(id);
}

public void clear() {
// Just in case...
this.activeLodestones.clear();
this.lodestones.clear();
}

@Getter
@AllArgsConstructor
@EqualsAndHashCode
public static class LodestonePos {
private final int id;
private final int x;
private final int y;
private final int z;
private final String dimension;

boolean equals(int x, int y, int z, String dimension) {
return this.x == x && this.y == y && this.z == z && this.dimension.equals(dimension);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@
import com.nukkitx.nbt.NbtType;
import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBClientRequestPacket;
import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBServerBroadcastPacket;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.session.cache.LodestoneCache;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.DimensionUtils;
import org.geysermc.connector.utils.LoadstoneTracker;

@Translator(packet = PositionTrackingDBClientRequestPacket.class)
public class BedrockPositionTrackingDBClientRequestTranslator extends PacketTranslator<PositionTrackingDBClientRequestPacket> {

@Override
public void translate(GeyserSession session, PositionTrackingDBClientRequestPacket packet) {
System.out.println(packet.toString());
PositionTrackingDBServerBroadcastPacket broadcastPacket = new PositionTrackingDBServerBroadcastPacket();
broadcastPacket.setTrackingId(packet.getTrackingId());

// Fetch the stored Loadstone
LoadstoneTracker.LoadstonePos pos = LoadstoneTracker.getPos(packet.getTrackingId());
// Fetch the stored lodestone
LodestoneCache.LodestonePos pos = session.getLodestoneCache().getPos(packet.getTrackingId());
System.out.println(pos);

// If we don't have data for that ID tell the client its not found
if (pos == null) {
Expand All @@ -58,22 +58,20 @@ public void translate(GeyserSession session, PositionTrackingDBClientRequestPack

broadcastPacket.setAction(PositionTrackingDBServerBroadcastPacket.Action.UPDATE);

// Build the nbt data for the update
// Build the NBT data for the update
NbtMapBuilder builder = NbtMap.builder();
builder.putInt("dim", DimensionUtils.javaToBedrock(pos.getDimension()));
builder.putString("id", String.format("%08X", packet.getTrackingId()));
builder.putString("id", "0x" + String.format("%08X", packet.getTrackingId()));

builder.putByte("version", (byte) 1); // Not sure what this is for
builder.putByte("status", (byte) 0); // Not sure what this is for

// Build the position for the update
IntList posList = new IntArrayList();
posList.add(pos.getX());
posList.add(pos.getY());
posList.add(pos.getZ());
builder.putList("pos", NbtType.INT, posList);
builder.putList("pos", NbtType.INT, pos.getX(), pos.getY(), pos.getZ());
broadcastPacket.setTag(builder.build());

System.out.println(broadcastPacket);

session.sendUpstreamPacket(broadcastPacket);
}
}
Loading