package net.CyanWool.entity.player; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.UUID; import net.CyanWool.CyanServer; import net.CyanWool.Transform; import net.CyanWool.api.Server; import net.CyanWool.api.entity.Entity; import net.CyanWool.api.entity.EntityType; import net.CyanWool.api.entity.component.DisplayNameComponent; import net.CyanWool.api.entity.player.Player; import net.CyanWool.api.network.PlayerNetwork; import net.CyanWool.api.world.Chunk; import net.CyanWool.api.world.ChunkCoords; import net.CyanWool.api.world.Location; import net.CyanWool.entity.CyanEntity; import net.CyanWool.entity.meta.ClientSettings; import net.CyanWool.entity.meta.CyanMetadataMap; import net.CyanWool.world.CyanChunk; import org.spacehq.mc.auth.GameProfile; import org.spacehq.mc.protocol.data.game.EntityMetadata; import org.spacehq.mc.protocol.data.game.Position; import org.spacehq.mc.protocol.data.game.values.entity.player.GameMode; import org.spacehq.mc.protocol.data.game.values.world.CustomSound; import org.spacehq.mc.protocol.data.game.values.world.Particle; import org.spacehq.mc.protocol.data.game.values.world.Sound; import org.spacehq.mc.protocol.data.game.values.world.WorldType; import org.spacehq.mc.protocol.data.game.values.world.effect.WorldEffect; import org.spacehq.mc.protocol.data.game.values.world.effect.WorldEffectData; import org.spacehq.mc.protocol.data.game.values.world.notify.ClientNotification; import org.spacehq.mc.protocol.packet.ingame.server.ServerChatPacket; import org.spacehq.mc.protocol.packet.ingame.server.ServerRespawnPacket; import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerDestroyEntitiesPacket; import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket; import org.spacehq.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket; import org.spacehq.mc.protocol.packet.ingame.server.entity.player.ServerUpdateHealthPacket; import org.spacehq.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerChunkDataPacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerPlaySoundPacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket; import org.spacehq.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; import org.spacehq.opennbt.tag.builtin.ByteTag; import org.spacehq.opennbt.tag.builtin.CompoundTag; import org.spacehq.opennbt.tag.builtin.FloatTag; import org.spacehq.opennbt.tag.builtin.IntTag; import org.spacehq.opennbt.tag.builtin.ShortTag; import org.spacehq.packetlib.packet.Packet; public class CyanPlayer extends CyanHuman implements Player { private CyanServer server; private PlayerNetwork connection; private List<Entity> knowEntities; private List<ChunkCoords> chunks; private ClientSettings settings; private CompoundTag compTag; public CyanPlayer(CyanServer server, GameProfile profile, Location location) { super(profile, location); super.setGamemode(GameMode.SURVIVAL); this.server = server; this.knowEntities = new ArrayList<Entity>(); this.chunks = new ArrayList<ChunkCoords>(); setSettings(ClientSettings.getDEFAULT()); ((DisplayNameComponent) getComponentManager().getComponent("displayName")).setDisplayName(profile.getName()); ((DisplayNameComponent) getComponentManager().getComponent("displayName")).setRenderDisplayName(true); // updateChunks(); } @Override public void kickPlayer(String message) { getPlayerNetwork().disconnect(message); } @Override public UUID getUniqueId() { return getGameProfile().getId(); } @Override public boolean isOp() { return false; } @Override public void setOp(boolean flag) { // TODO Auto-generated method stub } @Override public void executeCommand(String commandName) { getServer().getCommandManager().dispatchCommand(this, "/" + commandName); } @Override public void chat(String message) { String name = "UNKNOWN"; if (getComponentManager().hasComponent("displayName")) { name = ((DisplayNameComponent) getComponentManager().getComponent("displayName")).getDisplayName(); } String format = name + ": " + message; // TODO Event's ServerChatPacket packet = new ServerChatPacket(format); // getPlayerNetwork().sendPacket(packet); for (Player player : getWorld().getPlayers()) { ((CyanPlayer) player).getPlayerNetwork().sendPacket(packet); } server.getConsoleCommandSender().sendMessage(format); } @Override public boolean isBanned() { // TODO Auto-generated method stub return false; } @Override public void setBanned(boolean banned) { // TODO Auto-generated method stub } @Override public boolean isWhitelisted() { // TODO Auto-generated method stub return false; } @Override public void setWhitelisted(boolean whitelisted) { // TODO Auto-generated method stub } // @Override // public void displayGUI(InventoryType type) { // TODO Auto-generated method stub // } @Override public void onTick() { super.onTick(); // Chunks updateChunks(); updatePosition(); // Send change metadata's if (((CyanMetadataMap) metadata).getChanges() != null) { EntityMetadata[] changes = ((CyanMetadataMap) metadata).getChanges(); if (changes != null && changes.length > 0) { getPlayerNetwork().sendPacket(new ServerEntityMetadataPacket(getEntityID(), changes)); } } // Entities List<Entity> list = new ArrayList<Entity>(); List<Integer> destroy = new ArrayList<Integer>(); // Collect visible entities... Iterator<Entity> it = knowEntities.iterator(); while (it.hasNext()) { Entity e = it.next(); boolean canSee = e.isAlive() && canSeeEntity(e); if (canSee) { list.add(e); } else { destroy.add(e.getEntityID()); it.remove(); } } // Send destroy packets if (!destroy.isEmpty()) { for (int id : destroy) { getPlayerNetwork().sendPacket(new ServerDestroyEntitiesPacket(id)); } } // Send update packets for (Entity entity : list) { for (Packet packet : ((CyanEntity) entity).getUpdatePackets()) { getPlayerNetwork().sendPacket(packet); } } // Add know entities for (Entity entity : getWorld().getEntities()) { boolean canSee = entity.isAlive() && canSeeEntity(entity); if (canSee) { if (!knowEntities.contains(entity)) { knowEntities.add(entity); // sending... for (Packet packet : ((CyanEntity) entity).getSpawnPackets()) { getPlayerNetwork().sendPacket(packet); } } } } } @Override public void sendMessage(String message) { ServerChatPacket packet = new ServerChatPacket(message); getPlayerNetwork().sendPacket(packet); } @Override public Server getServer() { return server; } @Override public boolean isPlayer() { return true; } @Override public List<ChunkCoords> getChunks() { return chunks; } @Override public EntityType getEntityType() { return EntityType.PLAYER; } @Override public void playSound(Location location, String sound, float volume, float pitch) { // ServerPlaySoundPacket packet = new // ServerPlaySoundPacket(MagicValues.key(GenericSound.class, sound), // getLocation().getX(), getLocation().getY(), getLocation().getZ(), // volume, pitch); CustomSound sound1 = new CustomSound(sound); ServerPlaySoundPacket packet = new ServerPlaySoundPacket(sound1, location.getX(), location.getY(), location.getZ(), volume, pitch); getPlayerNetwork().sendPacket(packet); } @Override public void playSound(Location location, Sound sound, float volume, float pitch) { ServerPlaySoundPacket packet = new ServerPlaySoundPacket(sound, location.getX(), location.getY(), location.getZ(), volume, pitch); getPlayerNetwork().sendPacket(packet); } @Override public void playEffect(Location location, WorldEffect effect, WorldEffectData data) { Position pos = new Position(location.getBlockX(), location.getBlockY(), location.getBlockZ()); ServerPlayEffectPacket packet = new ServerPlayEffectPacket(effect, pos, data); getPlayerNetwork().sendPacket(packet); } @Override public void setTime(long time) { ServerUpdateTimePacket packet = new ServerUpdateTimePacket(getWorld().getWorldTime(), time); getPlayerNetwork().sendPacket(packet); } @Override public void sendChunk(Chunk chunk) { CyanChunk cchunk = (CyanChunk) chunk; ServerChunkDataPacket packet = new ServerChunkDataPacket(chunk.getX(), chunk.getZ(), cchunk.getSections(), chunk.getBiomeData()); getPlayerNetwork().sendPacket(packet); } @Override public List<Packet> getSpawnPackets() { List<Packet> list = new ArrayList<Packet>(); list.add(new ServerSpawnPlayerPacket(getEntityID(), getUniqueId(), getLocation().getX(), getLocation().getY(), getLocation().getZ(), getLocation().getYaw(), getLocation().getPitch(), 0, ((CyanMetadataMap) getMetadata()).getMetaArray())); list.add(new ServerEntityHeadLookPacket(getEntityID(), getLocation().getYaw())); // Inventory and etc. // TODO return list; } @Override public void setHealth(float health) { super.setHealth(health); ServerUpdateHealthPacket packet = new ServerUpdateHealthPacket(health, getFoodLevel(), 20);// ??? getPlayerNetwork().sendPacket(packet); } @Override public void setMaxHealth(float health) { super.setMaxHealth(health); ServerUpdateHealthPacket packet = new ServerUpdateHealthPacket(health, getFoodLevel(), 20);// ??? getPlayerNetwork().sendPacket(packet); } @Override public void setFoodLevel(int level) { super.setFoodLevel(level); ServerUpdateHealthPacket packet = new ServerUpdateHealthPacket(getHealth(), getFoodLevel(), 20);// ??? getPlayerNetwork().sendPacket(packet); } @Override public void setGamemode(GameMode mode) { super.setGamemode(mode); ServerNotifyClientPacket packet = new ServerNotifyClientPacket(ClientNotification.CHANGE_GAMEMODE, mode); getPlayerNetwork().sendPacket(packet); } @Override public void updateChunk(Chunk chunk) { CyanChunk cchunk = (CyanChunk) chunk; ServerChunkDataPacket packet = new ServerChunkDataPacket(chunk.getX(), chunk.getZ(), cchunk.getSections()); getPlayerNetwork().sendPacket(packet); } @Override public void respawn() { isAlive = true; getServer().getEntityManager().register(this); setHealth(getMaxHealth()); setFoodLevel(20); ServerRespawnPacket packet = new ServerRespawnPacket(getWorld().getDimension().getId(), getWorld().getDifficulty(), getGameMode(), WorldType.FLAT);// TEST getPlayerNetwork().sendPacket(packet); } // Not api @Override public PlayerNetwork getPlayerNetwork() { return connection; } public void setPlayerNetwork(PlayerNetwork network) { this.connection = network; } public ClientSettings getSettings() { return settings; } public void setSettings(ClientSettings settings) { this.settings = settings; } private void updatePosition() { for (Packet packet : getUpdatePackets()) { getPlayerNetwork().sendPacket(packet); } } private void updateChunks() { List<ChunkCoords> prev = new ArrayList<ChunkCoords>(chunks); List<ChunkCoords> newChunks = new ArrayList<ChunkCoords>(); int centralX = getLocation().getChunk().getX(); int centralZ = getLocation().getChunk().getZ(); int radius = Math.min(server.getConfiguration().getViewDistance(), 1 + settings.getViewDistance()); for (int x = (centralX - radius); x <= (centralX + radius); x++) { for (int z = (centralZ - radius); z <= (centralZ + radius); z++) { ChunkCoords key = new ChunkCoords(x, z); if (chunks.contains(key)) { prev.remove(key); } else { newChunks.add(key); } } } if (newChunks.size() == 0 && prev.size() == 0) { return; } Collections.sort(newChunks, new Comparator<ChunkCoords>() { @Override public int compare(ChunkCoords a, ChunkCoords b) { double dx = 16 * a.getX() + 8 - getLocation().getX(); double dz = 16 * a.getZ() + 8 - getLocation().getZ(); double da = dx * dx + dz * dz; dx = 16 * b.getX() + 8 - getLocation().getX(); dz = 16 * b.getZ() + 8 - getLocation().getZ(); double db = dx * dx + dz * dz; return Double.compare(da, db); } }); for (ChunkCoords chunkcoords : newChunks) { chunks.add(chunkcoords); CyanChunk chunk = (CyanChunk) getWorld().getChunkManager().getChunk(chunkcoords.getX(), chunkcoords.getZ()); chunk.addPlayer(); sendChunk(chunk); } // Maybe: TODO: ServerMultiChunkDataPacket if (!prev.isEmpty()) { for (ChunkCoords key : prev) { ServerChunkDataPacket packet = new ServerChunkDataPacket(key.getX(), key.getZ()); getPlayerNetwork().sendPacket(packet); CyanChunk chunk = (CyanChunk) getWorld().getChunkManager().getChunk(key.getX(), key.getZ()); chunk.removePlayer(); chunks.remove(key); } } prev.clear(); } // @Override public void loadCompoundTag(CompoundTag tag) { this.compTag = tag; // start load IntTag gm = tag.get("playerGameType"); setGamemode(Transform.transformGameMode(gm.getValue())); IntTag selectItem = tag.get("SelectedItemSlot"); getInventory().setHeldItemSlot(selectItem.getValue()); // CompoundTag item = tag.get("SelectedItem"); //TODO IntTag x = tag.get("SpawnX"); getLocation().setX(x.getValue()); IntTag y = tag.get("SpawnY"); getLocation().setX(y.getValue()); IntTag z = tag.get("SpawnZ"); getLocation().setX(z.getValue()); // IntTag spawnForced = tag.get("SpawnForced"); // TODO ByteTag sleeping = tag.get("Sleeping"); if (sleeping.getValue() == 1) { sleepInBedAt(x.getValue(), y.getValue(), z.getValue()); } ShortTag sleepingTicks = tag.get("SleepTimer"); setSleepingTicks(sleepingTicks.getValue()); IntTag foodLvl = tag.get("foodLevel"); setFoodLevel(foodLvl.getValue()); // TODO: foodExhaustionLevel, foodSaturationLevel, foodTickTimer // TODO: XpLevel, XpP, XpTotal, XpSeed, // TODO: Inventory, EnderItems CompoundTag abilities = tag.get("abilities"); FloatTag walk = abilities.get("walkSpeed"); setWalkSpeed(walk.getValue()); FloatTag fly = abilities.get("flySpeed"); setFlySpeed(fly.getValue()); ByteTag mayfly = abilities.get("mayfly"); if (mayfly.getValue() == 1) { setAllowFlying(true); } ByteTag flying = abilities.get("flying"); if (flying.getValue() == 1) { setFlying(true); } // TODO: invulnerable ByteTag mayBuild = abilities.get("mayBuild"); if (mayBuild.getValue() == 1) { setBuild(true); } // TODO: instabuild // End. } // @Override public void saveCompoundTag(CompoundTag tag) { // Map<String, Tag> map = tag.getValue(); // map.put("", new IntTag("playerGameType", // Transform.transformGameMode(getGameMode()))); // map.put("", new IntTag("SelectedItemSlot", // getInventory().getHeldItemSlot())); // map.put("", new IntTag("SpawnX", getLocation().getBlockX())); // map.put("", new IntTag("SpawnY", getLocation().getBlockY())); // map.put("", new IntTag("SpawnZ", getLocation().getBlockZ())); // TODO // tag.setValue(map); if (tag != null) { tag.put(new IntTag("playerGameType", Transform.transformGameMode(getGameMode()))); tag.put(new IntTag("SelectedItemSlot", getInventory().getHeldItemSlot())); tag.put(new IntTag("SpawnX", getLocation().getBlockX())); tag.put(new IntTag("SpawnY", getLocation().getBlockY())); tag.put(new IntTag("SpawnZ", getLocation().getBlockZ())); byte sleep = 0; if (isSleeping()) { sleep = 1; } tag.put(new ByteTag("Sleeping", sleep)); tag.put(new ShortTag("SleepTimer", (short) getSleepingTicks())); tag.put(new IntTag("foodLevel", getFoodLevel())); CompoundTag abilities = new CompoundTag("abilities"); abilities.put(new FloatTag("walkSpeed", getWalkSpeed())); abilities.put(new FloatTag("flySpeed", getFlySpeed())); byte mayfly = 0; if (isAllowFlying()) { mayfly = 1; } abilities.put(new ByteTag("mayfly", mayfly)); byte flying = 0; if (isFlying()) { flying = 1; } abilities.put(new ByteTag("flying", flying)); byte mayBuild = 0; if (canBuild()) { mayBuild = 1; } abilities.put(new ByteTag("mayBuild", mayBuild)); tag.put(abilities); } } @Override public CompoundTag getCompoundTag() { if (compTag == null) { compTag = new CompoundTag(""); } return compTag; } @Override public boolean isMonster() { // TODO Auto-generated method stub return false; } @Override public void playParticle(Location location, Particle particle, int amount, int data) { ServerSpawnParticlePacket packet = new ServerSpawnParticlePacket(particle, true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), 0, 0, 0, 0, amount, data); getPlayerNetwork().sendPacket(packet); } @Override public void loadData() { getWorld().getPlayerService().readPlayer(this); } @Override public void saveData() { final Player player = this; getServer().getScheduler().runTask(new Runnable() { @Override public void run() { getWorld().getPlayerService().savePlayer(player); } }, 1); } }