Lancer Posted March 6, 2016 Posted March 6, 2016 (edited) Hi there. How to inject this movement contoller into aCis latest source? package ru.catssoftware.gameserver.model.actor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import ru.catssoftware.gameserver.ThreadPoolManager; import ru.catssoftware.gameserver.ai.CtrlEvent; import ru.catssoftware.gameserver.ai.CtrlIntention; import ru.catssoftware.gameserver.ai.ParallelManager; import ru.catssoftware.gameserver.geodata.GeoData; import ru.catssoftware.gameserver.geodata.MathUtil; import ru.catssoftware.gameserver.geodata.pathfinding.AbstractNodeLoc; import ru.catssoftware.gameserver.geodata.pathfinding.PathFinding; import ru.catssoftware.gameserver.idfactory.IdFactory; import ru.catssoftware.gameserver.model.L2Character; import ru.catssoftware.gameserver.model.L2ItemInstance; import ru.catssoftware.gameserver.model.Location; import ru.catssoftware.gameserver.model.MoveModel; import ru.catssoftware.gameserver.network.serverpackets.MoveToLocation; import ru.catssoftware.gameserver.util.Util; import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; @Slf4j public class MovementController { private final static int MAX_DISTANCE = 5000; private final static int PAWN_OFFSET = 55; private final ReentrantLock lock = new ReentrantLock(true); private final L2Character actor; private ScheduledFuture<?> watchTask; private ScheduledFuture<?> pawnWatcher; private final AtomicReference<MoveModel> moveModel = new AtomicReference<>(); private List<AbstractNodeLoc> path; private Location originalEndPoint; @Getter private L2Character pawnTarget; private int pawnOffset; private long initTime; public MovementController(L2Character actor) { this.actor = actor; } public boolean isMoving() { return moveModel.get() != null; } public boolean isPawnMoving() { return pawnTarget != null || (pawnWatcher != null && !pawnWatcher.isDone()); } public Location getDestiny() { MoveModel model = moveModel.get(); if(model == null) return actor.getLoc(); return model.getEndMovePoint(); } public void stopMove() { stopWatcher(); stopPawnWatcher(); moveModel.set(null); originalEndPoint = null; pawnTarget = null; path = null; } public void movePawn(L2Character pawn, int offset) { if (true) { move(pawn.getX(), pawn.getY(), pawn.getZ(), offset, true, -1); return; } Location current = actor.getLoc(); Location dest = pawn.getLoc(); if (offset == 0) pawnOffset = PAWN_OFFSET; else pawnOffset = offset; double distance = current.getDistance(dest); //debug("movePawn: " + distance + " <= " + (pawnOffset) + " = " + (distance <= pawnOffset)); if(distance <= pawnOffset) { startPawnWatcher(pawn); ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED); return; } if(distance > MAX_DISTANCE) { stopMove(); ParallelManager.getInstance().intention(actor.getAI(), CtrlIntention.AI_INTENTION_ACTIVE); return; } initTime = System.currentTimeMillis(); movePawn0(pawn, current, dest); } private void movePawn0(L2Character pawn, Location current, Location dest) { lock.lock(); try { stopMove(); dest = normalizeByOffset(dest, pawnOffset); dest = checkWay(current, dest); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); validateHeading(current, dest); actor.broadcastPacket(new MoveToLocation(actor, dest)); pawnTarget = pawn; startWatcher(model); startPawnWatcher(pawn); } finally { lock.unlock(); } } private void stopWatcher() { if(watchTask != null && !watchTask.isDone()) watchTask.cancel(false); } private void startWatcher(MoveModel model) { if(model != null) model.setPrevUpdateTime(System.currentTimeMillis()); watchTask = ThreadPoolManager.getInstance().scheduleMove(new RunnableWatch(), getTime(actor)); } private void watch() { if (actor.isMovementDisabled()) { stopMove(); return; } if (initTime + 120000 < System.currentTimeMillis()) { stopMove(); return; } MoveModel moveModel = this.moveModel.get(); if (moveModel == null) { stopWatcher(); stopMove(); return; } long timeNow = System.currentTimeMillis(); double moveSpeed = actor.getStat().getMoveSpeed(); double complete = (moveSpeed / 1000d) * (timeNow - moveModel.getPrevUpdateTime()); double divider = (complete + moveModel.getCompleteDistance()) / moveModel.getDistance(); moveModel.setPrevUpdateTime(timeNow); moveModel.setCompleteDistance(complete + moveModel.getCompleteDistance()); if (divider >= 1) { actor.setXYZ(moveModel.getEndMovePoint()); completeMove(moveModel); return; } int dx = moveModel.getEndMovePoint().getX() - moveModel.getStartMovePoint().getX(); int dy = moveModel.getEndMovePoint().getY() - moveModel.getStartMovePoint().getY(); int dz = moveModel.getEndMovePoint().getZ() - moveModel.getStartMovePoint().getZ(); Location start = moveModel.getStartMovePoint(); int x = start.getX() + (int) Math.round(divider * dx); int y = start.getY() + (int) Math.round(divider * dy); int z; if (GeoData.getInstance().isEnabled() && moveModel.isWithoutGeodata()) z = start.getZ() + (int) Math.round(divider * dz); else z = GeoData.getInstance().getMoveHeight(x, y, actor.getZ()); if (!this.moveModel.compareAndSet(moveModel, moveModel)) return; dropItem(x, y, z, 57); actor.setXYZ(x, y, z); startWatcher(moveModel); actor.revalidateZoneMT(false); } private void startPawnWatcher(final L2Character pawn) { stopPawnWatcher(); pawnWatcher = ThreadPoolManager.getInstance().scheduleMove(new RunnableWatchPawn(pawn), getTime(pawn) << 1); } private void stopPawnWatcher() { if(pawnWatcher != null && !pawnWatcher.isDone()) pawnWatcher.cancel(false); } private void watchPawn(L2Character pawn) { if (actor.isMovementDisabled()) { stopMove(); return; } if(isMoving()) { startPawnWatcher(pawn); return; } //if (initTime + 120000 < System.currentTimeMillis()) //log.info("{}: watchPawn({}) very long ~ {} ms. {} -> {}", actor, pawn, System.currentTimeMillis() - initTime, actor.getLoc(), getDestiny()); Location current = actor.getLoc(); Location dest = pawn.getLoc(); double distance = current.getDistance(dest); //debug("watchPawn: " + distance + " <= " + (pawnOffset) + " = " + (distance <= pawnOffset)); if(distance <= pawnOffset) { startPawnWatcher(pawn); return; } if(distance > MAX_DISTANCE) { ParallelManager.getInstance().intention(actor.getAI(), CtrlIntention.AI_INTENTION_ACTIVE); return; } movePawn0(pawn, current, dest); } public void moveWoGeodata(int x, int y, int z, int offset, boolean broadcast) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); model.setWithoutGeodata(true); moveModel.set(model); if(broadcast) actor.broadcastPacket(new MoveToLocation(actor, dest)); initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } public void moveWoPathfind(int x, int y, int z, int offset, boolean broadcast, int doorid) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); double distance2 = current.getDistance2D(dest); if(actor.hasDebuger()) actor.say("Distance: {}", distance2); Location geoDest = cutByGeodata(dest, doorid); double destgeoDistance = dest.getDistance2D(geoDest); if(destgeoDistance > MathUtil.LossyPointsOnConvert) dest = geoDest; actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); if(broadcast) { validateHeading(current, dest); actor.broadcastPacket(new MoveToLocation(actor, dest)); } initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } public void move(int x, int y, int z, int offset, boolean broadcast, int doorid) { move(x, y, z, offset, broadcast, doorid, true); } public void move(int x, int y, int z, int offset, boolean broadcast, int doorid, boolean first) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); double distance2 = current.getDistance2D(dest); if(distance2 > MAX_DISTANCE) { originalEndPoint = dest; dest = normalizeByDistance(dest, MAX_DISTANCE); } dest = checkWay(current, dest); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); validateHeading(current, dest); if(broadcast) actor.broadcastPacket(new MoveToLocation(actor, dest)); if (first) initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } private Location normalizeByDistance(Location dest, double maxDistance) { Location current = actor.getLoc(); double distance = current.getDistance2D(dest); if(distance <= maxDistance) return dest; double divider = maxDistance / distance; int x = current.getX() + (int)Math.round(divider * (dest.getX() - current.getX())); int y = current.getY() + (int)Math.round(divider * (dest.getY() - current.getY())); if(GeoData.getInstance().isEnabled() && !GeoData.getInstance().hasGeo(x, y)) return null; int z; if(GeoData.getInstance().isEnabled()) z = GeoData.getInstance().getMoveHeight(x, y, dest.getZ()); else z = dest.getZ(); return new Location(x, y, z); } private Location normalizeByOffset(Location dest, int offset) { Location current = actor.getLoc(); double distance = current.getDistance(dest); double cos = (dest.getX() - current.getX()) / distance; double sin = (dest.getY() - current.getY()) / distance; int x = current.getX() + (int)((distance - offset + 10) * cos); int y = current.getY() + (int)((distance - offset + 10) * sin); if(GeoData.getInstance().isEnabled() && !GeoData.getInstance().hasGeo(x, y)) return null; int z; if(GeoData.getInstance().isEnabled()) z = GeoData.getInstance().getMoveHeight(x, y, dest.getZ()); else z = dest.getZ(); return new Location(x, y, z); } private Location cutByGeodata(Location dest, int doorid) { if(!GeoData.getInstance().isEnabled()) return dest; if (actor.getLoc() == null) log.error("cutByGeodata({}): {} have loc is null.", dest, actor); if (dest == null) log.error("cutByGeodata(NULL) have dest is null for actor: {}", actor); return GeoData.getInstance().moveCheck(actor.getLoc(), dest, actor.getInstanceId(), doorid); } /** * Метод проверяет маршрут персонажа, при необходимости - обрезает или создает путь. * @param current * @param dest * @return */ private Location checkWay(Location current, Location dest) { Location geoLockBlocked = cutByGeodata(dest, -1); dropItem(geoLockBlocked.getX(), geoLockBlocked.getY(), geoLockBlocked.getZ(), 65); //debug(String.format("checkWay: [%s] | %s -> %s", current, dest, geoLockBlocked)); // если расстояние от блокирущего блока до целевой точки больше размера гео-блока необходимо искать путь. if(dest.getDistance2D(geoLockBlocked) != 0) { path = PathFinding.getInstance().findPath(current.getX(), current.getY(), current.getZ(), dest.getX(), dest.getY(), dest.getZ(), actor.getInstanceId(), actor.isPlayer()); if(path != null && !path.isEmpty()) { dest = Location.fromNodeLoc(path.remove(0)); //debug(String.format("checkWay(%d,%d,%d) path size: %d | next: (%s) path: %s", dest.getX(), dest.getY(), dest.getZ(), path.size(), dest, path)); dropItem(dest.getX(), dest.getY(), dest.getZ(), 1062); } else { dest = normalizeByOffset(geoLockBlocked, MathUtil.LossyPointsOnConvert * 2); //debug(String.format("move(%d,%d,%d) path is empty", dest.getX(), dest.getY(), dest.getZ())); } } if (actor.hasDebuger()) { double a = current.getDistance2D(dest); double c = current.getDistance(dest); //debug(String.format("Path[%s]|[%s]", current, dest)); //debug(String.format("-> a/c: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(a/c)), Math.toDegrees(Math.cos(a/c)), Math.toDegrees(Math.asin(a/c)), Math.toDegrees(Math.acos(a/c)))); //debug(String.format("-> c/a: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(c/a)), Math.toDegrees(Math.cos(c/a)), Math.toDegrees(Math.asin(c/a)), Math.toDegrees(Math.acos(c/a)))); } return dest; } private boolean validateHeading(Location current, Location dest) { int heading = Util.calculateNormalHeading(current.getX(), current.getY(), dest.getX(), dest.getY()); if(MathUtil.isInRange(actor.getHeading() - 10, actor.getHeading() + 10, heading)) return false; actor.setHeading(heading); return true; } private void completeMove(MoveModel oldModel) { if(!moveModel.compareAndSet(oldModel, null)) return; if(path == null || path.isEmpty()) { Location originalEndPoint = this.originalEndPoint; L2Character pawnTarget = this.pawnTarget; stopMove(); if(originalEndPoint != null) //путь был обрезан из-за длины. продолжаем движение { move(originalEndPoint.getX(), originalEndPoint.getY(), originalEndPoint.getZ(), 0, true, -1, false); return; } if(pawnTarget != null && pawnTarget.getDistance(actor.getLoc()) > pawnOffset) { ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED_BLOCKED, actor.getLoc()); return; } ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED); return; } lock.lock(); try { Location sp = actor.getLoc(); Location ep = Location.fromNodeLoc(path.remove(0)); double dist = sp.getDistance(ep); if (actor.hasDebuger()) { double a = sp.getDistance2D(ep); double c = sp.getDistance(ep); //debug(String.format("Path[%s]|[%s]", sp, ep)); //debug(String.format("-> a/c: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(a/c)), Math.toDegrees(Math.cos(a/c)), Math.toDegrees(Math.asin(a/c)), Math.toDegrees(Math.acos(a/c)))); //debug(String.format("-> c/a: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(c/a)), Math.toDegrees(Math.cos(c/a)), Math.toDegrees(Math.asin(c/a)), Math.toDegrees(Math.acos(c/a)))); } /*if() { ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED_BLOCKED, actor.getLoc()); return; }*/ MoveModel model = new MoveModel(); model.setStartMovePoint(sp); model.setEndMovePoint(ep); model.setDistance(dist); model.setWithoutGeodata(false); if(!moveModel.compareAndSet(null, model)) return; validateHeading(sp, ep); actor.broadcastPacket(new MoveToLocation(actor, ep)); startWatcher(model); } finally { lock.unlock(); } } private void dropItem(int x, int y, int z, int itemId) { dropItem(x, y, z, itemId, 1); } private void dropItem(int x, int y, int z, int itemId, int count) { if(actor.hasDebuger()) { final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); item.setCount(count); item.dropMe(null, x, y, z); ThreadPoolManager.getInstance().schedule(new Runnable() { @Override public void run() { item.decayMe(); } }, 300000); } } private long getTime(L2Character actor) { return Math.round((MathUtil.LossyPointsOnConvert * 1000d) / actor.getStat().getMoveSpeed()); } private void debug(String text) { if (actor.hasDebuger() && actor.isPlayer()) actor.debug(text); } private class RunnableWatch implements Runnable { @Override public void run() { watch(); } } private class RunnableWatchPawn implements Runnable { private final L2Character pawn; private RunnableWatchPawn(L2Character pawn) { this.pawn = pawn; } @Override public void run() { watchPawn(pawn); } } } Edited March 6, 2016 by Lancer
Question
Lancer
Hi there. How to inject this movement contoller into aCis latest source?
package ru.catssoftware.gameserver.model.actor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import ru.catssoftware.gameserver.ThreadPoolManager; import ru.catssoftware.gameserver.ai.CtrlEvent; import ru.catssoftware.gameserver.ai.CtrlIntention; import ru.catssoftware.gameserver.ai.ParallelManager; import ru.catssoftware.gameserver.geodata.GeoData; import ru.catssoftware.gameserver.geodata.MathUtil; import ru.catssoftware.gameserver.geodata.pathfinding.AbstractNodeLoc; import ru.catssoftware.gameserver.geodata.pathfinding.PathFinding; import ru.catssoftware.gameserver.idfactory.IdFactory; import ru.catssoftware.gameserver.model.L2Character; import ru.catssoftware.gameserver.model.L2ItemInstance; import ru.catssoftware.gameserver.model.Location; import ru.catssoftware.gameserver.model.MoveModel; import ru.catssoftware.gameserver.network.serverpackets.MoveToLocation; import ru.catssoftware.gameserver.util.Util; import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; @Slf4j public class MovementController { private final static int MAX_DISTANCE = 5000; private final static int PAWN_OFFSET = 55; private final ReentrantLock lock = new ReentrantLock(true); private final L2Character actor; private ScheduledFuture<?> watchTask; private ScheduledFuture<?> pawnWatcher; private final AtomicReference<MoveModel> moveModel = new AtomicReference<>(); private List<AbstractNodeLoc> path; private Location originalEndPoint; @Getter private L2Character pawnTarget; private int pawnOffset; private long initTime; public MovementController(L2Character actor) { this.actor = actor; } public boolean isMoving() { return moveModel.get() != null; } public boolean isPawnMoving() { return pawnTarget != null || (pawnWatcher != null && !pawnWatcher.isDone()); } public Location getDestiny() { MoveModel model = moveModel.get(); if(model == null) return actor.getLoc(); return model.getEndMovePoint(); } public void stopMove() { stopWatcher(); stopPawnWatcher(); moveModel.set(null); originalEndPoint = null; pawnTarget = null; path = null; } public void movePawn(L2Character pawn, int offset) { if (true) { move(pawn.getX(), pawn.getY(), pawn.getZ(), offset, true, -1); return; } Location current = actor.getLoc(); Location dest = pawn.getLoc(); if (offset == 0) pawnOffset = PAWN_OFFSET; else pawnOffset = offset; double distance = current.getDistance(dest); //debug("movePawn: " + distance + " <= " + (pawnOffset) + " = " + (distance <= pawnOffset)); if(distance <= pawnOffset) { startPawnWatcher(pawn); ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED); return; } if(distance > MAX_DISTANCE) { stopMove(); ParallelManager.getInstance().intention(actor.getAI(), CtrlIntention.AI_INTENTION_ACTIVE); return; } initTime = System.currentTimeMillis(); movePawn0(pawn, current, dest); } private void movePawn0(L2Character pawn, Location current, Location dest) { lock.lock(); try { stopMove(); dest = normalizeByOffset(dest, pawnOffset); dest = checkWay(current, dest); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); validateHeading(current, dest); actor.broadcastPacket(new MoveToLocation(actor, dest)); pawnTarget = pawn; startWatcher(model); startPawnWatcher(pawn); } finally { lock.unlock(); } } private void stopWatcher() { if(watchTask != null && !watchTask.isDone()) watchTask.cancel(false); } private void startWatcher(MoveModel model) { if(model != null) model.setPrevUpdateTime(System.currentTimeMillis()); watchTask = ThreadPoolManager.getInstance().scheduleMove(new RunnableWatch(), getTime(actor)); } private void watch() { if (actor.isMovementDisabled()) { stopMove(); return; } if (initTime + 120000 < System.currentTimeMillis()) { stopMove(); return; } MoveModel moveModel = this.moveModel.get(); if (moveModel == null) { stopWatcher(); stopMove(); return; } long timeNow = System.currentTimeMillis(); double moveSpeed = actor.getStat().getMoveSpeed(); double complete = (moveSpeed / 1000d) * (timeNow - moveModel.getPrevUpdateTime()); double divider = (complete + moveModel.getCompleteDistance()) / moveModel.getDistance(); moveModel.setPrevUpdateTime(timeNow); moveModel.setCompleteDistance(complete + moveModel.getCompleteDistance()); if (divider >= 1) { actor.setXYZ(moveModel.getEndMovePoint()); completeMove(moveModel); return; } int dx = moveModel.getEndMovePoint().getX() - moveModel.getStartMovePoint().getX(); int dy = moveModel.getEndMovePoint().getY() - moveModel.getStartMovePoint().getY(); int dz = moveModel.getEndMovePoint().getZ() - moveModel.getStartMovePoint().getZ(); Location start = moveModel.getStartMovePoint(); int x = start.getX() + (int) Math.round(divider * dx); int y = start.getY() + (int) Math.round(divider * dy); int z; if (GeoData.getInstance().isEnabled() && moveModel.isWithoutGeodata()) z = start.getZ() + (int) Math.round(divider * dz); else z = GeoData.getInstance().getMoveHeight(x, y, actor.getZ()); if (!this.moveModel.compareAndSet(moveModel, moveModel)) return; dropItem(x, y, z, 57); actor.setXYZ(x, y, z); startWatcher(moveModel); actor.revalidateZoneMT(false); } private void startPawnWatcher(final L2Character pawn) { stopPawnWatcher(); pawnWatcher = ThreadPoolManager.getInstance().scheduleMove(new RunnableWatchPawn(pawn), getTime(pawn) << 1); } private void stopPawnWatcher() { if(pawnWatcher != null && !pawnWatcher.isDone()) pawnWatcher.cancel(false); } private void watchPawn(L2Character pawn) { if (actor.isMovementDisabled()) { stopMove(); return; } if(isMoving()) { startPawnWatcher(pawn); return; } //if (initTime + 120000 < System.currentTimeMillis()) //log.info("{}: watchPawn({}) very long ~ {} ms. {} -> {}", actor, pawn, System.currentTimeMillis() - initTime, actor.getLoc(), getDestiny()); Location current = actor.getLoc(); Location dest = pawn.getLoc(); double distance = current.getDistance(dest); //debug("watchPawn: " + distance + " <= " + (pawnOffset) + " = " + (distance <= pawnOffset)); if(distance <= pawnOffset) { startPawnWatcher(pawn); return; } if(distance > MAX_DISTANCE) { ParallelManager.getInstance().intention(actor.getAI(), CtrlIntention.AI_INTENTION_ACTIVE); return; } movePawn0(pawn, current, dest); } public void moveWoGeodata(int x, int y, int z, int offset, boolean broadcast) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); model.setWithoutGeodata(true); moveModel.set(model); if(broadcast) actor.broadcastPacket(new MoveToLocation(actor, dest)); initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } public void moveWoPathfind(int x, int y, int z, int offset, boolean broadcast, int doorid) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); double distance2 = current.getDistance2D(dest); if(actor.hasDebuger()) actor.say("Distance: {}", distance2); Location geoDest = cutByGeodata(dest, doorid); double destgeoDistance = dest.getDistance2D(geoDest); if(destgeoDistance > MathUtil.LossyPointsOnConvert) dest = geoDest; actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); if(broadcast) { validateHeading(current, dest); actor.broadcastPacket(new MoveToLocation(actor, dest)); } initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } public void move(int x, int y, int z, int offset, boolean broadcast, int doorid) { move(x, y, z, offset, broadcast, doorid, true); } public void move(int x, int y, int z, int offset, boolean broadcast, int doorid, boolean first) { lock.lock(); try { stopMove(); Location dest; if(offset != 0) dest = normalizeByOffset(new Location(x, y, z), offset); else dest = new Location(x, y, z); Location current = actor.getLoc(); double distance2 = current.getDistance2D(dest); if(distance2 > MAX_DISTANCE) { originalEndPoint = dest; dest = normalizeByDistance(dest, MAX_DISTANCE); } dest = checkWay(current, dest); actor.getListeners().onMove(actor, dest); MoveModel model = new MoveModel(); model.setWithoutGeodata(false); model.setStartMovePoint(current); model.setEndMovePoint(dest); model.setDistance(current.getDistance(dest)); moveModel.set(model); validateHeading(current, dest); if(broadcast) actor.broadcastPacket(new MoveToLocation(actor, dest)); if (first) initTime = System.currentTimeMillis(); startWatcher(model); } finally { lock.unlock(); } } private Location normalizeByDistance(Location dest, double maxDistance) { Location current = actor.getLoc(); double distance = current.getDistance2D(dest); if(distance <= maxDistance) return dest; double divider = maxDistance / distance; int x = current.getX() + (int)Math.round(divider * (dest.getX() - current.getX())); int y = current.getY() + (int)Math.round(divider * (dest.getY() - current.getY())); if(GeoData.getInstance().isEnabled() && !GeoData.getInstance().hasGeo(x, y)) return null; int z; if(GeoData.getInstance().isEnabled()) z = GeoData.getInstance().getMoveHeight(x, y, dest.getZ()); else z = dest.getZ(); return new Location(x, y, z); } private Location normalizeByOffset(Location dest, int offset) { Location current = actor.getLoc(); double distance = current.getDistance(dest); double cos = (dest.getX() - current.getX()) / distance; double sin = (dest.getY() - current.getY()) / distance; int x = current.getX() + (int)((distance - offset + 10) * cos); int y = current.getY() + (int)((distance - offset + 10) * sin); if(GeoData.getInstance().isEnabled() && !GeoData.getInstance().hasGeo(x, y)) return null; int z; if(GeoData.getInstance().isEnabled()) z = GeoData.getInstance().getMoveHeight(x, y, dest.getZ()); else z = dest.getZ(); return new Location(x, y, z); } private Location cutByGeodata(Location dest, int doorid) { if(!GeoData.getInstance().isEnabled()) return dest; if (actor.getLoc() == null) log.error("cutByGeodata({}): {} have loc is null.", dest, actor); if (dest == null) log.error("cutByGeodata(NULL) have dest is null for actor: {}", actor); return GeoData.getInstance().moveCheck(actor.getLoc(), dest, actor.getInstanceId(), doorid); } /** * Метод проверяет маршрут персонажа, при необходимости - обрезает или создает путь. * @param current * @param dest * @return */ private Location checkWay(Location current, Location dest) { Location geoLockBlocked = cutByGeodata(dest, -1); dropItem(geoLockBlocked.getX(), geoLockBlocked.getY(), geoLockBlocked.getZ(), 65); //debug(String.format("checkWay: [%s] | %s -> %s", current, dest, geoLockBlocked)); // если расстояние от блокирущего блока до целевой точки больше размера гео-блока необходимо искать путь. if(dest.getDistance2D(geoLockBlocked) != 0) { path = PathFinding.getInstance().findPath(current.getX(), current.getY(), current.getZ(), dest.getX(), dest.getY(), dest.getZ(), actor.getInstanceId(), actor.isPlayer()); if(path != null && !path.isEmpty()) { dest = Location.fromNodeLoc(path.remove(0)); //debug(String.format("checkWay(%d,%d,%d) path size: %d | next: (%s) path: %s", dest.getX(), dest.getY(), dest.getZ(), path.size(), dest, path)); dropItem(dest.getX(), dest.getY(), dest.getZ(), 1062); } else { dest = normalizeByOffset(geoLockBlocked, MathUtil.LossyPointsOnConvert * 2); //debug(String.format("move(%d,%d,%d) path is empty", dest.getX(), dest.getY(), dest.getZ())); } } if (actor.hasDebuger()) { double a = current.getDistance2D(dest); double c = current.getDistance(dest); //debug(String.format("Path[%s]|[%s]", current, dest)); //debug(String.format("-> a/c: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(a/c)), Math.toDegrees(Math.cos(a/c)), Math.toDegrees(Math.asin(a/c)), Math.toDegrees(Math.acos(a/c)))); //debug(String.format("-> c/a: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(c/a)), Math.toDegrees(Math.cos(c/a)), Math.toDegrees(Math.asin(c/a)), Math.toDegrees(Math.acos(c/a)))); } return dest; } private boolean validateHeading(Location current, Location dest) { int heading = Util.calculateNormalHeading(current.getX(), current.getY(), dest.getX(), dest.getY()); if(MathUtil.isInRange(actor.getHeading() - 10, actor.getHeading() + 10, heading)) return false; actor.setHeading(heading); return true; } private void completeMove(MoveModel oldModel) { if(!moveModel.compareAndSet(oldModel, null)) return; if(path == null || path.isEmpty()) { Location originalEndPoint = this.originalEndPoint; L2Character pawnTarget = this.pawnTarget; stopMove(); if(originalEndPoint != null) //путь был обрезан из-за длины. продолжаем движение { move(originalEndPoint.getX(), originalEndPoint.getY(), originalEndPoint.getZ(), 0, true, -1, false); return; } if(pawnTarget != null && pawnTarget.getDistance(actor.getLoc()) > pawnOffset) { ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED_BLOCKED, actor.getLoc()); return; } ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED); return; } lock.lock(); try { Location sp = actor.getLoc(); Location ep = Location.fromNodeLoc(path.remove(0)); double dist = sp.getDistance(ep); if (actor.hasDebuger()) { double a = sp.getDistance2D(ep); double c = sp.getDistance(ep); //debug(String.format("Path[%s]|[%s]", sp, ep)); //debug(String.format("-> a/c: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(a/c)), Math.toDegrees(Math.cos(a/c)), Math.toDegrees(Math.asin(a/c)), Math.toDegrees(Math.acos(a/c)))); //debug(String.format("-> c/a: sin: %.2f, cos: %.2f, asin: %.2f, acos: %.2f", Math.toDegrees(Math.sin(c/a)), Math.toDegrees(Math.cos(c/a)), Math.toDegrees(Math.asin(c/a)), Math.toDegrees(Math.acos(c/a)))); } /*if() { ParallelManager.getInstance().notify(actor.getAI(), CtrlEvent.EVT_ARRIVED_BLOCKED, actor.getLoc()); return; }*/ MoveModel model = new MoveModel(); model.setStartMovePoint(sp); model.setEndMovePoint(ep); model.setDistance(dist); model.setWithoutGeodata(false); if(!moveModel.compareAndSet(null, model)) return; validateHeading(sp, ep); actor.broadcastPacket(new MoveToLocation(actor, ep)); startWatcher(model); } finally { lock.unlock(); } } private void dropItem(int x, int y, int z, int itemId) { dropItem(x, y, z, itemId, 1); } private void dropItem(int x, int y, int z, int itemId, int count) { if(actor.hasDebuger()) { final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); item.setCount(count); item.dropMe(null, x, y, z); ThreadPoolManager.getInstance().schedule(new Runnable() { @Override public void run() { item.decayMe(); } }, 300000); } } private long getTime(L2Character actor) { return Math.round((MathUtil.LossyPointsOnConvert * 1000d) / actor.getStat().getMoveSpeed()); } private void debug(String text) { if (actor.hasDebuger() && actor.isPlayer()) actor.debug(text); } private class RunnableWatch implements Runnable { @Override public void run() { watch(); } } private class RunnableWatchPawn implements Runnable { private final L2Character pawn; private RunnableWatchPawn(L2Character pawn) { this.pawn = pawn; } @Override public void run() { watchPawn(pawn); } } }Edited by Lancer0 answers to this question
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now