Thread: [731] Player updating protocol

Results 1 to 6 of 6
  1. #1 [731] Player updating protocol 
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,788
    Thanks given
    706
    Thanks received
    702
    Rep Power
    570
    I've been trying to understand the update protocol for players, but there's something I'm still confused about. Why are the local/outside players processed in 2 parts (nsn2/nsn0)? I can't really see any logic with the 2 types of updates, there's nothing consistent about it. Here's an abridged version from what I understand:

    Code:
    Cycle 1, part 1, local players: Players who have been added from outside players OR those who were previously skipped
    Cycle 1, part 2, local players: Players who are being processed actively
    Cycle 2, part 1, outside players: Players who are being processed passively (just pos) OR players who have been added for the first time (OR players who have been removed from local players)
    Cycle 2, part 2, outside players: Players who have been previously skipped (OR players who have been removed from local players)
    If I had to take a guess, would it be some sort of way to handle AFK players in Cycle1P1 or Cycle2P2, except it's been implemented wrong? If so, it doesn't really make sense, because they're both handled the same way in the client:

    Code:
     static final void method10035(Stream stream) {
            int i = 0;
            stream.initBitAccess();
            for (int i_0_ = 0; i_0_ < Class30.anInt552; i_0_++) {
                int i_1_ = Class30.anIntArray558[i_0_];
                if ((Class30.aByteArray549[i_1_] & 0x1) == 0) {
                    if (i > 0) {
                        i--;
                        Class30.aByteArray549[i_1_] |= 0x2;
                    } else {
                        int i_2_ = stream.readBits(1);
                        if (i_2_ == 0) {
                            i = Class211.method3443(stream);
                            Class30.aByteArray549[i_1_] |= 0x2;
                        } else
                            Class18.method769(stream, i_1_);
                    }
                }
            }
            stream.finishBitAccess();
            if (i != 0)
                throw new RuntimeException();
            stream.initBitAccess();
            for (int i_3_ = 0; i_3_ < Class30.anInt552; i_3_++) {
                int i_4_ = Class30.anIntArray558[i_3_];
                if ((Class30.aByteArray549[i_4_] & 0x1) != 0) {
                    if (i > 0) {
                        i--;
                        Class30.aByteArray549[i_4_] |= 0x2;
                    } else {
                        int i_5_ = stream.readBits(1);
                        if (i_5_ == 0) {
                            i = Class211.method3443(stream);
                            Class30.aByteArray549[i_4_] |= 0x2;
                        } else
                            Class18.method769(stream, i_4_);
                    }
                }
            }
            stream.finishBitAccess();
            if (i != 0)
                throw new RuntimeException();
            stream.initBitAccess();
            for (int i_6_ = 0; i_6_ < Class30.anInt554; i_6_++) {
                int i_7_ = Class30.anIntArray555[i_6_];
                if ((Class30.aByteArray549[i_7_] & 0x1) != 0) {
                    if (i > 0) {
                        i--;
                        Class30.aByteArray549[i_7_] |= 0x2;
                    } else {
                        int i_8_ = stream.readBits(1);
                        if (i_8_ == 0) {
                            i = Class211.method3443(stream);
                            Class30.aByteArray549[i_7_] |= 0x2;
                        } else if (Class360.method6211(stream, i_7_))
                            Class30.aByteArray549[i_7_] |= 0x2;
                    }
                }
            }
            stream.finishBitAccess();
            if (i != 0)
                throw new RuntimeException();
            stream.initBitAccess();
            for (int i_9_ = 0; i_9_ < Class30.anInt554; i_9_++) {
                int i_10_ = Class30.anIntArray555[i_9_];
                if ((Class30.aByteArray549[i_10_] & 0x1) == 0) {
                    if (i > 0) {
                        i--;
                        Class30.aByteArray549[i_10_] |= 0x2;
                    } else {
                        int i_11_ = stream.readBits(1);
                        if (i_11_ == 0) {
                            i = Class211.method3443(stream);
                            Class30.aByteArray549[i_10_] |= 0x2;
                        } else if (Class360.method6211(stream, i_10_))
                            Class30.aByteArray549[i_10_] |= 0x2;
                    }
                }
            }
            stream.finishBitAccess();
            if (i != 0)
                throw new RuntimeException();
            Class30.anInt552 = 0;
            Class30.anInt554 = 0;
            for (int i_12_ = 1; i_12_ < 2048; i_12_++) {
                Class30.aByteArray549[i_12_] >>= 1;
                Player class402_sub1_sub3_sub2_sub1 =
                        client.players[i_12_];
                if (class402_sub1_sub3_sub2_sub1 != null)
                    Class30.anIntArray558[++Class30.anInt552 - 1] = i_12_;
                else
                    Class30.anIntArray555[++Class30.anInt554 - 1] = i_12_;
            }
        }
    Processing class from Matrix:

    Code:
    package com.rs.game.player;
    
    import java.security.MessageDigest;
    
    
    import com.rs.game.World;
    
    public final class LocalPlayerUpdate {
    
    	/**
    	 * The maximum amount of local players being added per tick. This is to
    	 * decrease time it takes to load crowded places (such as home).
    	 */
    	private static final int MAX_PLAYER_ADD = 15;
    
    	private transient Player player;
    
    	private byte[] slotFlags;
    
    	private transient Player[] localPlayers;
    	private int[] localPlayersIndexes;
    	private int localPlayersIndexesCount;
    
    	private int[] outPlayersIndexes;
    	private int outPlayersIndexesCount;
    
    	private int[] regionHashes;
    
    	private byte[][] cachedAppearencesHashes;
    	private int totalRenderDataSentLength;
    
    	/**
    	 * The amount of local players added this tick.
    	 */
    	private int localAddedPlayers;
    
    	public Player[] getLocalPlayers() {
    		return localPlayers;
    	}
    
    	public boolean needAppearenceUpdate(int index, byte[] hash) {
    		if (totalRenderDataSentLength > ((Settings.PACKET_SIZE_LIMIT - 500) / 2)
    				|| hash == null)
    			return false;
    		return cachedAppearencesHashes[index] == null
    				|| !MessageDigest.isEqual(cachedAppearencesHashes[index], hash);
    	}
    
    	public LocalPlayerUpdate() {
    
    	}
    
    	public LocalPlayerUpdate(Player player) {
    		this.player = player;
    		slotFlags = new byte[2048];
    		localPlayers = new Player[2048];
    		localPlayersIndexes = new int[Settings.PLAYERS_LIMIT];
    		outPlayersIndexes = new int[2048];
    		regionHashes = new int[2048];
    		cachedAppearencesHashes = new byte[Settings.PLAYERS_LIMIT][];
    	}
    
    	public void init(OutputStream stream) {
    		stream.initBitAccess();
    		stream.writeBits(30, player.getTileHash());
    		localPlayers[player.getIndex()] = player;
    		localPlayersIndexes[localPlayersIndexesCount++] = player.getIndex();
    		for (int playerIndex = 1; playerIndex < 2048; playerIndex++) {
    			if (playerIndex == player.getIndex())
    				continue;
    			Player player = World.getPlayers().get(playerIndex);
    			stream.writeBits(18, regionHashes[playerIndex] = player == null ? 0
    					: player.getRegionHash());
    			outPlayersIndexes[outPlayersIndexesCount++] = playerIndex;
    
    		}
    		stream.finishBitAccess();
    	}
    
    	private boolean needsRemove(Player p) {
    		return (p.hasFinished() || !player.withinDistance(p,
    				player.hasLargeSceneView() ? 126 : 14));
    	}
    
    	private boolean needsAdd(Player p) {
    		return p != null
    				&& !p.hasFinished()
    				&& player.withinDistance(p, player.hasLargeSceneView() ? 126
    						: 14) && localAddedPlayers < MAX_PLAYER_ADD;
    	}
    
    	private void updateRegionHash(OutputStream stream, int lastRegionHash,
    			int currentRegionHash) {
    		int lastRegionX = lastRegionHash >> 8;
    		int lastRegionY = 0xff & lastRegionHash;
    		int lastPlane = lastRegionHash >> 16;
    		int currentRegionX = currentRegionHash >> 8;
    		int currentRegionY = 0xff & currentRegionHash;
    		int currentPlane = currentRegionHash >> 16;
    		int planeOffset = currentPlane - lastPlane;
    		if (lastRegionX == currentRegionX && lastRegionY == currentRegionY) {
    			stream.writeBits(2, 1);
    			stream.writeBits(2, planeOffset);
    		} else if (Math.abs(currentRegionX - lastRegionX) <= 1
    				&& Math.abs(currentRegionY - lastRegionY) <= 1) {
    			int opcode;
    			int dx = currentRegionX - lastRegionX;
    			int dy = currentRegionY - lastRegionY;
    			if (dx == -1 && dy == -1)
    				opcode = 0;
    			else if (dx == 1 && dy == -1)
    				opcode = 2;
    			else if (dx == -1 && dy == 1)
    				opcode = 5;
    			else if (dx == 1 && dy == 1)
    				opcode = 7;
    			else if (dy == -1)
    				opcode = 1;
    			else if (dx == -1)
    				opcode = 3;
    			else if (dx == 1)
    				opcode = 4;
    			else
    				opcode = 6;
    			stream.writeBits(2, 2);
    			stream.writeBits(5, (planeOffset << 3) + (opcode & 0x7));
    		} else {
    			int xOffset = currentRegionX - lastRegionX;
    			int yOffset = currentRegionY - lastRegionY;
    			stream.writeBits(2, 3);
    			stream.writeBits(18, (yOffset & 0xff) + ((xOffset & 0xff) << 8)
    					+ (planeOffset << 16));
    		}
    	}
    
    	private void processOutsidePlayers(OutputStream stream,
    			OutputStream updateBlockData, boolean nsn2) {
    		stream.initBitAccess();
    		int skip = 0;
    		localAddedPlayers = 0;
    		for (int i = 0; i < outPlayersIndexesCount; i++) {
    			int playerIndex = outPlayersIndexes[i];
    			if (nsn2 ? (0x1 & slotFlags[playerIndex]) == 0
    					: (0x1 & slotFlags[playerIndex]) != 0)
    				continue;
    			if (skip > 0) {
    				skip--;
    				slotFlags[playerIndex] = (byte) (slotFlags[playerIndex] | 2);
    				continue;
    			}
    			Player p = World.getPlayers().get(playerIndex);
    			if (needsAdd(p)) {
    				stream.writeBits(1, 1);
    				stream.writeBits(2, 0); // request add
    				int hash = p.getRegionHash();
    				if (hash == regionHashes[playerIndex])
    					stream.writeBits(1, 0);
    				else {
    					stream.writeBits(1, 1);
    					updateRegionHash(stream, regionHashes[playerIndex], hash);
    					regionHashes[playerIndex] = hash;
    				}
    				stream.writeBits(6, p.getXInRegion());
    				stream.writeBits(6, p.getYInRegion());
    				boolean needAppearenceUpdate = needAppearenceUpdate(
    						p.getIndex(), p.getAppearence()
    								.getMD5AppeareanceDataHash());
    				appendUpdateBlock(p, updateBlockData, needAppearenceUpdate,
    						true);
    				stream.writeBits(1, 1);
    				localAddedPlayers++;
    				localPlayers[p.getIndex()] = p;
    				slotFlags[playerIndex] = (byte) (slotFlags[playerIndex] | 2);
    			} else {
    				int hash = p == null ? regionHashes[playerIndex] : p
    						.getRegionHash();
    				if (p != null && hash != regionHashes[playerIndex]) {
    					stream.writeBits(1, 1);
    					updateRegionHash(stream, regionHashes[playerIndex], hash);
    					regionHashes[playerIndex] = hash;
    				} else {
    					stream.writeBits(1, 0); // no update needed
    					for (int i2 = i + 1; i2 < outPlayersIndexesCount; i2++) {
    						int p2Index = outPlayersIndexes[i2];
    						if (nsn2 ? (0x1 & slotFlags[p2Index]) == 0
    								: (0x1 & slotFlags[p2Index]) != 0)
    							continue;
    						Player p2 = World.getPlayers().get(p2Index);
    						if (needsAdd(p2)
    								|| (p2 != null && p2.getRegionHash() != regionHashes[p2Index]))
    							break;
    						skip++;
    					}
    					skipPlayers(stream, skip);
    					slotFlags[playerIndex] = (byte) (slotFlags[playerIndex] | 2);
    				}
    			}
    		}
    		stream.finishBitAccess();
    	}
    
    	private void processLocalPlayers(OutputStream stream,
    			OutputStream updateBlockData, boolean nsn0) {
    		stream.initBitAccess();
    		int skip = 0;
    		for (int i = 0; i < localPlayersIndexesCount; i++) {
    			int playerIndex = localPlayersIndexes[i];
    			if (nsn0 ? (0x1 & slotFlags[playerIndex]) != 0
    					: (0x1 & slotFlags[playerIndex]) == 0)
    				continue;
    			if (skip > 0) {
    				skip--;
    				slotFlags[playerIndex] = (byte) (slotFlags[playerIndex] | 2);
    				continue;
    			}
    			Player p = localPlayers[playerIndex];
    			if (needsRemove(p)) {
    				stream.writeBits(1, 1); // needs update
    				stream.writeBits(1, 0); // no masks update needeed
    				stream.writeBits(2, 0); // request remove
    				regionHashes[playerIndex] = p.getLastWorldTile() == null ? p
    						.getRegionHash() : p.getLastWorldTile().getRegionHash();
    				int hash = p.getRegionHash();
    				if (hash == regionHashes[playerIndex])
    					stream.writeBits(1, 0);
    				else {
    					stream.writeBits(1, 1);
    					updateRegionHash(stream, regionHashes[playerIndex], hash);
    					regionHashes[playerIndex] = hash;
    				}
    				localPlayers[playerIndex] = null;
    			} else {
    				boolean needAppearenceUpdate = needAppearenceUpdate(
    						p.getIndex(), p.getAppearence()
    								.getMD5AppeareanceDataHash());
    				boolean needUpdate = p.needMasksUpdate()
    						|| needAppearenceUpdate;
    				if (needUpdate)
    					appendUpdateBlock(p, updateBlockData, needAppearenceUpdate,
    							false);
    				if (p.hasTeleported()) {
    					stream.writeBits(1, 1); // needs update
    					stream.writeBits(1, needUpdate ? 1 : 0);
    					stream.writeBits(2, 3);
    					int xOffset = p.getX() - p.getLastWorldTile().getX();
    					int yOffset = p.getY() - p.getLastWorldTile().getY();
    					int planeOffset = p.getPlane()
    							- p.getLastWorldTile().getPlane();
    					if (Math.abs(p.getX() - p.getLastWorldTile().getX()) <= 14 // 14
    																				// for
    																				// safe
    							&& Math.abs(p.getY() - p.getLastWorldTile().getY()) <= 14) { // 14
    																							// for
    																							// safe
    						stream.writeBits(1, 0);
    						if (xOffset < 0) // viewport used to be 15 now 16
    							xOffset += 32;
    						if (yOffset < 0)
    							yOffset += 32;
    						stream.writeBits(12, yOffset + (xOffset << 5)
    								+ (planeOffset << 10));
    					} else {
    						stream.writeBits(1, 1);
    						stream.writeBits(30, (yOffset & 0x3fff)
    								+ ((xOffset & 0x3fff) << 14)
    								+ ((planeOffset & 0x3) << 28));
    					}
    				} else if (p.getNextWalkDirection() != -1) {
    					int dx = Utils.DIRECTION_DELTA_X[p.getNextWalkDirection()];
    					int dy = Utils.DIRECTION_DELTA_Y[p.getNextWalkDirection()];
    					boolean running;
    					int opcode;
    					if (p.getNextRunDirection() != -1) {
    						dx += Utils.DIRECTION_DELTA_X[p.getNextRunDirection()];
    						dy += Utils.DIRECTION_DELTA_Y[p.getNextRunDirection()];
    						opcode = Utils.getPlayerRunningDirection(dx, dy);
    						if (opcode == -1) {
    							running = false;
    							opcode = Utils.getPlayerWalkingDirection(dx, dy);
    						} else
    							running = true;
    					} else {
    						running = false;
    						opcode = Utils.getPlayerWalkingDirection(dx, dy);
    					}
    					stream.writeBits(1, 1);
    					if ((dx == 0 && dy == 0)) {
    						stream.writeBits(1, 1); // quick fix
    						stream.writeBits(2, 0);
    						if (!needUpdate) // hasnt been sent yet
    							appendUpdateBlock(p, updateBlockData,
    									needAppearenceUpdate, false);
    					} else {
    						stream.writeBits(1, needUpdate ? 1 : 0);
    						stream.writeBits(2, running ? 2 : 1);
    						stream.writeBits(running ? 4 : 3, opcode);
    					}
    				} else if (needUpdate) {
    					stream.writeBits(1, 1); // needs update
    					stream.writeBits(1, 1);
    					stream.writeBits(2, 0);
    				} else { // skip
    					stream.writeBits(1, 0); // no update needed
    					for (int i2 = i + 1; i2 < localPlayersIndexesCount; i2++) {
    						int p2Index = localPlayersIndexes[i2];
    						if (nsn0 ? (0x1 & slotFlags[p2Index]) != 0
    								: (0x1 & slotFlags[p2Index]) == 0)
    							continue;
    						Player p2 = localPlayers[p2Index];
    						if (needsRemove(p2)
    								|| p2.hasTeleported()
    								|| p2.getNextWalkDirection() != -1
    								|| (p2.needMasksUpdate() || needAppearenceUpdate(
    										p2.getIndex(), p2.getAppearence()
    												.getMD5AppeareanceDataHash())))
    							break;
    						skip++;
    					}
    					skipPlayers(stream, skip);
    					slotFlags[playerIndex] = (byte) (slotFlags[playerIndex] | 2);
    				}
    
    			}
    		}
    		stream.finishBitAccess();
    	}
    
    	private void skipPlayers(OutputStream stream, int amount) {
    		stream.writeBits(2, amount == 0 ? 0 : amount > 255 ? 3
    				: (amount > 31 ? 2 : 1));
    		if (amount > 0) {
    			stream.writeBits(amount > 255 ? 11 : (amount > 31 ? 8 : 5), amount);
    		}
    	}
    
    	public OutputStream createPacketAndProcess() {
    		OutputStream stream = new OutputStream();
    		OutputStream updateBlockData = new OutputStream();
    		stream.writePacketVarShort(player, 117);
    		processLocalPlayers(stream, updateBlockData, true);
    		processLocalPlayers(stream, updateBlockData, false);
    		processOutsidePlayers(stream, updateBlockData, true);
    		processOutsidePlayers(stream, updateBlockData, false);
    		stream.writeBytes(updateBlockData.getBuffer(), 0,
    				updateBlockData.getOffset());
    		stream.endPacketVarShort();
    		totalRenderDataSentLength = 0;
    		localPlayersIndexesCount = 0;
    		outPlayersIndexesCount = 0;
    		for (int playerIndex = 1; playerIndex < 2048; playerIndex++) {
    			slotFlags[playerIndex] >>= 1;
    			Player player = localPlayers[playerIndex];
    			if (player == null)
    				outPlayersIndexes[outPlayersIndexesCount++] = playerIndex;
    			else
    				localPlayersIndexes[localPlayersIndexesCount++] = playerIndex;
    		}
    		return stream;
    	}
    
    }
    Edit: Someone linked me this doc: https://docs.google.com/document/d/1...xnlnBewWo/edit

    I've read it, and I understand when each block is suposed to be called, but it still doesn't answer the question of why? Why is there 2 nsn for skipped/non-skipped players instead of just 1?


    Edit2: Someone helped me figure it out. Basically the "skip" nsn blocks groups players so they can be skipped more efficiently the next time if they're inactive again. PM me if you have more questions.
    Project thread
    Reply With Quote  
     

  2. #2  
    Registered Member

    Join Date
    Dec 2009
    Posts
    774
    Thanks given
    367
    Thanks received
    455
    Rep Power
    927
    My eyes actually hurt when reading matrix's player updating. Here's mine. Maybe this can help you:

    Code:
    public final class PlayerRenderer implements Renderer<Player> {
    
    	/**
    	 * The maximum amount of players to register per cycle.
    	 */
    	private static final int MAX_ADD_COUNT = 10;
    
    	/**
    	 * The player reference.
    	 */
    	private final Player player;
    
    	/**
    	 * The player's render information.
    	 */
    	private final RenderInformation information;
    
    	/**
    	 * Construct a new {@code PlayerRenderer} {@code Object}.
    	 * @param player The player.
    	 */
    	public PlayerRenderer(Player player) {
    		this.player = player;
    		information = player.getRenderInformation();
    	}
    
    	@Override
    	public void process(OutputBuffer stream, OutputBuffer masks) {
    		updateMovement(stream, masks);
    		stream.writeBits(8, information.getLocalPlayers().size());
    		for (final Iterator<Player> iterator = information.getLocalPlayers().iterator(); iterator.hasNext();) {
    			final Player local = iterator.next();
    			if (local == null || !local.isActive() || !local.getLocation().withinDistance(player.getLocation()) || local.getConfigurations().hasTeleported() || World.getPlayerByName(local.getName()) == null) {
    				stream.writeBits(1, 1);
    				stream.writeBits(2, 3);
    				iterator.remove();
    				continue;
    			}
    			renderLocal(local, stream, masks);
    		}
    		int count = 0;
    		for (final Player local : RegionManager.getLocalPlayers(player, Distances.VIEWING)) {
    			if (local == player || !local.isActive() || information.getLocalPlayers().contains(local)) {
    				continue;
    			}
    			if (information.getLocalPlayers().size() >= 255 || ++count == MAX_ADD_COUNT) {
    				break;
    			}
    			addLocal(local, stream, masks);
    		}
    	}
    
    	@Override
    	public void renderLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = local.getMasks().isUpdateRequired();
    		stream.writeBits(1, (update || local.getMovement().getWalkDirection() != -1) ? 1 : 0);
    		if (local.getMovement().getWalkDirection() != -1) {
    			stream.writeBits(2, local.getMovement().getRunDirection() == -1 ? 1 : 2);
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(1, 1);
    			}
    			stream.writeBits(3, local.getMovement().getWalkDirection());
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(3, local.getMovement().getRunDirection());
    			}
    			stream.writeBits(1, update ? 1 : 0);
    		} else if (update) {
    			stream.writeBits(2, 0);
    		}
    		if (update) {
    			updateFlaggedMasks(local, masks, false, false);
    		}
    	}
    
    	@Override
    	public void addLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		stream.writeBits(11, local.getIndex());
    		int offsetX = (local.getLocation().getX() - player.getLocation().getX());
    		int offsetY = (local.getLocation().getY() - player.getLocation().getY());
    		if (offsetY < 0) {
    			offsetY += 32;
    		}
    		if (offsetX < 0) {
    			offsetX += 32;
    		}
    		final boolean appearance = information.getAppearanceStamps()[local.getIndex() & 0x800] != local.getMasks().getAppearanceStamp();
    		final boolean update = appearance || local.getMasks().isUpdateRequired() || local.getMasks().hasSynced();
    		stream.writeBits(5, offsetY);
    		stream.writeBits(5, offsetX);
    		stream.writeBits(1, local.getConfigurations().hasTeleported() ? 1 : 0);
    		stream.writeBits(1, update ? 1 : 0);
    		stream.writeBits(3, local.getDirection().ordinal());
    		information.getLocalPlayers().add(local);
    		if (update) {
    			if (appearance) {
    				information.getAppearanceStamps()[local.getIndex() & 0x800] = local.getMasks().getAppearanceStamp();
    			}
    			updateFlaggedMasks(local, masks, appearance, true);
    		}
    	}
    
    	@Override
    	public void updateMovement(OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = player.getMasks().isUpdateRequired();
    		if (player.getConfigurations().isUpdateSceneGraph()|| player.getConfigurations().hasTeleported()) {
    			stream.writeBits(1, 1);
    			stream.writeBits(2, 3);
    			stream.writeBits(1, update ? 1 : 0);
    			stream.writeBits(2, player.getLocation().getZ());
    			stream.writeBits(1, player.getConfigurations().hasTeleported() ? 1 : 0);
    			stream.writeBits(7, player.getLocation().getSceneX(player.getAttributes().get("last_scene_graph")));
    			stream.writeBits(7, player.getLocation().getSceneY(player.getAttributes().get("last_scene_graph")));
    			if (update) {
    				updateFlaggedMasks(player, masks, false, false);
    			}
    		} else {
    			renderLocal(player, stream, masks);
    		}
    	}
    
    	@Override
    	public void updateFlaggedMasks(Player local, OutputBuffer masks, boolean appearance, boolean sync) {
    		if (sync) {
    			local.getMasks().writeSynced(masks, appearance);
    		} else if (local.getMasks().isUpdateRequired()) {
    			local.getMasks().write(masks);
    		}
    	}
    
    }
    Code:
    	@Override
    	public Packet dispatch(Player player, EmptyContext context) {
    		final Packet packet = new Packet(107);
    		final OutputBuffer masks = new OutputBuffer();
    		packet.initBitAccess();
    		player.getPlayerRenderer().process(packet, masks);
    		if(masks.getOffset() > 0) {
    			packet.writeBits(11, 2047);
    		}
    		packet.finishBitAccess();
    		packet.writeBytes(masks.array(), 0, masks.getOffset());
    		return packet;
    	}
    Although this is 562. Can't remember if anything changed.
    link removed
    Reply With Quote  
     

  3. #3  
    Contributor

    clem585's Avatar
    Join Date
    Sep 2013
    Posts
    3,788
    Thanks given
    706
    Thanks received
    702
    Rep Power
    570
    Quote Originally Posted by Admiral Slee View Post
    My eyes actually hurt when reading matrix's player updating. Here's mine. Maybe this can help you:

    Code:
    public final class PlayerRenderer implements Renderer<Player> {
    
    	/**
    	 * The maximum amount of players to register per cycle.
    	 */
    	private static final int MAX_ADD_COUNT = 10;
    
    	/**
    	 * The player reference.
    	 */
    	private final Player player;
    
    	/**
    	 * The player's render information.
    	 */
    	private final RenderInformation information;
    
    	/**
    	 * Construct a new {@code PlayerRenderer} {@code Object}.
    	 * @param player The player.
    	 */
    	public PlayerRenderer(Player player) {
    		this.player = player;
    		information = player.getRenderInformation();
    	}
    
    	@Override
    	public void process(OutputBuffer stream, OutputBuffer masks) {
    		updateMovement(stream, masks);
    		stream.writeBits(8, information.getLocalPlayers().size());
    		for (final Iterator<Player> iterator = information.getLocalPlayers().iterator(); iterator.hasNext();) {
    			final Player local = iterator.next();
    			if (local == null || !local.isActive() || !local.getLocation().withinDistance(player.getLocation()) || local.getConfigurations().hasTeleported() || World.getPlayerByName(local.getName()) == null) {
    				stream.writeBits(1, 1);
    				stream.writeBits(2, 3);
    				iterator.remove();
    				continue;
    			}
    			renderLocal(local, stream, masks);
    		}
    		int count = 0;
    		for (final Player local : RegionManager.getLocalPlayers(player, Distances.VIEWING)) {
    			if (local == player || !local.isActive() || information.getLocalPlayers().contains(local)) {
    				continue;
    			}
    			if (information.getLocalPlayers().size() >= 255 || ++count == MAX_ADD_COUNT) {
    				break;
    			}
    			addLocal(local, stream, masks);
    		}
    	}
    
    	@Override
    	public void renderLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = local.getMasks().isUpdateRequired();
    		stream.writeBits(1, (update || local.getMovement().getWalkDirection() != -1) ? 1 : 0);
    		if (local.getMovement().getWalkDirection() != -1) {
    			stream.writeBits(2, local.getMovement().getRunDirection() == -1 ? 1 : 2);
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(1, 1);
    			}
    			stream.writeBits(3, local.getMovement().getWalkDirection());
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(3, local.getMovement().getRunDirection());
    			}
    			stream.writeBits(1, update ? 1 : 0);
    		} else if (update) {
    			stream.writeBits(2, 0);
    		}
    		if (update) {
    			updateFlaggedMasks(local, masks, false, false);
    		}
    	}
    
    	@Override
    	public void addLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		stream.writeBits(11, local.getIndex());
    		int offsetX = (local.getLocation().getX() - player.getLocation().getX());
    		int offsetY = (local.getLocation().getY() - player.getLocation().getY());
    		if (offsetY < 0) {
    			offsetY += 32;
    		}
    		if (offsetX < 0) {
    			offsetX += 32;
    		}
    		final boolean appearance = information.getAppearanceStamps()[local.getIndex() & 0x800] != local.getMasks().getAppearanceStamp();
    		final boolean update = appearance || local.getMasks().isUpdateRequired() || local.getMasks().hasSynced();
    		stream.writeBits(5, offsetY);
    		stream.writeBits(5, offsetX);
    		stream.writeBits(1, local.getConfigurations().hasTeleported() ? 1 : 0);
    		stream.writeBits(1, update ? 1 : 0);
    		stream.writeBits(3, local.getDirection().ordinal());
    		information.getLocalPlayers().add(local);
    		if (update) {
    			if (appearance) {
    				information.getAppearanceStamps()[local.getIndex() & 0x800] = local.getMasks().getAppearanceStamp();
    			}
    			updateFlaggedMasks(local, masks, appearance, true);
    		}
    	}
    
    	@Override
    	public void updateMovement(OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = player.getMasks().isUpdateRequired();
    		if (player.getConfigurations().isUpdateSceneGraph()|| player.getConfigurations().hasTeleported()) {
    			stream.writeBits(1, 1);
    			stream.writeBits(2, 3);
    			stream.writeBits(1, update ? 1 : 0);
    			stream.writeBits(2, player.getLocation().getZ());
    			stream.writeBits(1, player.getConfigurations().hasTeleported() ? 1 : 0);
    			stream.writeBits(7, player.getLocation().getSceneX(player.getAttributes().get("last_scene_graph")));
    			stream.writeBits(7, player.getLocation().getSceneY(player.getAttributes().get("last_scene_graph")));
    			if (update) {
    				updateFlaggedMasks(player, masks, false, false);
    			}
    		} else {
    			renderLocal(player, stream, masks);
    		}
    	}
    
    	@Override
    	public void updateFlaggedMasks(Player local, OutputBuffer masks, boolean appearance, boolean sync) {
    		if (sync) {
    			local.getMasks().writeSynced(masks, appearance);
    		} else if (local.getMasks().isUpdateRequired()) {
    			local.getMasks().write(masks);
    		}
    	}
    
    }
    Code:
    	@Override
    	public Packet dispatch(Player player, EmptyContext context) {
    		final Packet packet = new Packet(107);
    		final OutputBuffer masks = new OutputBuffer();
    		packet.initBitAccess();
    		player.getPlayerRenderer().process(packet, masks);
    		if(masks.getOffset() > 0) {
    			packet.writeBits(11, 2047);
    		}
    		packet.finishBitAccess();
    		packet.writeBytes(masks.array(), 0, masks.getOffset());
    		return packet;
    	}
    Although this is 562. Can't remember if anything changed.
    I also don't find the code clear enough as it is, that's why I'm refactoring it. It's still pretty efficient, even though I'd be better if it were to be seperated into different methods. As for the code you showed, I'm pretty sure it's changed since on 731 the player is processed the same way as other players, and is not at the start of the packet (updateMovement) like in the code you posted. Here's some info on the 601 one which seems to be similar to the 731 one.
    Project thread
    Reply With Quote  
     

  4. #4  
    Registered Member

    Join Date
    Dec 2009
    Posts
    774
    Thanks given
    367
    Thanks received
    455
    Rep Power
    927
    Quote Originally Posted by clem585 View Post
    I also don't find it perfectly efficient, that's why I'm refactoring it. It's still mostly accurate, even though I'd be better if it were to be seperated into different methods. As for the code you showed, I'm pretty sure it's changed since on 731 the player is processed the same way as other players, and is not at the start of the packet (updateMovement) like in the code you posted. Here's some info on the 601 one which seems to be similar to the 731 one.
    In my updateMovement method there's an else which calls the renderLocal method. That's where Matrix starts with.

    Anyways, I guess it changed, but not that much.
    link removed
    Reply With Quote  
     

  5. #5  
    WVWVWVWVWVWVWVW

    _jordan's Avatar
    Join Date
    Nov 2012
    Posts
    3,046
    Thanks given
    111
    Thanks received
    1,848
    Rep Power
    5000
    Quote Originally Posted by Admiral Slee View Post
    My eyes actually hurt when reading matrix's player updating. Here's mine. Maybe this can help you:

    Code:
    public final class PlayerRenderer implements Renderer<Player> {
    
    	/**
    	 * The maximum amount of players to register per cycle.
    	 */
    	private static final int MAX_ADD_COUNT = 10;
    
    	/**
    	 * The player reference.
    	 */
    	private final Player player;
    
    	/**
    	 * The player's render information.
    	 */
    	private final RenderInformation information;
    
    	/**
    	 * Construct a new {@code PlayerRenderer} {@code Object}.
    	 * @param player The player.
    	 */
    	public PlayerRenderer(Player player) {
    		this.player = player;
    		information = player.getRenderInformation();
    	}
    
    	@Override
    	public void process(OutputBuffer stream, OutputBuffer masks) {
    		updateMovement(stream, masks);
    		stream.writeBits(8, information.getLocalPlayers().size());
    		for (final Iterator<Player> iterator = information.getLocalPlayers().iterator(); iterator.hasNext();) {
    			final Player local = iterator.next();
    			if (local == null || !local.isActive() || !local.getLocation().withinDistance(player.getLocation()) || local.getConfigurations().hasTeleported() || World.getPlayerByName(local.getName()) == null) {
    				stream.writeBits(1, 1);
    				stream.writeBits(2, 3);
    				iterator.remove();
    				continue;
    			}
    			renderLocal(local, stream, masks);
    		}
    		int count = 0;
    		for (final Player local : RegionManager.getLocalPlayers(player, Distances.VIEWING)) {
    			if (local == player || !local.isActive() || information.getLocalPlayers().contains(local)) {
    				continue;
    			}
    			if (information.getLocalPlayers().size() >= 255 || ++count == MAX_ADD_COUNT) {
    				break;
    			}
    			addLocal(local, stream, masks);
    		}
    	}
    
    	@Override
    	public void renderLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = local.getMasks().isUpdateRequired();
    		stream.writeBits(1, (update || local.getMovement().getWalkDirection() != -1) ? 1 : 0);
    		if (local.getMovement().getWalkDirection() != -1) {
    			stream.writeBits(2, local.getMovement().getRunDirection() == -1 ? 1 : 2);
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(1, 1);
    			}
    			stream.writeBits(3, local.getMovement().getWalkDirection());
    			if (local.getMovement().getRunDirection() != -1) {
    				stream.writeBits(3, local.getMovement().getRunDirection());
    			}
    			stream.writeBits(1, update ? 1 : 0);
    		} else if (update) {
    			stream.writeBits(2, 0);
    		}
    		if (update) {
    			updateFlaggedMasks(local, masks, false, false);
    		}
    	}
    
    	@Override
    	public void addLocal(Player local, OutputBuffer stream, OutputBuffer masks) {
    		stream.writeBits(11, local.getIndex());
    		int offsetX = (local.getLocation().getX() - player.getLocation().getX());
    		int offsetY = (local.getLocation().getY() - player.getLocation().getY());
    		if (offsetY < 0) {
    			offsetY += 32;
    		}
    		if (offsetX < 0) {
    			offsetX += 32;
    		}
    		final boolean appearance = information.getAppearanceStamps()[local.getIndex() & 0x800] != local.getMasks().getAppearanceStamp();
    		final boolean update = appearance || local.getMasks().isUpdateRequired() || local.getMasks().hasSynced();
    		stream.writeBits(5, offsetY);
    		stream.writeBits(5, offsetX);
    		stream.writeBits(1, local.getConfigurations().hasTeleported() ? 1 : 0);
    		stream.writeBits(1, update ? 1 : 0);
    		stream.writeBits(3, local.getDirection().ordinal());
    		information.getLocalPlayers().add(local);
    		if (update) {
    			if (appearance) {
    				information.getAppearanceStamps()[local.getIndex() & 0x800] = local.getMasks().getAppearanceStamp();
    			}
    			updateFlaggedMasks(local, masks, appearance, true);
    		}
    	}
    
    	@Override
    	public void updateMovement(OutputBuffer stream, OutputBuffer masks) {
    		final boolean update = player.getMasks().isUpdateRequired();
    		if (player.getConfigurations().isUpdateSceneGraph()|| player.getConfigurations().hasTeleported()) {
    			stream.writeBits(1, 1);
    			stream.writeBits(2, 3);
    			stream.writeBits(1, update ? 1 : 0);
    			stream.writeBits(2, player.getLocation().getZ());
    			stream.writeBits(1, player.getConfigurations().hasTeleported() ? 1 : 0);
    			stream.writeBits(7, player.getLocation().getSceneX(player.getAttributes().get("last_scene_graph")));
    			stream.writeBits(7, player.getLocation().getSceneY(player.getAttributes().get("last_scene_graph")));
    			if (update) {
    				updateFlaggedMasks(player, masks, false, false);
    			}
    		} else {
    			renderLocal(player, stream, masks);
    		}
    	}
    
    	@Override
    	public void updateFlaggedMasks(Player local, OutputBuffer masks, boolean appearance, boolean sync) {
    		if (sync) {
    			local.getMasks().writeSynced(masks, appearance);
    		} else if (local.getMasks().isUpdateRequired()) {
    			local.getMasks().write(masks);
    		}
    	}
    
    }
    Code:
    	@Override
    	public Packet dispatch(Player player, EmptyContext context) {
    		final Packet packet = new Packet(107);
    		final OutputBuffer masks = new OutputBuffer();
    		packet.initBitAccess();
    		player.getPlayerRenderer().process(packet, masks);
    		if(masks.getOffset() > 0) {
    			packet.writeBits(11, 2047);
    		}
    		packet.finishBitAccess();
    		packet.writeBytes(masks.array(), 0, masks.getOffset());
    		return packet;
    	}
    Although this is 562. Can't remember if anything changed.
    your
    PlayerRenderer
    class looks like it's not yours. no offense wanted to clarify.

    OT: here is a great read The Player Updating Procedure [570+]
    Attached image
    Attached image
    Reply With Quote  
     

  6. #6  
    Registered Member

    Join Date
    Dec 2009
    Posts
    774
    Thanks given
    367
    Thanks received
    455
    Rep Power
    927
    Quote Originally Posted by _jordan View Post
    your class looks like it's not yours. no offense wanted to clarify.

    OT: here is a great read The Player Updating Procedure [570+]
    Me and apachenick wrote it. It's mine.
    link removed
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. The player updating procedure
    By veer in forum Informative Threads
    Replies: 30
    Last Post: 01-08-2012, 11:24 PM
  2. Replies: 2
    Last Post: 04-22-2009, 01:19 PM
  3. [508] Player Update Masks.
    By Ian... in forum Configuration
    Replies: 9
    Last Post: 08-30-2008, 06:12 PM
  4. All 481 Player Update Masks
    By ZachHaley in forum RS2 Server
    Replies: 13
    Last Post: 07-07-2008, 07:30 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •