diff --git a/pom.xml b/pom.xml
index c0f81fec..9039be89 100755
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
net.tridentsdk
trident
- 1.0-SNAPSHOT
+ 0.3-SNAPSHOT
Trident
http://www.tridentsdk.net/
jar
diff --git a/src/main/java/net/tridentsdk/server/entity/TridentEntity.java b/src/main/java/net/tridentsdk/server/entity/TridentEntity.java
index e55d0265..1a803433 100755
--- a/src/main/java/net/tridentsdk/server/entity/TridentEntity.java
+++ b/src/main/java/net/tridentsdk/server/entity/TridentEntity.java
@@ -35,6 +35,7 @@
import net.tridentsdk.server.packets.play.out.PacketPlayOutEntityVelocity;
import net.tridentsdk.server.player.TridentPlayer;
import net.tridentsdk.server.threads.ThreadsHandler;
+import net.tridentsdk.server.world.TridentChunk;
import net.tridentsdk.server.world.TridentWorld;
import net.tridentsdk.util.Vector;
import net.tridentsdk.util.WeakEntity;
@@ -183,16 +184,6 @@ protected void encodeMetadata(ProtocolMetadata protocolMeta) {
doEncodeMeta(protocolMeta);
}
- /**
- * Moves the entity to the new coordinates. Not for teleportation.
- *
- * @param newCoords the new location for the entity
- */
- public void doMove(Position newCoords) {
- HANDLER.trackMovement(this, position(), newCoords);
- this.setLocation(newCoords);
- }
-
@Override
public void teleport(double x, double y, double z) {
this.teleport(Position.create(this.world(), x, y, z));
@@ -233,7 +224,14 @@ public Position position() {
return this.loc;
}
- public void setLocation(Position loc) {
+ public void setPosition(Position loc) {
+ TridentChunk from = (TridentChunk) position().chunk();
+ TridentChunk chunk = (TridentChunk) loc.chunk();
+ if (!from.equals(chunk)) {
+ from.entitiesInternal().remove(this);
+ chunk.entitiesInternal().add(this);
+ }
+
this.loc = loc;
}
diff --git a/src/main/java/net/tridentsdk/server/packets/login/PacketLoginInStart.java b/src/main/java/net/tridentsdk/server/packets/login/PacketLoginInStart.java
index 8d9883d5..86f6f926 100755
--- a/src/main/java/net/tridentsdk/server/packets/login/PacketLoginInStart.java
+++ b/src/main/java/net/tridentsdk/server/packets/login/PacketLoginInStart.java
@@ -120,9 +120,16 @@ public void handleReceived(ClientConnection connection) {
// parse the response and set the ID
JsonArray array = PacketLoginInEncryptionResponse.GSON.fromJson(sb.toString(), JsonArray.class);
+ JsonArray jsonArray = array.getAsJsonArray();
+ if (jsonArray.size() == 0) {
+ // TODO more checks, session validity
+ connection.sendPacket(
+ new PacketLoginOutDisconnect().setJsonMessage("This server is in online-mode"));
+ return;
+ }
id = UUID.fromString(PacketLoginInEncryptionResponse.idDash.matcher(
- array.getAsJsonArray().get(0).getAsJsonObject().get("id").getAsString())
+ jsonArray.get(0).getAsJsonObject().get("id").getAsString())
.replaceAll("$1-$2-$3-$4-$5"));
if (TridentPlayer.getPlayer(id) != null) {
diff --git a/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerLook.java b/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerLook.java
index 27895938..a9cc364e 100755
--- a/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerLook.java
+++ b/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerLook.java
@@ -82,6 +82,6 @@ public void handleReceived(ClientConnection connection) {
return;
}
- player.setLocation(to);
+ player.setPosition(to);
}
}
diff --git a/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerMove.java b/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerMove.java
index b3a80127..694a37ca 100755
--- a/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerMove.java
+++ b/src/main/java/net/tridentsdk/server/packets/play/in/PacketPlayInPlayerMove.java
@@ -87,6 +87,6 @@ public void handleReceived(ClientConnection connection) {
return;
}
- player.setLocation(to);
+ player.setPosition(to);
}
}
diff --git a/src/main/java/net/tridentsdk/server/packets/play/out/PacketPlayOutEntityEquipment.java b/src/main/java/net/tridentsdk/server/packets/play/out/PacketPlayOutEntityEquipment.java
index 46a1e844..b460cced 100755
--- a/src/main/java/net/tridentsdk/server/packets/play/out/PacketPlayOutEntityEquipment.java
+++ b/src/main/java/net/tridentsdk/server/packets/play/out/PacketPlayOutEntityEquipment.java
@@ -18,6 +18,7 @@
package net.tridentsdk.server.packets.play.out;
import io.netty.buffer.ByteBuf;
+import net.tridentsdk.server.data.Slot;
import net.tridentsdk.server.netty.Codec;
import net.tridentsdk.server.netty.packet.OutPacket;
@@ -25,8 +26,7 @@ public class PacketPlayOutEntityEquipment extends OutPacket {
protected int entityId;
protected short slot;
- protected long item;
- // TODO: mojang slot shit
+ protected Slot item;
@Override
public int id() {
@@ -41,10 +41,14 @@ public short slot() {
return this.slot;
}
+ public Slot item() {
+ return this.item;
+ }
+
@Override
public void encode(ByteBuf buf) {
Codec.writeVarInt32(buf, this.entityId);
buf.writeShort((int) this.slot);
- buf.writeLong(item); // TODO this is the way?
+ item.write(buf);
}
}
diff --git a/src/main/java/net/tridentsdk/server/player/TridentPlayer.java b/src/main/java/net/tridentsdk/server/player/TridentPlayer.java
index 15c587ac..a5a4628a 100755
--- a/src/main/java/net/tridentsdk/server/player/TridentPlayer.java
+++ b/src/main/java/net/tridentsdk/server/player/TridentPlayer.java
@@ -25,6 +25,7 @@
import net.tridentsdk.docs.InternalUseOnly;
import net.tridentsdk.entity.Entity;
import net.tridentsdk.entity.living.Player;
+import net.tridentsdk.entity.types.EntityType;
import net.tridentsdk.event.player.PlayerJoinEvent;
import net.tridentsdk.factory.Factories;
import net.tridentsdk.meta.ChatColor;
@@ -36,7 +37,6 @@
import net.tridentsdk.server.netty.ClientConnection;
import net.tridentsdk.server.netty.packet.Packet;
import net.tridentsdk.server.packets.play.out.*;
-import net.tridentsdk.server.threads.TaskGroup;
import net.tridentsdk.server.threads.ThreadsHandler;
import net.tridentsdk.server.world.TridentChunk;
import net.tridentsdk.server.world.TridentWorld;
@@ -117,7 +117,7 @@ public static TridentPlayer spawnPlayer(ClientConnection connection, UUID id, St
p.abilities.canFly = 1;
// DEBUG =====
- p.setLocation(new Position(p.world(), 0, 255, 0));
+ p.setPosition(new Position(p.world(), 0, 255, 0));
p.spawnLocation = new Position(p.world(), 0, 255, 0);
// =====
@@ -152,6 +152,7 @@ public static TridentPlayer spawnPlayer(ClientConnection connection, UUID id, St
p.encodeMetadata(metadata);
});
+ p.spawn();
return p;
}
@@ -225,11 +226,6 @@ public void resumeLogin() {
}
}
- @Override // Overridden to execute on the player handler instead
- public void tick() {
- ThreadsHandler.playerExecutor().execute(this::doTick);
- }
-
@Override
protected void doTick() {
int distance = viewDistance();
@@ -245,29 +241,34 @@ protected void doTick() {
ticksExisted.incrementAndGet();
}
- public Set cleanChunks() {
- if (knownChunks.size() > 441) {
+ public void cleanChunks() {
+ int toClean = knownChunks.size() - 441;
+ if (toClean > 0) {
Position pos = position();
int x = (int) pos.x() / 16;
int z = (int) pos.z() / 16;
int viewDist = viewDistance();
- TaskGroup.process(knownChunks).every(4).with(ThreadsHandler.chunkExecutor()).using((location) -> {
+ int cleaned = 0;
+ for (ChunkLocation location : knownChunks) {
int cx = location.x();
int cz = location.z();
int abs = Math.abs(cx - x);
int abs1 = Math.abs(cz - z);
- // TODO some possibility of deviating
if (abs > viewDist || abs1 > viewDist) {
- connection.sendPacket(new PacketPlayOutChunkData(new byte[512], location, true, (short) 0));
- knownChunks.remove(location);
+ boolean tried = ((TridentWorld) world()).loadedChunks.tryRemove(location);
+ if (tried) {
+ connection.sendPacket(new PacketPlayOutChunkData(new byte[0], location, true, (short) 0));
+ knownChunks.remove(location);
+ cleaned++;
+ }
}
- });
- }
- return knownChunks;
+ if (cleaned >= toClean) return;
+ }
+ }
}
@Override
@@ -279,10 +280,7 @@ protected void doRemove() {
}
@Override
- public void setLocation(Position loc) {
- ProtocolMetadata metadata = new ProtocolMetadata();
- encodeMetadata(metadata);
-
+ public void setPosition(Position loc) {
players().stream()
.filter((p) -> !p.equals(this))
.forEach((p) -> {
@@ -292,7 +290,7 @@ public void setLocation(Position loc) {
.set("onGround", onGround));
});
- super.setLocation(loc);
+ super.setPosition(loc);
}
/*
@@ -446,4 +444,9 @@ public void setViewDistance(int viewDistance) {
public int viewDistance() {
return Math.min(viewDistance, MAX_VIEW);
}
+
+ @Override
+ public EntityType type() {
+ return EntityType.PLAYER;
+ }
}
diff --git a/src/main/java/net/tridentsdk/server/world/ChunkCache.java b/src/main/java/net/tridentsdk/server/world/ChunkCache.java
index 8d57c70b..25ca4973 100644
--- a/src/main/java/net/tridentsdk/server/world/ChunkCache.java
+++ b/src/main/java/net/tridentsdk/server/world/ChunkCache.java
@@ -19,7 +19,7 @@
import com.google.common.collect.Lists;
import net.tridentsdk.concurrent.HeldValueLatch;
import net.tridentsdk.docs.AccessNoDoc;
-import net.tridentsdk.server.threads.TaskGroup;
+import net.tridentsdk.entity.types.EntityType;
import net.tridentsdk.server.threads.ThreadsHandler;
import net.tridentsdk.util.TridentLogger;
import net.tridentsdk.world.Chunk;
@@ -29,9 +29,10 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
@AccessNoDoc
-class ChunkCache {
+public class ChunkCache {
private final ConcurrentMap> cachedChunks = new ConcurrentHashMap<>();
private final TridentWorld world;
@@ -79,27 +80,38 @@ public TridentChunk get(ChunkLocation location, boolean gen) {
return (TridentChunk) chunk;
}
- public void retain(Set locations) {
- // Generate is much more appropriate thread pool
- // not only because it is used only for loading bytes
- // but because using the chunk executor interferes
- // with other tasks and might cause livelocks for no
- // reason
- TaskGroup.process(keys()).every(100).with(ThreadsHandler.saver()).using((loc) -> {
- HeldValueLatch chunk = cachedChunks.get(loc);
- TridentChunk rem;
- if (chunk != null && chunk.hasValue()) {
- rem = chunk.get();
- } else {
- // Remove the chunk once it is available
- return;
- }
+ public boolean tryRemove(ChunkLocation location) {
+ try {
+ return ThreadsHandler.genExecutor().submit(() -> {
+ HeldValueLatch chunk = cachedChunks.get(location);
+ if (chunk == null) {
+ return false;
+ }
- if (!locations.contains(loc) && chunk.hasValue()) {
- world.loader().saveChunk(rem);
- cachedChunks.remove(loc);
- }
- });
+ if (chunk.hasValue()) { // No value = needs to generate
+ Chunk c = chunk.get();
+ if (c.entities() // Ensure there are no players
+ .stream()
+ .filter(e -> e.type().equals(EntityType.PLAYER))
+ .count() == 0) {
+ remove(location);
+ c.unload();
+
+ return true;
+ }
+ }
+
+ return false;
+ }).get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+
+ public void remove(ChunkLocation location) {
+ cachedChunks.remove(location);
}
public Set keys() {
diff --git a/src/main/java/net/tridentsdk/server/world/TridentChunk.java b/src/main/java/net/tridentsdk/server/world/TridentChunk.java
index 291d5e91..8c2b6dd4 100755
--- a/src/main/java/net/tridentsdk/server/world/TridentChunk.java
+++ b/src/main/java/net/tridentsdk/server/world/TridentChunk.java
@@ -17,11 +17,14 @@
package net.tridentsdk.server.world;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import net.tridentsdk.Position;
import net.tridentsdk.base.Block;
import net.tridentsdk.base.Substance;
import net.tridentsdk.concurrent.TaskExecutor;
+import net.tridentsdk.entity.Entity;
+import net.tridentsdk.factory.Factories;
import net.tridentsdk.meta.nbt.*;
import net.tridentsdk.server.packets.play.out.PacketPlayOutChunkData;
import net.tridentsdk.server.threads.ThreadsHandler;
@@ -36,6 +39,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
@@ -43,6 +47,7 @@ public class TridentChunk implements Chunk {
private final TridentWorld world;
private final ChunkLocation location;
private final TaskExecutor executor = ThreadsHandler.chunkExecutor().scaledThread();
+ private final Set entities = Factories.collect().createSet();
public volatile ChunkSection[] sections;
private volatile int lastFileAccess;
private volatile long lastModified;
@@ -78,6 +83,15 @@ protected void setLastFileAccess(int last) {
this.lastFileAccess = last;
}
+ @Override
+ public Set entities() {
+ return ImmutableSet.copyOf(entities);
+ }
+
+ public Set entitiesInternal() {
+ return entities;
+ }
+
@Override
public void generate() {
executor.addTask(() -> {
@@ -306,6 +320,12 @@ public void load(CompoundTag root) {
this.inhabitedTime = inhabitedTime.value(); // Cumulative number of ticks player have been in the chunk
}
+ @Override
+ public void unload() {
+ world.loader().saveChunk(this);
+ world.loadedChunks.remove(location);
+ }
+
public CompoundTag asNbt() {
CompoundTag root = new CompoundTag("root");
CompoundTag level = new CompoundTag("Level");
diff --git a/src/main/java/net/tridentsdk/server/world/TridentChunkSnapshot.java b/src/main/java/net/tridentsdk/server/world/TridentChunkSnapshot.java
index b8ffe1c8..b00cc06c 100755
--- a/src/main/java/net/tridentsdk/server/world/TridentChunkSnapshot.java
+++ b/src/main/java/net/tridentsdk/server/world/TridentChunkSnapshot.java
@@ -18,6 +18,7 @@
package net.tridentsdk.server.world;
import net.tridentsdk.base.Block;
+import net.tridentsdk.entity.Entity;
import net.tridentsdk.meta.nbt.CompoundTag;
import net.tridentsdk.world.Chunk;
import net.tridentsdk.world.ChunkLocation;
@@ -25,6 +26,7 @@
import net.tridentsdk.world.World;
import java.util.List;
+import java.util.Set;
public class TridentChunkSnapshot implements ChunkSnapshot {
private final TridentWorld world;
@@ -59,6 +61,12 @@ public void load() {
// TODO
}
+ @Override
+ public Set entities() {
+ // TODO
+ return null;
+ }
+
@Override
public void generate() {
}
@@ -92,4 +100,9 @@ public Block blockAt(int relX, int y, int relZ) {
public ChunkSnapshot snapshot() {
return this;
}
+
+ @Override
+ public void unload() {
+ throw new UnsupportedOperationException("Cannot unload a snapshot");
+ }
}
diff --git a/src/main/java/net/tridentsdk/server/world/TridentWorld.java b/src/main/java/net/tridentsdk/server/world/TridentWorld.java
index 8b994281..afd46bab 100755
--- a/src/main/java/net/tridentsdk/server/world/TridentWorld.java
+++ b/src/main/java/net/tridentsdk/server/world/TridentWorld.java
@@ -19,7 +19,6 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
-import net.tridentsdk.Defaults;
import net.tridentsdk.Difficulty;
import net.tridentsdk.GameMode;
import net.tridentsdk.Position;
@@ -27,7 +26,6 @@
import net.tridentsdk.entity.Entity;
import net.tridentsdk.entity.Projectile;
import net.tridentsdk.entity.block.SlotProperties;
-import net.tridentsdk.entity.living.Player;
import net.tridentsdk.entity.living.ProjectileLauncher;
import net.tridentsdk.entity.traits.EntityProperties;
import net.tridentsdk.entity.types.EntityType;
@@ -257,7 +255,7 @@ public void tick() {
ThreadsHandler.worldExecutor().execute(() -> {
redstoneTick = !redstoneTick;
- if (time >= 2400)
+ if (time >= 24000)
time = 0;
if (time % 40 == 0)
TridentPlayer.sendAll(new PacketPlayOutTimeUpdate().set("worldAge", existed).set("time", time));
@@ -275,21 +273,9 @@ public void tick() {
thunderTime = ThreadLocalRandom.current().nextInt();
}
- // Complex idiom saves a bit of time on large iterations #nanobenchmarking
- if (time % Defaults.CHUNK_CLEAN_TICK_INTERVAL == 0) {
- Set retain = Factories.collect().createSet();
- for (Entity entity : entities) {
- ((TridentEntity) entity).tick();
- if (entity instanceof Player) {
- retain.addAll(((TridentPlayer) entity).cleanChunks());
- }
- }
- loadedChunks.retain(retain);
- } else {
- for (Entity entity : entities) {
- ((TridentEntity) entity).tick();
- }
+ for (Entity entity : entities) {
+ ((TridentEntity) entity).tick();
}
time++;
@@ -373,6 +359,15 @@ public Entity addEntity(Entity entity) {
public void removeEntity(Entity entity) {
this.entities.remove(entity);
+
+ TridentChunk c = (TridentChunk) entity.position().chunk();
+ if (!c.entitiesInternal().remove(entity)) {
+ for (Chunk chunk : loadedChunks.values()) {
+ // If we don't do this a simple concurrency miss
+ // can lead to a memory leak
+ if (((TridentChunk) chunk).entitiesInternal().remove(entity)) return;
+ }
+ }
}
@Override