[[Category Packet]] [[Category Packet 317]] == Player Updating == === Description === This packet begins the player updating. (I will use Hyperions player updating to sort of explain this packet--by the documentation) MAY TAKE A BIT READING :P I need time to finish trying to explain this packet to my best ability. If you hate what I have so far or doesn't make ANY sense. Just edit it. I wouldn't mind. Or START OVER COMPLETELY === Setup === '''Step 1''': The first thing we need to do before this packet is fully received, we need to check if the player's map region has changed. If it has, then we need to send the [https://rswiki.moparisthebest.com/index.php?title=317:Construct_map_region Map Region Packet] '''Step 2''': Then we set up an update block, like so: [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Explaining_.281.29 (1)] {| border=2 ! Method |- | PacketBuilder updateBlock = new PacketBuilder(); |- |} '''Step 3''': Since this packet is written in bits instead of bytes and holds information about the local list, players to add/remove, movement and which updates are required we need to do: '''(Method 1)'''.Then once we've done that we need to make that new field initiate the bit access like so: '''(Method 2)'''. {| border=2 ! Method # ! Method |- | Method 1 | PacketBuilder packet = new PacketBuilder(188, VARIABLE_SHORT); |- | Method 2 | packet.initiateBitAccess(); |- |} '''Step 4''': We then need to update both the players movement and the player itself. For this go to [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Player_Movement Player Movement] and [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Player_Update Update Player]. '''Step 5''': We need to write the current size of the player list so we put bits (8, and the size of the local players). Then we need to iterate through the local player list with a, for loop. And within that for loop we get the next player. Then check if the player should still be in our list. If so, then we send the update player movement method and check if an update is required. If so, send the player update. If the player should not be in our list still, then remove the player from the list and tell the client to remove the player by putting bits (1, 1) and (2, 3). {| border=2 ! Data ! Description |- | putBits(8, local player size); | Writes the current local player size |- | putBits(1, 1); | N/A |- | putBits(2, 3); | N/A |- |} '''Step 6''': Loop through every player and check if there is room left in the local list. If the size is '''>= 255''' then there is no more room left. Therefore, we cannot add more players, so we just ignore them until they get replaced by the other players that get removed. After that, we check if they should not be added, by going through the local player list and seeing if it contains the other player, if so, ignore them (continue). After those checks we add the player to the list, add the player in the packet, and update the player forcing the appearance flag. '''Step 7''': Check if the update block is not empty, if so, write a magic id indicating an update block follows (look below). Then we are finished with the bit access. Still in the update block check, we add the update block at the end of this packet. If the update block is empty, we terminate the packet normally (which means finish the bit access). {| border=2 ! Data ! Description |- | putBits(11, 2047); | Indicates an update block follows |- |} '''Step 8''': We write the packet. === Player Movement === Check which type of movement took place. (PRIMARY) If no movement did take place, check if an update is required. If an update is required put bits (1, 1)//Update happened and (2, 0)//No movement. If no update is required put bits (1, 0)//Nothing changed. (SECONDARY) The player moved but didn't run? Put bits (1, 1)//Update required (2, 1)//moved one tile (3, (PRIMARY))//Write the primary sprite and (1, isUpdateRequired() ? 1 : 0). We then put an else statement for the (SECONDARY) check. Within that, we put bits (1, 1)//Update happened (2, 2)//Two tiles (3, (PRIMARY))// Walking direction (3, (SECONDARY))//Run direction and (1, isUpdateRequired() ? 1 : 0)//Block update happened. {| border=2 ! Data ! Description |- | putBits(1, 1); | Update happened |- | putBits(2, 0); | No movement |- | putBits(1, 0); | Nothing changed |- | putBits(1, 1); | Update required |- | putBits(2, 1); | Moved one tile |- | putBits(3, otherPlayer.getSprites().getPrimarySprite()); | Walking direction |- | putBits(1, otherPlayer.getUpdateFlags().isUpdateRequired ? 1 : 0); | Block update happened |- | putBits(1, 1); | Update happened |- | putBits(2, 2); | Moved two tiles |- | putBits(3, otherPlayer.getSprites().getPrimarySprite()); | Walking direction |- | putBits(3, otherPlayer.getSprites().getSecondarySprite()); | Running direction |- | putBits(1, otherPlayer.getUpdateFlags().isUpdateRequired ? 1 : 0); | Block update happened |- |} === Add Player === {| border=2 ! Data ! Description |- | putBits(11, otherPlayer.getIndex()); | Write the player index |- | int yPos = other player y - player y; | Calculate the y offsets |- | int xPos = other player x - player x; | Calculate the x offsets |- | putBits(5, xPos); | Write the x offsets |- | putBits(5, yPos); | Write the y offsets |- | putBits(1, 1); | Indicates update is required (this is always true!) |- | putBits(1, 1); | Indicates we should discard client-side walk queues |- |} === Player Update === '''Step 1''': Before we start, we need to check if there is no update required flag nor a force appearance flag. If there is not, return. '''Step 2''': Now we use the cached update block in a synchronized block. '''(All of the below will be within this synchronized block)'''. We check if the player has a cached update block then we put the cached update block into the payload and flip it, then return. '''Step 3''': We have to construct and cache our own block. {| border=2 ! Method |- | PacketBuilder block = new PacketBuilder(); |- |} '''Step 4''': Now we get into the masks! Yippee! To refer to the different mask go to the 317 Protocol [https://rswiki.moparisthebest.com/index.php?title=317_Protocol#Player_Updating Player Update Masks]. So we first make an integer named 'mask' and make a field named 'flags' that equals the otherPlayer update flags. * Appearance: If we have a flag that equals our apperance flag and a force appearance is enabled. Our mask |= 0x1. * Animation: If we have a flag that equals our animation flag, our mask |= 0x2. * Chat: If we have a flag that equals our chat flag and !no chat, our mask |= 0x40. * Graphics: If we have a flag that equals our graphics flag, our mask |= 0x100. So after that we check if the bitmask would overflow a byte. Like so: {| border=2 ! Method |- | if (mask >= 0x100) |- |} If so, our mask |= 0x80 and we write as a short and indicate we have done so. {| border=2 ! Method |- | block.put((byte) (mask & 0xFF)) |- | block.put((byte) (mask >> 8)) |- |} If not, we write it as a byte. {| border=2 ! Method |- | block.put((byte) (mask)) |- |} And then we get into what the flags contain. * Apperance: If our flag gets the update flag appearance or the appearance is forced we go to method > Player Appearance Update. * Animation: If our flag gets the update flag animation, we go to the method > [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Animation_Update Animation Update]. * Graphics: If our flag gets the update flag graphics, we go to method > [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Graphics_Update Graphics Update]. * Chat: If our flag gets the update flag chat and !noChat, we go to method > [https://rswiki.moparisthebest.com/index.php?title=317:Begin_player_updating#Chat_Update Chat Update]. Then we convert the block builder to a packet. {| border=2 ! Method |- | Packet blockPacket = block.toPacket() |- |} Now it is over, cache the block if we can and finally append the block at the end. === Animation Update === This update appends an animation update. This will contain parameters block and otherPlayer. The block will put a short of the current animations id and then put a byte of the current animations delay. === Graphics Update === This update appends a graphics update. This will contain parameters block and otherPlayer. The block will put a short of the current graphics id and then put an int of the current graphics delay. === Chat Update === This update appends a chat text update. This will contain parameters packet and otherPlayer. We first make 2 fields: {| border=2 ! Method |- | ChatMessage cm = otherPlayer.getCurrentChatMessage(); |- | byte[] bytes = cm.getText() |- |} Then we put a range of data: {| border=2 ! Method |- | putShort(((cm.getColor() & 0xFF) << 8) | (cm.getEffects() & 0xFF)) |- | put((byte) otherPlayer.getRights().toInteger()) |- | put((byte) bytes.length) |- | put(bytes) |- |} Then we are finished with this update. === Explaining (1) === The update block packet holds update blocks and is sent after the main packet.