Added Entity#isAutoViewable & making Viewable#addViewer and Viewable#removeViewer return boolean

This commit is contained in:
Felix Cravic 2020-05-23 17:57:56 +02:00
parent a4b530c1dc
commit 883e7eb80f
16 changed files with 160 additions and 86 deletions

View File

@ -8,6 +8,7 @@ import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.entity.*;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.type.EntityBoat;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
@ -19,11 +20,12 @@ import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.block.Block;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.scoreboard.Sidebar;
import net.minestom.server.timer.TaskRunnable;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Position;
@ -40,6 +42,8 @@ public class PlayerInit {
private static volatile InstanceContainer instanceContainer;
private static volatile InstanceContainer netherTest;
private static volatile Inventory inventory;
static {
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("chunk_data");
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
@ -61,6 +65,15 @@ public class PlayerInit {
instanceContainer.loadChunk(x, z);
netherTest.loadChunk(x, z);
}
inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory");
inventory.addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> {
p.sendMessage("click type inventory: " + clickType);
System.out.println("slot inv: " + slot);
inventoryConditionResult.setCancel(false);
});
inventory.setItemStack(0, new ItemStack(Material.DIAMOND, (byte) 34));
}
public static void init() {
@ -157,9 +170,9 @@ public class PlayerInit {
player.addEventCallback(ItemDropEvent.class, event -> {
ItemStack droppedItem = event.getItemStack();
ItemEntity itemEntity = new ItemEntity(droppedItem);
itemEntity.setPickupDelay(500);
itemEntity.refreshPosition(player.getPosition().clone().add(0, 1.5f, 0));
Position position = player.getPosition().clone().add(0, 1.5f, 0);
ItemEntity itemEntity = new ItemEntity(droppedItem, position);
itemEntity.setPickupDelay(500, TimeUnit.MILLISECOND);
itemEntity.setInstance(player.getInstance());
Vector velocity = player.getPosition().clone().getDirection().multiply(6);
itemEntity.setVelocity(velocity);
@ -179,38 +192,36 @@ public class PlayerInit {
System.out.println("slot player: " + slot);
});
Sidebar scoreboard = new Sidebar("Scoreboard Title");
/*Sidebar scoreboard = new Sidebar("Scoreboard Title");
for (int i = 0; i < 15; i++) {
scoreboard.createLine(new Sidebar.ScoreboardLine("id" + i, "Hey guys " + i, i));
}
scoreboard.addViewer(player);
scoreboard.updateLineContent("id3", "I HAVE BEEN UPDATED");
scoreboard.setTitle("test");
scoreboard.setTitle("test");*/
});
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.SURVIVAL);
player.teleport(new Position(0, 75, 0));
player.teleport(new Position(0, 70, 0));
ItemStack item = new ItemStack(Material.STONE, (byte) 43);
ItemStack item = new ItemStack(Material.STONE_SWORD, (byte) 1);
item.setDisplayName("Item name");
item.getLore().add("a lore line");
//item.setEnchantment(Enchantment.SHARPNESS, 2);
item.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
item.setEnchantment(Enchantment.SHARPNESS, (short) 2);
player.getInventory().addItemStack(item);
Inventory inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory");
inventory.addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> {
player.sendMessage("click type inventory: " + clickType);
System.out.println("slot inv: " + slot);
inventoryConditionResult.setCancel(false);
});
inventory.setItemStack(0, item.clone());
player.openInventory(inventory);
player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100));
player.getInventory().addItemStack(new ItemStack(Material.DIAMOND_CHESTPLATE, (byte) 1));
EntityBoat entityBoat = new EntityBoat(player.getPosition());
entityBoat.setInstance(player.getInstance());
//entityBoat.addPassenger(player);
//player.getInventory().addItemStack(new ItemStack(Material.DIAMOND_CHESTPLATE, (byte) 1));
/*TeamManager teamManager = Main.getTeamManager();
Team team = teamManager.createTeam(getUsername());

View File

@ -14,6 +14,9 @@ public class ChickenCreature extends EntityCreature {
public ChickenCreature(Position defaultPosition) {
super(EntityType.SKELETON, defaultPosition);
setAutoViewable(true);
setBoundingBox(0.4f, 0.7f, 0.4f);
setHelmet(new ItemStack(Material.DIAMOND_HELMET, (byte) 1));
}

View File

@ -9,9 +9,17 @@ import java.util.Set;
public interface Viewable {
void addViewer(Player player);
/**
* @param player the viewer to add
* @return true if the player has been added, false otherwise (could be because he is already a viewer)
*/
boolean addViewer(Player player);
void removeViewer(Player player);
/**
* @param player the viewer to remove
* @return true if the player has been removed, false otherwise (could be because he was not a viewer)
*/
boolean removeViewer(Player player);
Set<Player> getViewers();

View File

@ -27,17 +27,19 @@ public class BossBar implements Viewable {
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
player.refreshAddBossbar(this);
addToPlayer(player);
return result;
}
@Override
public void removeViewer(Player player) {
this.viewers.remove(player);
public boolean removeViewer(Player player) {
boolean result = this.viewers.remove(player);
player.refreshRemoveBossbar(this);
removeToPlayer(player);
return result;
}
@Override

View File

@ -61,6 +61,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected float gravityDragPerTick;
protected float eyeHeight;
private boolean autoViewable;
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private Data data;
private Set<Entity> passengers = new CopyOnWriteArraySet<>();
@ -110,6 +111,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
setBoundingBox(0, 0, 0);
setAutoViewable(true);
entityById.put(id, this);
setVelocityUpdatePeriod(5);
}
@ -204,27 +207,54 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
teleport(position, null);
}
/**
* When set to true, the entity will automatically get new viewers when they come too close
* This can be use to complete control over which player can see it, without having to deal with
* raw packets
* <p>
* True by default for all entities
* When set to false, it is important to mention that the players will not be removed automatically from its viewers
* list, you would have to do that manually when being too far
*
* @return true if the entity is automatically viewable for close players, false otherwise
*/
public boolean isAutoViewable() {
return autoViewable;
}
/**
* @param autoViewable should the entity be automatically viewable for close players
*/
public void setAutoViewable(boolean autoViewable) {
this.autoViewable = autoViewable;
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
player.viewableEntities.add(this);
PlayerConnection playerConnection = player.getPlayerConnection();
playerConnection.sendPacket(getVelocityPacket());
playerConnection.sendPacket(getPassengersPacket());
playerConnection.sendPacket(getMetadataPacket());
return result;
}
@Override
public void removeViewer(Player player) {
public boolean removeViewer(Player player) {
boolean result;
synchronized (viewers) {
if (!viewers.contains(player))
return;
this.viewers.remove(player);
result = viewers.remove(player);
if (!result)
return false;
DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket();
destroyEntitiesPacket.entityIds = new int[]{getEntityId()};
player.getPlayerConnection().sendPacket(destroyEntitiesPacket);
}
player.viewableEntities.remove(this);
return result;
}
@Override
@ -571,7 +601,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
instance.removeEntityFromChunk(this, lastChunk);
instance.addEntityToChunk(this, newChunk);
}
updateView(this, lastChunk, newChunk);
updateView(lastChunk, newChunk);
}
}
}
@ -580,16 +610,16 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
refreshPosition(position.getX(), position.getY(), position.getZ());
}
private void updateView(Entity entity, Chunk lastChunk, Chunk newChunk) {
if (entity instanceof Player)
((Player) entity).onChunkChange(lastChunk, newChunk); // Refresh loaded chunk
private void updateView(Chunk lastChunk, Chunk newChunk) {
boolean isPlayer = this instanceof Player;
if (isPlayer)
((Player) this).onChunkChange(lastChunk, newChunk); // Refresh loaded chunk
// Refresh entity viewable list
long[] lastVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * lastChunk.getChunkX(), 0, 16 * lastChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE);
long[] updatedVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE);
boolean isPlayer = entity instanceof Player;
int[] oldChunksEntity = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunksEntity, updatedVisibleChunksEntity);
for (int index : oldChunksEntity) {
int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunksEntity[index]);
@ -599,12 +629,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
instance.getChunkEntities(chunk).forEach(ent -> {
if (ent instanceof Player) {
Player player = (Player) ent;
removeViewer(player);
if (isAutoViewable())
removeViewer(player);
if (isPlayer) {
player.removeViewer((Player) entity);
player.removeViewer((Player) this);
}
} else if (isPlayer) {
ent.removeViewer((Player) entity);
ent.removeViewer((Player) this);
}
});
}
@ -618,12 +649,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
instance.getChunkEntities(chunk).forEach(ent -> {
if (ent instanceof Player) {
Player player = (Player) ent;
addViewer(player);
if (entity instanceof Player) {
player.addViewer((Player) entity);
if (isAutoViewable())
addViewer(player);
if (this instanceof Player) {
player.addViewer((Player) this);
}
} else if (isPlayer) {
ent.addViewer((Player) entity);
ent.addViewer((Player) this);
}
});
}

