Issue #126 : Eliminated (almost) all object creation in AbstractMovementPacketHandler. (#487)

* Eliminated (almost) all object creation in AbstractMovementPacketHandler. Pets still use old system.

* Removed debug code & comments I forgot about.
This commit is contained in:
Ubaware
2019-07-16 16:14:18 -07:00
committed by Ronan Lana
parent ab5cec7f33
commit 2df59b293b
10 changed files with 230 additions and 113 deletions

View File

@@ -1276,7 +1276,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void broadcastStance() {
map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement()), false);
map.broadcastMessage(this, MaplePacketCreator.movePlayer(id, this.getIdleMovement(), getIdleMovementDataLength()), false);
}
public MapleMap getWarpMap(int map) {

View File

@@ -30,7 +30,6 @@ import server.maps.AnimatedMapleMapObject;
import server.movement.AbsoluteLifeMovement;
import server.movement.ChangeEquip;
import server.movement.JumpDownMovement;
import server.movement.LifeMovement;
import server.movement.LifeMovementFragment;
import server.movement.RelativeLifeMovement;
import server.movement.TeleportMovement;
@@ -144,17 +143,96 @@ public abstract class AbstractMovementPacketHandler extends AbstractMaplePacketH
}
return res;
}
protected void updatePosition(List<LifeMovementFragment> movement, AnimatedMapleMapObject target, int yoffset) {
for (LifeMovementFragment move : movement) {
if (move instanceof LifeMovement) {
if (move instanceof AbsoluteLifeMovement) {
Point position = ((LifeMovement) move).getPosition();
position.y += yoffset;
target.setPosition(position);
protected void updatePosition(LittleEndianAccessor lea, AnimatedMapleMapObject target, int yOffset) {
byte numCommands = lea.readByte();
for (byte i = 0; i < numCommands; i++) {
byte command = lea.readByte();
switch (command) {
case 0: // normal move
case 5:
case 17: { // Float
//Absolute movement - only this is important for the server, other movement can be passed to the client
short xpos = lea.readShort(); //is signed fine here?
short ypos = lea.readShort();
target.setPosition(new Point(xpos, ypos + yOffset));
lea.skip(6); //xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); //duration
break;
}
target.setStance(((LifeMovement) move).getNewstate());
case 1:
case 2:
case 6: // fj
case 12:
case 13: // Shot-jump-back thing
case 16: // Float
case 18:
case 19: // Springs on maps
case 20: // Aran Combat Step
case 22: {
//Relative movement - server only cares about stance
lea.skip(4); //xpos = lea.readShort(); ypos = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); //duration
break;
}
case 3:
case 4: // tele... -.-
case 7: // assaulter
case 8: // assassinate
case 9: // rush
case 11: //chair
{
// case 14: {
//Teleport movement - same as above
lea.skip(8); //xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
break;
}
case 14:
lea.skip(9); // jump down (?)
break;
case 10: // Change Equip
//ignored by server
lea.readByte();
break;
/*case 11: { // Chair
short xpos = lea.readShort();
short ypos = lea.readShort();
short fh = lea.readShort();
byte newstate = lea.readByte();
short duration = lea.readShort();
ChairMovement cm = new ChairMovement(command, new Point(xpos, ypos), duration, newstate);
cm.setFh(fh);
res.add(cm);
break;
}*/
case 15: {
//Jump down movement - stance only
lea.skip(12); //short xpos = lea.readShort(); ypos = lea.readShort(); xwobble = lea.readShort(); ywobble = lea.readShort(); fh = lea.readShort(); ofh = lea.readShort();
byte newstate = lea.readByte();
target.setStance(newstate);
lea.readShort(); // duration
break;
}
case 21: {//Causes aran to do weird stuff when attacking o.o
/*byte newstate = lea.readByte();
short unk = lea.readShort();
AranMovement am = new AranMovement(command, null, unk, newstate);
res.add(am);*/
lea.skip(3);
break;
}
default:
System.out.println("Unhandled Case:" + command);
return;
}
}
return;
}
}

View File

@@ -21,12 +21,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.server.channel.handlers;
import java.awt.Point;
import client.MapleCharacter;
import client.MapleClient;
import java.awt.Point;
import java.util.List;
import server.maps.MapleDragon;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -36,14 +35,16 @@ public class MoveDragonHandler extends AbstractMovementPacketHandler {
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
final MapleCharacter chr = c.getPlayer();
final Point startPos = new Point(slea.readShort(), slea.readShort());
List<LifeMovementFragment> res = parseMovement(slea);
long movementDataStart = slea.getPosition();
final MapleDragon dragon = chr.getDragon();
if (dragon != null && res != null && res.size() > 0) {
updatePosition(res, dragon, 0);
updatePosition(slea, dragon, 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
if (dragon != null && movementDataLength > 0) {
slea.seek(movementDataStart);
if (chr.isHidden()) {
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, res));
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength));
} else {
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, res), dragon.getPosition());
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength), dragon.getPosition());
}
}
}

View File

@@ -141,24 +141,26 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
short start_x = slea.readShort(); // hmm.. startpos?
short start_y = slea.readShort(); // hmm...
Point startPos = new Point(start_x, start_y - 2);
List<LifeMovementFragment> res = parseMovement(slea);
long movementDataStart = slea.getPosition();
updatePosition(slea, monster, 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
Boolean aggro = monster.aggroMoveLifeUpdate(player);
if (aggro == null) return;
if (nextUse != null) {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, nextSkillId, nextSkillLevel));
Boolean aggro = monster.aggroMoveLifeUpdate(player);
if (aggro == null) return;
if (nextUse != null) {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, nextSkillId, nextSkillLevel));
} else {
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
}
if (res != null) {
if (ServerConstants.USE_DEBUG_SHOW_RCVD_MVLIFE) {
System.out.println((isSkill ? "SKILL " : (isAttack ? "ATTCK " : " ")) + "castPos: " + castPos + " rawAct: " + rawActivity + " opt: " + pOption + " skillID: " + useSkillId + " skillLV: " + useSkillLevel + " " + "allowSkill: " + nextMovementCouldBeSkill + " mobMp: " + mobMp);
}
map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, res), monster.getPosition());
updatePosition(res, monster, -2);
if (movementDataLength > 0) {
if (ServerConstants.USE_DEBUG_SHOW_RCVD_MVLIFE) {
System.out.println((isSkill ? "SKILL " : (isAttack ? "ATTCK " : " ")) + "castPos: " + castPos + " rawAct: " + rawActivity + " opt: " + pOption + " skillID: " + useSkillId + " skillLV: " + useSkillLevel + " " + "allowSkill: " + nextMovementCouldBeSkill + " mobMp: " + mobMp);
}
slea.seek(movementDataStart);
map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, slea, movementDataLength), monster.getPosition());
//updatePosition(res, monster, -2); //does this need to be done after the packet is broadcast?
map.moveMonster(monster, monster.getPosition());
}

View File

@@ -35,7 +35,7 @@ public final class MovePetHandler extends AbstractMovementPacketHandler {
slea.readLong();
// Point startPos = StreamUtil.readShortPoint(slea);
List<LifeMovementFragment> res = parseMovement(slea);
if (res.isEmpty()) {
if (res == null || res.isEmpty()) {
return;
}
MapleCharacter player = c.getPlayer();

View File

@@ -22,8 +22,6 @@
package net.server.channel.handlers;
import client.MapleClient;
import java.util.List;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -31,14 +29,16 @@ public final class MovePlayerHandler extends AbstractMovementPacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(9);
final List<LifeMovementFragment> res = parseMovement(slea);
if (res != null) {
updatePosition(res, c.getPlayer(), 0);
long movementDataStart = slea.getPosition();
updatePosition(slea, c.getPlayer(), 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
if (movementDataLength > 0) {
slea.seek(movementDataStart);
c.getPlayer().getMap().movePlayer(c.getPlayer(), c.getPlayer().getPosition());
if (c.getPlayer().isHidden()) {
c.getPlayer().getMap().broadcastGMMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), res), false);
c.getPlayer().getMap().broadcastGMMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
} else {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), res), false);
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.movePlayer(c.getPlayer().getId(), slea, movementDataLength), false);
}
}
}

View File

@@ -23,11 +23,10 @@ package net.server.channel.handlers;
import java.awt.Point;
import java.util.Collection;
import java.util.List;
import client.MapleCharacter;
import client.MapleClient;
import server.maps.MapleSummon;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -36,7 +35,6 @@ public final class MoveSummonHandler extends AbstractMovementPacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int oid = slea.readInt();
Point startPos = new Point(slea.readShort(), slea.readShort());
List<LifeMovementFragment> res = parseMovement(slea);
MapleCharacter player = c.getPlayer();
Collection<MapleSummon> summons = player.getSummonsValues();
MapleSummon summon = null;
@@ -46,9 +44,12 @@ public final class MoveSummonHandler extends AbstractMovementPacketHandler {
break;
}
}
long movementDataStart = slea.getPosition();
updatePosition(slea, summon, 0);
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
if (summon != null) {
updatePosition(res, summon, 0);
player.getMap().broadcastMessage(player, MaplePacketCreator.moveSummon(player.getId(), oid, startPos, res), summon.getPosition());
slea.seek(movementDataStart);
player.getMap().broadcastMessage(player, MaplePacketCreator.moveSummon(player.getId(), oid, startPos, slea, movementDataLength), summon.getPosition());
}
}
}

