private void sendModules(List<NetData.ModuleRequest> moduleRequestList) { for (NetData.ModuleRequest request : moduleRequestList) { NetData.ModuleDataHeader.Builder result = NetData.ModuleDataHeader.newBuilder(); result.setId(request.getModuleId()); Module module = moduleManager.getEnvironment().get(new Name(request.getModuleId())); if (module.isOnClasspath() || module.getLocations().size() != 1 || !Files.isReadable(module.getLocations().get(0))) { result.setError("Module not available for download"); } else { Path location = module.getLocations().get(0); try { result.setVersion(module.getVersion().toString()); result.setSize(Files.size(location)); channelHandlerContext .getChannel() .write(NetData.NetMessage.newBuilder().setModuleDataHeader(result).build()); } catch (IOException e) { logger.error("Error sending module data header", e); channelHandlerContext.getChannel().close(); break; } try (InputStream stream = new BufferedInputStream(Files.newInputStream(location))) { long remainingData = Files.size(location); byte[] data = new byte[1024]; while (remainingData > 0) { int nextBlock = (int) Math.min(remainingData, 1024); ByteStreams.read(stream, data, 0, nextBlock); channelHandlerContext .getChannel() .write( NetData.NetMessage.newBuilder() .setModuleData( NetData.ModuleData.newBuilder() .setModule(ByteString.copyFrom(data, 0, nextBlock))) .build()); remainingData -= nextBlock; } } catch (IOException e) { logger.error("Error sending module", e); channelHandlerContext.getChannel().close(); break; } } } }
private void processInvalidatedChunks(NetData.NetMessage message) { for (NetData.InvalidateChunkMessage chunk : message.getInvalidateChunkList()) { Vector3i chunkPos = NetMessageUtil.convert(chunk.getPos()); remoteWorldProvider.invalidateChunks(chunkPos); awaitingChunkReadyBlockUpdates.removeAll(chunkPos); awaitingChunkReadyBiomeUpdates.removeAll(chunkPos); } }
private void processRemoveEntities(NetData.NetMessage message) { for (NetData.RemoveEntityMessage removeEntity : message.getRemoveEntityList()) { int netId = removeEntity.getNetId(); EntityRef entity = networkSystem.getEntity(netId); if (entity.exists()) { logger.info("Destroying entity: {}", entity); entity.destroy(); networkSystem.unregisterClientNetworkEntity(netId); } } }
@Override public void update(boolean netTick) { processReceivedChunks(); if (entityManager != null) { if (netTick) { NetData.NetMessage.Builder message = NetData.NetMessage.newBuilder(); message.setTime(time.getGameTimeInMs()); sendEntities(message); sendEvents(message); send(message.build()); } else if (!queuedOutgoingEvents.isEmpty()) { NetData.NetMessage.Builder message = NetData.NetMessage.newBuilder(); message.setTime(time.getGameTimeInMs()); sendEvents(message); send(message.build()); } processMessages(); } }
private void processMessages() { List<NetData.NetMessage> messages = Lists.newArrayListWithExpectedSize(queuedMessages.size()); queuedMessages.drainTo(messages); for (NetData.NetMessage message : messages) { if (message.hasTime()) { time.updateTimeFromServer(message.getTime()); } processBlockRegistrations(message); processReceivedChunks(message); processInvalidatedChunks(message); processBlockChanges(message); processBiomeChanges(message); processRemoveEntities(message); for (NetData.CreateEntityMessage createEntity : message.getCreateEntityList()) { createEntityMessage(createEntity); } for (NetData.UpdateEntityMessage updateEntity : message.getUpdateEntityList()) { updateEntity(updateEntity); } for (NetData.EventMessage event : message.getEventList()) { try { processEvent(event); } catch (RuntimeException e) { logger.error("Error processing server event", e); } } } }
private void processBlockChanges(NetData.NetMessage message) { for (NetData.BlockChangeMessage blockChange : message.getBlockChangeList()) { Block newBlock = blockManager.getBlock((short) blockChange.getNewBlock()); logger.debug("Received block change to {}", newBlock); // TODO: Store changes to blocks that aren't ready to be modified (the surrounding chunks // aren't available) WorldProvider worldProvider = CoreRegistry.get(WorldProvider.class); Vector3i pos = NetMessageUtil.convert(blockChange.getPos()); if (worldProvider.isBlockRelevant(pos)) { worldProvider.setBlock(pos, newBlock); } else { awaitingChunkReadyBlockUpdates.put(ChunkMath.calcChunkPos(pos), blockChange); } } }
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { NetData.NetMessage message = (NetData.NetMessage) e.getMessage(); if (message.hasServerInfoRequest()) { NetData.ServerInfoMessage serverInfo = networkSystem.getServerInfoMessage(); ctx.getChannel() .write( NetData.NetMessage.newBuilder() .setServerInfo(serverInfo) .setTime(serverInfo.getTime()) .build()); } else if (message.hasJoin()) { receivedConnect(message.getJoin()); } else if (message.getModuleRequestCount() > 0) { sendModules(message.getModuleRequestList()); } else { logger.error("Received unexpected message"); } }
private void processBlockRegistrations(NetData.NetMessage message) { for (NetData.BlockFamilyRegisteredMessage blockFamily : message.getBlockFamilyRegisteredList()) { if (blockFamily.getBlockIdCount() != blockFamily.getBlockUriCount()) { logger.error("Received block registration with mismatched id<->uri mapping"); } else if (blockFamily.getBlockUriCount() == 0) { logger.error("Received empty block registration"); } else { try { BlockUri family = new BlockUri(blockFamily.getBlockUri(0)).getFamilyUri(); Map<String, Integer> registrationMap = Maps.newHashMap(); for (int i = 0; i < blockFamily.getBlockIdCount(); ++i) { registrationMap.put(blockFamily.getBlockUri(i), blockFamily.getBlockId(i)); } blockManager.receiveFamilyRegistration(family, registrationMap); } catch (BlockUriParseException e) { logger.error("Received invalid block uri", blockFamily.getBlockUri(0)); } } } }
private void processReceivedChunks(NetData.NetMessage message) { for (EntityData.ChunkStore chunkInfo : message.getChunkInfoList()) { Chunk chunk = ChunkSerializer.decode(chunkInfo, blockManager, biomeManager); chunkQueue.offer(chunk); } }
private void send(NetData.NetMessage data) { logger.trace("Sending with size {}", data.getSerializedSize()); channel.write(data); }