View File

@ -133,8 +133,8 @@ public abstract class EntityCreature extends LivingEntity {
}
@Override
public void addViewer(Player player) {
super.addViewer(player);
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
PlayerConnection playerConnection = player.getPlayerConnection();
EntityPacket entityPacket = new EntityPacket();
@ -150,6 +150,7 @@ public abstract class EntityCreature extends LivingEntity {
playerConnection.sendPacket(entityPacket);
playerConnection.sendPacket(spawnLivingEntityPacket);
playerConnection.sendPacket(getMetadataPacket());
return result;
}
@Override

View File

@ -25,7 +25,7 @@ public class ExperienceOrb extends Entity {
}
@Override
public void addViewer(Player player) {
public boolean addViewer(Player player) {
PlayerConnection playerConnection = player.getPlayerConnection();
SpawnExperienceOrbPacket experienceOrbPacket = new SpawnExperienceOrbPacket();
@ -33,7 +33,7 @@ public class ExperienceOrb extends Entity {
experienceOrbPacket.position = getPosition();
experienceOrbPacket.expCount = experienceCount;
playerConnection.sendPacket(experienceOrbPacket);
super.addViewer(player); // Add player to viewers list and send velocity packet
return super.addViewer(player); // Add player to viewers list and send velocity packet
}
public short getExperienceCount() {

View File

@ -6,6 +6,7 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.time.TimeUnit;
import java.util.Set;
import java.util.function.Consumer;
@ -83,11 +84,6 @@ public class ItemEntity extends ObjectEntity {
this.spawnTime = System.currentTimeMillis();
}
@Override
public void addViewer(Player player) {
super.addViewer(player);
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> {
@ -118,7 +114,7 @@ public class ItemEntity extends ObjectEntity {
public void setItemStack(ItemStack itemStack) {
this.itemStack = itemStack;
sendMetadataIndex(7); // Refresh itemstack for viewers
sendMetadataIndex(7); // Refresh the ItemStack for viewers
}
public boolean isPickable() {
@ -141,8 +137,8 @@ public class ItemEntity extends ObjectEntity {
return pickupDelay;
}
public void setPickupDelay(long pickupDelay) {
this.pickupDelay = pickupDelay;
public void setPickupDelay(long delay, TimeUnit timeUnit) {
this.pickupDelay = timeUnit.toMilliseconds(delay);
}
public long getSpawnTime() {

View File

@ -81,6 +81,11 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
BoundingBox livingBoundingBox = expandedBoundingBox;
for (Entity entity : entities) {
if (entity instanceof ItemEntity) {
// Do not pickup if not visible
if (this instanceof Player && !entity.isViewer((Player) this))
continue;
ItemEntity itemEntity = (ItemEntity) entity;
if (!itemEntity.isPickable())
continue;
@ -135,11 +140,12 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
@Override
public void addViewer(Player player) {
super.addViewer(player);
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
// Equipments synchronization
syncEquipments();
return result;
}
/**

View File

@ -14,7 +14,7 @@ public abstract class ObjectEntity extends Entity {
public abstract int getObjectData();
@Override
public void addViewer(Player player) {
public boolean addViewer(Player player) {
PlayerConnection playerConnection = player.getPlayerConnection();
SpawnEntityPacket spawnEntityPacket = new SpawnEntityPacket();
@ -25,12 +25,12 @@ public abstract class ObjectEntity extends Entity {
spawnEntityPacket.data = getObjectData();
playerConnection.sendPacket(spawnEntityPacket);
playerConnection.sendPacket(getMetadataPacket());
super.addViewer(player); // Add player to viewers list and send velocity packet
return super.addViewer(player); // Add player to viewers list and send velocity packet
}
@Override
public void removeViewer(Player player) {
super.removeViewer(player);
public boolean removeViewer(Player player) {
return super.removeViewer(player);
}
}

View File

@ -333,10 +333,11 @@ public class Player extends LivingEntity {
}
@Override
public void addViewer(Player player) {
public boolean addViewer(Player player) {
if (player == this)
return;
super.addViewer(player);
return false;
boolean result = super.addViewer(player);
PlayerConnection viewerConnection = player.getPlayerConnection();
String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19";
SpawnPlayerPacket spawnPlayerPacket = new SpawnPlayerPacket();
@ -356,13 +357,15 @@ public class Player extends LivingEntity {
// Team
if (team != null)
viewerConnection.sendPacket(team.getTeamsCreationPacket());
return result;
}
@Override
public void removeViewer(Player player) {
public boolean removeViewer(Player player) {
if (player == this)
return;
super.removeViewer(player);
return false;
boolean result = super.removeViewer(player);
PlayerConnection viewerConnection = player.getPlayerConnection();
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER);
playerInfoPacket.playerInfos.add(new PlayerInfoPacket.RemovePlayer(getUuid()));
@ -371,6 +374,7 @@ public class Player extends LivingEntity {
// Team
if (team != null && team.getPlayers().size() == 1) // If team only contains "this" player
viewerConnection.sendPacket(team.createTeamDestructionPacket());
return result;
}
@Override

View File

@ -374,20 +374,22 @@ public class Chunk implements Viewable {
// UNSAFE
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
PlayerChunkLoadEvent playerChunkLoadEvent = new PlayerChunkLoadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkLoadEvent.class, playerChunkLoadEvent);
return result;
}
// UNSAFE
@Override
public void removeViewer(Player player) {
this.viewers.remove(player);
public boolean removeViewer(Player player) {
boolean result = this.viewers.remove(player);
PlayerChunkUnloadEvent playerChunkUnloadEvent = new PlayerChunkUnloadEvent(player, chunkX, chunkZ);
player.callEvent(PlayerChunkUnloadEvent.class, playerChunkUnloadEvent);
return result;
}
@Override

View File

@ -315,7 +315,8 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
}
if (ent instanceof Player) {
entity.addViewer((Player) ent);
if (entity.isAutoViewable())
entity.addViewer((Player) ent);
}
});
}
@ -332,7 +333,10 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
RemoveEntityFromInstanceEvent event = new RemoveEntityFromInstanceEvent(this, entity);
callCancellableEvent(RemoveEntityFromInstanceEvent.class, event, () -> {
entity.getViewers().forEach(p -> entity.removeViewer(p)); // Remove this entity from players viewable list and send delete entities packet
if (entity.isAutoViewable()) {
// Remove this entity from players viewable list and send delete entities packet
entity.getViewers().forEach(p -> entity.removeViewer(p));
}
Chunk chunk = getChunkAt(entity.getPosition());
removeEntityFromChunk(entity, chunk);

View File

@ -133,7 +133,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
public void update(Player player) {
if (!getViewers().contains(player))
return;
PacketWriterUtils.writeAndSend(player, getWindowItemsPacket());
}
@ -143,17 +143,19 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
WindowItemsPacket windowItemsPacket = getWindowItemsPacket();
player.getPlayerConnection().sendPacket(windowItemsPacket);
return result;
}
@Override
public void removeViewer(Player player) {
this.viewers.remove(player);
public boolean removeViewer(Player player) {
boolean result = this.viewers.remove(player);
this.cursorPlayersItem.remove(player);
this.clickProcessor.clearCache(player);
return result;
}
public ItemStack getCursorItem(Player player) {

View File

@ -53,15 +53,16 @@ public class BelowNameScoreboard implements Viewable {
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
PlayerConnection playerConnection = player.getPlayerConnection();
playerConnection.sendPacket(scoreboardObjectivePacket);
return result;
}
@Override
public void removeViewer(Player player) {
this.viewers.remove(player);
public boolean removeViewer(Player player) {
return this.viewers.remove(player);
}
@Override

View File

@ -124,8 +124,8 @@ public class Sidebar implements Viewable {
}
@Override
public void addViewer(Player player) {
this.viewers.add(player);
public boolean addViewer(Player player) {
boolean result = this.viewers.add(player);
PlayerConnection playerConnection = player.getPlayerConnection();
ScoreboardObjectivePacket scoreboardObjectivePacket = new ScoreboardObjectivePacket();
@ -145,11 +145,12 @@ public class Sidebar implements Viewable {
playerConnection.sendPacket(line.sidebarTeam.getCreationPacket());
playerConnection.sendPacket(line.getScoreCreationPacket(objectiveName));
}
return result;
}
@Override
public void removeViewer(Player player) {
this.viewers.remove(player);
public boolean removeViewer(Player player) {
boolean result = this.viewers.remove(player);
PlayerConnection playerConnection = player.getPlayerConnection();
ScoreboardObjectivePacket scoreboardObjectivePacket = new ScoreboardObjectivePacket();
scoreboardObjectivePacket.objectiveName = objectiveName;
@ -160,6 +161,7 @@ public class Sidebar implements Viewable {
playerConnection.sendPacket(line.getScoreDestructionPacket(objectiveName)); // Is it necessary?
playerConnection.sendPacket(line.sidebarTeam.getDestructionPacket());
}
return result;
}
@Override