mirror of
https://github.com/moparisthebest/MoparClassic
synced 2025-02-28 08:21:52 -05:00
Added PacketThrottler, fixed AFK message, and added the AFK timeout to the config.
This commit is contained in:
parent
ff86ee7bfb
commit
d20ca77221
@ -81,4 +81,12 @@
|
|||||||
|
|
||||||
<!-- The class that should be used for the DataStore -->
|
<!-- The class that should be used for the DataStore -->
|
||||||
<entry key="data-store">org.moparscape.msc.gs.persistence.impl.XMLUsingXStream</entry>
|
<entry key="data-store">org.moparscape.msc.gs.persistence.impl.XMLUsingXStream</entry>
|
||||||
|
|
||||||
|
<!-- The amount of packets per second before the user is disconnected. -->
|
||||||
|
<entry key="packet-per-second-threshold">15</entry>
|
||||||
|
<!-- Alert when someone has broken the threshold? -->
|
||||||
|
<entry key="packet-per-second-alert">true</entry>
|
||||||
|
|
||||||
|
<!-- The afk timeout in minutes -->
|
||||||
|
<entry key="afk-timeout">5</entry>
|
||||||
</properties>
|
</properties>
|
||||||
|
@ -43,6 +43,9 @@ public class Config {
|
|||||||
OS_LEVEL_THROTTLE_ALERT, OS_LEVEL_UNBLOCK_FAILED_ALERT,
|
OS_LEVEL_THROTTLE_ALERT, OS_LEVEL_UNBLOCK_FAILED_ALERT,
|
||||||
CONGRATS_FOR_MAX_LEVEL;
|
CONGRATS_FOR_MAX_LEVEL;
|
||||||
public static String DATA_STORE;
|
public static String DATA_STORE;
|
||||||
|
public static int PACKET_PER_SECOND_THRESHOLD;
|
||||||
|
public static boolean PACKET_PER_SECOND_ALERT;
|
||||||
|
public static int AFK_TIMEOUT;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
loadEnv();
|
loadEnv();
|
||||||
@ -130,6 +133,11 @@ public class Config {
|
|||||||
.getProperty("max-level-congrats"));
|
.getProperty("max-level-congrats"));
|
||||||
|
|
||||||
DATA_STORE = props.getProperty("data-store");
|
DATA_STORE = props.getProperty("data-store");
|
||||||
|
|
||||||
|
PACKET_PER_SECOND_THRESHOLD = Integer.parseInt(props.getProperty("packet-per-second-threshold"));
|
||||||
|
PACKET_PER_SECOND_ALERT = Boolean.parseBoolean(props.getProperty("packet-per-second-alert"));
|
||||||
|
|
||||||
|
AFK_TIMEOUT = Integer.parseInt(props.getProperty("afk-timeout"));
|
||||||
|
|
||||||
props.clear();
|
props.clear();
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import org.apache.mina.transport.socket.nio.SocketSessionConfig;
|
|||||||
import org.moparscape.msc.config.Config;
|
import org.moparscape.msc.config.Config;
|
||||||
import org.moparscape.msc.gs.connection.RSCConnectionHandler;
|
import org.moparscape.msc.gs.connection.RSCConnectionHandler;
|
||||||
import org.moparscape.msc.gs.connection.filter.ConnectionFilter;
|
import org.moparscape.msc.gs.connection.filter.ConnectionFilter;
|
||||||
|
import org.moparscape.msc.gs.connection.filter.PacketThrottler;
|
||||||
import org.moparscape.msc.gs.core.GameEngine;
|
import org.moparscape.msc.gs.core.GameEngine;
|
||||||
import org.moparscape.msc.gs.core.LoginConnector;
|
import org.moparscape.msc.gs.core.LoginConnector;
|
||||||
import org.moparscape.msc.gs.event.DelayedEvent;
|
import org.moparscape.msc.gs.event.DelayedEvent;
|
||||||
@ -46,7 +47,6 @@ public class Server {
|
|||||||
displayConfigDefaulting(configFile);
|
displayConfigDefaulting(configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Config.initConfig(configFile);
|
Config.initConfig(configFile);
|
||||||
world = Instance.getWorld();
|
world = Instance.getWorld();
|
||||||
try {
|
try {
|
||||||
@ -156,6 +156,8 @@ public class Server {
|
|||||||
|
|
||||||
acceptor = new SocketAcceptor(Runtime.getRuntime()
|
acceptor = new SocketAcceptor(Runtime.getRuntime()
|
||||||
.availableProcessors() + 1, Executors.newCachedThreadPool());
|
.availableProcessors() + 1, Executors.newCachedThreadPool());
|
||||||
|
acceptor.getFilterChain().addFirst("packetthrottler",
|
||||||
|
PacketThrottler.getInstance());
|
||||||
acceptor.getFilterChain().addFirst("connectionfilter",
|
acceptor.getFilterChain().addFirst("connectionfilter",
|
||||||
new ConnectionFilter());
|
new ConnectionFilter());
|
||||||
IoAcceptorConfig config = new SocketAcceptorConfig();
|
IoAcceptorConfig config = new SocketAcceptorConfig();
|
||||||
@ -252,7 +254,7 @@ public class Server {
|
|||||||
public static Server getServer() {
|
public static Server getServer() {
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void displayConfigDefaulting(String file) {
|
private static void displayConfigDefaulting(String file) {
|
||||||
System.out.println("Defaulting to use " + file);
|
System.out.println("Defaulting to use " + file);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
package org.moparscape.msc.gs.connection.filter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.jcip.annotations.ThreadSafe;
|
||||||
|
|
||||||
|
import org.apache.mina.common.IoFilterAdapter;
|
||||||
|
import org.apache.mina.common.IoSession;
|
||||||
|
import org.moparscape.msc.config.Config;
|
||||||
|
import org.moparscape.msc.gs.Instance;
|
||||||
|
import org.moparscape.msc.gs.alert.AlertHandler;
|
||||||
|
import org.moparscape.msc.gs.event.DelayedEvent;
|
||||||
|
import org.moparscape.msc.gs.model.Player;
|
||||||
|
import org.moparscape.msc.gs.util.annotation.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This filter will disconnect players that have exceeded the packet per second
|
||||||
|
* threshold, and if configured, send an alert.
|
||||||
|
*
|
||||||
|
* @author CodeForFame
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
@Singleton
|
||||||
|
public class PacketThrottler extends IoFilterAdapter {
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
///////// Singleton Boilerplate /////////
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
private static final PacketThrottler instance = new PacketThrottler();
|
||||||
|
|
||||||
|
public static PacketThrottler getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
/////// Singleton Boilerplate End ///////
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of username hashes to packet per second.
|
||||||
|
*/
|
||||||
|
private Map<Long, Integer> playerToPacketCount = new ConcurrentHashMap<Long, Integer>();
|
||||||
|
|
||||||
|
private PacketThrottler() {
|
||||||
|
// Clears the count every second, so we can check the packets per second.
|
||||||
|
Instance.getDelayedEventHandler().add(new DelayedEvent(null, 1000) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
playerToPacketCount.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(NextFilter nextFilter, IoSession session,
|
||||||
|
Object message) {
|
||||||
|
|
||||||
|
Player player = (Player) session.getAttachment();
|
||||||
|
if (session.isClosing() || player.destroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = incrementAndGet(player.getUsernameHash());
|
||||||
|
|
||||||
|
if (count > Config.PACKET_PER_SECOND_THRESHOLD) {
|
||||||
|
|
||||||
|
if (Config.PACKET_PER_SECOND_ALERT) {
|
||||||
|
// If the player is initialized, then use the username,
|
||||||
|
// otherwise use the IP.
|
||||||
|
String s = (player.isInitialized() ? player.getUsername()
|
||||||
|
: player.getCurrentIP())
|
||||||
|
+ " has exceeded the packet per second threshold";
|
||||||
|
// Sends an alert with a priority of 2.
|
||||||
|
AlertHandler.sendAlert(s, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroys the user and discards the packet.
|
||||||
|
player.destroy(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFilter.messageReceived(session, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments and returns the current count.
|
||||||
|
*
|
||||||
|
* @param hash
|
||||||
|
* - The hash of the player.
|
||||||
|
*/
|
||||||
|
private int incrementAndGet(long hash) {
|
||||||
|
final int count;
|
||||||
|
|
||||||
|
// Even though operations are atomic, there are multiple, therefore it
|
||||||
|
// needs to be synchronized.
|
||||||
|
synchronized (playerToPacketCount) {
|
||||||
|
|
||||||
|
// If it is null, it will default to 0
|
||||||
|
count = playerToPacketCount.get(hash) + 1;
|
||||||
|
|
||||||
|
// Update/Create entry
|
||||||
|
playerToPacketCount.put(hash, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package org.moparscape.msc.gs.core;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.moparscape.msc.config.Config;
|
||||||
import org.moparscape.msc.gs.Instance;
|
import org.moparscape.msc.gs.Instance;
|
||||||
import org.moparscape.msc.gs.builders.GameObjectPositionPacketBuilder;
|
import org.moparscape.msc.gs.builders.GameObjectPositionPacketBuilder;
|
||||||
import org.moparscape.msc.gs.builders.ItemPositionPacketBuilder;
|
import org.moparscape.msc.gs.builders.ItemPositionPacketBuilder;
|
||||||
@ -396,13 +397,17 @@ public final class ClientUpdater {
|
|||||||
if (curTime - p.getLastPing() >= 30000) {
|
if (curTime - p.getLastPing() >= 30000) {
|
||||||
p.destroy(false);
|
p.destroy(false);
|
||||||
} else if (p.warnedToMove()) {
|
} else if (p.warnedToMove()) {
|
||||||
if (curTime - p.getLastMoved() >= 960000 && p.loggedIn()) {
|
if (curTime - p.getLastMoved() >= ((Config.AFK_TIMEOUT + 1) * 60000)
|
||||||
|
&& p.loggedIn()) {
|
||||||
p.destroy(false);
|
p.destroy(false);
|
||||||
}
|
}
|
||||||
} else if (curTime - p.getLastMoved() >= 900000) {
|
} else if (curTime - p.getLastMoved() >= (Config.AFK_TIMEOUT * 60000)
|
||||||
|
&& !p.warnedToMove()) {
|
||||||
p.getActionSender()
|
p.getActionSender()
|
||||||
.sendMessage(
|
.sendMessage(
|
||||||
"@cya@You have not moved for 15 mins, please move to a new area to avoid logout.");
|
"@cya@You have not moved for "
|
||||||
|
+ Config.AFK_TIMEOUT
|
||||||
|
+ " mins, please move to a new area to avoid logout.");
|
||||||
p.warnToMove();
|
p.warnToMove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.moparscape.msc.gs.util.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This annotation is used to denote that a Java class is a singleton. Scala
|
||||||
|
* objects do not need this annotation, because they are singletons by
|
||||||
|
* definition.
|
||||||
|
*
|
||||||
|
* @author CodeForFame
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface Singleton {
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user