From f1d8e6588fc4e9f3db2e5cc58b9c6ac995303edb Mon Sep 17 00:00:00 2001 From: rogiel Date: Fri, 29 Apr 2011 20:17:57 -0300 Subject: [PATCH] Change-Id: I375a10c9d7ce56df457a998e5cb9d02465865973 --- .../net/packet/client/AuthLoginPacket.java | 76 +++++++ .../server/CharSelectionInfoPacket.java | 185 ++++++++++++++++++ .../game/net/packet/server/KeyPacket.java | 102 ++++++++++ .../l2jserver/model/world/AbstractActor.java | 144 ++++++++++++++ .../model/world/actor/ActorEvent.java | 8 + .../model/world/actor/ActorListener.java | 6 + .../model/world/capability/Actor.java | 17 ++ .../model/world/capability/Invisible.java | 14 ++ .../model/world/capability/Talker.java | 11 ++ .../model/world/capability/Teleportable.java | 15 ++ .../model/world/capability/Teleporter.java | 14 ++ .../world/player/PlayerTeleportEvent.java | 10 + .../com/l2jserver/service/ServiceModule.java | 14 ++ .../game/world/WorldEventDispatcher.java | 21 ++ .../com/l2jserver/util/BlowFishKeygen.java | 67 +++++++ .../world/WorldEventDispatcherImplTest.java | 121 ++++++++++++ 16 files changed, 825 insertions(+) create mode 100644 src/main/java/com/l2jserver/game/net/packet/client/AuthLoginPacket.java create mode 100644 src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java create mode 100644 src/main/java/com/l2jserver/game/net/packet/server/KeyPacket.java create mode 100644 src/main/java/com/l2jserver/model/world/AbstractActor.java create mode 100644 src/main/java/com/l2jserver/model/world/actor/ActorEvent.java create mode 100644 src/main/java/com/l2jserver/model/world/actor/ActorListener.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Actor.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Invisible.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Talker.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Teleportable.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Teleporter.java create mode 100644 src/main/java/com/l2jserver/model/world/player/PlayerTeleportEvent.java create mode 100644 src/main/java/com/l2jserver/service/ServiceModule.java create mode 100644 src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java create mode 100644 src/main/java/com/l2jserver/util/BlowFishKeygen.java create mode 100644 src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java diff --git a/src/main/java/com/l2jserver/game/net/packet/client/AuthLoginPacket.java b/src/main/java/com/l2jserver/game/net/packet/client/AuthLoginPacket.java new file mode 100644 index 000000000..9a32ef26e --- /dev/null +++ b/src/main/java/com/l2jserver/game/net/packet/client/AuthLoginPacket.java @@ -0,0 +1,76 @@ +package com.l2jserver.game.net.packet.client; + +import java.nio.charset.Charset; + +import org.jboss.netty.buffer.ChannelBuffer; + +import com.google.inject.Inject; +import com.l2jserver.game.net.Lineage2Connection; +import com.l2jserver.game.net.packet.AbstractClientPacket; +import com.l2jserver.service.game.world.WorldService; + +public class AuthLoginPacket extends AbstractClientPacket { + public static final int OPCODE = 0x0e; + + @Inject + private WorldService world; + + // packet + private String loginName; + private int playKey1; + private int playKey2; + private int loginKey1; + private int loginKey2; + + @Override + public void read(ChannelBuffer buffer) { + this.loginName = buffer.readBytes(buffer.bytesBefore((byte) 0x00)) + .toString(Charset.defaultCharset()); + this.playKey1 = buffer.readInt(); + this.playKey2 = buffer.readInt(); + this.loginKey1 = buffer.readInt(); + this.loginKey2 = buffer.readInt(); + } + + @Override + public void process(final Lineage2Connection conn) { + // assume it is correct, for now + // send character list + world.getEventDispatcher().dispatch(null); + } + + /** + * @return the loginName + */ + public String getLoginName() { + return loginName; + } + + /** + * @return the playKey1 + */ + public int getPlayKey1() { + return playKey1; + } + + /** + * @return the playKey2 + */ + public int getPlayKey2() { + return playKey2; + } + + /** + * @return the loginKey1 + */ + public int getLoginKey1() { + return loginKey1; + } + + /** + * @return the loginKey2 + */ + public int getLoginKey2() { + return loginKey2; + } +} diff --git a/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java b/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java new file mode 100644 index 000000000..84162b2c5 --- /dev/null +++ b/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java @@ -0,0 +1,185 @@ +package com.l2jserver.game.net.packet.server; + +import org.jboss.netty.buffer.ChannelBuffer; + +import com.l2jserver.game.net.packet.AbstractServerPacket; + +public class CharSelectionInfoPacket extends AbstractServerPacket { + public static final int OPCODE = 0x09; + + private final String loginName; + private final int sessionId; + private final int activeId; + private final Character[] characters; + + public CharSelectionInfoPacket(int opcode, String loginName, int sessionId, + int activeId, Character... characters) { + super(opcode); + this.loginName = loginName; + this.sessionId = sessionId; + this.activeId = activeId; + this.characters = characters; + } + + @Override + public void write(ChannelBuffer buffer) { + // buffer.writeByte(0x09); + // int size = (characters.length); + // buffer.writeInt(size); + // + // // Can prevent players from creating new characters (if 0); (if 1, + // the client will ask if chars may be created (0x13) Response: (0x0D) ) + // buffer.writeInt(0x07); + // buffer.writeByte(0x00); + // + // long lastAccess = 0L; + // + // // if (activeId == -1) { + // // for (int i = 0; i < size; i++) { + // // if (lastAccess < characters[i].getLastAccess()) { + // // lastAccess = characters[i].getLastAccess(); + // // _activeId = i; + // // } + // // } + // // } + // + // for (int i = 0; i < size; i++) + // { + // Character character = characters[i]; + // + // buffer.writeBytes(character.getName()); + // buffer.writeInt(character.getCharId()); + // writeS(_loginName); + // buffer.writeInt(_sessionId); + // buffer.writeInt(character.getClanId()); + // buffer.writeInt(0x00); // ?? + // + // buffer.writeInt(character.getSex()); + // buffer.writeInt(character.getRace()); + // + // if (character.getClassId() == character.getBaseClassId()) + // buffer.writeInt(character.getClassId()); + // else + // buffer.writeInt(character.getBaseClassId()); + // + // buffer.writeInt(0x01); // active ?? + // + // buffer.writeInt(character.getX()); // x + // buffer.writeInt(character.getY()); // y + // buffer.writeInt(character.getZ()); // z + // + // buffer.writeDouble(character.getCurrentHp()); // hp cur + // buffer.writeDouble(character.getCurrentMp()); // mp cur + // + // buffer.writeInt(character.getSp()); + // writeQ(character.getExp()); + // buffer.writeInt(character.getLevel()); + // + // buffer.writeInt(character.getKarma()); // karma + // buffer.writeInt(character.getPkKills()); + // + // buffer.writeInt(character.getPvPKills()); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // buffer.writeInt(0x00); + // + // + // for(int id = 0; id <27; id++) { + // buffer.writeInt(0x00); + // } + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIR)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_REAR)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LEAR)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_NECK)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RFINGER)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LFINGER)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HEAD)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RHAND)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LHAND)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_GLOVES)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_CHEST)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LEGS)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_FEET)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_CLOAK)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RHAND)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIR)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIR2)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RBRACELET)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LBRACELET)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO1)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO2)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO3)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO4)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO5)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO6)); + // // + // buffer.writeInt(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_BELT)); + // + // buffer.writeInt(character.getHairStyle()); + // buffer.writeInt(character.getHairColor()); + // buffer.writeInt(character.getFace()); + // + // buffer.writeDouble(character.getMaxHp()); // hp max + // buffer.writeDouble(character.getMaxMp()); // mp max + // + // long deleteTime = character.getDeleteTimer(); + // int deletedays = 0; + // if (deleteTime > 0) + // deletedays = (int)((deleteTime-System.currentTimeMillis())/1000); + // buffer.writeInt(deletedays); // days left before + // // delete .. if != 0 + // // then char is inactive + // buffer.writeInt(character.getClassId()); + // if (i == _activeId) + // buffer.writeInt(0x01); + // else + // buffer.writeInt(0x00); //c3 auto-select char + // + // buffer.writeByte(character.getEnchantEffect() > 127 ? 127 : + // character.getEnchantEffect()); + // + // buffer.writeInt(character.getAugmentationId()); + // + // //buffer.writeInt(charInfoPackage.getTransformId()); // Used to + // display Transformations + // buffer.writeInt(0x00); // Currently on retail when you are on + // character select you don't see your transformation. + // + // // Freya by Vistall: + // buffer.writeInt(0); // npdid - 16024 Tame Tiny Baby Kookaburra A9E89C + // buffer.writeInt(0); // level + // buffer.writeInt(0); // ? + // buffer.writeInt(0); // food? - 1200 + // buffer.writeDouble(0); // max Hp + // buffer.writeDouble(0); // cur Hp + } +} diff --git a/src/main/java/com/l2jserver/game/net/packet/server/KeyPacket.java b/src/main/java/com/l2jserver/game/net/packet/server/KeyPacket.java new file mode 100644 index 000000000..0f6ee39ac --- /dev/null +++ b/src/main/java/com/l2jserver/game/net/packet/server/KeyPacket.java @@ -0,0 +1,102 @@ +package com.l2jserver.game.net.packet.server; + +import java.util.Arrays; + +import org.jboss.netty.buffer.ChannelBuffer; + +import com.l2jserver.game.net.packet.AbstractServerPacket; + +/** + *

0x2e "KeyPacket"

+ *

+ * byte[8] key
+ * byte protocolStatus + * + * @author Rogiel + */ +public class KeyPacket extends AbstractServerPacket { + /** + * Message OPCODE + */ + public static final int OPCODE = 0x2e; + + /** + * 8-byte key cryptography key + */ + private byte[] key; + /** + * The protocol state. True if valid, false if not. + */ + private boolean status; + + public KeyPacket(byte[] key, boolean status) { + super(OPCODE); + this.key = Arrays.copyOfRange(key, 0, 8); + this.status = status; + } + + /** + * Creates a new {@link KeyPacket} with key and valid protocol. + * + * @param key + * the key + * @return the new instance + */ + public static KeyPacket valid(byte[] key) { + return new KeyPacket(key, true); + } + + /** + * Creates a new {@link KeyPacket} with key and invalid protocol. + * + * @param key + * the key + * @return the new instance + */ + public static KeyPacket invalid(byte[] key) { + return new KeyPacket(key, false); + } + + @Override + public void write(ChannelBuffer buffer) { + buffer.writeByte((status ? 0x01 : 0x00)); + for (int i = 0; i < 8; i++) { + buffer.writeByte(key[i]); + } + // buffer.writeBytes(key); + buffer.writeInt(0x01); + buffer.writeInt(0x01); // server id + buffer.writeByte(0x01); + buffer.writeInt(0x00); // obfuscation key + } + + /** + * @return the key + */ + public byte[] getKey() { + return key; + } + + /** + * @param key + * the key to set + */ + public void setKey(byte[] key) { + this.key = key; + } + + /** + * @return the status + */ + public boolean isStatus() { + return status; + } + + /** + * @param status + * the status to set + */ + public void setStatus(boolean status) { + this.status = status; + } +} diff --git a/src/main/java/com/l2jserver/model/world/AbstractActor.java b/src/main/java/com/l2jserver/model/world/AbstractActor.java new file mode 100644 index 000000000..22478bd17 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/AbstractActor.java @@ -0,0 +1,144 @@ +package com.l2jserver.model.world; + +import java.util.List; + +import com.l2jserver.model.template.SkillTemplate; +import com.l2jserver.model.template.capability.Attackable; +import com.l2jserver.model.world.actor.ActorEvent; +import com.l2jserver.model.world.actor.ActorListener; +import com.l2jserver.model.world.capability.Actor; +import com.l2jserver.model.world.capability.Attacker; +import com.l2jserver.model.world.capability.Castable; +import com.l2jserver.model.world.capability.Equipable; +import com.l2jserver.model.world.capability.Equiper; +import com.l2jserver.util.Coordinate; +import com.l2jserver.util.factory.CollectionFactory; + +public abstract class AbstractActor extends AbstractObject implements Actor { + private final List listeners = CollectionFactory + .newList(ActorListener.class); + + protected int level; + protected int hp; + protected Coordinate position; + + @Override + public void receiveDamage(int damage) { + // TODO Auto-generated method stub + + } + + @Override + public int getHP() { + return hp; + } + + @Override + public void setHP(int hp) { + this.hp = hp; + } + + @Override + public void receiveAttack(Attacker attacker, Attackable weapon) { + // TODO + } + + @Override + public void attack(com.l2jserver.model.world.capability.Attackable target, + Attackable weapon) { + // TODO + } + + @Override + public void cast() { + // TODO + } + + @Override + public void cast(SkillTemplate skill, Castable cast) { + // TODO + } + + @Override + public void spawn(Coordinate coordinate) { + // TODO + } + + @Override + public boolean isSpawned() { + return false; + } + + @Override + public Coordinate getPosition() { + return position; + } + + @Override + public void setPosition(Coordinate coord) { + this.position = coord; + } + + @Override + public int getLevel() { + return level; + } + + @Override + public void setLevel(int level) { + this.level = level; + } + + @Override + public void die(WorldObject killer) { + // TODO + } + + @Override + public void equip(Equipable equipable) { + // TODO + } + + @Override + public boolean isEquiped(Equipable equipment) { + return false; + } + + @Override + public boolean isEquiped( + com.l2jserver.model.template.capability.Equipable equipable) { + return false; + } + + @Override + public void setEquipment(Object slot, Equipable equipment) { + // TODO + } + + @Override + public void getEquipment(Object slot) { + // TODO + } + + @Override + public void equip(Equiper equiper) { + // TODO + } + + @Override + public void addListener(ActorListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(ActorListener listener) { + listeners.remove(listener); + } + + @Override + public void dispatch(ActorEvent e) { + for (final ActorListener listener : listeners) { + listener.dispatch(e); + } + } +} diff --git a/src/main/java/com/l2jserver/model/world/actor/ActorEvent.java b/src/main/java/com/l2jserver/model/world/actor/ActorEvent.java new file mode 100644 index 000000000..0945e0239 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/actor/ActorEvent.java @@ -0,0 +1,8 @@ +package com.l2jserver.model.world.actor; + +import com.l2jserver.model.world.capability.Actor; +import com.l2jserver.model.world.event.WorldEvent; + +public interface ActorEvent extends WorldEvent { + Actor getActor(); +} diff --git a/src/main/java/com/l2jserver/model/world/actor/ActorListener.java b/src/main/java/com/l2jserver/model/world/actor/ActorListener.java new file mode 100644 index 000000000..fc4836b16 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/actor/ActorListener.java @@ -0,0 +1,6 @@ +package com.l2jserver.model.world.actor; + +import com.l2jserver.model.world.event.WorldListener; + +public interface ActorListener extends WorldListener { +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Actor.java b/src/main/java/com/l2jserver/model/world/capability/Actor.java new file mode 100644 index 000000000..5f61acde9 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Actor.java @@ -0,0 +1,17 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; +import com.l2jserver.model.world.actor.ActorEvent; +import com.l2jserver.model.world.actor.ActorListener; + +/** + * Defines an {@link AbstractObject} that defines an Actor (NPC, player, pet, + * etc...) + * + * @author Rogiel + */ +public interface Actor extends Listenable, + Spawnable, Positionable, Damagable, Attackable, Attacker, Castable, + Caster, Levelable, Killable, Equiper, Equipable { + +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Invisible.java b/src/main/java/com/l2jserver/model/world/capability/Invisible.java new file mode 100644 index 000000000..f1635ef16 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Invisible.java @@ -0,0 +1,14 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; + +/** + * Defines an {@link AbstractObject} that can become invisible to other objects. + * + * @author Rogiel + */ +public interface Invisible extends ObjectCapability { + boolean isInvisible(); + + void setInvisible(); +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Talker.java b/src/main/java/com/l2jserver/model/world/capability/Talker.java new file mode 100644 index 000000000..a1d865651 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Talker.java @@ -0,0 +1,11 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; + +/** + * Defines an {@link AbstractObject} that can talk to an {@link Conversable}. + * + * @author Rogiel + */ +public interface Talker extends ObjectCapability { +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Teleportable.java b/src/main/java/com/l2jserver/model/world/capability/Teleportable.java new file mode 100644 index 000000000..296e159a4 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Teleportable.java @@ -0,0 +1,15 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; +import com.l2jserver.util.Coordinate; + +/** + * Defines an {@link AbstractObject} that can be teleported by + * {@link Teleporter} objects. Note that it is also possible to teleport + * without a teleporter! + * + * @author Rogiel + */ +public interface Teleportable extends ObjectCapability, Positionable, Spawnable { + void teleport(Coordinate coordinate); +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Teleporter.java b/src/main/java/com/l2jserver/model/world/capability/Teleporter.java new file mode 100644 index 000000000..7912acebf --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Teleporter.java @@ -0,0 +1,14 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; +import com.l2jserver.util.Coordinate; + +/** + * Defines an {@link AbstractObject} that can teleport {@link Teleportable} + * objects. + * + * @author Rogiel + */ +public interface Teleporter extends ObjectCapability { + void teleport(Coordinate coord, Teleportable target); +} diff --git a/src/main/java/com/l2jserver/model/world/player/PlayerTeleportEvent.java b/src/main/java/com/l2jserver/model/world/player/PlayerTeleportEvent.java new file mode 100644 index 000000000..aa446755f --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/player/PlayerTeleportEvent.java @@ -0,0 +1,10 @@ +package com.l2jserver.model.world.player; + +import com.l2jserver.model.world.Player; +import com.l2jserver.util.Coordinate; + +public class PlayerTeleportEvent extends PlayerSpawnEvent { + public PlayerTeleportEvent(Player player, Coordinate coordinate) { + super(player, coordinate); + } +} diff --git a/src/main/java/com/l2jserver/service/ServiceModule.java b/src/main/java/com/l2jserver/service/ServiceModule.java new file mode 100644 index 000000000..4fe21df7d --- /dev/null +++ b/src/main/java/com/l2jserver/service/ServiceModule.java @@ -0,0 +1,14 @@ +package com.l2jserver.service; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.l2jserver.service.network.NettyNetworkService; +import com.l2jserver.service.network.NetworkService; + +public class ServiceModule extends AbstractModule { + @Override + protected void configure() { + bind(NetworkService.class).to(NettyNetworkService.class).in( + Scopes.SINGLETON); + } +} diff --git a/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java new file mode 100644 index 000000000..ba734d385 --- /dev/null +++ b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java @@ -0,0 +1,21 @@ +package com.l2jserver.service.game.world; + +import com.l2jserver.model.world.event.WorldEvent; + +/** + * This event dispatcher notify listeners that an certain event occured in their + * objects. + * + * @author Rogiel + */ +public interface WorldEventDispatcher { + /** + * Notify listeners of the event. Note that not all implementation + * need to invoke listeners immediately. Dispatching can occur + * concurrently. + * + * @param event + * the event + */ + void dispatch(WorldEvent event); +} diff --git a/src/main/java/com/l2jserver/util/BlowFishKeygen.java b/src/main/java/com/l2jserver/util/BlowFishKeygen.java new file mode 100644 index 000000000..e8c2579cb --- /dev/null +++ b/src/main/java/com/l2jserver/util/BlowFishKeygen.java @@ -0,0 +1,67 @@ +/* + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +package com.l2jserver.util; + +import java.util.Random; + +/** + * Blowfish keygen for GameServer client connections + * + * @author KenM + */ +public class BlowFishKeygen { + private static final int CRYPT_KEYS_SIZE = 20; + private static final byte[][] CRYPT_KEYS = new byte[CRYPT_KEYS_SIZE][16]; + + private static final Random random = new Random(); + + static { + // init the GS encryption keys on class load + + for (int i = 0; i < CRYPT_KEYS_SIZE; i++) { + // randomize the 8 first bytes + for (int j = 0; j < CRYPT_KEYS[i].length; j++) { + CRYPT_KEYS[i][j] = (byte) random.nextInt(255); + } + + // the last 8 bytes are static + CRYPT_KEYS[i][8] = (byte) 0xc8; + CRYPT_KEYS[i][9] = (byte) 0x27; + CRYPT_KEYS[i][10] = (byte) 0x93; + CRYPT_KEYS[i][11] = (byte) 0x01; + CRYPT_KEYS[i][12] = (byte) 0xa1; + CRYPT_KEYS[i][13] = (byte) 0x6c; + CRYPT_KEYS[i][14] = (byte) 0x31; + CRYPT_KEYS[i][15] = (byte) 0x97; + } + } + + // block instantiation + private BlowFishKeygen() { + + } + + /** + * Returns a key from this keygen pool, the logical ownership is retained by + * this keygen.
+ * Thus when getting a key with interests other then read-only a copy must + * be performed.
+ * + * @return A key from this keygen pool. + */ + public static byte[] getRandomKey() { + return CRYPT_KEYS[random.nextInt(CRYPT_KEYS_SIZE)]; + } +} diff --git a/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java new file mode 100644 index 000000000..e298fa2f8 --- /dev/null +++ b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java @@ -0,0 +1,121 @@ +package com.l2jserver.service.world; + +import java.util.concurrent.atomic.AtomicBoolean; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Scopes; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.item.ItemDropEvent; +import com.l2jserver.model.world.item.ItemEvent; +import com.l2jserver.model.world.item.ItemListener; +import com.l2jserver.model.world.player.PlayerEvent; +import com.l2jserver.model.world.player.PlayerListener; +import com.l2jserver.model.world.player.PlayerSpawnEvent; +import com.l2jserver.service.BasicServiceModule; +import com.l2jserver.service.ServiceStartException; +import com.l2jserver.service.game.world.WorldEventDispatcher; +import com.l2jserver.service.game.world.WorldEventDispatcherImpl; +import com.l2jserver.service.game.world.WorldService; +import com.l2jserver.service.game.world.WorldServiceImpl; + +public class WorldEventDispatcherImplTest { + private WorldService world; + private WorldEventDispatcher dispatcher; + + @Before + public void tearUp() throws ServiceStartException { + Injector injector = Guice.createInjector(new BasicServiceModule(), + new AbstractModule() { + @Override + protected void configure() { + bind(WorldService.class).to(WorldServiceImpl.class).in( + Scopes.SINGLETON); + bind(WorldEventDispatcher.class).to( + WorldEventDispatcherImpl.class).in( + Scopes.SINGLETON); + } + }); + + world = injector.getInstance(WorldService.class); + dispatcher = injector.getInstance(WorldEventDispatcher.class); + Assert.assertNotNull(world); + Assert.assertNotNull(dispatcher); + world.start(); + } + + @Test + public void testListeners1() { + final L2Character character1 = new L2Character(); + final L2Character character2 = new L2Character(); + final Item item1 = new Item(); + world.add(character1); + world.add(character2); + world.add(item1); + + final AtomicBoolean bool = new AtomicBoolean(); + Assert.assertFalse(bool.get()); + character1.addListener(new PlayerListener() { + @Override + protected void dispatch(PlayerEvent e) { + bool.set(true); + e.getPlayer().removeListener(this); + } + }); + character1.addListener(new PlayerListener() { + @Override + protected void dispatch(PlayerEvent e) { + // bool.set(true); + } + }); + dispatcher.dispatch(new PlayerSpawnEvent(character1, null)); + Assert.assertTrue(bool.get()); + + bool.set(false); + + dispatcher.dispatch(new PlayerSpawnEvent(character1, null)); + Assert.assertFalse(bool.get()); + } + + @Test + public void testListeners2() { + final L2Character character1 = new L2Character(); + final L2Character character2 = new L2Character(); + final Item item1 = new Item(); + final Item item2 = new Item(); + world.add(character1); + world.add(character2); + world.add(item1); + world.add(item2); + + final AtomicBoolean bool1 = new AtomicBoolean(); + final AtomicBoolean bool2 = new AtomicBoolean(); + + Assert.assertFalse(bool1.get()); + Assert.assertFalse(bool2.get()); + + character1.addListener(new PlayerListener() { + @Override + public void dispatch(PlayerEvent e) { + bool1.set(true); + } + }); + item1.addListener(new ItemListener() { + @Override + public void dispatch(ItemEvent e) { + bool2.set(true); + } + }); + + dispatcher.dispatch(new ItemDropEvent(character1, item1)); + Assert.assertTrue(bool1.get()); + Assert.assertTrue(bool2.get()); + } +}