View File

@@ -1337,7 +1337,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
aggroRemoveController();
setPosition(newPoint);
map.broadcastMessage(MaplePacketCreator.moveMonster(this.getObjectId(), false, -1, 0, 0, 0, this.getPosition(), this.getIdleMovement()));
map.broadcastMessage(MaplePacketCreator.moveMonster(this.getObjectId(), false, -1, 0, 0, 0, this.getPosition(), this.getIdleMovement(), getIdleMovementDataLength()));
map.moveMonster(this, this.getPosition());
aggroUpdateController();

View File

@@ -21,14 +21,31 @@
*/
package server.maps;
import java.awt.Point;
import java.util.Collections;
import java.util.List;
import server.movement.AbsoluteLifeMovement;
import server.movement.LifeMovementFragment;
import java.util.Arrays;
import tools.data.input.ByteArrayByteStream;
import tools.data.input.GenericSeekableLittleEndianAccessor;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.data.output.MaplePacketLittleEndianWriter;
public abstract class AbstractAnimatedMapleMapObject extends AbstractMapleMapObject implements AnimatedMapleMapObject {
private int stance;
static {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter((int) getIdleMovementDataLength());
mplew.write(1); //movement command count
mplew.writeShort(-1); //x
mplew.writeShort(-1); //y
mplew.writeShort(0); //xwobble
mplew.writeShort(0); //ywobble
mplew.writeShort(0); //fh
mplew.write(-1); //stance
mplew.writeShort(0); //duration
idleMovementPacketData = mplew.getPacket();
}
private static final byte[] idleMovementPacketData;
private int stance;
@Override
public int getStance() {
@@ -45,11 +62,20 @@ public abstract class AbstractAnimatedMapleMapObject extends AbstractMapleMapObj
return Math.abs(stance) % 2 == 1;
}
public List<LifeMovementFragment> getIdleMovement() {
AbsoluteLifeMovement alm = new AbsoluteLifeMovement(0, getPosition(), 0, getStance());
alm.setPixelsPerSecond(new Point(0, 0));
List<LifeMovementFragment> moveUpdate = Collections.singletonList((LifeMovementFragment) alm);
return moveUpdate;
public SeekableLittleEndianAccessor getIdleMovement() {
byte[] movementData = Arrays.copyOf(idleMovementPacketData, idleMovementPacketData.length);
//seems wasteful to create a whole packet writer when only a few values are changed
int x = getPosition().x;
int y = getPosition().y;
movementData[1] = (byte) (x & 0xFF); //x
movementData[2] = (byte) (x >> 8 & 0xFF);
movementData[3] = (byte) (y & 0xFF); //y
movementData[4] = (byte) (y >> 8 & 0xFF);
movementData[11] = (byte) (getStance() & 0xFF);
return new GenericSeekableLittleEndianAccessor(new ByteArrayByteStream(movementData));
}
public static long getIdleMovementDataLength() {
return 14;
}
}

View File

@@ -35,48 +35,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.opcodes.SendOpcode;
import net.server.PlayerCoolDownValueHolder;
import net.server.Server;
import net.server.channel.Channel;
import net.server.channel.handlers.PlayerInteractionHandler;
import net.server.channel.handlers.SummonDamageHandler.SummonAttackEntry;
import net.server.guild.MapleAlliance;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleGuildSummary;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import net.server.world.PartyOperation;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import server.CashShop.SpecialCashItem;
import server.DueyPackage;
import server.MTSItemInfo;
import server.MapleItemInformationProvider;
import server.MapleShopItem;
import server.MapleTrade;
import server.events.gm.MapleSnowball;
import server.life.MapleMonster;
import server.life.MapleNPC;
import server.life.MobSkill;
import server.maps.MapleHiredMerchant;
import server.maps.MapleDoor;
import server.maps.MapleDoorObject;
import server.maps.MapleDragon;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
import server.maps.MapleMist;
import server.maps.MapleMiniGame;
import server.maps.MapleMiniGame.MiniGameResult;
import server.maps.MaplePlayerShop;
import server.maps.MaplePlayerShopItem;
import server.maps.MapleReactor;
import server.maps.MapleSummon;
import server.life.MaplePlayerNPC;
import server.movement.LifeMovementFragment;
import tools.data.output.LittleEndianWriter;
import tools.data.output.MaplePacketLittleEndianWriter;
import client.BuddylistEntry;
import client.MapleBuffStat;
import client.MapleCharacter;
@@ -110,8 +68,51 @@ import constants.ServerConstants;
import constants.skills.Buccaneer;
import constants.skills.Corsair;
import constants.skills.ThunderBreaker;
import java.util.TimeZone;
import net.opcodes.SendOpcode;
import net.server.PlayerCoolDownValueHolder;
import net.server.Server;
import net.server.channel.Channel;
import net.server.channel.handlers.PlayerInteractionHandler;
import net.server.channel.handlers.SummonDamageHandler.SummonAttackEntry;
import net.server.guild.MapleAlliance;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleGuildSummary;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import net.server.world.PartyOperation;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import server.CashShop.SpecialCashItem;
import server.DueyPackage;
import server.MTSItemInfo;
import server.MapleItemInformationProvider;
import server.MapleShopItem;
import server.MapleTrade;
import server.events.gm.MapleSnowball;
import server.life.MapleMonster;
import server.life.MapleNPC;
import server.life.MaplePlayerNPC;
import server.life.MobSkill;
import server.maps.AbstractMapleMapObject;
import server.maps.MapleDoor;
import server.maps.MapleDoorObject;
import server.maps.MapleDragon;
import server.maps.MapleHiredMerchant;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
import server.maps.MapleMiniGame;
import server.maps.MapleMiniGame.MiniGameResult;
import server.maps.MapleMist;
import server.maps.MaplePlayerShop;
import server.maps.MaplePlayerShopItem;
import server.maps.MapleReactor;
import server.maps.MapleSummon;
import server.movement.LifeMovementFragment;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.data.output.LittleEndianWriter;
import tools.data.output.MaplePacketLittleEndianWriter;
import java.util.TimeZone;
/**
*
@@ -2272,33 +2273,41 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
private static void rebroadcastMovementList(LittleEndianWriter lew, SeekableLittleEndianAccessor slea, long movementDataLength) {
//movement command length is sent by client, probably not a big issue? (could be calculated on server)
//if multiple write/reads are slow, could use a (cached?) byte[] buffer
for(long i = 0; i < movementDataLength; i++) {
lew.write(slea.readByte());
}
}
private static void serializeMovementList(LittleEndianWriter lew, List<LifeMovementFragment> moves) {
lew.write(moves.size());
for (LifeMovementFragment move : moves) {
move.serialize(lew);
}
lew.write(moves.size());
for(LifeMovementFragment move : moves) {
move.serialize(lew);
}
}
public static byte[] movePlayer(int cid, List<LifeMovementFragment> moves) {
public static byte[] movePlayer(int cid, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MOVE_PLAYER.getValue());
mplew.writeInt(cid);
mplew.writeInt(0);
serializeMovementList(mplew, moves);
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
return mplew.getPacket();
}
public static byte[] moveSummon(int cid, int oid, Point startPos, List<LifeMovementFragment> moves) {
public static byte[] moveSummon(int cid, int oid, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MOVE_SUMMON.getValue());
mplew.writeInt(cid);
mplew.writeInt(oid);
mplew.writePos(startPos);
serializeMovementList(mplew, moves);
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
return mplew.getPacket();
}
public static byte[] moveMonster(int oid, boolean skillPossible, int skill, int skillId, int skillLevel, int pOption, Point startPos, List<LifeMovementFragment> moves) {
public static byte[] moveMonster(int oid, boolean skillPossible, int skill, int skillId, int skillLevel, int pOption, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MOVE_MONSTER.getValue());
mplew.writeInt(oid);
@@ -2309,7 +2318,7 @@ public class MaplePacketCreator {
mplew.write(skillLevel);
mplew.writeShort(pOption);
mplew.writePos(startPos);
serializeMovementList(mplew, moves);
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
return mplew.getPacket();
}
@@ -8021,12 +8030,12 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] moveDragon(MapleDragon dragon, Point startPos, List<LifeMovementFragment> res) {
public static byte[] moveDragon(MapleDragon dragon, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MOVE_DRAGON.getValue());
mplew.writeInt(dragon.getOwner().getId());
mplew.writePos(startPos);
serializeMovementList(mplew, res);
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
return mplew.getPacket();
}