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 -->
|
||||
<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>
|
||||
|
@ -43,6 +43,9 @@ public class Config {
|
||||
OS_LEVEL_THROTTLE_ALERT, OS_LEVEL_UNBLOCK_FAILED_ALERT,
|
||||
CONGRATS_FOR_MAX_LEVEL;
|
||||
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 {
|
||||
loadEnv();
|
||||
@ -131,6 +134,11 @@ public class Config {
|
||||
|
||||
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();
|
||||
|
||||
Constants.GameServer.MOTD = "@yel@Welcome to @whi@"
|
||||
|
@ -14,6 +14,7 @@ import org.apache.mina.transport.socket.nio.SocketSessionConfig;
|
||||
import org.moparscape.msc.config.Config;
|
||||
import org.moparscape.msc.gs.connection.RSCConnectionHandler;
|
||||
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.LoginConnector;
|
||||
import org.moparscape.msc.gs.event.DelayedEvent;
|
||||
@ -46,7 +47,6 @@ public class Server {
|
||||
displayConfigDefaulting(configFile);
|
||||
}
|
||||
|
||||
|
||||
Config.initConfig(configFile);
|
||||
world = Instance.getWorld();
|
||||
try {
|
||||
@ -156,6 +156,8 @@ public class Server {
|
||||
|
||||
acceptor = new SocketAcceptor(Runtime.getRuntime()
|
||||
.availableProcessors() + 1, Executors.newCachedThreadPool());
|
||||
acceptor.getFilterChain().addFirst("packetthrottler",
|
||||
PacketThrottler.getInstance());
|
||||
acceptor.getFilterChain().addFirst("connectionfilter",
|
||||
new ConnectionFilter());
|
||||
IoAcceptorConfig config = new SocketAcceptorConfig();
|
||||
|
@ -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.List;
|
||||
|
||||
import org.moparscape.msc.config.Config;
|
||||
import org.moparscape.msc.gs.Instance;
|
||||
import org.moparscape.msc.gs.builders.GameObjectPositionPacketBuilder;
|
||||
import org.moparscape.msc.gs.builders.ItemPositionPacketBuilder;
|
||||
@ -396,13 +397,17 @@ public final class ClientUpdater {
|
||||
if (curTime - p.getLastPing() >= 30000) {
|
||||
p.destroy(false);
|
||||
} 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);
|
||||
}
|
||||
} else if (curTime - p.getLastMoved() >= 900000) {
|
||||
} else if (curTime - p.getLastMoved() >= (Config.AFK_TIMEOUT * 60000)
|
||||
&& !p.warnedToMove()) {
|
||||
p.getActionSender()
|
||||
.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();
|
||||
}
|
||||
}
|
||||
|
@ -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