Thread: NPC Updating

Results 1 to 5 of 5
  1. #1 NPC Updating 
    Registered Member
    The Wanderer's Avatar
    Join Date
    Mar 2010
    Posts
    596
    Thanks given
    44
    Thanks received
    152
    Rep Power
    196
    Code:
    RS2 user client - release #317
    Error: mopar size mismatch in getnpcpos - pos:1 psize:2
    Error: T2 - 65,81,73 - 2,3222,3218 - 0,0,
    I get this error in the client whenever I try and login. I tried adding npc updating to apollo and I am 99% sure all of the bits being wrote to the client are correct... Here's my classes.

    Encoder:
    Code:
    package org.apollo.net.release.r317;
    
    import org.apollo.game.event.impl.NPCSynchronizationEvent;
    import org.apollo.game.model.Animation;
    import org.apollo.game.model.Direction;
    import org.apollo.game.model.Graphic;
    import org.apollo.game.model.Position;
    import org.apollo.game.sync.block.AnimationBlock;
    import org.apollo.game.sync.block.GraphicBlock;
    import org.apollo.game.sync.block.SynchronizationBlockSet;
    import org.apollo.game.sync.block.TurnToPositionBlock;
    import org.apollo.game.sync.seg.AddCharacterSegment;
    import org.apollo.game.sync.seg.MovementSegment;
    import org.apollo.game.sync.seg.SegmentType;
    import org.apollo.game.sync.seg.SynchronizationSegment;
    import org.apollo.net.codec.game.DataOrder;
    import org.apollo.net.codec.game.DataType;
    import org.apollo.net.codec.game.GamePacket;
    import org.apollo.net.codec.game.GamePacketBuilder;
    import org.apollo.net.meta.PacketType;
    import org.apollo.net.release.EventEncoder;
    /**
     * NPCSynchronizationEventEncoder.java
     * @author The Wanderer
     */
    public class NPCSynchronizationEventEncoder extends EventEncoder<NPCSynchronizationEvent> {
    
    	@Override
    	public GamePacket encode(NPCSynchronizationEvent event) {
    		GamePacketBuilder builder = new GamePacketBuilder(65, PacketType.VARIABLE_SHORT);
    		builder.switchToBitAccess();
    		
                    GamePacketBuilder blockBuilder = new GamePacketBuilder();
                    
                    putMovementUpdate(event.getSegment(), event, builder);
    		putBlocks(event.getSegment(), blockBuilder);
    		/*
    		 * Write the current size of the npc list.
    		 */
    		builder.putBits(8, event.getLocalNPCs());
                    
                    //TODO: Handle removing npc SegmentType
                    for (SynchronizationSegment segment : event.getSegments()) {
    			SegmentType type = segment.getType();
    			if (type == SegmentType.ADD_CHARACTER) {
    				putAddCharacterUpdate((AddCharacterSegment) segment, event, builder);
    				putBlocks(segment, blockBuilder);
    			} else {
    				putMovementUpdate(segment, event, builder);
    				putBlocks(segment, blockBuilder);
    			}
    		}
    		
    		/*
    		 * Check if the update block isn't empty.
    		 */
    		if(blockBuilder.getLength() > 0) {
    			/*
    			 * If so, put a flag indicating that an update block follows.
    			 */
    			builder.putBits(14, 16383);
    			builder.switchToByteAccess();
    			
    			/*
    			 * And append the update block.
    			 */
    			builder.putRawBuilder(blockBuilder);
    		} else {
    			/*
    			 * Terminate the packet normally.
    			 */
    			builder.switchToByteAccess();
    		}
    		
    		/*
    		 * Write the packet.
    		 */
    		return builder.toGamePacket();
    	}
    
    	/**
    	 * Adds a new NPC.
    	 * @param packet The main packet.
    	 * @param npc The npc to add.
    	 */
    	private void putAddCharacterUpdate(AddCharacterSegment seg, NPCSynchronizationEvent event, GamePacketBuilder builder) {
                    boolean updateRequired = seg.getBlockSet().size() > 0;
                    Position npc = event.getPosition();
    		Position other = seg.getPosition();
    		builder.putBits(14, seg.getIndex());
    		builder.putBits(5, npc.getY() - other.getY());
    		builder.putBits(5, npc.getX() - other.getX());
                    builder.putBits(1, 0); // discard walking queue?
                    builder.putBits(12, event.getNpcId());
                    builder.putBits(1, updateRequired ? 1 : 0);
    	}
    
    	/**
    	 * Update an NPC's movement.
    	 * @param packet The main packet.
    	 * @param npc The npc.
    	 */
    	private void putMovementUpdate(SynchronizationSegment seg, NPCSynchronizationEvent event, GamePacketBuilder builder) {
                    boolean updateRequired = seg.getBlockSet().size() > 0;
    		if (seg.getType() == SegmentType.RUN) {
    			Direction[] directions = ((MovementSegment) seg).getDirections();
    			builder.putBits(1, 1);
    			builder.putBits(2, 2);
    			builder.putBits(3, directions[0].toInteger());
    			builder.putBits(3, directions[1].toInteger());
    			builder.putBits(1, updateRequired ? 1 : 0);
    		} else if (seg.getType() == SegmentType.WALK) {
    			Direction[] directions = ((MovementSegment) seg).getDirections();
    			builder.putBits(1, 1);
    			builder.putBits(2, 1);
    			builder.putBits(3, directions[0].toInteger());
    			builder.putBits(1, updateRequired ? 1 : 0);
    		} else {
    			if (updateRequired) {
    				builder.putBits(1, 1);
    				builder.putBits(2, 0);
    			} else {
    				builder.putBits(1, 0);
    			}
    		}
    	}
    	
    	/**
    	 * Update an NPC.
    	 * @param packet The update block.
    	 * @param npc The npc.
    	 */
    	private void putBlocks(SynchronizationSegment segment, GamePacketBuilder blockBuilder) {
    		SynchronizationBlockSet blockSet = segment.getBlockSet();
                    if (blockSet.size() > 0) {
    			int mask = 0;
                            //TODO: masks Hit, Hit_2, Transform, Face Entity, and Forced Chat
                            if (blockSet.contains(GraphicBlock.class)) {
    				mask |= 0x80;
    			}
    
    			if (blockSet.contains(AnimationBlock.class)){
    				mask |= 0x10;
    			}
    
    			if (blockSet.contains(TurnToPositionBlock.class)) {
    				mask |= 0x4;
    			}
                            
    			blockBuilder.put(DataType.BYTE, mask);
    
    			if (blockSet.contains(GraphicBlock.class)) {
    				putGraphicBlock(blockSet.get(GraphicBlock.class), blockBuilder);
    			}
    
    			if (blockSet.contains(AnimationBlock.class)) {
    				putAnimationBlock(blockSet.get(AnimationBlock.class), blockBuilder);
    			}
    
    			if (blockSet.contains(TurnToPositionBlock.class)) {
    				putTurnToPositionBlock(blockSet.get(TurnToPositionBlock.class), blockBuilder);
    			}
                    }
    	}
            
            /**
    	 * Puts a turn to position block into the specified builder.
    	 * @param block The block.
    	 * @param blockBuilder The builder.
    	 */
    	private void putTurnToPositionBlock(TurnToPositionBlock block, GamePacketBuilder blockBuilder) {
    		Position pos = block.getPosition();
    		blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, pos.getX() * 2 + 1);
    		blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, pos.getY() * 2 + 1);
    	}
    
    	/**
    	 * Puts a graphic block into the specified builder.
    	 * @param block The block.
    	 * @param blockBuilder The builder.
    	 */
    	private void putGraphicBlock(GraphicBlock block, GamePacketBuilder blockBuilder) {
    		Graphic graphic = block.getGraphic();
    		blockBuilder.put(DataType.SHORT, graphic.getId());
    		blockBuilder.put(DataType.INT, graphic.getDelay());
    	}
    
    	/**
    	 * Puts an animation block into the specified builder.
    	 * @param block The block.
    	 * @param blockBuilder The builder.
    	 */
    	private void putAnimationBlock(AnimationBlock block, GamePacketBuilder blockBuilder) {
    		Animation animation = block.getAnimation();
    		blockBuilder.put(DataType.SHORT, DataOrder.LITTLE, animation.getId());
    		blockBuilder.put(DataType.BYTE, animation.getDelay());
    	}
        
    }
    Task:
    Code:
    package org.apollo.game.sync.task;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import org.apollo.game.event.impl.NPCSynchronizationEvent;
    import org.apollo.game.model.NPC;
    import org.apollo.game.model.Player;
    import org.apollo.game.model.World;
    import org.apollo.game.sync.block.SynchronizationBlockSet;
    import org.apollo.game.sync.seg.AddCharacterSegment;
    import org.apollo.game.sync.seg.MovementSegment;
    import org.apollo.game.sync.seg.RemoveCharacterSegment;
    import org.apollo.game.sync.seg.SynchronizationSegment;
    import org.apollo.util.CharacterRepository;
    
    /**
     * NPCSynchronizzationTask.java
     * @author The Wanderer
     */
    public class NPCSynchronizationTask extends SynchronizationTask {
    
    	/**
    	 * The maximum number of players to load per cycle. This prevents the
    	 * update packet from becoming too large (the client uses a 5000 byte
    	 * buffer) and also stops old spec PCs from crashing when they login or
    	 * teleport.
    	 */
    	private static final int NEW_PLAYERS_PER_CYCLE = 20;
            
            private final NPC npc;
            
            /**
    	 * The player.
    	 */
    	private final Player player;
    
    	/**
    	 * Creates the {@link NPCSynchronizationTask} for the specified player.
    	 * @param player The player.
    	 */
    	public NPCSynchronizationTask(Player player, NPC npc) {
                    this.player = player;
                    this.npc = npc;
    	}
    
    	@Override
    	public void run() {
    		SynchronizationSegment segment;
    		SynchronizationBlockSet blockSet = npc.getBlockSet();
    
    		segment = new MovementSegment(blockSet, npc.getDirections());
    		
    
    		List<NPC> localNPCs = player.getLocalNPCList();
    		int oldLocalPlayers = localNPCs.size();
    		List<SynchronizationSegment> segments = new ArrayList<SynchronizationSegment>();
    
    		for (Iterator<NPC> it = localNPCs.iterator(); it.hasNext(); ) {
    			NPC n = it.next();
    			if (!n.isActive() || n.isTeleporting() || n.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance()) {
    				it.remove();
    				segments.add(new RemoveCharacterSegment());
    			} else {
    				segments.add(new MovementSegment(n.getBlockSet(), n.getDirections()));
    			}
    		}
    
    		int added = 0;
    
    		CharacterRepository<NPC> repository = World.getWorld().getNPCRepository();
    		for (Iterator<NPC> it = repository.iterator(); it.hasNext(); ) {
    			NPC n = it.next();
    			if (localNPCs.size() >= 255) {
    				player.flagExcessivePlayers();
    				break;
    			} else if (added >= NEW_PLAYERS_PER_CYCLE) {
    				break;
    			}
    			// we do not check n.isActive() here, since if they are active they must be in the repository
    			if (n != npc && n.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance()) && !localNPCs.contains(n)) {
    				localNPCs.add(n);
    				added++;
    
    				blockSet = n.getBlockSet();
    
    				segments.add(new AddCharacterSegment(blockSet, n.getIndex(), n.getPosition()));
    			}
    		}
    
    		NPCSynchronizationEvent event = new NPCSynchronizationEvent(npc.getPosition(), segment, oldLocalPlayers, segments, npc.getDefinition().getId());
    		player.send(event);
    	}
    }
    Event:
    Code:
    package org.apollo.game.event.impl;
    
    import java.util.List;
    import org.apollo.game.event.Event;
    import org.apollo.game.model.Position;
    import org.apollo.game.sync.seg.SynchronizationSegment;
    
    /**
     * NPCSynchronizationEvent.java
     * @author The Wanderer
     */
    public class NPCSynchronizationEvent extends Event {
    
    	/**
    	 * The npc's position.
    	 */
    	private final Position position;
    
    	/**
    	 * The current player's synchronization segment.
    	 */
    	private final SynchronizationSegment segment;
    
    	/**
    	 * The number of local players.
    	 */
    	private final int localNPCs;
            
            /**
             * The NPC id.
             */
            private final int npcId;
    
    	/**
    	 * A list of segments.
    	 */
    	private final List<SynchronizationSegment> segments;
    
    	/**
    	 * Creates the player synchronization event.
    	 * @param lastKnownRegion The last known region.
    	 * @param position The player's current position.
    	 * @param regionChanged A flag indicating if the region has changed.
    	 * @param segment The current player's synchronization segment.
    	 * @param localPlayers The number of local players.
    	 * @param segments A list of segments.
             * @param npcId The NPC id.
    	 */
    	public NPCSynchronizationEvent(Position position, SynchronizationSegment segment, int localNPCs, List<SynchronizationSegment> segments, int npcId) {
    		this.position = position;
    		this.segment = segment;
    		this.localNPCs = localNPCs;
    		this.segments = segments;
                    this.npcId = npcId;
    	}
    
    
    	/**
    	 * Gets the player's position.
    	 * @return The player's position.
    	 */
    	public Position getPosition() {
    		return position;
    	}
    
    	/**
    	 * Gets the current player's segment.
    	 * @return The current player's segment.
    	 */
    	public SynchronizationSegment getSegment() {
    		return segment;
    	}
    
    	/**
    	 * Gets the number of local players.
    	 * @return The number of local players.
    	 */
    	public int getLocalNPCs() {
    		return localNPCs;
    	}
    
    	/**
    	 * Gets the synchronization segments.
    	 * @return The segments.
    	 */
    	public List<SynchronizationSegment> getSegments() {
    		return segments;
    	}
            
            /**
             * Gets the NPC's id.
             * @return The NPC's id.
             */
            public int getNpcId() {
                return npcId;
            }
    }
    Usage:
    Code:
    package org.apollo.game.sync;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Phaser;
    import java.util.concurrent.ThreadFactory;
    
    import org.apollo.game.GameService;
    import org.apollo.game.model.NPC;
    import org.apollo.game.model.Player;
    import org.apollo.game.model.World;
    import org.apollo.game.sync.task.NPCSynchronizationTask;
    import org.apollo.game.sync.task.PhasedSynchronizationTask;
    import org.apollo.game.sync.task.PlayerSynchronizationTask;
    import org.apollo.game.sync.task.PostPlayerSynchronizationTask;
    import org.apollo.game.sync.task.PrePlayerSynchronizationTask;
    import org.apollo.game.sync.task.SynchronizationTask;
    import org.apollo.util.CharacterRepository;
    import org.apollo.util.NamedThreadFactory;
    
    /**
     * An implementation of {@link ClientSynchronizer} which runs in a thread pool.
     * A {@link Phaser} is used to ensure that the synchronization is complete,
     * allowing control to return to the {@link GameService} that started the
     * synchronization. This class will scale well with machines that have multiple
     * cores/processors. The {@link SequentialClientSynchronizer} will work better
     * on machines with a single core/processor, however, both classes will work.
     * @author Graham
     */
    public final class ParallelClientSynchronizer extends ClientSynchronizer {
    
    	/**
    	 * The executor service.
    	 */
    	private final ExecutorService executor;
    
    	/**
    	 * The phaser.
    	 */
    	private final Phaser phaser = new Phaser(1);
    
    	/**
    	 * Creates the parallel client synchronizer backed by a thread pool with a
    	 * number of threads equal to the number of processing cores available
    	 * (this is found by the {@link Runtime#availableProcessors()} method.
    	 */
    	public ParallelClientSynchronizer() {
    		int processors = Runtime.getRuntime().availableProcessors();
    		ThreadFactory factory = new NamedThreadFactory("ClientSynchronizer");
    		executor = Executors.newFixedThreadPool(processors, factory);
    	}
    
    	@Override
    	public void synchronize() {
    		CharacterRepository<Player> players = World.getWorld().getPlayerRepository();
    		int playerCount = players.size();
                    CharacterRepository<NPC> npcs = World.getWorld().getNPCRepository();
    		int npcCount = npcs.size();
    
    		phaser.bulkRegister(playerCount);
    		for (Player player : players) {
    			SynchronizationTask task = new PrePlayerSynchronizationTask(player);
    			executor.submit(new PhasedSynchronizationTask(phaser, task));
    		}
    		phaser.arriveAndAwaitAdvance();
    
    		phaser.bulkRegister(playerCount);
    		for (Player player : players) {
    			SynchronizationTask task = new PlayerSynchronizationTask(player);
    			executor.submit(new PhasedSynchronizationTask(phaser, task));
    		}
    		phaser.arriveAndAwaitAdvance();
                    
                    phaser.bulkRegister(playerCount);
                    for (Player player : players) {
                        for(NPC npc : npcs) {
                            SynchronizationTask task = new NPCSynchronizationTask(player, npc);
                            executor.submit(new PhasedSynchronizationTask(phaser, task));
                        }
                    }
    		phaser.arriveAndAwaitAdvance();
    
    		phaser.bulkRegister(playerCount);
    		for (Player player : players) {
    			SynchronizationTask task = new PostPlayerSynchronizationTask(player);
    			executor.submit(new PhasedSynchronizationTask(phaser, task));
    		}
    		phaser.arriveAndAwaitAdvance();
    	}
    
    }
    "But men may construe things after their fashion,. Clean from the purpose of the things themselves" - Shakespeare
    Reply With Quote  
     

  2. #2  
    Номер 1


    Leanbow's Avatar
    Join Date
    Feb 2008
    Posts
    5,895
    Thanks given
    1,564
    Thanks received
    2,624
    Rep Power
    5000
    Error: mopar size mismatch in getnpcpos - pos:1 psize:2

    You have too many bytes being sent/received can't remember
    Reply With Quote  
     

  3. #3  
    Programmer, Contributor, RM and Veteran




    Join Date
    Mar 2007
    Posts
    5,147
    Thanks given
    2,656
    Thanks received
    3,731
    Rep Power
    5000
    for (Player player : players) {
    for(NPC npc : npcs) {
    SynchronizationTask task = new NPCSynchronizationTask(player, npc);
    executor.submit(new PhasedSynchronizationTask(phaser, task));
    }
    }

    This would effectively send one update packet per npc per player which shouldn't be done. You just need one update packet per player, as the single update packet has the data for all the local NPCs within it.

    The actual error as Men said is the packet is probably slightly wrong, look over it carefully several times and you'll probably find you are missing a bit somewhere.
    .
    Reply With Quote  
     

  4. #4  
    q.q


    Join Date
    Dec 2010
    Posts
    6,519
    Thanks given
    1,072
    Thanks received
    3,535
    Rep Power
    4752
    this problem isn't directly related to the bytes specified in the update block, other things can cause it iirc

    just make sure

    Code:
    builder.putBits(14, seg.getIndex());
    		builder.putBits(5, npc.getY() - other.getY());
    		builder.putBits(5, npc.getX() - other.getX());
                    builder.putBits(1, 0); // discard walking queue?
                    builder.putBits(12, event.getNpcId());
                    builder.putBits(1, updateRequired ? 1 : 0);
    matches with this method

    Code:
    private void method46(int i, Stream stream) {
    		while(stream.bitPosition + 21 < i * 8) {
    			int k = stream.readBits(14);
    			if(k == 16383)
    				break;
    			if(npcArray[k] == null)
    				npcArray[k] = new NPC();
    			NPC npc = npcArray[k];
    			npcIndices[npcCount++] = k;
    			npc.anInt1537 = loopCycle;
    			int l = stream.readBits(5);
    			if(l > 15)
    				l -= 32;
    			int i1 = stream.readBits(5);
    			if(i1 > 15)
    				i1 -= 32;
    			int j1 = stream.readBits(1);
    			npc.npcId = EntityDef.forID(stream.readBits(14));
    			int k1 = stream.readBits(1);
    			if(k1 == 1)
    				anIntArray894[anInt893++] = k;
    			npc.anInt1540 = npc.npcId.aByte68;
    			npc.anInt1504 = npc.npcId.anInt79;
    			npc.anInt1554 = npc.npcId.walkAnim;
    			npc.anInt1555 = npc.npcId.anInt58;
    			npc.anInt1556 = npc.npcId.anInt83;
    			npc.anInt1557 = npc.npcId.anInt55;
    			npc.anInt1511 = npc.npcId.standAnim;
    			npc.setPos(myPlayer.smallX[0] + i1, myPlayer.smallY[0] + l, j1 == 1);
    		}
    		stream.finishBitAccess();
    	}
    as you can see ours don't match
    Reply With Quote  
     

  5. #5  
    Registered Member
    The Wanderer's Avatar
    Join Date
    Mar 2010
    Posts
    596
    Thanks given
    44
    Thanks received
    152
    Rep Power
    196
    http://www.rune-server.org/runescape...ml#post3019348

    Fixed. If anyone wants it or wants to look over code to make sure I'm doing it right.
    "But men may construe things after their fashion,. Clean from the purpose of the things themselves" - Shakespeare
    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. Player updating/Region updating
    By Ecstasy in forum Help
    Replies: 5
    Last Post: 04-25-2011, 06:01 PM
  2. Help with updating !
    By Xynasty in forum Help
    Replies: 6
    Last Post: 12-28-2010, 08:11 AM
  3. Updating [REP++]!
    By Fusebox in forum Help
    Replies: 0
    Last Post: 08-11-2010, 05:59 PM
  4. too much updating..
    By michael5252 in forum RS 503+ Client & Server
    Replies: 29
    Last Post: 09-27-2009, 12:48 AM
  5. updating help
    By Dannos in forum Help
    Replies: 0
    Last Post: 09-12-2009, 02:06 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
  •