Reworked logging framework

This commit is contained in:
Ceikry
2022-12-27 04:22:25 +00:00
committed by Ryan
parent be10a69325
commit 73bee78d31
15 changed files with 347 additions and 361 deletions
@@ -13,11 +13,11 @@ import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.login.PlayerParser;
import core.game.node.entity.state.EntityState;
import core.game.node.item.Item;
import core.game.system.monitor.PlayerMonitor;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import kotlin.Unit;
import rs09.game.content.global.action.EquipHandler;
import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.system.config.ItemConfigParser;
import java.text.DecimalFormat;
@@ -311,7 +311,7 @@ public final class DuelSession extends ComponentPlugin {
log = log.substring(0, log.length() - 1);
}
log += "}";
player.getMonitor().log(log, PlayerMonitor.DUEL_LOG);
PlayerMonitor.logMisc(player, "Duel", log);
} else {
player.removeExtension(DuelSession.class);
}
@@ -37,7 +37,6 @@ import core.game.node.entity.skill.summoning.familiar.FamiliarManager;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.system.communication.CommunicationInfo;
import core.game.system.monitor.PlayerMonitor;
import core.game.system.task.Pulse;
import core.game.world.map.*;
import core.game.world.map.build.DynamicRegion;
@@ -73,6 +72,7 @@ import rs09.game.node.entity.combat.equipment.EquipmentDegrader;
import rs09.game.node.entity.player.graves.Grave;
import rs09.game.node.entity.player.graves.GraveType;
import rs09.game.node.entity.player.graves.GraveController;
import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.node.entity.player.info.login.PlayerSaver;
import rs09.game.node.entity.skill.runecrafting.PouchManager;
import rs09.game.node.entity.state.newsys.State;
@@ -88,6 +88,7 @@ import rs09.tools.TickUtilsKt;
import rs09.worker.ManagementEvents;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static api.ContentAPIKt.*;
import static rs09.game.node.entity.player.info.stats.StatAttributeKeysKt.STATS_BASE;
@@ -255,11 +256,6 @@ public class Player extends Entity {
* The farming manager.
*/
/**
* The monitor which monitors player actions.
*/
private final PlayerMonitor monitor = new PlayerMonitor();
/**
* Represents the players warning messages.
*/
@@ -383,6 +379,7 @@ public class Player extends Entity {
details.save();
sendLogoutEvents();
Repository.getDisconnectionQueue().add(this);
checkForWealthUpdate(true);
}
private void sendLogoutEvents() {
@@ -475,6 +472,39 @@ public class Player extends Entity {
//Decrements prayer points
getPrayer().tick();
//update wealth tracking
checkForWealthUpdate(false);
}
private void checkForWealthUpdate(boolean force) {
if (isArtificial()) return;
long previousWealth = getAttribute("last-wealth", -1L);
long lastWealthCheck = getAttribute("last-wealth-check", -1L);
long nowTime = System.currentTimeMillis();
if (force || nowTime - lastWealthCheck >= TimeUnit.MINUTES.toMillis(5)) {
long totalWealth = 0L;
for (Item i : inventory.toArray()) {
if (i == null) continue;
totalWealth += (long) i.getDefinition().getValue() * i.getAmount();
}
for (Item i : bank.toArray()) {
if (i == null) break;
totalWealth += (long) i.getDefinition().getValue() * i.getAmount();
}
for (Item i : bankSecondary.toArray()) {
if (i == null) break;
totalWealth += (long) i.getDefinition().getValue() * i.getAmount();
}
long diff = previousWealth == -1 ? 0L : totalWealth - previousWealth;
setAttribute("/save:last-wealth", totalWealth);
setAttribute("/save:last-wealth-check", nowTime);
if (diff != 0)
PlayerMonitor.logWealthChange(this, totalWealth, diff);
}
}
@Override
@@ -611,8 +641,11 @@ public class Player extends Entity {
Grave g = GraveController.produceGrave(GraveController.getGraveType(this));
g.initialize(this, location, Arrays.stream(c[1].toArray()).filter(Objects::nonNull).toArray(Item[]::new)); //note: the amount of code required to filter nulls from an array in Java is atrocious.
} else {
StringBuilder itemsLost = new StringBuilder();
for (Item item : c[1].toArray()) {
if (item == null) continue;
if (killer instanceof Player)
itemsLost.append(getItemName(item.getId())).append("(").append(item.getAmount()).append("), ");
if (GraveController.shouldCrumble(item.getId()))
continue;
if (GraveController.shouldRelease(item.getId()))
@@ -620,6 +653,8 @@ public class Player extends Entity {
item = GraveController.checkTransform(item);
GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this);
}
if (killer instanceof Player)
PlayerMonitor.logMisc((Player) killer, "PK", "Killed " + name + ", who dropped: " + itemsLost);
sendMessage(colorize("%RDue to the circumstances of your death, you do not have a grave."));
}
@@ -1173,13 +1208,6 @@ public class Player extends Entity {
* @return The farmingManager.
*/
/**
* Gets the monitor.
* @return The monitor.
*/
public PlayerMonitor getMonitor() {
return monitor;
}
/**
* Gets the warningMessages.
@@ -7,10 +7,9 @@ import core.game.node.entity.player.Player
import core.game.node.entity.player.link.request.RequestModule
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.system.monitor.PlayerMonitor
import rs09.game.ai.AIRepository
import rs09.game.ai.general.scriptrepository.DoublingMoney
import rs09.game.system.SystemLogger
import rs09.game.node.entity.player.info.PlayerMonitor
import java.text.DecimalFormat
import java.util.*
@@ -352,17 +351,16 @@ class TradeModule
* @param module the module.
*/
private fun giveContainers(module: TradeModule) {
val pContainer: Container? = module.container
val oContainer: Container? = getExtension(module.target)!!.container
val pContainer: Container = module.container ?: return
val oContainer: Container = getExtension(module.target)!!.container ?: return
SystemLogger.logTrade(module.player!!.username + " -> " + module.target!!.username + " " + Arrays.toString(pContainer!!.toArray()))
SystemLogger.logTrade(module.target!!.username + " -> " + module.player!!.username + " " + Arrays.toString(oContainer!!.toArray()))
PlayerMonitor.logTrade(module.player!!, module.target!!, pContainer, oContainer)
(AIRepository.PulseRepository[module.player!!.username.lowercase()]?.botScript as DoublingMoney?)?.itemsReceived(module.target!!, oContainer)
(AIRepository.PulseRepository[module.target!!.username.lowercase()]?.botScript as DoublingMoney?)?.itemsReceived(module.player!!, pContainer)
addContainer(module.player, module.target, oContainer)
addContainer(module.target, module.player, pContainer)
addContainer(module.player, oContainer)
addContainer(module.target, pContainer)
module.target!!.packetDispatch.sendMessage("Accepted trade.")
module.player!!.packetDispatch.sendMessage("Accepted trade.")
}
@@ -373,10 +371,9 @@ class TradeModule
* @param target the target who gains the items.
* @param container the container.
*/
private fun addContainer(player: Player?, target: Player?, container: Container?) {
private fun addContainer(player: Player?, container: Container?) {
val c = Container(container!!.itemCount(), ContainerType.ALWAYS_STACK)
c.addAll(container)
var log = "traded => " + target!!.name + " received => {"
for (i in container.toArray()) {
if (i == null) {
continue
@@ -388,17 +385,6 @@ class TradeModule
GroundItemManager.create(i, player)
}
}
for (i in c.toArray()) {
if (i == null) {
continue
}
log += i.name + " x " + i.amount + ","
}
if (log[log.length - 1] == ',') {
log = log.substring(0, log.length - 1)
}
log += "}"
player!!.monitor.log(log, PlayerMonitor.TRADE_LOG)
}
/**
@@ -14,8 +14,10 @@ import core.game.world.update.flag.player.AppearanceFlag;
import core.net.packet.PacketRepository;
import core.net.packet.context.SkillContext;
import core.net.packet.out.SkillLevel;
import kotlin.Pair;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.node.entity.skill.skillcapeperks.SkillcapePerks;
import rs09.game.world.GameWorld;
import rs09.game.world.repository.Repository;
@@ -23,6 +25,8 @@ import rs09.plugin.CorePluginTypes.XPGainPlugins;
import org.rs09.consts.Items;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import static java.lang.Math.floor;
import static java.lang.Math.max;
@@ -68,6 +72,10 @@ public final class Skills {
*/
private final double[] experience;
private double[] lastUpdateXp = null;
private int lastUpdate = GameWorld.getTicks();
/**
* An array containing all the maximum levels.
*/
@@ -212,6 +220,8 @@ public final class Skills {
* @param experience The experience.
*/
public void addExperience(int slot, double experience, boolean playerMod) {
if (lastUpdateXp == null)
lastUpdateXp = this.experience.clone();
double mod = getExperienceMod(slot, experience, playerMod, true);
final Player player = entity instanceof Player ? ((Player) entity) : null;
final AssistSession assist = entity.getExtension(AssistSession.class);
@@ -278,6 +288,18 @@ public final class Skills {
PacketRepository.send(SkillLevel.class, new SkillContext((Player) entity, slot));
entity.dispatch(new XPGainEvent(slot, experienceAdd));
}
if (GameWorld.getTicks() - lastUpdate >= 200) {
ArrayList<Pair<Integer,Double>> diffs = new ArrayList<>();
for (int i = 0; i < this.experience.length; i++) {
double diff = this.experience[i] - lastUpdateXp[i];
if (diff != 0.0) {
diffs.add(new Pair<>(i, diff));
}
}
PlayerMonitor.logXpGains(player, diffs);
lastUpdateXp = this.experience.clone();
lastUpdate = GameWorld.getTicks();
}
}
/**
@@ -7,6 +7,7 @@ import rs09.Server;
import rs09.ServerConstants;
import rs09.ServerStore;
import rs09.game.ai.AIRepository;
import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld;
import rs09.game.world.repository.Repository;
@@ -55,6 +56,7 @@ public final class SystemTermination {
}
}
GameWorld.getShutdownListeners().forEach(ShutdownListener::shutdown);
PlayerMonitor.flushRemainingEventsImmediately();
ServerStore s = null;
for (PersistWorld wld : GameWorld.getWorldPersists()) {
if (wld instanceof ServerStore)
@@ -5,9 +5,9 @@ import core.game.content.activity.ActivityPlugin;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.PlayerDetails;
import core.game.node.entity.player.info.Rights;
import core.game.system.monitor.PlayerMonitor;
import proto.management.ClanJoinNotification;
import proto.management.ClanLeaveNotification;
import rs09.game.node.entity.player.info.PlayerMonitor;
import rs09.game.world.GameWorld;
import rs09.game.world.repository.Repository;
import core.net.amsc.WorldCommunicator;
@@ -198,9 +198,7 @@ public final class ClanRepository {
return;
}
}
StringBuilder sb = new StringBuilder(message);
sb.append(" => ").append(name).append(" (owned by ").append(owner).append(")");
player.getMonitor().log(sb.toString(), PlayerMonitor.CLAN_CHAT_LOG);
PlayerMonitor.logChat(player, "clan", message);
for (Iterator<ClanEntry> it = players.iterator(); it.hasNext();) {
ClanEntry entry = it.next();
Player p = entry.getPlayer();
@@ -6,7 +6,6 @@ import org.jetbrains.annotations.NotNull;
import proto.management.PrivateMessage;
import rs09.auth.UserAccountInfo;
import rs09.game.system.SystemLogger;
import core.game.system.monitor.PlayerMonitor;
import core.game.system.mysql.SQLTable;
import core.game.system.task.Pulse;
import rs09.game.world.GameWorld;
@@ -1,284 +0,0 @@
package core.game.system.monitor;
import core.cache.misc.buffer.ByteBufferUtils;
import core.game.node.entity.player.Player;
import java.nio.ByteBuffer;
/**
* Handles the player monitoring.
* @author Emperor
*/
public final class PlayerMonitor {
/**
* The public chat log.
*/
public static final int PUBLIC_CHAT_LOG = 0;
/**
* The private chat log.
*/
public static final int PRIVATE_CHAT_LOG = 1;
/**
* The clan chat log.
*/
public static final int CLAN_CHAT_LOG = 2;
/**
* The IP/MAC-address log.
*/
public static final int ADDRESS_LOG = 3;
/**
* The command log.
*/
public static final int COMMAND_LOG = 4;
/**
* The trade log.
*/
public static final int TRADE_LOG = 5;
/**
* The GE logs.
*/
public static final int GRAND_EXCHANGE_LOG = 6;
/**
* The duel stake logs.
*/
public static final int DUEL_LOG = 7;
/**
* The macro flag for a click when the client was out of focus.
*/
public static final int MF_NO_FOCUS_CLICK = 0x1;
/**
* The networth of the player.
*/
private long networth;
/**
* If the client is currently focused.
*/
private boolean clientFocus = true;
/**
* How likely it is this player has used a macro.
*/
private int macroFlag;
/**
* The duplication log.
*/
private DuplicationLog duplicationLog;
/**
* The message monitors.
*/
private MessageLog[] logs = new MessageLog[8];
/**
* Constructs a new {@code PlayerMonitor} {@code Object}.
*/
public PlayerMonitor() {
logs[PUBLIC_CHAT_LOG] = new MessageLog(500);
logs[PRIVATE_CHAT_LOG] = new MessageLog(500);
logs[CLAN_CHAT_LOG] = new MessageLog(500);
logs[ADDRESS_LOG] = new MessageLog(200);
logs[COMMAND_LOG] = new MessageLog(200);
logs[TRADE_LOG] = new MessageLog(200);
logs[GRAND_EXCHANGE_LOG] = new MessageLog(500);
logs[DUEL_LOG] = new MessageLog(200);
}
/**
* Clears the logs.
*/
public void clear() {
for (int i = 0; i < logs.length; i++) {
if (logs[i] == null) {
continue;
}
logs[i].getMessages().clear();
}
duplicationLog.getMessages().clear();
}
/**
* If the player's actions should be logged.
* @return {@code True} if so.
*/
public boolean isLogActions() {
return duplicationLog != null && duplicationLog.isLoggingFlagged();
}
/**
* Logs the given string.
* @param string The string to log.
* @param type The log type.
*/
public void log(String string, int type) {
log(string, type, true);
}
/**
* Logs the given string.
* @param string The string to log.
* @param type The log type.
* @param timeStamp If we should time stamp the logged string.
*/
public void log(String string, int type, boolean timeStamp) {
if (type < 3) {
String check = string.toLowerCase();
if (check.contains("dupe") || check.contains("duping") || check.contains("bug") || check.contains("glitch") || check.contains("exploit")) {
getDuplicationLog().flag(DuplicationLog.DUPE_TALK);
String prefix = null;
if (type == PUBLIC_CHAT_LOG) {
prefix = "Public";
} else if (type == PRIVATE_CHAT_LOG) {
prefix = "Private";
} else {
prefix = "Clan";
}
getDuplicationLog().log(prefix + " chat message: " + string, true);
}
}
logs[type].log(string, timeStamp);
}
/**
* Checks the networth difference for a player (called on logout).
* @param player The player.
* @param currentNet The current networth.
*/
public void checkNetworth(Player player, long currentNet) {
long difference = currentNet - this.networth;
if (difference < 1) { // The player lost money.
return;
}
if (difference > 150_000_000l) {
getDuplicationLog().flag(DuplicationLog.NW_INCREASE);
getDuplicationLog().log("Large networth increase - [incr=" + difference + ", old=" + this.networth + ", cur=" + currentNet + "].", true);
}
}
/**
* Called when the player does a mouse click.
* @param x The x-coordinate of the cursor.
* @param y The y-coordinate of the cursor.
* @param delay The time between this click and last.
* @param rightClick If the right mouse-button was used to click.
*/
public void handleMouseClick(int x, int y, int delay, boolean rightClick) {
if (!clientFocus) {
macroFlag |= MF_NO_FOCUS_CLICK;
}
}
/**
* Gets the address log.
* @param original the original log.
* @param address the address.
* @return the address.
*/
public static String getAddressLog(String original, String address) {
String log = "";
if (original != null && original.length() > 0) {
log += original;
if (log.charAt(log.length() - 1) != '|') {
log += "|";
}
}
if (address != null && address.length() > 0 && (original == null || !original.contains(address))) {
log += address + "|";
}
if (log.length() > 0 && log.charAt(log.length() - 1) == '|') {
log = log.substring(0, log.length() - 1);
}
if (log == null) {
log = "";
}
return log;
}
/**
* Adds a macro flag.
* @param flag The flag.
*/
public void addMacroFlag(int flag) {
macroFlag |= flag;
}
/**
* Gets the macroFlag.
* @return The macroFlag.
*/
public int getMacroFlag() {
return macroFlag;
}
/**
* Sets the macroFlag.
* @param macroFlag The macroFlag to set.
*/
public void setMacroFlag(int macroFlag) {
this.macroFlag = macroFlag;
}
/**
* Gets the networth.
* @return The networth.
*/
public long getNetworth() {
return networth;
}
/**
* Sets the networth.
* @param networth The networth to set.
*/
public void setNetworth(long networth) {
this.networth = networth;
}
/**
* Gets the clientFocus.
* @return The clientFocus.
*/
public boolean isClientFocus() {
return clientFocus;
}
/**
* Sets the clientFocus.
* @param clientFocus The clientFocus to set.
*/
public void setClientFocus(boolean clientFocus) {
this.clientFocus = clientFocus;
}
/**
* Gets the logs.
* @return The logs.
*/
public MessageLog[] getLogs() {
return logs;
}
/**
* Gets the duplicationLog.
* @return The duplicationLog.
*/
public DuplicationLog getDuplicationLog() {
if (duplicationLog == null) {
duplicationLog = new DuplicationLog();
}
return duplicationLog;
}
}
@@ -1,6 +1,7 @@
package rs09.game.content.global.action
import api.events.PickUpEvent
import api.getItemName
import core.game.content.dialogue.FacialExpression
import core.game.content.global.GodType
import core.game.node.entity.player.Player
@@ -13,6 +14,7 @@ import core.game.node.item.Item
import core.game.world.map.RegionManager
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.system.SystemLogger
import rs09.game.system.config.GroundSpawnLoader
import rs09.game.world.GameWorld
@@ -55,6 +57,9 @@ object PickupHandler {
return true
}
if (item.isActive && player.inventory.add(add)) {
if (item.dropper is Player && item.dropper.details.uid != player.details.uid){
PlayerMonitor.logMisc(item.dropper, "DropTrade", "${getItemName(item.id)} x${item.amount} picked up by ${player.name}.")
}
if (!RegionManager.isTeleportPermitted(item.location)) {
player.animate(Animation.create(535))
}
@@ -0,0 +1,256 @@
package rs09.game.node.entity.player.info
import api.getItemName
import core.game.container.Container
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import discord.Discord
import kotlinx.coroutines.*
import org.sqlite.SQLiteDataSource
import rs09.ServerConstants
import rs09.game.system.SystemLogger
import java.io.File
import java.sql.Connection
import java.util.concurrent.LinkedBlockingQueue
import kotlin.math.abs
object PlayerMonitor {
private val eventQueue = LinkedBlockingQueue<LogEvent>()
private var activeTask: Job? = null
@JvmStatic fun logWealthChange(player: Player, totalWealth: Long, diff: Long) {
val event = LogEvent.WealthLog(
player.name,
player.details.uid,
totalWealth,
diff,
System.currentTimeMillis()
)
dispatch(event)
if (abs(diff) >= 500_000L)
Discord.postPlayerAlert(player.name, "Dubious change in wealth: $diff, total wealth: $totalWealth")
}
@JvmStatic fun logChat(player: Player, type: String, message: String) {
val event = LogEvent.ChatLog(
player.name,
player.details.uid,
type,
message,
System.currentTimeMillis()
)
checkForFlaggedText(player.name, message)
dispatch(event)
}
@JvmStatic fun logTrade(player1: Player, player2: Player, container1: Container, container2: Container) {
val container1String = StringBuilder()
val container2String = StringBuilder()
for (item in container1.toArray()) {
item ?: continue
container1String.append(getItemName(item.id) + "(${item.amount}), ")
}
for (item in container2.toArray()) {
item ?: continue
container2String.append(getItemName(item.id) + "(${item.amount}), ")
}
val event = LogEvent.TradeLog(
player1.name,
player1.details.uid,
player2.name,
player2.details.uid,
container1String.toString(),
container2String.toString(),
System.currentTimeMillis()
)
dispatch(event)
}
@JvmStatic fun logPrivateChat(sender: Player, receiver: String, message: String) {
val event = LogEvent.ChatLog(
sender.name,
sender.details.uid,
"private",
"=> $receiver: $message",
System.currentTimeMillis()
)
checkForFlaggedText(sender.name, message)
dispatch(event)
}
@JvmStatic fun logMisc(player: Player, type: String, details: String) {
val event = LogEvent.MiscLog(
player.name,
player.details.uid,
type,
details,
System.currentTimeMillis()
)
dispatch(event)
}
@JvmStatic fun logXpGains(player: Player, xpDiff: List<Pair<Int,Double>>) {
if (player.isArtificial) return
if (xpDiff.isEmpty()) return
val query = StringBuilder("INSERT INTO xp_gains(player,uid,")
val xpNames = StringBuilder()
val xpAmounts = StringBuilder()
for ((skillId, amount) in xpDiff) {
xpNames.append(Skills.SKILL_NAME[skillId].lowercase() + ",")
xpAmounts.append("$amount,")
}
query.append(xpNames)
query.append("timestamp) VALUES(")
query.append("'" + player.name + "',")
query.append(player.details.uid.toString() + ",")
query.append(xpAmounts)
query.append(System.currentTimeMillis().toString())
query.append(");")
dispatch(LogEvent.XpLog(query.toString()))
}
private fun dispatch(event: LogEvent) {
eventQueue.put(event)
if (eventQueue.size >= 50) {
processQueuedEvents()
}
}
fun processQueuedEvents() {
val path = ServerConstants.LOGS_PATH + "playerlogs.db"
if (activeTask?.isActive == true)
return
if (!File(path).exists()) {
createSqliteDatabase(path)
}
activeTask = GlobalScope.launch {
val conn = connect(path)
conn.use {
while (eventQueue.isNotEmpty()) {
val event = withContext(Dispatchers.IO) { eventQueue.take() }
process(event, it)
}
}
}
}
@JvmStatic fun flushRemainingEventsImmediately() {
SystemLogger.logInfo(this::class.java, "Flushing player log events...")
val path = ServerConstants.LOGS_PATH + "playerlogs.db"
if (!File(path).exists()) {
createSqliteDatabase(path)
}
if (activeTask != null)
activeTask?.cancel("Interrupted by shutdown. This is probably fine.")
val conn = connect(path)
conn.use {
while (eventQueue.isNotEmpty())
process(eventQueue.take(), it)
}
}
private fun connect(path: String) : Connection {
val source = SQLiteDataSource()
source.url = "jdbc:sqlite:$path"
return source.connection
}
private fun createSqliteDatabase(path: String) {
if (!File(ServerConstants.LOGS_PATH).exists())
File(ServerConstants.LOGS_PATH).mkdirs()
val connection = connect(path)
val stmt = connection.createStatement()
stmt.execute(
"""
CREATE TABLE "chat_logs" ( "player" TEXT, "uid" INTEGER, "type" TEXT, "message" TEXT, "timestamp" NUMERIC );
""")
stmt.execute(
"""
CREATE TABLE "misc_logs" ( "player" TEXT, "uid" INTEGER, "type" TEXT, "details" TEXT , "timestamp" NUMERIC);
""")
stmt.execute(
"""
CREATE TABLE "trade_logs" ( "player_a" TEXT, "player_b" TEXT, "uid_a" INTEGER, "uid_b" INTEGER, "items_a" TEXT, "items_b" TEXT, "timestamp" NUMERIC );
""")
stmt.execute(
"""
CREATE TABLE "xp_gains" ( "player" TEXT, "uid" INTEGER, "attack" INTEGER, "defence" INTEGER, "strength" INTEGER, "hitpoints" INTEGER, "ranged" INTEGER, "prayer" INTEGER, "magic" INTEGER, "cooking" INTEGER, "woodcutting" INTEGER, "fletching" INTEGER, "fishing" INTEGER, "firemaking" INTEGER, "crafting" INTEGER, "smithing" INTEGER, "mining" INTEGER, "herblore" INTEGER, "agility" INTEGER, "thieving" INTEGER, "slayer" INTEGER, "farming" INTEGER, "runecrafting" INTEGER, "hunter" INTEGER, "construction" INTEGER, "summoning" INTEGER , "timestamp" NUMERIC)
""")
stmt.execute(
"""
CREATE TABLE "wealth_logs" ( "player" TEXT, "uid" INTEGER, "total" NUMERIC, "diff" NUMERIC, "timestamp" NUMERIC )
""")
stmt.close()
connection.close()
}
private fun process(event: LogEvent, conn: Connection) {
when (event) {
is LogEvent.ChatLog -> {
val stmt = conn.prepareStatement(CHAT_LOG_INSERT)
stmt.setString(1, event.player)
stmt.setInt(2, event.uid)
stmt.setString(3, event.type)
stmt.setString(4, event.message)
stmt.setLong(5, event.timestamp)
stmt.execute()
}
is LogEvent.TradeLog -> {
val stmt = conn.prepareStatement(TRADE_LOG_INSERT)
stmt.setString(1, event.player1)
stmt.setString(2, event.player2)
stmt.setInt(3, event.uid1)
stmt.setInt(4, event.uid2)
stmt.setString(5, event.items1)
stmt.setString(6, event.items2)
stmt.setLong(7, event.timestamp)
stmt.execute()
}
is LogEvent.MiscLog -> {
val stmt = conn.prepareStatement(MISC_LOG_INSERT)
stmt.setString(1, event.player)
stmt.setInt(2, event.uid)
stmt.setString(3, event.type)
stmt.setString(4, event.details)
stmt.setLong(5, event.timestamp)
stmt.execute()
}
is LogEvent.XpLog -> {
val stmt = conn.createStatement()
stmt.execute(event.query)
}
is LogEvent.WealthLog -> {
val stmt = conn.prepareStatement(WEALTH_LOG_INSERT)
stmt.setString(1, event.player)
stmt.setInt(2, event.uid)
stmt.setLong(3, event.total)
stmt.setLong(4, event.diff)
stmt.setLong(5, event.timeStamp)
stmt.execute()
}
}
}
fun checkForFlaggedText(username: String, message: String) {
if (message.contains("dupe") || message.contains("bug") || message.contains("exploit") || message.contains("glitch")) {
Discord.postPlayerAlert(username, "Flagged Chat - $message")
}
}
private sealed class LogEvent {
data class ChatLog(val player: String, val uid: Int, val type: String, val message: String, val timestamp: Long) : LogEvent()
data class TradeLog(val player1: String, val uid1: Int, val player2 : String, val uid2: Int, val items1: String, val items2: String, val timestamp: Long) : LogEvent()
data class MiscLog(val player: String, val uid: Int, val type: String, val details: String, val timestamp: Long) : LogEvent()
data class XpLog(val query: String) : LogEvent()
data class WealthLog(val player: String, val uid: Int, val total: Long, val diff: Long, val timeStamp: Long) : LogEvent()
}
private const val CHAT_LOG_INSERT = "INSERT INTO chat_logs(player,uid,type,message,timestamp) VALUES (?,?,?,?,?);"
private const val TRADE_LOG_INSERT = "INSERT INTO trade_logs(player_a,player_b,uid_a,uid_b,items_a,items_b,timestamp) VALUES (?,?,?,?,?,?,?);"
private const val MISC_LOG_INSERT = "INSERT INTO misc_logs(player,uid,type,details,timestamp) VALUES (?,?,?,?,?);"
private const val WEALTH_LOG_INSERT = "INSERT INTO wealth_logs(player,uid,total,diff,timestamp) VALUES (?,?,?,?,?);"
}
@@ -7,7 +7,6 @@ import core.game.node.entity.player.info.login.LoginConfiguration
import core.game.node.entity.player.info.login.PlayerParser
import core.game.node.entity.player.info.login.Response
import core.game.system.SystemManager
import core.game.system.monitor.PlayerMonitor
import core.game.system.task.Pulse
import rs09.auth.AuthResponse
import rs09.game.world.GameWorld
@@ -53,9 +52,6 @@ class LoginParser(val details: PlayerDetails) {
flag(AuthResponse.Success)
player.init()
}
player.monitor.log(player.details.ipAddress, PlayerMonitor.ADDRESS_LOG)
player.monitor.log(player.details.serial, PlayerMonitor.ADDRESS_LOG)
player.monitor.log(player.details.macAddress, PlayerMonitor.ADDRESS_LOG)
} else {
Repository.playerNames.remove(player.name)
}
@@ -208,19 +208,6 @@ class PlayerSaveParser(val player: Player) {
}
fun parseMonitor() {
val monitorData = saveFile!!["playerMonitor"] as JSONObject
if (monitorData.containsKey("duplicationFlag")) {
val duplicationFlag: Int = (monitorData.get("duplicationFlag") as String).toInt()
player.monitor.duplicationLog.flag(duplicationFlag)
}
if (monitorData.containsKey("macroFlag")) {
val macroFlag: Int = (monitorData.get("macroFlag") as String).toInt()
player.monitor.macroFlag = macroFlag
}
if (monitorData.containsKey("lastIncreaseFlag")) {
val lastIncreaseFlag: Long = (monitorData.get("lastIncreaseFlag") as String).toLong()
player.monitor.duplicationLog.lastIncreaseFlag = lastIncreaseFlag
}
}
fun parseConfigs() {
@@ -304,17 +304,7 @@ class PlayerSaver (val player: Player){
}
fun savePlayerMonitor(root: JSONObject){
val playerMonitor = JSONObject()
if(player.monitor.duplicationLog != null && player.monitor.duplicationLog.flag != 0){
playerMonitor.put("duplicationFlag",player.monitor.duplicationLog.flag.toString())
}
if(player.monitor.macroFlag != 0){
playerMonitor.put("macroFlag",player.monitor.macroFlag.toString())
}
if(player.monitor.duplicationLog != null && player.monitor.duplicationLog.isLoggingFlagged){
playerMonitor.put("lastIncreaseFlag",player.monitor.duplicationLog.lastIncreaseFlag.toString())
}
root.put("playerMonitor",playerMonitor)
}
fun saveConfigs(root: JSONObject){
@@ -29,7 +29,6 @@ import core.game.node.item.Item
import core.game.node.scenery.Scenery
import core.game.system.communication.ClanRank
import core.game.system.communication.CommunicationInfo
import core.game.system.monitor.PlayerMonitor
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.RegionManager
@@ -54,6 +53,7 @@ import rs09.game.interaction.InteractionListeners
import rs09.game.interaction.InterfaceListeners
import rs09.game.interaction.QCRepository
import rs09.game.interaction.inter.ge.StockMarket
import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.node.entity.skill.magic.SpellListener
import rs09.game.node.entity.skill.magic.SpellListeners
import rs09.game.node.entity.skill.magic.SpellUtils
@@ -199,8 +199,8 @@ object PacketProcessor {
pkt.player.interfaceManager.closeChatbox()
}
is Packet.Command -> {
if (CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine))
pkt.player.monitor.log(pkt.commandLine, PlayerMonitor.COMMAND_LOG)
PlayerMonitor.logMisc(pkt.player, "CommandUse", pkt.commandLine)
CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine)
}
is Packet.ChatMessage -> {
if (pkt.player.details.isMuted)
@@ -215,7 +215,7 @@ object PacketProcessor {
ManagementEvents.publish(builder.build())
return
}
pkt.player.monitor.log(pkt.message, PlayerMonitor.PUBLIC_CHAT_LOG)
PlayerMonitor.logChat(pkt.player, "public", pkt.message)
val ctx = ChatMessage(pkt.player, pkt.message, pkt.effects, pkt.message.length)
pkt.player.updateMasks.register(ChatFlag(ctx))
}
@@ -229,6 +229,7 @@ object PacketProcessor {
pkt.player.sendMessage("You have been muted due to breaking a rule.")
else
CommunicationInfo.sendMessage(pkt.player, pkt.username, pkt.message)
PlayerMonitor.logPrivateChat(pkt.player, pkt.username, pkt.message)
}
is Packet.PacketCountUpdate -> {
val final = pkt.count - pkt.player.interfaceManager.getPacketCount(0)
@@ -282,7 +283,7 @@ object PacketProcessor {
private fun processTrackingPacket(pkt: Packet) {
when(pkt) {
is Packet.TrackingFocus -> pkt.player.monitor.isClientFocus = pkt.isFocused
is Packet.TrackingFocus -> {}
is Packet.TrackingDisplayUpdate -> {
pkt.player.session.clientInfo.screenWidth = pkt.screenWidth
pkt.player.session.clientInfo.screenHeight = pkt.screenHeight
@@ -298,9 +299,7 @@ object PacketProcessor {
}
is Packet.TrackingMouseClick -> {
//TODO see above todo
if (!pkt.player.monitor.isClientFocus) {
Discord.postPlayerAlert(pkt.player.username, "Mouseclick without window focus!")
}
}
}
}
@@ -19,6 +19,7 @@ import rs09.ServerStore
import rs09.ServerStore.Companion.addToList
import rs09.ServerStore.Companion.getList
import rs09.auth.AuthResponse
import rs09.game.node.entity.player.info.PlayerMonitor
import rs09.game.node.entity.player.info.login.LoginParser
import rs09.game.system.SystemLogger
import rs09.game.world.GameWorld
@@ -131,6 +132,7 @@ object Login {
}
val player = Player(details)
PlayerMonitor.logMisc(player, "login_ip", details.ipAddress)
if (canBypassAccountLimitCheck(player)) {
proceedWithAcceptableLogin(session, player, opcode)
} else {