Optimization to prevent permanent map lookup

This commit is contained in:
themode 2020-11-14 09:02:29 +01:00
parent 648cad85c2
commit 0abedd7453
7 changed files with 82 additions and 86 deletions

View File

@ -51,6 +51,7 @@ public interface CommandSender extends PermissionHandler {
* Casts this object to a {@link Player}.
* No checks are performed, {@link ClassCastException} can very much happen.
*
* @throws ClassCastException if 'this' is not a player
* @see #isPlayer()
*/
default Player asPlayer() {
@ -61,6 +62,7 @@ public interface CommandSender extends PermissionHandler {
* Casts this object to a {@link ConsoleSender}.
* No checks are performed, {@link ClassCastException} can very much happen.
*
* @throws ClassCastException if 'this' is not a console sender
* @see #isConsole()
*/
default ConsoleSender asConsole() {

View File

@ -379,8 +379,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
return;
}
BlockPosition blockPosition = position.toBlockPosition();
if (!ChunkUtils.isLoaded(instance, position.getX(), position.getZ()) || !ChunkUtils.isLoaded(instance, blockPosition.getX(), blockPosition.getZ())) {
final Chunk currentChunk = getChunk(); // current entity chunk
if (!ChunkUtils.isLoaded(currentChunk)) {
// No update for entities in unloaded chunk
return;
}
@ -468,8 +469,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer, P
float drag;
if (onGround) {
final CustomBlock customBlock =
instance.getCustomBlock(blockPosition);
final BlockPosition blockPosition = position.toBlockPosition();
final CustomBlock customBlock = instance.getCustomBlock(blockPosition);
if (customBlock != null) {
// Custom drag
drag = customBlock.getDrag(instance, blockPosition);

View File

@ -19,7 +19,9 @@ import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -29,7 +31,11 @@ import java.util.function.Consumer;
public abstract class LivingEntity extends Entity implements EquipmentHandler {
// Item pickup
protected boolean canPickupItem;
protected UpdateOption itemPickupCooldown = new UpdateOption(10, TimeUnit.TICK);
protected long lastItemPickupTime;
protected boolean isDead;
private float health;
@ -90,8 +96,10 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
// Items picking
if (canPickupItem()) {
final Chunk chunk = instance.getChunkAt(getPosition()); // TODO check surrounding chunks
if (canPickupItem() && !CooldownUtils.hasCooldown(time, lastItemPickupTime, itemPickupCooldown)) {
this.lastItemPickupTime = time;
final Chunk chunk = getChunk(); // TODO check surrounding chunks
final Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) {
if (entity instanceof ItemEntity) {

View File

@ -55,6 +55,9 @@ import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.instance.InstanceUtils;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.NotNull;
@ -126,6 +129,10 @@ public class Player extends LivingEntity implements CommandSender {
private byte targetStage; // The current stage of the target block, only if multi player breaking is disabled
private final Set<Player> targetBreakers = new HashSet<>(1); // Only used if multi player breaking is disabled, contains only this player
// Experience orb pickup
protected UpdateOption experiencePickupCooldown = new UpdateOption(10, TimeUnit.TICK);
protected long lastExperiencePickupTime;
private BelowNameTag belowNameTag;
private int permissionLevel;
@ -347,20 +354,24 @@ public class Player extends LivingEntity implements CommandSender {
}
// Experience orb pickup
final Chunk chunk = instance.getChunkAt(getPosition()); // TODO check surrounding chunks
final Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) {
if (entity instanceof ExperienceOrb) {
final ExperienceOrb experienceOrb = (ExperienceOrb) entity;
final BoundingBox itemBoundingBox = experienceOrb.getBoundingBox();
if (expandedBoundingBox.intersect(itemBoundingBox)) {
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
continue;
PickupExperienceEvent pickupExperienceEvent = new PickupExperienceEvent(experienceOrb);
callCancellableEvent(PickupExperienceEvent.class, pickupExperienceEvent, () -> {
short experienceCount = pickupExperienceEvent.getExperienceCount(); // TODO give to player
entity.remove();
});
if (!CooldownUtils.hasCooldown(time, lastExperiencePickupTime, experiencePickupCooldown)) {
this.lastExperiencePickupTime = time;
final Chunk chunk = getChunk(); // TODO check surrounding chunks
final Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) {
if (entity instanceof ExperienceOrb) {
final ExperienceOrb experienceOrb = (ExperienceOrb) entity;
final BoundingBox itemBoundingBox = experienceOrb.getBoundingBox();
if (expandedBoundingBox.intersect(itemBoundingBox)) {
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
continue;
PickupExperienceEvent pickupExperienceEvent = new PickupExperienceEvent(experienceOrb);
callCancellableEvent(PickupExperienceEvent.class, pickupExperienceEvent, () -> {
short experienceCount = pickupExperienceEvent.getExperienceCount(); // TODO give to player
entity.remove();
});
}
}
}
}

View File

@ -605,6 +605,15 @@ public class InstanceContainer extends Instance {
return Collections.unmodifiableList(sharedInstances);
}
/**
* Gets if this instance has {@link SharedInstance} linked to it.
*
* @return true if {@link #getSharedInstances()} is not empty
*/
public boolean hasSharedInstances() {
return !sharedInstances.isEmpty();
}
/**
* Assigns a {@link SharedInstance} to this container.
* <p>

View File

@ -112,7 +112,7 @@ public abstract class ThreadProvider {
// INSTANCE UPDATE
/**
* Process a whole tick for a chunk.
* Processes a whole tick for a chunk.
*
* @param instance the instance of the chunk
* @param chunkIndex the index of the chunk {@link ChunkUtils#getChunkIndex(int, int)}
@ -243,6 +243,10 @@ public abstract class ThreadProvider {
private void updateSharedInstances(@NotNull Instance instance, @NotNull Consumer<SharedInstance> callback) {
if (instance instanceof InstanceContainer) {
final InstanceContainer instanceContainer = (InstanceContainer) instance;
if (!instanceContainer.hasSharedInstances())
return;
for (SharedInstance sharedInstance : instanceContainer.getSharedInstances()) {
callback.accept(sharedInstance);
}

View File

@ -1,8 +1,6 @@
package net.minestom.server.utils;
import io.netty.buffer.ByteBuf;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.block.Block;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.UUID;
@ -94,6 +92,32 @@ public final class Utils {
return new UUID(uuidMost, uuidLeast);
}
public static void writeBlocks(ByteBuf buffer, short[] palette, long[] blocksId, int bitsPerEntry) {
/*short count = 0;
for (short id : blocksId)
if (id != 0)
count++;*/
//buffer.writeShort(count);
buffer.writeShort(200);
buffer.writeByte((byte) bitsPerEntry);
// Palette
if (bitsPerEntry < 9) {
// Palette has to exist
writeVarIntBuf(buffer, palette.length);
for (short paletteValue : palette) {
writeVarIntBuf(buffer, paletteValue);
}
}
final long[] data = blocksId;
writeVarIntBuf(buffer, data.length);
for (long datum : data) {
buffer.writeLong(datum);
}
}
private static final int[] MAGIC = {
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
@ -116,69 +140,6 @@ public final class Utils {
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
0, 5};
public static void writeBlocks(ByteBuf buffer, short[] palette, long[] blocksId, int bitsPerEntry) {
/*short count = 0;
for (short id : blocksId)
if (id != 0)
count++;*/
//buffer.writeShort(count);
buffer.writeShort(200);
buffer.writeByte((byte) bitsPerEntry);
// Palette
if (bitsPerEntry < 9) {
// Palette has to exist
writeVarIntBuf(buffer, palette.length);
for (short paletteValue : palette) {
writeVarIntBuf(buffer, paletteValue);
}
}
final long[] data = blocksId;//encodeBlocksTEST(bitsPerEntry);
writeVarIntBuf(buffer, data.length);
for (long datum : data) {
buffer.writeLong(datum);
}
}
public synchronized static long[] encodeBlocksTEST(int bitsPerEntry) {
//long test = (Block.TORCH.getBlockId() << (64 - 50 - bitsPerEntry + 1));
//System.out.println("BINARY: 0b" + Long.toBinaryString(test) + " " + (64 - 50 - bitsPerEntry + 1));
final int blockCount = 16 * 16 * 16; // A whole chunk section
final int longSize = Long.SIZE; // 64
final char valuesPerLong = (char) (longSize / bitsPerEntry);
final int arraySize = blockCount / valuesPerLong;
long[] data = new long[arraySize];
data[0] = 0b000000010001L;
data[1] = 0b000000010001L;
if (true) {
return data;
}
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
final long blockId = x % 2 == 0 && z % 2 == 0 ? Block.AIR.getBlockId() : Block.LAVA.getBlockId();
int sectionIndex = (((y * 16) + z) * 16) + x;
final int index = sectionIndex / valuesPerLong;
final int bitIndex = sectionIndex % valuesPerLong * bitsPerEntry;
data[index] |= (blockId << bitIndex);
}
}
}
return data;
}
private static String binary(long value) {
return "0b" + Long.toBinaryString(value);
}
public static long[] encodeBlocks(int[] blocks, int bitsPerEntry) {
final long maxEntryValue = (1L << bitsPerEntry) - 1;
final char valuesPerLong = (char) (64 / bitsPerEntry);