First implementation of dynamic chunk loading. Super buggy, WIP
This commit is contained in:
parent
eaea6fdad9
commit
cde854346c
@ -107,15 +107,15 @@ implements GenericChunk<
|
||||
return data;
|
||||
}
|
||||
|
||||
public void markForUpdate() {
|
||||
public synchronized void markForUpdate() {
|
||||
this.needsUpdate = true;
|
||||
}
|
||||
|
||||
public boolean needsUpdate() {
|
||||
public synchronized boolean needsUpdate() {
|
||||
return needsUpdate;
|
||||
}
|
||||
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
public synchronized void render(ShapeRenderHelper renderer) {
|
||||
if (model == null || needsUpdate()) {
|
||||
buildModel();
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ implements GenericWorld<
|
||||
|
||||
private final WorldData data;
|
||||
|
||||
private final Map<ChunkData, ChunkRender> chunks = new HashMap<>();
|
||||
private final Map<ChunkData, ChunkRender> chunks =
|
||||
Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<EntityData, EntityRenderable> entityModels =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
@ -94,23 +95,18 @@ implements GenericWorld<
|
||||
}
|
||||
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.render(renderer);
|
||||
}
|
||||
|
||||
getChunks().forEach(chunk -> chunk.render(renderer));
|
||||
renderEntities(renderer);
|
||||
}
|
||||
|
||||
private void renderEntities(ShapeRenderHelper renderer) {
|
||||
FaceCulling.push(false);
|
||||
|
||||
for (ChunkRender chunk : getChunks()) {
|
||||
chunk.getData().forEachEntity(entity -> {
|
||||
getData().forEachEntity(entity -> {
|
||||
renderer.pushTransform().translate(entity.getPosition());
|
||||
getEntityRenderable(entity).render(renderer);
|
||||
renderer.popTransform();
|
||||
});
|
||||
}
|
||||
|
||||
FaceCulling.pop();
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package ru.windcorp.progressia.common.world;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
|
||||
public class PacketRevokeChunk extends PacketChunkChange {
|
||||
|
||||
private final Vec3i position = new Vec3i();
|
||||
|
||||
public PacketRevokeChunk() {
|
||||
this("Core:RevokeChunk");
|
||||
}
|
||||
|
||||
protected PacketRevokeChunk(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public void set(Vec3i chunkPos) {
|
||||
this.position.set(chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput input) throws IOException {
|
||||
this.position.set(input.readInt(), input.readInt(), input.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput output) throws IOException {
|
||||
output.writeInt(this.position.x);
|
||||
output.writeInt(this.position.y);
|
||||
output.writeInt(this.position.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(WorldData world) {
|
||||
synchronized (world) {
|
||||
ChunkData chunk = world.getChunk(position);
|
||||
if (chunk != null) {
|
||||
world.removeChunk(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAffectedChunk(Vec3i output) {
|
||||
output.set(getPosition().x, getPosition().y, getPosition().z);
|
||||
}
|
||||
|
||||
public Vec3i getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
@ -9,12 +9,16 @@ import ru.windcorp.progressia.common.io.ChunkIO;
|
||||
import ru.windcorp.progressia.common.util.DataBuffer;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
|
||||
public class PacketLoadChunk extends PacketChunkChange {
|
||||
public class PacketSendChunk extends PacketChunkChange {
|
||||
|
||||
private final DataBuffer data = new DataBuffer();
|
||||
private final Vec3i position = new Vec3i();
|
||||
|
||||
public PacketLoadChunk(String id) {
|
||||
public PacketSendChunk() {
|
||||
this("Core:SendChunk");
|
||||
}
|
||||
|
||||
protected PacketSendChunk(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ implements GenericWorld<
|
||||
TileDataStack,
|
||||
ChunkData,
|
||||
EntityData
|
||||
>{
|
||||
> {
|
||||
|
||||
private final ChunkMap<ChunkData> chunksByPos = new LongBasedChunkMap<>(
|
||||
new TSynchronizedLongObjectMap<>(new TLongObjectHashMap<>(), this)
|
||||
@ -87,7 +87,7 @@ implements GenericWorld<
|
||||
}
|
||||
|
||||
public void tmp_generate() {
|
||||
final int size = 10;
|
||||
final int size = 1;
|
||||
Vec3i cursor = new Vec3i(0, 0, 0);
|
||||
|
||||
for (cursor.x = -(size / 2); cursor.x <= (size / 2); ++cursor.x) {
|
||||
|
@ -0,0 +1,22 @@
|
||||
package ru.windcorp.progressia.common.world.generic;
|
||||
|
||||
import gnu.trove.impl.sync.TSynchronizedLongSet;
|
||||
import gnu.trove.set.hash.TLongHashSet;
|
||||
|
||||
public class ChunkSets {
|
||||
|
||||
public static ChunkSet newHashSet() {
|
||||
return new LongBasedChunkSet(new TLongHashSet());
|
||||
}
|
||||
|
||||
public static ChunkSet newSyncHashSet(Object mutex) {
|
||||
return new LongBasedChunkSet(new TSynchronizedLongSet(new TLongHashSet(), mutex));
|
||||
}
|
||||
|
||||
public static ChunkSet newSyncHashSet() {
|
||||
return new LongBasedChunkSet(new TSynchronizedLongSet(new TLongHashSet()));
|
||||
}
|
||||
|
||||
private ChunkSets() {}
|
||||
|
||||
}
|
@ -118,8 +118,10 @@ public interface GenericWorld<
|
||||
*/
|
||||
|
||||
default void forEachEntity(Consumer<? super E> action) {
|
||||
synchronized (this) { // TODO HORRIBLY MUTILATE THE CORPSE OF TROVE4J so that gnu.trove.impl.sync.SynchronizedCollection.forEach is synchronized
|
||||
getEntities().forEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
default void forEachEntityIn(Vec3i min, Vec3i max, Consumer<? super E> action) {
|
||||
forEachEntity(e -> {
|
||||
|
@ -1,83 +0,0 @@
|
||||
package ru.windcorp.progressia.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import gnu.trove.set.hash.TLongHashSet;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.generic.ChunkSet;
|
||||
import ru.windcorp.progressia.common.world.generic.LongBasedChunkSet;
|
||||
import ru.windcorp.progressia.test.TestContent;
|
||||
|
||||
public class ChunkLoadManager {
|
||||
|
||||
private final Server server;
|
||||
|
||||
private final Collection<Collection<? extends ChunkLoader>> allChunkLoaders =
|
||||
Collections.synchronizedCollection(new ArrayList<>());
|
||||
|
||||
private final ChunkSet requested = new LongBasedChunkSet(new TLongHashSet());
|
||||
private final ChunkSet toLoad = new LongBasedChunkSet(new TLongHashSet());
|
||||
private final ChunkSet toUnload = new LongBasedChunkSet(new TLongHashSet());
|
||||
|
||||
public ChunkLoadManager(Server server) {
|
||||
this.server = server;
|
||||
allChunkLoaders.add(server.getPlayerManager().getPlayers());
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
gatherRequests();
|
||||
updateQueues();
|
||||
processQueues();
|
||||
}
|
||||
|
||||
private void gatherRequests() {
|
||||
requested.clear();
|
||||
|
||||
allChunkLoaders.forEach(collection -> {
|
||||
collection.forEach(this::gatherRequests);
|
||||
});
|
||||
}
|
||||
|
||||
private void gatherRequests(ChunkLoader loader) {
|
||||
loader.requestChunksToLoad(requested::add);
|
||||
}
|
||||
|
||||
private void updateQueues() {
|
||||
ChunkSet loaded = getServer().getWorld().getData().getLoadedChunks();
|
||||
|
||||
toLoad.clear();
|
||||
toLoad.addAll(requested);
|
||||
toLoad.removeAll(loaded);
|
||||
|
||||
toUnload.clear();
|
||||
toUnload.addAll(loaded);
|
||||
toUnload.removeAll(requested);
|
||||
}
|
||||
|
||||
private void processQueues() {
|
||||
toUnload.forEach(this::unloadChunk);
|
||||
toLoad.forEach(this::loadChunk);
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void loadChunk(Vec3i pos) {
|
||||
|
||||
ChunkData chunk = new ChunkData(pos, getServer().getWorld().getData());
|
||||
TestContent.generateChunk(chunk);
|
||||
getServer().getWorld().getData().addChunk(chunk);
|
||||
|
||||
}
|
||||
|
||||
public void unloadChunk(Vec3i pos) {
|
||||
|
||||
getServer().getWorld().getData().removeChunk(getServer().getWorld().getData().getChunk(pos));
|
||||
|
||||
}
|
||||
|
||||
}
|
180
src/main/java/ru/windcorp/progressia/server/ChunkManager.java
Normal file
180
src/main/java/ru/windcorp/progressia/server/ChunkManager.java
Normal file
@ -0,0 +1,180 @@
|
||||
package ru.windcorp.progressia.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.generic.ChunkSet;
|
||||
import ru.windcorp.progressia.common.world.generic.ChunkSets;
|
||||
import ru.windcorp.progressia.test.TestChunkSender;
|
||||
import ru.windcorp.progressia.test.TestContent;
|
||||
|
||||
public class ChunkManager {
|
||||
|
||||
private class PlayerVision {
|
||||
|
||||
private final ChunkSet visible = ChunkSets.newSyncHashSet();
|
||||
private final ChunkSet requested = ChunkSets.newHashSet();
|
||||
private final ChunkSet toSend = ChunkSets.newHashSet();
|
||||
private final ChunkSet toRevoke = ChunkSets.newHashSet();
|
||||
|
||||
public boolean isChunkVisible(Vec3i chunkPos) {
|
||||
return visible.contains(chunkPos);
|
||||
}
|
||||
|
||||
public void gatherRequests(Player player) {
|
||||
requested.clear();
|
||||
player.requestChunksToLoad(requested::add);
|
||||
}
|
||||
|
||||
public void updateQueues(Player player) {
|
||||
toSend.clear();
|
||||
toSend.addAll(requested);
|
||||
toSend.removeAll(visible);
|
||||
toSend.retainAll(loaded);
|
||||
|
||||
toRevoke.clear();
|
||||
toRevoke.addAll(visible);
|
||||
toRevoke.removeIf(v -> loaded.contains(v) && requested.contains(v));
|
||||
}
|
||||
|
||||
public void processQueues(Player player) {
|
||||
toRevoke.forEach(chunkPos -> revokeChunk(player, chunkPos));
|
||||
toRevoke.clear();
|
||||
|
||||
toSend.forEach(chunkPos -> sendChunk(player, chunkPos));
|
||||
toSend.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Server server;
|
||||
|
||||
private final ChunkSet loaded;
|
||||
private final ChunkSet requested = ChunkSets.newHashSet();
|
||||
private final ChunkSet toLoad = ChunkSets.newHashSet();
|
||||
private final ChunkSet toUnload = ChunkSets.newHashSet();
|
||||
|
||||
// TODO replace with a normal Map managed by some sort of PlayerListener, weak maps are weak
|
||||
private final Map<Player, PlayerVision> visions = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public ChunkManager(Server server) {
|
||||
this.server = server;
|
||||
this.loaded = server.getWorld().getData().getLoadedChunks();
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
synchronized (getServer().getWorld().getData()) {
|
||||
synchronized (visions) {
|
||||
gatherRequests();
|
||||
updateQueues();
|
||||
processQueues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void gatherRequests() {
|
||||
requested.clear();
|
||||
|
||||
server.getPlayerManager().getPlayers().forEach(p -> {
|
||||
PlayerVision vision = getVision(p, true);
|
||||
vision.gatherRequests(p);
|
||||
requested.addAll(vision.requested);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateQueues() {
|
||||
toLoad.clear();
|
||||
toLoad.addAll(requested);
|
||||
toLoad.removeAll(loaded);
|
||||
|
||||
toUnload.clear();
|
||||
toUnload.addAll(loaded);
|
||||
toUnload.removeAll(requested);
|
||||
|
||||
visions.forEach((p, v) -> {
|
||||
v.updateQueues(p);
|
||||
});
|
||||
}
|
||||
|
||||
private void processQueues() {
|
||||
toUnload.forEach(this::unloadChunk);
|
||||
toUnload.clear();
|
||||
toLoad.forEach(this::loadChunk);
|
||||
toLoad.clear();
|
||||
|
||||
visions.forEach((p, v) -> {
|
||||
v.processQueues(p);
|
||||
});
|
||||
}
|
||||
|
||||
private PlayerVision getVision(Player player, boolean createIfMissing) {
|
||||
return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player);
|
||||
}
|
||||
|
||||
public void loadChunk(Vec3i chunkPos) {
|
||||
|
||||
LogManager.getLogger().info("Loading {} {} {}", chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
|
||||
WorldData world = getServer().getWorld().getData();
|
||||
|
||||
ChunkData chunk = new ChunkData(chunkPos, world);
|
||||
TestContent.generateChunk(chunk);
|
||||
world.addChunk(chunk);
|
||||
|
||||
}
|
||||
|
||||
public void unloadChunk(Vec3i chunkPos) {
|
||||
|
||||
LogManager.getLogger().info("Unloading {} {} {}", chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
|
||||
WorldData world = getServer().getWorld().getData();
|
||||
|
||||
ChunkData chunk = world.getChunk(chunkPos);
|
||||
if (chunk == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Chunk (%d; %d; %d) not loaded, cannot unload",
|
||||
chunkPos.x, chunkPos.y, chunkPos.z
|
||||
));
|
||||
}
|
||||
world.removeChunk(chunk);
|
||||
|
||||
}
|
||||
|
||||
public void sendChunk(Player player, Vec3i chunkPos) {
|
||||
LogManager.getLogger().info("Sending {} {} {}", chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
TestChunkSender.sendChunk(server, player.getClient(), chunkPos);
|
||||
|
||||
getVision(player, true).visible.add(chunkPos);
|
||||
}
|
||||
|
||||
public void revokeChunk(Player player, Vec3i chunkPos) {
|
||||
LogManager.getLogger().info("Revoking {} {} {}", chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
TestChunkSender.revokeChunk(player.getClient(), chunkPos);
|
||||
|
||||
PlayerVision vision = getVision(player, false);
|
||||
if (vision != null) {
|
||||
vision.visible.remove(chunkPos);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isChunkVisible(Vec3i chunkPos, Player player) {
|
||||
PlayerVision vision = getVision(player, false);
|
||||
|
||||
if (vision == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return vision.isChunkVisible(chunkPos);
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,8 @@ public class Player extends PlayerData implements ChunkLoader {
|
||||
super(entity);
|
||||
this.server = server;
|
||||
this.client = client;
|
||||
|
||||
client.setPlayer(this);
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
@ -43,6 +45,7 @@ public class Player extends PlayerData implements ChunkLoader {
|
||||
for (cursor.y = -iRadius; cursor.y <= +iRadius; ++cursor.y) {
|
||||
for (cursor.z = -iRadius; cursor.z <= +iRadius; ++cursor.z) {
|
||||
if (cursor.x * cursor.x + cursor.y * cursor.y + cursor.z * cursor.z <= radius) {
|
||||
|
||||
cursor.add(start);
|
||||
chunkConsumer.accept(cursor);
|
||||
cursor.sub(start);
|
||||
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.test.TestContent;
|
||||
@ -29,7 +31,13 @@ public class PlayerManager {
|
||||
public EntityData conjurePlayerEntity(String login) {
|
||||
// TODO Live up to the name
|
||||
if (TestContent.PLAYER_LOGIN.equals(login)) {
|
||||
// TODO load appropriate chunks
|
||||
|
||||
Vec3i chunkPos = Vectors.ZERO_3i;
|
||||
|
||||
if (getServer().getWorld().getChunk(chunkPos) == null) {
|
||||
getServer().getChunkManager().loadChunk(chunkPos);
|
||||
}
|
||||
|
||||
return getServer().getWorld().getData().getEntity(TestContent.PLAYER_ENTITY_ID);
|
||||
} else {
|
||||
CrashReports.report(null, "Unknown login %s, javahorse stupid", login);
|
||||
|
@ -29,8 +29,9 @@ public class Server {
|
||||
|
||||
private final ServerThread serverThread;
|
||||
|
||||
private final ClientManager clientManager = new ClientManager(this);
|
||||
private final PlayerManager playerManager = new PlayerManager(this);
|
||||
private final ClientManager clientManager;
|
||||
private final PlayerManager playerManager;
|
||||
private final ChunkManager chunkManager;
|
||||
|
||||
private final TaskQueue taskQueue = new TaskQueue(this::isServerThread);
|
||||
|
||||
@ -40,7 +41,12 @@ public class Server {
|
||||
this.world = new WorldLogic(world, this);
|
||||
this.serverThread = new ServerThread(this);
|
||||
|
||||
this.clientManager = new ClientManager(this);
|
||||
this.playerManager = new PlayerManager(this);
|
||||
this.chunkManager = new ChunkManager(this);
|
||||
|
||||
schedule(this::scheduleChunkTicks);
|
||||
schedule(chunkManager::tick);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,6 +70,10 @@ public class Server {
|
||||
return playerManager;
|
||||
}
|
||||
|
||||
public ChunkManager getChunkManager() {
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this thread is the main thread of this server.
|
||||
* @return {@code true} iff the invocation occurs in server main thread
|
||||
@ -160,7 +170,7 @@ public class Server {
|
||||
}
|
||||
|
||||
public float getLoadDistance(Player player) {
|
||||
return Units.get(100.0f, "m");
|
||||
return Units.get(10.0f, "m");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ru.windcorp.progressia.server.comms;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -11,10 +10,6 @@ import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import ru.windcorp.progressia.common.comms.CommsChannel.State;
|
||||
import ru.windcorp.progressia.common.comms.packets.Packet;
|
||||
import ru.windcorp.progressia.common.io.ChunkIO;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.PacketLoadChunk;
|
||||
import ru.windcorp.progressia.common.world.PacketSetLocalPlayer;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.server.Player;
|
||||
@ -62,30 +57,16 @@ public class ClientManager {
|
||||
|
||||
private void addClientPlayer(ClientPlayer client) {
|
||||
String login = client.getLogin();
|
||||
EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login);
|
||||
|
||||
EntityData entity;
|
||||
synchronized (getServer().getWorld().getData()) {
|
||||
entity = getServer().getPlayerManager().conjurePlayerEntity(login);
|
||||
|
||||
Player player = new Player(entity, getServer(), client);
|
||||
|
||||
getServer().getPlayerManager().getPlayers().add(player);
|
||||
|
||||
for (ChunkData chunk : server.getWorld().getData().getChunks()) {
|
||||
if (!client.canSeeChunk(chunk.getPosition())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PacketLoadChunk packet = new PacketLoadChunk("Core:LoadChunk");
|
||||
packet.getPosition().set(
|
||||
chunk.getPosition().x,
|
||||
chunk.getPosition().y,
|
||||
chunk.getPosition().z
|
||||
);
|
||||
|
||||
try {
|
||||
ChunkIO.save(chunk, packet.getData().getOutputStream());
|
||||
} catch (IOException e) {
|
||||
CrashReports.report(e, "ClientManager fjcked up. javahorse stupid");
|
||||
}
|
||||
client.sendPacket(packet);
|
||||
getServer().getChunkManager().sendChunk(player, entity.getChunkCoords(null));
|
||||
}
|
||||
|
||||
PacketSetLocalPlayer packet = new PacketSetLocalPlayer();
|
||||
@ -119,7 +100,7 @@ public class ClientManager {
|
||||
getClients().forEach(c -> {
|
||||
if (c.getState() != State.CONNECTED) return;
|
||||
if (!(c instanceof ClientPlayer)) return;
|
||||
if (!((ClientPlayer) c).canSeeChunk(chunkPos)) return;
|
||||
if (!((ClientPlayer) c).isChunkVisible(chunkPos)) return;
|
||||
c.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
@ -133,7 +114,7 @@ public class ClientManager {
|
||||
getClients().forEach(c -> {
|
||||
if (c.getState() != State.CONNECTED) return;
|
||||
if (!(c instanceof ClientPlayer)) return;
|
||||
if (!((ClientPlayer) c).canSeeEntity(entityId)) return;
|
||||
if (!((ClientPlayer) c).isChunkVisible(entityId)) return;
|
||||
c.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
|
@ -1,20 +1,32 @@
|
||||
package ru.windcorp.progressia.server.comms;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.server.Player;
|
||||
|
||||
public abstract class ClientPlayer extends Client {
|
||||
public abstract class ClientPlayer extends ClientChat {
|
||||
|
||||
private Player player;
|
||||
|
||||
public ClientPlayer(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public abstract String getLogin();
|
||||
|
||||
public boolean canSeeChunk(Vec3i chunkPos) {
|
||||
return true;
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public boolean canSeeEntity(long entityId) {
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public abstract String getLogin();
|
||||
|
||||
public boolean isChunkVisible(Vec3i chunkPos) {
|
||||
if (player == null) return false;
|
||||
return player.getServer().getChunkManager().isChunkVisible(chunkPos, player);
|
||||
}
|
||||
|
||||
public boolean isChunkVisible(long entityId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogic;
|
||||
import ru.windcorp.progressia.server.world.tile.TileLogicStack;
|
||||
import ru.windcorp.progressia.test.TestChunkSender;
|
||||
|
||||
public class WorldLogic
|
||||
implements GenericWorld<
|
||||
@ -48,7 +47,6 @@ implements GenericWorld<
|
||||
});
|
||||
|
||||
data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server)));
|
||||
data.addListener(new TestChunkSender(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,34 +2,29 @@ package ru.windcorp.progressia.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.io.ChunkIO;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.world.ChunkData;
|
||||
import ru.windcorp.progressia.common.world.PacketLoadChunk;
|
||||
import ru.windcorp.progressia.common.world.PacketSetLocalPlayer;
|
||||
import ru.windcorp.progressia.common.world.WorldData;
|
||||
import ru.windcorp.progressia.common.world.WorldDataListener;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.PacketRevokeChunk;
|
||||
import ru.windcorp.progressia.common.world.PacketSendChunk;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.comms.ClientPlayer;
|
||||
|
||||
public class TestChunkSender implements WorldDataListener {
|
||||
public class TestChunkSender {
|
||||
|
||||
private final Server server;
|
||||
public static void sendChunk(Server server, ClientPlayer receiver, Vec3i chunkPos) {
|
||||
ChunkData chunk = server.getWorld().getData().getChunk(chunkPos);
|
||||
|
||||
public TestChunkSender(Server server) {
|
||||
this.server = server;
|
||||
if (chunk == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Chunk (%d; %d; %d) is not loaded, cannot send",
|
||||
chunkPos.x, chunkPos.y, chunkPos.z
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkLoaded(WorldData world, ChunkData chunk) {
|
||||
PacketLoadChunk packet = new PacketLoadChunk("Core:LoadChunk");
|
||||
|
||||
packet.getPosition().set(
|
||||
chunk.getPosition().x,
|
||||
chunk.getPosition().y,
|
||||
chunk.getPosition().z
|
||||
);
|
||||
PacketSendChunk packet = new PacketSendChunk();
|
||||
packet.getPosition().set(chunkPos.x, chunkPos.y, chunkPos.z);
|
||||
|
||||
try {
|
||||
ChunkIO.save(chunk, packet.getData().getOutputStream());
|
||||
@ -37,22 +32,13 @@ public class TestChunkSender implements WorldDataListener {
|
||||
CrashReports.report(e, "TestChunkSender fjcked up. javahorse stupid");
|
||||
}
|
||||
|
||||
server.getClientManager().broadcastLocal(packet, chunk.getPosition());
|
||||
|
||||
tmp_sendPlayerIfPossible(world, chunk);
|
||||
receiver.sendPacket(packet);
|
||||
}
|
||||
|
||||
private void tmp_sendPlayerIfPossible(WorldData world, ChunkData chunk) {
|
||||
EntityData e = world.getEntity(TestContent.PLAYER_ENTITY_ID);
|
||||
if (e == null) return;
|
||||
|
||||
if (Glm.equals(e.getChunkCoords(null), chunk.getPosition())) {
|
||||
System.out.printf("TestChunkSender: player found in (%d; %d; %d)\n", e.getChunkCoords(null).x, e.getChunkCoords(null).y, e.getChunkCoords(null).z);
|
||||
|
||||
PacketSetLocalPlayer packet = new PacketSetLocalPlayer();
|
||||
packet.set(e.getEntityId());
|
||||
server.getClientManager().broadcastToAllPlayers(packet);
|
||||
}
|
||||
public static void revokeChunk(ClientPlayer receiver, Vec3i chunkPos) {
|
||||
PacketRevokeChunk packet = new PacketRevokeChunk();
|
||||
packet.set(chunkPos);
|
||||
receiver.sendPacket(packet);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -346,10 +346,10 @@ public class TestContent {
|
||||
));
|
||||
chunk.getEntities().add(player);
|
||||
|
||||
EntityData statie = EntityDataRegistry.getInstance().create("Test:Statie");
|
||||
statie.setEntityId(STATIE_ENTITY_ID);
|
||||
statie.setPosition(new Vec3(0, 15, 16));
|
||||
chunk.getEntities().add(statie);
|
||||
// EntityData statie = EntityDataRegistry.getInstance().create("Test:Statie");
|
||||
// statie.setEntityId(STATIE_ENTITY_ID);
|
||||
// statie.setPosition(new Vec3(0, 15, 16));
|
||||
// chunk.getEntities().add(statie);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||
import ru.windcorp.progressia.common.Units;
|
||||
import ru.windcorp.progressia.common.util.FloatMathUtils;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
|
||||
public class TestPlayerControls {
|
||||
|
||||
@ -96,6 +97,13 @@ public class TestPlayerControls {
|
||||
}
|
||||
|
||||
player.getVelocity().set(change);
|
||||
|
||||
// THIS IS TERRIBLE TEST
|
||||
EntityData serverEntity = ServerState.getInstance().getWorld().getData().getEntity(TestContent.PLAYER_ENTITY_ID);
|
||||
if (serverEntity != null) {
|
||||
serverEntity.setPosition(player.getPosition());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void handleInput(Input input) {
|
||||
|
Reference in New Issue
Block a user