Added initial version

This commit is contained in:
Ceikry
2021-03-07 20:37:32 -06:00
commit b452bd670c
13290 changed files with 1178433 additions and 0 deletions
@@ -0,0 +1,28 @@
package ms.net;
import java.nio.ByteBuffer;
/**
* Used for producing I/O events.
* @author Emperor
*
*/
public interface EventProducer {
/**
* Produces a new read event.
* @param session The session.
* @param buffer The buffer to read.
* @return The read event handler.
*/
IoReadEvent produceReader(IoSession session, ByteBuffer buffer);
/**
* Produces a new writing event.
* @param session The session.
* @param context The context.
* @return The write event handler.
*/
IoWriteEvent produceWriter(IoSession session, Object context);
}
@@ -0,0 +1,106 @@
package ms.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
/**
* I/O event handling.
* @author Emperor
*
*/
public final class IoEventHandler {
/**
* The executor service.
*/
private final ExecutorService service;
/**
* Constructs a new {@code IoEventHandler}.
* @param service The executor service used for handling events.
*/
public IoEventHandler(ExecutorService service) {
this.service = service;
}
/**
* Called when making a new connection.
* @param key The selection key.
*/
public void connect(SelectionKey key) {
/*
* empty.
*/
}
/**
* Used for accepting a new connection.
* @param key The selection key.
* @param selector The selector.
* @throws IOException When an I/O exception occurs.
*/
public void accept(SelectionKey key, Selector selector) throws IOException {
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
sc.configureBlocking(false);
sc.socket().setTcpNoDelay(true);
sc.register(selector, SelectionKey.OP_READ);
}
/**
* Reads the incoming packet data.
* @param key The selection key.
* @throws IOException When an I/O exception occurs.
*/
public void read(SelectionKey key) throws IOException {
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100_000);
IoSession session = (IoSession) key.attachment();
if (channel.read(buffer) == -1) {
System.out.println("Existing session disconnected - likely portscanner or server status checker.");
key.cancel();
return;
}
buffer.flip();
if (session == null) {
key.attach(session = new IoSession(key, service));
}
service.execute(session.getProducer().produceReader(session, buffer));
}
/**
* Writes the outgoing packet data.
* @param key The selection key.
*/
public void write(SelectionKey key) {
IoSession session = (IoSession) key.attachment();
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
session.write();
}
/**
* Disconnects a connection.
* @param key The selection key.
* @param t The occurred exception (if any).
*/
public void disconnect(SelectionKey key, Throwable t) {
try {
IoSession session = (IoSession) key.attachment();
String cause = "" + t;
if (t != null && !(t instanceof ClosedChannelException || cause.contains("De externe host") || cause.contains("De software op uw") || cause.contains("An established connection was aborted") || cause.contains("An existing connection") || cause.contains("AsynchronousClose"))) {
t.printStackTrace();
}
if (session != null) {
session.disconnect();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,73 @@
package ms.net;
import java.nio.ByteBuffer;
/**
* Handles a reading event.
* @author Emperor
*
*/
public abstract class IoReadEvent implements Runnable {
/**
* The I/O session.
*/
private final IoSession session;
/**
* The buffer.
*/
private ByteBuffer buffer;
/**
* If the queued reading buffer was used (debugging purposes).
*/
protected boolean usedQueuedBuffer;
/**
* Constructs a new {@code IoReadEvent}.
* @param session The session.
* @param buffer The buffer to read from.
*/
public IoReadEvent(IoSession session, ByteBuffer buffer) {
this.session = session;
this.buffer = buffer;
}
@Override
public void run() {
try {
if (session.getReadingQueue() != null) {
buffer = session.getReadingQueue().put(buffer);
buffer.flip();
session.setReadingQueue(null);
usedQueuedBuffer = true;
}
read(session, buffer);
} catch (Throwable t) {
t.printStackTrace();
session.disconnect();
}
}
/**
* Queues the buffer until more data has been received.
* @param data The data that has been read already.
*/
public void queueBuffer(int...data) {
ByteBuffer queue = ByteBuffer.allocate(data.length + buffer.remaining() + 100_000);
for (int value : data) {
queue.put((byte) value);
}
queue.put(buffer);
session.setReadingQueue(queue);
}
/**
* Reads the data from the buffer.
* @param session The session.
* @param buffer The buffer to read from.
*/
public abstract void read(IoSession session, ByteBuffer buffer);
}
@@ -0,0 +1,351 @@
package ms.net;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import ms.ServerConstants;
import ms.net.producer.HSEventProducer;
import ms.world.GameServer;
/**
* Represents a connected I/O session.
* @author Emperor
*
*/
public class IoSession {
/**
* The handshake event producer.
*/
private static final EventProducer HANDSHAKE_PRODUCER = new HSEventProducer();
/**
* The selection key.
*/
private final SelectionKey key;
/**
* The executor service.
*/
private final ExecutorService service;
/**
* The event producer.
*/
private EventProducer producer = HANDSHAKE_PRODUCER;
/**
* The currently queued writing data.
*/
private List<ByteBuffer> writingQueue = new ArrayList<>();
/**
* The currently queued reading data.
*/
private ByteBuffer readingQueue;
/**
* The writing lock.
*/
private Lock writingLock = new ReentrantLock();
/**
* The name hash.
*/
private int nameHash;
/**
* The server key.
*/
private long serverKey;
/**
* The JS-5 encryption value.
*/
private int js5Encryption;
/**
* If the session is active.
*/
private boolean active = true;
/**
* The last ping time stamp.
*/
private long lastPing;
/**
* The address.
*/
private final String address;
/**
* The game server object for this session.
*/
private GameServer gameServer;
/**
* Constructs a new {@code IoSession}.
* @param key The selection key.
* @param service The executor service.
*/
public IoSession(SelectionKey key, ExecutorService service) {
this.key = key;
this.service = service;
String address = getRemoteAddress().replaceAll("/", "").split(":")[0];
if (address.equals("127.0.0.1")) {
address = ServerConstants.HOST_ADDRESS;
}
this.address = address;
}
/**
* Fires a write event created using the current event producer.
* @param context The event context.
*/
public void write(Object context) {
write(context, false);
}
/**
* Fires a write event created using the current event producer.
* @param context The event context.
* @param instant If the event should be instantly executed on this thread.
*/
public void write(Object context, boolean instant) {
if (context == null) {
throw new IllegalStateException("Invalid writing context!");
}
if (instant) {
producer.produceWriter(this, context).run();
return;
}
service.execute(producer.produceWriter(this, context));
}
/**
* Sends the packet data (without write event encoding).
* @param buffer The buffer.
*/
public void queue(ByteBuffer buffer) {
try {
writingLock.tryLock(1000L, TimeUnit.MILLISECONDS);
} catch (Exception e){
System.out.println(e);
writingLock.unlock();
return;
}
writingQueue.add(buffer);
writingLock.unlock();
write();
}
/**
* Handles the writing of all buffers in the queue.
*/
public void write() {
if (!key.isValid()) {
disconnect();
return;
}
writingLock.lock();
SocketChannel channel = (SocketChannel) key.channel();
try {
while (!writingQueue.isEmpty()) {
ByteBuffer buffer = writingQueue.get(0);
channel.write(buffer);
if (buffer.hasRemaining()) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
break;
}
writingQueue.remove(0);
}
} catch (IOException e) {
disconnect();
}
writingLock.unlock();
}
/**
* Disconnects the session.
*/
public void disconnect() {
try {
if (!active) {
return;
}
active = false;
key.cancel();
SocketChannel channel = (SocketChannel) key.channel();
channel.socket().close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Gets the IP-address (without the port).
* @return The address.
*/
public String getAddress() {
return address;
}
/**
* Gets the remote address of this session.
* @return The remote address, as a String.
*/
public String getRemoteAddress() {
try {
return ((SocketChannel) key.channel()).getRemoteAddress().toString();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Gets the current event producer.
* @return The producer.
*/
public EventProducer getProducer() {
return producer;
}
/**
* Sets the event producer.
* @param producer The producer to set.
*/
public void setProducer(EventProducer producer) {
this.producer = producer;
}
/**
* Gets the queued reading data.
* @return The readingQueue.
*/
public ByteBuffer getReadingQueue() {
synchronized (this) {
return readingQueue;
}
}
/**
* Queues reading data.
* @param readingQueue The readingQueue to set.
*/
public void setReadingQueue(ByteBuffer readingQueue) {
synchronized (this) {
this.readingQueue = readingQueue;
}
}
/**
* Gets the writing lock.
* @return The writing lock.
*/
public Lock getWritingLock() {
return writingLock;
}
/**
* Gets the selection key.
* @return The selection key.
*/
public SelectionKey getKey() {
return key;
}
/**
* @return The active.
*/
public boolean isActive() {
return active;
}
/**
* @return The js5Encryption.
*/
public int getJs5Encryption() {
return js5Encryption;
}
/**
* @param js5Encryption The js5Encryption to set.
*/
public void setJs5Encryption(int js5Encryption) {
this.js5Encryption = js5Encryption;
}
/**
* Gets the lastPing.
* @return The lastPing.
*/
public long getLastPing() {
return lastPing;
}
/**
* Sets the lastPing.
* @param lastPing The lastPing to set.
*/
public void setLastPing(long lastPing) {
this.lastPing = lastPing;
}
/**
* Gets the nameHash.
* @return The nameHash.
*/
public int getNameHash() {
return nameHash;
}
/**
* Sets the nameHash.
* @param nameHash The nameHash to set.
*/
public void setNameHash(int nameHash) {
this.nameHash = nameHash;
}
/**
* Gets the serverKey.
* @return The serverKey.
*/
public long getServerKey() {
return serverKey;
}
/**
* Sets the serverKey.
* @param serverKey The serverKey to set.
*/
public void setServerKey(long serverKey) {
this.serverKey = serverKey;
}
/**
* Gets the gameServer value.
* @return The gameServer.
*/
public GameServer getGameServer() {
return gameServer;
}
/**
* Sets the gameServer value.
* @param gameServer The gameServer to set.
*/
public void setGameServer(GameServer gameServer) {
this.gameServer = gameServer;
}
}
@@ -0,0 +1,50 @@
package ms.net;
import java.nio.channels.CancelledKeyException;
/**
* Handles a writing event.
* @author Emperor
*/
public abstract class IoWriteEvent implements Runnable {
/**
* The I/O session.
*/
private final IoSession session;
/**
* The buffer.
*/
private final Object context;
/**
* Constructs a new {@code IoWriteEvent}.
* @param session The session.
* @param context The write event context.
*/
public IoWriteEvent(IoSession session, Object context) {
this.session = session;
this.context = context;
}
@Override
public void run() {
try {
write(session, context);
} catch (Throwable t) {
if (!(t instanceof CancelledKeyException)) {
t.printStackTrace();
}
session.disconnect();
}
}
/**
* Writes the data.
* @param session The session.
* @param context The write event context.
*/
public abstract void write(IoSession session, Object context);
}
@@ -0,0 +1,133 @@
package ms.net;
import ms.Management;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Handles (NIO-based) networking events using the reactor pattern.
* @author Emperor
*/
public final class NioReactor implements Runnable {
/**
* The executor service.
*/
private final ExecutorService service;
/**
* The selector
*/
private Selector selector;
/**
* The socket channel.
*/
private ServerSocketChannel channel;
/**
* The I/O event handling instance.
*/
private final IoEventHandler eventHandler;
/**
* If the reactor is running.
*/
private boolean running;
/**
* Constructs a new {@code NioReactor}.
* @param poolSize The pool size.
*/
private NioReactor(int poolSize) {
this.service = Executors.newSingleThreadScheduledExecutor();
this.eventHandler = new IoEventHandler(Executors.newFixedThreadPool(poolSize));
}
/**
* Creates and configures a new {@code NioReactor} with a pool size of 1.
* @param port The port.
* @return The {@code NioReactor} {@code Object}.
* @throws IOException When an I/O exception occurs.
*/
public static NioReactor configure(int port) throws IOException {
return configure(port, 1);
}
/**
* Creates and configures a new {@code NioReactor}.
* @param port The port.
* @param poolSize The amount of threads in the thread pool.
* @return The {@code NioReactor} {@code Object}.
* @throws IOException When an I/O exception occurs.
*/
public static NioReactor configure(int port, int poolSize) throws IOException {
NioReactor reactor = new NioReactor(poolSize);
reactor.channel = ServerSocketChannel.open();
reactor.selector = Selector.open();
reactor.channel.bind(new InetSocketAddress(port));
reactor.channel.configureBlocking(false);
reactor.channel.register(reactor.selector, SelectionKey.OP_ACCEPT);
return reactor;
}
/**
* Starts the reactor.
*/
public void start() {
running = true;
service.execute(this);
}
@Override
public void run() {
while (running && Management.active) {
try {
if(selector.select() > 0){
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
try {
if (!key.isValid() || !key.channel().isOpen()) {
key.cancel();
continue;
}
if (key.isAcceptable()) {
eventHandler.accept(key, selector);
}
if (key.isReadable()) {
eventHandler.read(key);
}
else if (key.isWritable()) {
eventHandler.write(key);
}
} catch (Throwable t) {
eventHandler.disconnect(key, t);
}
}
} else {
System.out.println("SLEEPING");
Thread.sleep(200);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Terminates the reactor (once it's done processing current I/O events).
*/
public void terminate() {
running = false;
}
}
@@ -0,0 +1,54 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.world.WorldDatabase;
import ms.system.util.ByteBufferUtils;
/**
* Handles handshake read events.
* @author Emperor
*/
public final class HSReadEvent extends IoReadEvent {
/**
* The password used to verify
*/
private static final String PASSWORD = "0x14ari0SSbh98989910";
/**
* Constructs a new {@code HSReadEvent}.
* @param session The session.
* @param buffer The buffer.
*/
public HSReadEvent(IoSession session, ByteBuffer buffer) {
super(session, buffer);
}
@Override
public void read(IoSession session, ByteBuffer buffer) {
int opcode = buffer.get() & 0xFF;
switch (opcode) {
case 88:
String password = ByteBufferUtils.getString(buffer);
if (!password.equals(PASSWORD)) {
System.out.println("Password mismatch (attempt=" + password + ")!");
session.disconnect();
break;
}
session.write(opcode);
break;
case 255: // World list
int updateStamp = buffer.getInt();
WorldDatabase.sendUpdate(session, updateStamp);
break;
default:
System.err.println("Unhandled handshake opcode: " + opcode + ".");
session.disconnect();
break;
}
}
}
@@ -0,0 +1,38 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.producer.RegistryEventProducer;
/**
* Handles Handshake write events.
* @author Emperor
*/
public final class HSWriteEvent extends IoWriteEvent {
/**
* The login event producer.
*/
private static final RegistryEventProducer REGISTRY_PRODUCER = new RegistryEventProducer();
/**
* Constructs a new {@code HSWriteEvent} {@code Object}.
* @param session The session.
* @param context The context.
*/
public HSWriteEvent(IoSession session, Object context) {
super(session, context);
}
@Override
public void write(IoSession session, Object context) {
ByteBuffer buffer = ByteBuffer.allocate(9);
buffer.put((byte) 14);
session.setProducer( REGISTRY_PRODUCER);
buffer.flip();
session.queue(buffer);
}
}
@@ -0,0 +1,101 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.net.packet.WorldPacketRepository;
/**
* Handles world packet reading events.
* @author Emperor
*
*/
public final class PacketReadEvent extends IoReadEvent {
/**
* The packet sizes.
*/
private static final int[] PACKET_SIZE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
/**
* Constructs a new {@code PacketReadEvent} {@code Object}.
* @param session The I/O session.
* @param buffer The buffer to read from.
*/
public PacketReadEvent(IoSession session, ByteBuffer buffer) {
super(session, buffer);
}
@Override
public void read(IoSession session, ByteBuffer buffer) {
int last = -1;
while (buffer.hasRemaining()) {
int opcode = buffer.get() & 0xFF;
if (opcode >= PACKET_SIZE.length) {
break;
}
int header = PACKET_SIZE[opcode];
int size = header;
if (header < 0) {
size = getPacketSize(buffer, opcode, header, last);
}
if (size == -1) {
break;
}
if (buffer.remaining() < size) {
switch (header) {
case -2:
queueBuffer(opcode, size >> 8, size);
break;
case -1:
queueBuffer(opcode, size);
break;
default:
queueBuffer(opcode);
break;
}
break;
}
byte[] data = new byte[size];
buffer.get(data);
last = opcode;
try {
WorldPacketRepository.handleIncoming(session, opcode, ByteBuffer.wrap(data));
} catch (Throwable t) {
t.printStackTrace();
}
}
}
/**
* Gets the packet size for the given opcode.
* @param buffer The buffer.
* @param opcode The opcode.
* @param header The packet header.
* @param last The last opcode.
* @return The packet size.
*/
private int getPacketSize(ByteBuffer buffer, int opcode, int header, int last) {
if (header == -1) {
if (buffer.remaining() < 1) {
queueBuffer(opcode);
return -1;
}
return buffer.get() & 0xFF;
}
if (header == -2) {
if (buffer.remaining() < 2) {
queueBuffer(opcode);
return -1;
}
return buffer.getShort() & 0xFFFF;
}
System.err.println("Invalid packet [opcode=" + opcode + ", last=" + last + ", queued=" + usedQueuedBuffer + "]!");
return -1;
}
}
@@ -0,0 +1,46 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.packet.IoBuffer;
/**
* Handles world packet writing events.
* @author Emperor
*
*/
public final class PacketWriteEvent extends IoWriteEvent {
/**
* Constructs a new {@code PacketWriteEvent} {@code Object}.
* @param session The I/O session.
* @param context The packet context.
*/
public PacketWriteEvent(IoSession session, Object context) {
super(session, context);
}
@Override
public void write(IoSession session, Object context) {
IoBuffer b = (IoBuffer) context;
int size = b.toByteBuffer().position();
ByteBuffer buffer = ByteBuffer.allocate(1 + size + b.getHeader().ordinal());
buffer.put((byte) b.opcode());
switch (b.getHeader()) {
case NORMAL:
break;
case BYTE:
buffer.put((byte) size);
break;
case SHORT:
buffer.putShort((short) size);
break;
}
buffer.put((ByteBuffer) b.toByteBuffer().flip());
session.queue((ByteBuffer) buffer.flip());
}
}
@@ -0,0 +1,75 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.ServerConstants;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.world.WorldDatabase;
import ms.system.util.ByteBufferUtils;
import ms.world.info.CountryFlag;
import ms.world.info.WorldInfo;
/**
* Handles world registry read events.
* @author Emperor
*
*/
public final class RegistryReadEvent extends IoReadEvent {
/**
* The string check.
*/
private static final String CHECK = "12x4578f5g45hrdjiofed59898";
//kratos = 666x14x88x28shhhwpwwb&h
//12x4578f5g45hrdjiofed59898
/**
* Constructs a new {@code RegistryReadEvent} {@code Object}.
* @param session The session.
* @param buffer The buffer to read.
*/
public RegistryReadEvent(IoSession session, ByteBuffer buffer) {
super(session, buffer);
}
@Override
public void read(IoSession session, ByteBuffer buffer) {
int worldId = buffer.get() & 0xFF;
if (buffer.remaining() < 2) {
queueBuffer(worldId);
return;
}
int revision = buffer.getInt();
int country = buffer.get() & 0xFF;
boolean members = buffer.get() == 1;
boolean pvp = buffer.get() == 1;
boolean quickChat = buffer.get() == 1;
boolean lootshare = buffer.get() == 1;
String activity = ByteBufferUtils.getString(buffer);
System.out.println("["+ revision + "], country = " + country + ", members = " + members + ", pvp = " + pvp + ", quickChat = " + quickChat + ", lootShare = " + lootshare + ", activity = " + activity);
for (int i = 0; i < CHECK.length(); i++) {
if ((char) buffer.get() != CHECK.charAt(i)) {
session.write(3);
return;
}
}
if (worldId >= ServerConstants.WORLD_LIMIT) {
session.write(0);
return;
}
if (WorldDatabase.isActive(worldId)) {
session.write(2);
return;
}
try {
WorldInfo info = new WorldInfo(worldId, session.getAddress(), revision, CountryFlag.values()[country], activity, members, pvp, quickChat, lootshare);
WorldDatabase.register(info).configure(session);
session.write(1);
} catch (Throwable t) {
t.printStackTrace();
session.write(3);
}
}
}
@@ -0,0 +1,43 @@
package ms.net.event;
import java.nio.ByteBuffer;
import ms.net.EventProducer;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.producer.PacketEventProducer;
/**
* Handles game world registry writing events.
* @author Emperor
*
*/
public final class RegistryWriteEvent extends IoWriteEvent {
/**
* The event producer.
*/
public static final EventProducer PRODUCER = new PacketEventProducer();
/**
* Constructs a new {@code RegistryWriteEvent} {@code Object}.
* @param session The I/O session.
* @param context The writing context.
*/
public RegistryWriteEvent(IoSession session, Object context) {
super(session, context);
}
@Override
public void write(IoSession session, Object context) {
ByteBuffer buffer = ByteBuffer.allocate(1);
int opcode = (int) context;
buffer.put((byte) opcode);
buffer.flip();
if (opcode == 1) {
session.setProducer(PRODUCER);
}
session.queue(buffer);
}
}
@@ -0,0 +1,677 @@
package ms.net.packet;
import java.nio.ByteBuffer;
import ms.system.util.ByteBufferUtils;
/**
* Represents the buffer used for reading/writing packets.
* @author Emperor
*
*/
public class IoBuffer {
/**
* The bit masks.
*/
private static final int[] BIT_MASK = new int[32];
/**
* The packet size.
*/
private int packetSize;
/**
* The opcode.
*/
private final int opcode;
/**
* The packet header.
*/
private final PacketHeader header;
/**
* The byte buffer.
*/
private ByteBuffer buf;
/**
* The bit position.
*/
private int bitPosition = 0;
/**
* Constructs a new {@code IoBuffer} {@code Object}.
*/
public IoBuffer() {
this(-1, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
}
/**
* Constructs a new {@code IoBuffer} {@code Object}.
* @param opcode The opcode.
*/
public IoBuffer(int opcode) {
this(opcode, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
}
/**
* Constructs a new {@code IoBuffer} {@code Object}.
* @param opcode The opcode.
* @param header The packet header.
*/
public IoBuffer(int opcode, PacketHeader header) {
this(opcode, header, ByteBuffer.allocate((1 << 16) + 1));
}
/**
* Constructs a new {@code IoBuffer} {@code Object}.
* @param opcode The opcode.
* @param header The packet header.
* @param buf The byte buffer.
*/
public IoBuffer(int opcode, PacketHeader header, ByteBuffer buf) {
this.opcode = opcode;
this.header = header;
this.buf = buf;
}
static {
for (int i = 0; i < 32; i++) {
BIT_MASK[i] = (1 << i) - 1;
}
}
/**
*
* @return
*/
public IoBuffer clear() {
buf.clear();
bitPosition = 0;
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer put(int val) {
buf.put((byte) val);
return this;
}
/**
*
* @param datas
* @param offset
* @param len
* @return
*/
public IoBuffer putBytes(byte[] datas, int offset, int len) {
for (int i = offset; i < len; i++) {
put(datas[i]);
}
return this;
}
public final void getBytes(byte data[], int off, int len) {
for (int k = off; k < len + off; k++) {
data[k] = data[off++];
}
}
/**
*
* @param val
* @return
*/
public IoBuffer putA(int val) {
buf.put((byte) (val + 128));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putC(int val) {
buf.put((byte) -val);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putS(int val) {
buf.put((byte) (128 - val));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putTri(int val) {
buf.put((byte) (val >> 16));
buf.put((byte) (val >> 8));
buf.put((byte) val);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putShort(int val) {
buf.putShort((short) val);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putLEShort(int val) {
buf.put((byte) val);
buf.put((byte) (val >> 8));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putShortA(int val) {
buf.put((byte) (val >> 8));
buf.put((byte) (val + 128));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putLEShortA(int val) {
buf.put((byte) (val + 128));
buf.put((byte) (val >> 8));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putInt(int val) {
buf.putInt(val);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putLEInt(int val) {
buf.put((byte) val);
buf.put((byte) (val >> 8));
buf.put((byte) (val >> 16));
buf.put((byte) (val >> 24));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putIntA(int val) {
buf.put((byte) (val >> 8));
buf.put((byte) val);
buf.put((byte) (val >> 24));
buf.put((byte) (val >> 16));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putIntB(int val) {
buf.put((byte) (val >> 16));
buf.put((byte) (val >> 24));
buf.put((byte) val);
buf.put((byte) (val >> 8));
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putLong(long val) {
buf.putLong(val);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putSmart(int val) {
if (val > Byte.MAX_VALUE) {
buf.putShort((short) (val + 32768));
} else {
buf.put((byte) val);
}
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putIntSmart(int val) {
if (val > Short.MAX_VALUE) {
buf.putInt(val + 32768);
} else {
buf.putShort((short) val);
}
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putString(String val) {
buf.put(val.getBytes());
buf.put((byte) 0);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putJagString(String val) {
buf.put((byte) 0);
buf.put(val.getBytes());
buf.put((byte) 0);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer putJagString2(String val) {
byte[] packed = new byte[256];
int length = ByteBufferUtils.packGJString2(0, packed, val);
buf.put((byte) 0).put(packed, 0, length).put((byte) 0);
return this;
}
/**
*
* @param val
* @return
*/
public IoBuffer put(byte[] val) {
buf.put(val);
return this;
}
/**
* Puts a byte array as byte A in reverse.
* @param data The data to put.
* @param start The start index.
* @param offset The offset.
*/
public void putReverseA(byte[] data, int start, int offset) {
for (int i = offset + start; i >= start; i--) {
putA(data[i]);
}
}
/**
*
* @param numBits
* @param value
* @return
*/
public IoBuffer putBits(int numBits, int value) {
int bytePos = getBitPosition() >> 3;
int bitOffset = 8 - (getBitPosition() & 7);
bitPosition += numBits;
for (; numBits > bitOffset; bitOffset = 8) {
byte b = buf.get(bytePos);
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
buf.put(bytePos++, b |= value >> numBits - bitOffset & BIT_MASK[bitOffset]);
numBits -= bitOffset;
}
byte b = buf.get(bytePos);
if (numBits == bitOffset) {
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
buf.put(bytePos, b |= value & BIT_MASK[bitOffset]);
} else {
buf.put(bytePos, b &= ~(BIT_MASK[numBits] << bitOffset - numBits));
buf.put(bytePos, b |= (value & BIT_MASK[numBits]) << bitOffset - numBits);
}
return this;
}
/**
*
* @param buffer
* @return
*/
public IoBuffer put(IoBuffer buffer) {
buffer.toByteBuffer().flip();
buf.put(buffer.toByteBuffer());
return this;
}
/**
*
* @param buffer
* @return
*/
public IoBuffer putA(IoBuffer buffer) {
buffer.toByteBuffer().flip();
while (buffer.toByteBuffer().hasRemaining()) {
putA(buffer.toByteBuffer().get());
}
return this;
}
/**
*
* @param buffer
* @return
*/
public IoBuffer put(ByteBuffer buffer) {
buf.put(buffer);
return this;
}
/**
*
* @return
*/
public IoBuffer setBitAccess() {
bitPosition = buf.position() * 8;
return this;
}
/**
*
* @return
*/
public IoBuffer setByteAccess() {
buf.position((getBitPosition() + 7) / 8);
return this;
}
/**
*
* @return
*/
public int get() {
return buf.get();
}
/**
*
* @return
*/
public int getA() {
return (buf.get() & 0xFF) - 128;
}
/**
*
* @return
*/
public int getC() {
return -buf.get();
}
/**
*
* @return
*/
public int getS() {
return 128 - buf.get();
}
/**
*
* @return
*/
public int getTri() {
return ((buf.get() << 16) & 0xFF) | ((buf.get() << 8) & 0xFF) | (buf.get() & 0xFF);
}
/**
*
* @return
*/
public int getShort() {
return buf.getShort();
}
/**
*
* @return
*/
public int getLEShort() {
return (buf.get() & 0xFF) | ((buf.get() & 0xFF) << 8);
}
/**
*
* @return
*/
public int getShortA() {
return ((buf.get() & 0xFF) << 8) | (buf.get() - 128 & 0xFF);
}
/**
*
* @return
*/
public int getLEShortA() {
return (buf.get() - 128 & 0xFF) | ((buf.get() & 0xFF) << 8);
}
/**
*
* @return
*/
public int getInt() {
return buf.getInt();
}
/**
*
* @return
*/
public int getLEInt() {
return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8)
+ ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24);
}
/**
*
* @return
*/
public int getIntA() {
return ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF)+ ((buf.get() & 0xFF) << 24) + ((buf.get() & 0xFF) << 16);
}
/**
*
* @return
*/
public int getIntB() {
return ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24)
+ (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8);
}
/**
*
* @return
*/
public long getLongL() {
long first = getIntB();
long second = getIntB();
if (second < 0)
second = second & 0xffffffffL;
return (first << -41780448) + second;
}
/**
*
* @return
*/
public long getLong() {
return buf.getLong();
}
/**
*
* @return
*/
public int getSmart() {
int peek = buf.get(buf.position());
if (peek <= Byte.MAX_VALUE) {
return buf.get() & 0xFF;
}
return (buf.getShort() & 0xFFFF) - 32768;
}
/**
*
* @return
*/
public int getIntSmart() {
int peek = buf.getShort(buf.position());
if (peek <= Short.MAX_VALUE) {
return buf.getShort() & 0xFFFF;
}
return (buf.getInt() & 0xFFFFFFFF) - 32768;
}
/**
*
* @return
*/
public String getString() {
return ByteBufferUtils.getString(buf);
}
/**
*
* @return
*/
public String getJagString() {
buf.get();
return ByteBufferUtils.getString(buf);
}
/**
*
* @param is
* @param offset
* @param length
* @return
*/
public IoBuffer getReverseA(byte[] is, int offset, int length) {
for (int i = (offset + length - 1); i >= offset; i--) {
is[i] = (byte) (buf.get() - 128);
}
return this;
}
/**
*
* @return
*/
public ByteBuffer toByteBuffer() {
return buf;
}
/**
*
* @return
*/
public int opcode() {
return opcode;
}
/**
*
* @return
*/
public int readableBytes() {
return buf.capacity() - buf.remaining();
}
/**
*
* @return
*/
public PacketHeader getHeader() {
return header;
}
/**
*
* @return
*/
public byte[] array() {
return buf.array();
}
/**
* @return the packetSize.
*/
public int getPacketSize() {
return packetSize;
}
/**
* @param packetSize the packetSize to set.
*/
public void setPacketSize(int packetSize) {
this.packetSize = packetSize;
}
/**
* Gets the bitPosition.
* @return The bitPosition.
*/
public int getBitPosition() {
return bitPosition;
}
}
@@ -0,0 +1,25 @@
package ms.net.packet;
/**
* Represents the types of packet headers.
* @author Emperor
*
*/
public enum PacketHeader {
/**
* The normal packet header.
*/
NORMAL,
/**
* The byte packet header.
*/
BYTE,
/**
* The short packet header.
*/
SHORT;
}
@@ -0,0 +1,587 @@
package ms.net.packet;
import java.nio.ByteBuffer;
import java.util.List;
import ms.ServerConstants;
import ms.net.IoSession;
import ms.system.PunishmentStorage;
import ms.world.GameServer;
import ms.world.PlayerSession;
import ms.world.WorldDatabase;
import ms.system.communication.ClanRank;
import ms.system.communication.ClanRepository;
import ms.system.communication.CommunicationInfo;
import ms.world.info.Response;
import ms.world.info.UIDInfo;
/**
* Repository class for world packets.
* @author Emperor
*
*/
public final class WorldPacketRepository {
/**
* Sends the player registry response.
* @param server The game server.
* @param player The player session.
* @param response The registry response.
*/
public static void sendRegistryResponse(GameServer server, PlayerSession player, Response response) {
IoBuffer buffer = new IoBuffer(0, PacketHeader.BYTE);
buffer.putString(player.getUsername());
buffer.put((byte) response.opcode());
if (response == Response.MOVING_WORLD) {
long delay = ServerConstants.WORLD_SWITCH_DELAY - (System.currentTimeMillis() - player.getDisconnectionTime());
buffer.put((byte) (delay / 1000));
}
server.getSession().write(buffer);
}
/**
* Sends a message to the player.
* @param player The player.
* @param message The message to send.
*/
public static void sendPlayerMessage(PlayerSession player, String message) {
if (player == null) {
return;
}
IoBuffer buffer = new IoBuffer(2, PacketHeader.BYTE);
buffer.putString(player.getUsername());
buffer.putString(message);
player.getWorld().getSession().write(buffer);
}
public static void sendPlayerMessage(PlayerSession player, String[] messages) {
if (player == null) {
return;
}
for (String message : messages)
sendPlayerMessage(player, message);
}
/**
* Sends the contact information.
* @param player The player.
*/
public static void sendContactInformation(PlayerSession player) {
CommunicationInfo info = player.getCommunication();
IoBuffer buffer = new IoBuffer(3, PacketHeader.SHORT);
buffer.putString(player.getUsername());
buffer.put(info.getContacts().size());
for (String contact : info.getContacts().keySet()) {
buffer.putString(contact);
buffer.put(info.getRank(contact).ordinal());
buffer.put(CommunicationInfo.getWorldId(player, contact));
}
buffer.put(info.getBlocked().size());
for (String contact : info.getBlocked()) {
buffer.putString(contact);
}
if (info.getCurrentClan() == null) {
buffer.put(0);
} else {
buffer.put(1);
buffer.putString(info.getCurrentClan());
}
player.getWorld().getSession().write(buffer);
}
/**
* Sends a contact update.
* @param player The player who's contacts we're changing.
* @param contact The contact to update.
* @param block If we're updating the blocked list.
* @param remove If the contact should be removed.
* @param worldId The world id of the contact.
* @param rank The clan rank.
*/
public static void sendContactUpdate(PlayerSession player, String contact, boolean block, boolean remove, int worldId, ClanRank rank) {
IoBuffer buffer = new IoBuffer(4, PacketHeader.BYTE);
buffer.putString(player.getUsername());
buffer.putString(contact);
buffer.put((byte) (block ? 1 : 0));
if (rank != null) {
buffer.put((byte) (2 + rank.ordinal()));
} else {
buffer.put((byte) (remove ? 1 : 0));
if (!block && !remove) {
buffer.put((byte) worldId);
}
}
player.getWorld().getSession().write(buffer);
}
/**
* Sends a clan message.
* @param player The player to send the message to.
* @param p The player sending the message.
* @param message The message to send.
* @param type The message type.
*/
public static void sendMessage(PlayerSession player, PlayerSession p, int type, String message) {
IoBuffer buffer = new IoBuffer(5, PacketHeader.BYTE);
buffer.putString(player.getUsername());
buffer.putString(p.getUsername());
buffer.put((byte) type);
buffer.put((byte) p.getChatIcon());
buffer.putString(message);
player.getWorld().getSession().write(buffer);
}
/**
* Sends clan information to the server.
* @param server The server.
* @param clan The clan.
*/
public static void sendClanInformation(GameServer server, ClanRepository clan) {
IoBuffer buffer = new IoBuffer(6, PacketHeader.SHORT);
buffer.putString(clan.getOwner().getUsername());
buffer.putString(clan.getName());
int length = clan.getPlayers().size();
if (length > ClanRepository.MAX_MEMBERS) {
length = ClanRepository.MAX_MEMBERS;
}
buffer.put((byte) length);
for (int i = 0; i < length; i++) {
PlayerSession player = clan.getPlayers().get(i);
buffer.putString(player.getUsername());
buffer.put(player.getWorldId());
buffer.put((byte) clan.getRank(player).ordinal());
}
buffer.put((byte) clan.getJoinRequirement().ordinal());
buffer.put((byte) clan.getKickRequirement().ordinal());
buffer.put((byte) clan.getMessageRequirement().ordinal());
buffer.put((byte) clan.getLootRequirement().ordinal());
server.getSession().write(buffer);
}
/**
* Sends the leave clan packet.
* @param player The player leaving the clan.
*/
public static void sendLeaveClan(PlayerSession player) {
IoBuffer buffer = new IoBuffer(7, PacketHeader.BYTE);
buffer.putString(player.getUsername());
player.getWorld().getSession().write(buffer);
}
/**
* Sends the player login notification.
* @param server The server.
* @param player The player logging in.
* @param names The names.
*/
public static void notifyPlayers(GameServer server, PlayerSession player, List<String> names) {
IoBuffer buffer = new IoBuffer(8, PacketHeader.SHORT);
buffer.putString(player.getUsername());
buffer.put((byte) player.getWorldId());
buffer.put((byte) names.size());
for (String name : names) {
buffer.putString(name);
}
server.getSession().write(buffer);
}
/**
* Notifies the game server a player logged out.
* @param server The game server to notify.
* @param player The player logging out.
*/
public static void notifyLogout(GameServer server, PlayerSession player) {
IoBuffer buffer = new IoBuffer(9, PacketHeader.BYTE);
buffer.putString(player.getUsername());
server.getSession().write(buffer);
}
/**
* Sends the update countdown to the server.
* @param server The server.
* @param ticks The amount of ticks left.
*/
public static void sendUpdate(GameServer server, int ticks) {
IoBuffer buffer = new IoBuffer(10);
buffer.putInt(ticks);
server.getSession().write(buffer);
}
/**
* Sends the punishment update packet.
* @param world The world to send the packet to.
* @param key The punishment key.
* @param type The punishment type.
* @param duration The duration of the punishment.
*/
public static void sendPunishUpdate(GameServer world, String key, int type, long duration) {
IoBuffer buffer = new IoBuffer(11, PacketHeader.BYTE);
buffer.putString(key);
buffer.put((byte) type);
buffer.putLong(duration);
world.getSession().write(buffer);
}
/**
* Sends a configuration reload.
* @param world the world.
*/
public static void sendConfigReload(GameServer world) {
world.getSession().write(new IoBuffer(15, PacketHeader.BYTE));
}
/**
* Handles incoming world packets.
* @param session The I/O session.
* @param opcode The opcode.
* @param b The buffer to read from.
*/
public static void handleIncoming(IoSession session, int opcode, ByteBuffer b) {
IoBuffer buffer = new IoBuffer(opcode, PacketHeader.NORMAL, b);
GameServer server = session.getGameServer();
switch (opcode) {
case 0:
handlePlayerRegistration(server, buffer);
break;
case 1:
handlePlayerRemoval(server, buffer);
break;
case 2:
handlePunishment(server, buffer);
break;
case 3:
handleCommunicationRequest(server, buffer);
break;
case 4:
case 5:
handleContactUpdate(server, buffer, opcode == 5);
break;
case 6:
handleJoinClan(server, buffer);
break;
case 7:
handleClanRename(server, buffer);
break;
case 8:
handleClanSetting(server, buffer);
break;
case 9:
handleClanKick(server, buffer);
break;
case 10:
handleClanMessage(server, buffer);
break;
case 11:
handlePrivateMessage(server, buffer);
break;
case 12:
handleClanInfoRequest(server, buffer);
break;
case 13:
handleChatSetting(server, buffer);
break;
case 14:
handleInfoUpdate(server, buffer);
break;
default:
System.err.println("Handling incoming packet [opcode=" + opcode + ", size=" + b.limit() + "].");
}
}
/**
* Handles the info of a player update.
* @param server the server.
* @param buffer the buffer.
*/
private static void handleInfoUpdate(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player != null) {
player.setChatIcon((int) buffer.get());
}
}
/**
* Handles a player registration.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handlePlayerRegistration(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
String password = buffer.getString();
String ipAddress = buffer.getString();
String macAddress = buffer.getString();
String compName = buffer.getString();
String serial = buffer.getString();
int rights = server.getInfo().getRevision() == 498 ? 0 : buffer.getInt();
int chatIcon = server.getInfo().getRevision() == 498 ? 0 : buffer.get();
UIDInfo uid = new UIDInfo(ipAddress, compName, macAddress, serial);
PlayerSession player = new PlayerSession(username, password, new UIDInfo(ipAddress, compName, macAddress, serial));
if (WorldDatabase.isActivePlayer(username)) {
sendRegistryResponse(server, player, Response.ALREADY_ONLINE);
return;
}
player.setUid(uid);
player.setRights(rights);
player.setChatIcon(chatIcon);
if (PunishmentStorage.isSystemBanned(uid)) {
sendRegistryResponse(server, player, Response.BANNED);
return;
}
player.parse();
if (player.isBanned()) {
sendRegistryResponse(server, player, Response.ACCOUNT_DISABLED);
return;
}
if (player.getLastWorld() != server.getInfo().getWorldId() && player.hasMovedWorld()) {
sendRegistryResponse(server, player, Response.MOVING_WORLD);
return;
}
server.register(player);
}
/**
* Handles the removal of a player.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handlePlayerRemoval(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
PlayerSession session = server.getPlayers().get(username);
if (session != null) {
session.setActive(false);
PlayerSession player = server.getPlayers().remove(username);
if (player != null) {
session.remove();
}
session.setWorldId(0);
}
}
/**
* Handles a player registration.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handlePunishment(GameServer server, IoBuffer buffer) {
int type = buffer.get() & 0xFF;
String target = buffer.getString();
long duration = buffer.getLong();
String staff = buffer.getString();
PunishmentStorage.handlePunishment(staff, target, type, duration);
}
/**
* Handles the communication info request packet.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handleCommunicationRequest(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null) {
return;
}
sendContactInformation(player);
}
/**
* Handles a contact update packet.
* @param server The server.
* @param buffer The buffer to read from.
* @param block If the list is for blocked players.
*/
private static void handleContactUpdate(GameServer server, IoBuffer buffer, boolean block) {
String username = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null) {
return;
}
String contact = buffer.getString();
switch (buffer.get()) {
case 0:
if (block) {
player.getCommunication().block(contact);
break;
}
player.getCommunication().add(contact);
break;
case 1:
player.getCommunication().remove(contact, block);
break;
case 2:
player.getCommunication().updateClanRank(contact, ClanRank.values()[buffer.get()]);
break;
}
}
/**
* Handles a clan related packet.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handleJoinClan(GameServer server, IoBuffer buffer) {
String name = buffer.getString();
String clanName = buffer.getString();
PlayerSession player = server.getPlayers().get(name);
if (player == null || !player.isActive()) {
System.err.println("Invalid player specified in clan packet!");
return;
}
if (player.getClan() != null) {
player.getClan().leave(player, true);
return;
}
if (clanName.length() < 1) {
sendLeaveClan(player);
return;
}
ClanRepository clan = ClanRepository.get(server, clanName);
if (clan == null) {
sendPlayerMessage(player, new String[]{ "The channel you tried to join does not exist.", "Try joining the main clan named '" + ServerConstants.SERVER_NAME + "'.:clan:" });
return;
}
clan.enter(player);
}
/**
* Handles renaming a clan.
* @param server The server.
* @param buffer The buffer.
*/
private static void handleClanRename(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
String name = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null || !player.isActive()) {
return;
}
ClanRepository clan = ClanRepository.getClans().get(username);
player.getCommunication().setClanName(name);
if (clan != null) {
if (name.length() < 1) {
clan.clean(true);
} else {
clan.rename(name);
}
}
}
/**
* Handles changing clan settings packet.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handleClanSetting(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
int type = buffer.get();
ClanRank rank = type < 4 ? ClanRank.values()[buffer.get() & 0xFF] : null;
PlayerSession player = server.getPlayers().get(username);
if (player == null || !player.isActive()) {
return;
}
ClanRepository clan = ClanRepository.get(server,username);
switch (type) {
case 0:
player.getCommunication().setJoinRequirement(rank);
if (clan != null) {
clan.clean(false);
}
break;
case 1:
player.getCommunication().setMessageRequirement(rank);
break;
case 2:
player.getCommunication().setKickRequirement(rank);
if (clan != null) {
clan.update();
}
break;
case 3:
player.getCommunication().setLootRequirement(rank);
break;
}
}
/**
* Handles kicking a player from the clan.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handleClanKick(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
String playerName = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null || !player.isActive() || player.getClan() == null) {
return;
}
PlayerSession target = WorldDatabase.getPlayer(playerName);
if (target == null || !target.isActive()) {
return;
}
player.getClan().kick(player, target);
}
/**
* Handles a clan message.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handleClanMessage(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
String message = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null || !player.isActive() || player.getClan() == null) {
return;
}
player.getClan().message(player, message);
}
/**
* Handles a clan message.
* @param server The game server.
* @param buffer The buffer.
*/
private static void handlePrivateMessage(GameServer server, IoBuffer buffer) {
String username = buffer.getString();
String receiver = buffer.getString();
String message = buffer.getString();
PlayerSession player = server.getPlayers().get(username);
if (player == null || !player.isActive()) {
return;
}
player.getCommunication().sendMessage(receiver, message);
}
/**
* Handles a clan information request packet.
* @param server The server.
* @param buffer The buffer.
*/
private static void handleClanInfoRequest(GameServer server, IoBuffer buffer) {
String name = buffer.getString();
ClanRepository clan = ClanRepository.get(server, name);
if (clan == null) {
return;
}
sendClanInformation(server, clan);
}
/**
* Handles a chat setting update packet.
* @param server The server.
* @param buffer The buffer.
*/
private static void handleChatSetting(GameServer server, IoBuffer buffer) {
String name = buffer.getString();
int publicSetting = buffer.get();
int privateSetting = buffer.get();
int tradeSetting = buffer.get();
PlayerSession player = server.getPlayers().get(name);
if (player == null || !player.isActive()) {
return;
}
player.getCommunication().updateSettings(publicSetting, privateSetting, tradeSetting);
}
}
@@ -0,0 +1,29 @@
package ms.net.producer;
import java.nio.ByteBuffer;
import ms.net.EventProducer;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.event.HSReadEvent;
import ms.net.event.HSWriteEvent;
/**
* Produces I/O events for the handshake protocol.
* @author Emperor
*
*/
public final class HSEventProducer implements EventProducer {
@Override
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
return new HSReadEvent(session, buffer);
}
@Override
public IoWriteEvent produceWriter(IoSession session, Object context) {
return new HSWriteEvent(session, context);
}
}
@@ -0,0 +1,29 @@
package ms.net.producer;
import java.nio.ByteBuffer;
import ms.net.EventProducer;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.event.PacketReadEvent;
import ms.net.event.PacketWriteEvent;
/**
* The packet event producer.
* @author Emperor
*
*/
public final class PacketEventProducer implements EventProducer {
@Override
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
return new PacketReadEvent(session, buffer);
}
@Override
public IoWriteEvent produceWriter(IoSession session, Object context) {
return new PacketWriteEvent(session, context);
}
}
@@ -0,0 +1,29 @@
package ms.net.producer;
import java.nio.ByteBuffer;
import ms.net.EventProducer;
import ms.net.IoReadEvent;
import ms.net.IoSession;
import ms.net.IoWriteEvent;
import ms.net.event.RegistryReadEvent;
import ms.net.event.RegistryWriteEvent;
/**
* Handles world server registry.
* @author Emperor
*
*/
public final class RegistryEventProducer implements EventProducer {
@Override
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
return new RegistryReadEvent(session, buffer);
}
@Override
public IoWriteEvent produceWriter(IoSession session, Object context) {
return new RegistryWriteEvent(session, context);
}
}