Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ceikry 2021-03-08 11:50:13 -06:00
commit 67d8706256
116 changed files with 833 additions and 1488 deletions

33
.gitignore vendored
View file

@ -3,3 +3,36 @@
/Management-Server/build/tmp/
/Management-Server/build/kotlin/
/Management-Server/build/generated/
/Client/build/
/Client/build/classes/
/Client/build/tmp/
/Client/build/kotlin/
/Client/build/generated/
/Server/build/
/Server/build/classes/
/Server/build/tmp/
/Server/build/kotlin/
/Server/build/generated/
/Server/data/eco/bot_offers.json
**/.idea/workspace.xml
**/.idea/tasks.xml
Server/**/*.class
CompiledServer/*
CompiledServer/
Server/gradle/
Server/build/
Server/.gradle/
Client/gradle/
Client/build/
Client/.gradle/
Management-Server/.gradle
Management-Server/build/
Management-Server/org/
Server/data/eco/grand_exchange_db.emp
Single-Player/*
Single-Player/
docker
.gradle
gradle
.idea
.idea/

View file

@ -0,0 +1,15 @@
{
"DatabaseInformation": {
"database_name": "global",
"database_username": "root",
"database_password": "",
"database_host": "127.0.0.1",
"database_port": "3306"
},
"WorldTechnicalInformation": {
"world_limit": "10",
"worldhop_delay": "20000"
}
}

View file

@ -6,10 +6,12 @@ import ms.net.packet.WorldPacketRepository;
import ms.system.ShutdownSequence;
import ms.system.mysql.SQLManager;
import ms.system.util.Command;
import ms.system.util.ManagementConfigParser;
import ms.world.GameServer;
import ms.world.PlayerSession;
import ms.world.WorldDatabase;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
@ -128,6 +130,7 @@ public final class Management {
}
System.out.println("-------- 530 Management server --------");
System.out.println("Starting up...");
new ManagementConfigParser("managementprops" + File.separator + "properties.json");
SQLManager.init();
//NioReactor.configure(ServerConstants.PORT).start();
NioReactor.configure(5555).start();

View file

@ -8,16 +8,6 @@ import ms.system.OperatingSystem;
*
*/
public final class ServerConstants {
/**
* The port to be used for communications.
*/
public static final String SERVER_NAME = "2009Scape";
/**
* The port to be used for communications.
*/
public static final int PORT = 5555;
/**
* The maximum amount of worlds.
@ -27,22 +17,12 @@ public final class ServerConstants {
/**
* The world switching delay in milliseconds.
*/
public static final long WORLD_SWITCH_DELAY = 20_000l;
public static final long WORLD_SWITCH_DELAY = 20_000L;
/**
* The address of the Management server.
*/
public static final String HOST_ADDRESS = "127.0.0.1";
/**
* The store path.
*/
public static final String STORE_PATH = "./store/";
/**
* The maximum amount of players per world.
*/
public static final int MAX_PLAYERS = (1 << 11) - 1;
/**
* The operating system of the management server

View file

@ -1,25 +0,0 @@
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;
}

View file

@ -0,0 +1,23 @@
package ms.net.packet
/**
* Represents the types of packet headers.
* @author Emperor
*/
enum class PacketHeader {
/**
* The normal packet header.
*/
NORMAL,
/**
* The byte packet header.
*/
BYTE,
/**
* The short packet header.
*/
SHORT
}

View file

@ -1,587 +0,0 @@
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);
}
}

View file

@ -0,0 +1,555 @@
package ms.net.packet
import ms.net.IoSession
import ms.system.PunishmentStorage
import ms.system.communication.ClanRank
import ms.system.communication.ClanRepository
import ms.system.communication.CommunicationInfo
import ms.system.util.ManagementConstants.Companion.WORLD_HOP_DELAY
import ms.world.GameServer
import ms.world.PlayerSession
import ms.world.WorldDatabase
import ms.world.info.Response
import ms.world.info.UIDInfo
import java.nio.ByteBuffer
/**
* Repository class for world packets.
* @author Emperor
*/
object WorldPacketRepository {
/**
* Sends the player registry response.
* @param server The game server.
* @param player The player session.
* @param response The registry response.
*/
@JvmStatic
fun sendRegistryResponse(server: GameServer, player: PlayerSession, response: Response) {
val buffer = IoBuffer(0, PacketHeader.BYTE)
buffer.putString(player.username)
buffer.put(response.opcode())//byte
if (response == Response.MOVING_WORLD) {
val delay: Long = WORLD_HOP_DELAY - (System.currentTimeMillis() - player.disconnectionTime)
buffer.put((delay / 1000).toInt())
}
server.session.write(buffer)
}
/**
* Sends a message to the player.
* @param player The player.
* @param message The message to send.
*/
@JvmStatic
fun sendPlayerMessage(player: PlayerSession?, message: String?) {
if (player == null) {
return
}
val buffer = IoBuffer(2, PacketHeader.BYTE)
buffer.putString(player.username)
buffer.putString(message)
player.world.session.write(buffer)
}
fun sendPlayerMessage(player: PlayerSession?, messages: Array<String?>) {
if (player == null) {
return
}
for (message in messages) sendPlayerMessage(player, message)
}
/**
* Sends the contact information.
* @param player The player.
*/
fun sendContactInformation(player: PlayerSession) {
val info = player.communication
val buffer = IoBuffer(3, PacketHeader.SHORT)
buffer.putString(player.username)
buffer.put(info.contacts.size)
for (contact in info.contacts.keys) {
buffer.putString(contact)
buffer.put(info.getRank(contact).ordinal)
buffer.put(CommunicationInfo.getWorldId(player, contact))
}
buffer.put(info.blocked.size)
for (contact in info.blocked) {
buffer.putString(contact)
}
if (info.currentClan == null) {
buffer.put(0)
} else {
buffer.put(1)
buffer.putString(info.currentClan)
}
player.world.session.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.
*/
@JvmStatic
fun sendContactUpdate(
player: PlayerSession,
contact: String?,
block: Boolean,
remove: Boolean,
worldId: Int,
rank: ClanRank?
) {
val buffer = IoBuffer(4, PacketHeader.BYTE)
buffer.putString(player.username)
buffer.putString(contact)
buffer.put((if (block) 1 else 0))
if (rank != null) {
buffer.put((2 + rank.ordinal))
} else {
buffer.put((if (remove) 1 else 0))
if (!block && !remove) {
buffer.put(worldId)
}
}
player.world.session.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.
*/
@JvmStatic
fun sendMessage(player: PlayerSession, p: PlayerSession, type: Int, message: String?) {
val buffer = IoBuffer(5, PacketHeader.BYTE)
buffer.putString(player.username)
buffer.putString(p.username)
buffer.put(type)
buffer.put(p.chatIcon)
buffer.putString(message)
println("Send Message: ${player.username} -> ${p.username} T: $type ICO: ${p.chatIcon} $message")
player.world.session.write(buffer)
}
/**
* Sends clan information to the server.
* @param server The server.
* @param clan The clan.
*/
@JvmStatic
fun sendClanInformation(server: GameServer, clan: ClanRepository) {
val buffer = IoBuffer(6, PacketHeader.SHORT)
buffer.putString(clan.owner.username)
buffer.putString(clan.name)
var length = clan.players.size
if (length > ClanRepository.MAX_MEMBERS) {
length = ClanRepository.MAX_MEMBERS
}
buffer.put(length)
for (i in 0 until length) {
val player = clan.players[i]
buffer.putString(player.username)
buffer.put(player.worldId)
buffer.put(clan.getRank(player).ordinal)
}
buffer.put(clan.joinRequirement.ordinal)
buffer.put(clan.kickRequirement.ordinal)
buffer.put(clan.messageRequirement.ordinal)
buffer.put(clan.lootRequirement.ordinal)
server.session.write(buffer)
}
/**
* Sends the leave clan packet.
* @param player The player leaving the clan.
*/
@JvmStatic
fun sendLeaveClan(player: PlayerSession) {
val buffer = IoBuffer(7, PacketHeader.BYTE)
buffer.putString(player.username)
player.world.session.write(buffer)
}
/**
* Sends the player login notification.
* @param server The server.
* @param player The player logging in.
* @param names The names.
*/
@JvmStatic
fun notifyPlayers(server: GameServer, player: PlayerSession, names: List<String?>) {
val buffer = IoBuffer(8, PacketHeader.SHORT)
buffer.putString(player.username)
buffer.put(player.worldId)
buffer.put(names.size)
for (name in names) {
buffer.putString(name)
}
server.session.write(buffer)
}
/**
* Notifies the game server a player logged out.
* @param server The game server to notify.
* @param player The player logging out.
*/
@JvmStatic
fun notifyLogout(server: GameServer, player: PlayerSession) {
val buffer = IoBuffer(9, PacketHeader.BYTE)
buffer.putString(player.username)
server.session.write(buffer)
}
/**
* Sends the update countdown to the server.
* @param server The server.
* @param ticks The amount of ticks left.
*/
@JvmStatic
fun sendUpdate(server: GameServer, ticks: Int) {
val buffer = IoBuffer(10)
buffer.putInt(ticks)
server.session.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.
*/
@JvmStatic
fun sendPunishUpdate(world: GameServer, key: String?, type: Int, duration: Long) {
val buffer = IoBuffer(11, PacketHeader.BYTE)
buffer.putString(key)
buffer.put(type)
buffer.putLong(duration)
world.session.write(buffer)
}
/**
* Sends a configuration reload.
* @param world the world.
*/
@JvmStatic
fun sendConfigReload(world: GameServer) {
world.session.write(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.
*/
@JvmStatic
fun handleIncoming(session: IoSession, opcode: Int, b: ByteBuffer) {
val buffer = IoBuffer(opcode, PacketHeader.NORMAL, b)
val server = session.gameServer
when (opcode) {
0 -> handlePlayerRegistration(server, buffer)
1 -> handlePlayerRemoval(server, buffer)
2 -> handlePunishment(server, buffer)
3 -> handleCommunicationRequest(server, buffer)
4, 5 -> handleContactUpdate(server, buffer, opcode == 5)
6 -> handleJoinClan(server, buffer)
7 -> handleClanRename(server, buffer)
8 -> handleClanSetting(server, buffer)
9 -> handleClanKick(server, buffer)
10 -> handleClanMessage(server, buffer)
11 -> handlePrivateMessage(server, buffer)
12 -> handleClanInfoRequest(server, buffer)
13 -> handleChatSetting(server, buffer)
14 -> handleInfoUpdate(server, buffer)
else -> 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 fun handleInfoUpdate(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val player = server.players[username]
if (player != null) {
player.chatIcon = buffer.get()
}
}
/**
* Handles a player registration.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handlePlayerRegistration(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val password = buffer.string
val ipAddress = buffer.string
val macAddress = buffer.string
val compName = buffer.string
val serial = buffer.string
val rights = buffer.int
val chatIcon = buffer.get()
val uid = UIDInfo(ipAddress, compName, macAddress, serial)
val player = PlayerSession(username, password, UIDInfo(ipAddress, compName, macAddress, serial))
if (WorldDatabase.isActivePlayer(username)) {
sendRegistryResponse(server, player, Response.ALREADY_ONLINE)
return
}
player.uid = uid
player.rights = rights
player.chatIcon = 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.lastWorld != server.info.worldId && 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 fun handlePlayerRemoval(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val session = server.players[username]
if (session != null) {
session.isActive = false
val player = server.players.remove(username)
if (player != null) {
session.remove()
}
session.worldId = 0
}
}
/**
* Handles a player registration.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handlePunishment(server: GameServer, buffer: IoBuffer) {
val type = buffer.get() and 0xFF
val target = buffer.string
val duration = buffer.long
val staff = buffer.string
PunishmentStorage.handlePunishment(staff, target, type, duration)
}
/**
* Handles the communication info request packet.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handleCommunicationRequest(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val player = server.players[username] ?: 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 fun handleContactUpdate(server: GameServer, buffer: IoBuffer, block: Boolean) {
val username = buffer.string
val player = server.players[username] ?: return
val contact = buffer.string
when (buffer.get()) {
0 -> {
if (block) {
player.communication.block(contact)
}
player.communication.add(contact)
}
1 -> player.communication.remove(contact, block)
2 -> player.communication.updateClanRank(contact, ClanRank.values()[buffer.get()])
}
}
/**
* Handles a clan related packet.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handleJoinClan(server: GameServer, buffer: IoBuffer) {
val name = buffer.string
val clanName = buffer.string
val player = server.players[name]
if (player == null || !player.isActive) {
System.err.println("Invalid player specified in clan packet!")
return
}
if (player.clan != null) {
player.clan.leave(player, true)
return
}
if (clanName.length < 1) {
sendLeaveClan(player)
return
}
val clan = ClanRepository.get(server, clanName)
if (clan == null) {
sendPlayerMessage(
player,
arrayOf(
"The channel you tried to join does not exist.",
"Try joining the main clan named '2009Scape'.:clan:"
)
)
return
}
clan.enter(player)
}
/**
* Handles renaming a clan.
* @param server The server.
* @param buffer The buffer.
*/
private fun handleClanRename(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val name = buffer.string
val player = server.players[username]
if (player == null || !player.isActive) {
return
}
val clan = ClanRepository.getClans()[username]
player.communication.clanName = name
if (clan != null) {
if (name.isEmpty()) {
clan.clean(true)
} else {
clan.rename(name)
}
}
}
/**
* Handles changing clan settings packet.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handleClanSetting(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val type = buffer.get()
val rank = if (type < 4) ClanRank.values()[buffer.get() and 0xFF] else null
val player = server.players[username]
if (player == null || !player.isActive) {
return
}
val clan = ClanRepository.get(server, username)
when (type) {
0 -> {
player.communication.joinRequirement = rank
clan?.clean(false)
}
1 -> player.communication.messageRequirement = rank
2 -> {
player.communication.kickRequirement = rank
clan?.update()
}
3 -> player.communication.lootRequirement = rank
}
}
/**
* Handles kicking a player from the clan.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handleClanKick(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val playerName = buffer.string
val player = server.players[username]
if (player == null || !player.isActive || player.clan == null) {
return
}
val target = WorldDatabase.getPlayer(playerName)
if (target == null || !target.isActive) {
return
}
player.clan.kick(player, target)
}
/**
* Handles a clan message.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handleClanMessage(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val message = buffer.string
val player = server.players[username]
if (player == null || !player.isActive || player.clan == null) {
return
}
player.clan.message(player, message)
}
/**
* Handles a clan message.
* @param server The game server.
* @param buffer The buffer.
*/
private fun handlePrivateMessage(server: GameServer, buffer: IoBuffer) {
val username = buffer.string
val receiver = buffer.string
val message = buffer.string
val player = server.players[username]
if (player == null || !player.isActive) {
return
}
player.communication.sendMessage(receiver, message)
}
/**
* Handles a clan information request packet.
* @param server The server.
* @param buffer The buffer.
*/
private fun handleClanInfoRequest(server: GameServer, buffer: IoBuffer) {
val name = buffer.string
val clan = ClanRepository.get(server, name) ?: return
sendClanInformation(server, clan)
}
/**
* Handles a chat setting update packet.
* @param server The server.
* @param buffer The buffer.
*/
private fun handleChatSetting(server: GameServer, buffer: IoBuffer) {
val name = buffer.string
val publicSetting = buffer.get()
val privateSetting = buffer.get()
val tradeSetting = buffer.get()
val player = server.players[name]
if (player == null || !player.isActive) {
return
}
player.communication.updateSettings(publicSetting, privateSetting, tradeSetting)
}
}

View file

@ -1,13 +0,0 @@
package ms.system;
/**
* The operating systems
* @author Clayton Williams
*
*/
public enum OperatingSystem {
UNIX,
WINDOWS
}

View file

@ -0,0 +1,9 @@
package ms.system
/**
* The operating systems
* @author Clayton Williams
*/
enum class OperatingSystem {
UNIX, WINDOWS
}

View file

@ -476,11 +476,6 @@ public final class CommunicationInfo {
* @return The rank.
*/
public ClanRank getRank(String contact) {
for (String name : ServerConstants.ADMINISTRATORS) {
if (contact.equals(name)) {
return ClanRank.ADMINISTRATOR;
}
}
return contacts.get(contact);
}

View file

@ -1,100 +0,0 @@
package ms.system.mysql;
import ms.ServerConstants;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Manages the sql connections.
* @author Vexia
*
*/
public final class SQLManager {
/**
* If the sql manager is locally hosted.
*/
public static final boolean LOCAL = true;
/**
* The database URL.
*/
public static final String DATABASE_URL = (LOCAL ? "127.0.0.1" : "keldagrim.org") + ":3306/" + (SQLManager.LOCAL ? "global" : ServerConstants.DATABASE_NAMES[1]);
/**
* The username of the user.
*/
private static final String USERNAME = (LOCAL ? "root" : "keldagr1_user");
/**
* The password of the user.
*/
private static final String PASSWORD = (LOCAL ? "" : "2jf4wkz$");
/**
* IF the sql manager is initialized.
*/
private static boolean initialized;
/**
* Constructs a new {@code SQLManager} {@code Object}
*/
public SQLManager() {
/**
* empty.
*/
}
/**
* Initializes the sql manager.
*/
public static void init() {
initialized = true;
WorldListSQLHandler.clearWorldList();
}
/**
* Gets a connection from the pool.
* @return The connection.
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://" + DATABASE_URL + "?useTimezone=true&serverTimezone=UTC", USERNAME, PASSWORD);
} catch (SQLException e) {
System.out.println("Error: Mysql error message=" + e.getMessage() + ".");
}
return null;
}
/**
* Releases the connection so it's available for usage.
* @param connection The connection.
*/
public static void close(Connection connection) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Gets the initialized.
* @return the initialized
*/
public static boolean isInitialized() {
return initialized;
}
/**
* Sets the bainitialized.
* @param initialized the initialized to set.
*/
public static void setInitialized(boolean initialized) {
SQLManager.initialized = initialized;
}
}

View file

@ -0,0 +1,64 @@
package ms.system.mysql
import ms.system.util.ManagementConstants
import ms.system.util.ManagementConstants.Companion.DATABASE_HOST_ADDRESS
import ms.system.util.ManagementConstants.Companion.DATABASE_NAME
import ms.system.util.ManagementConstants.Companion.DATABASE_PASSWORD
import ms.system.util.ManagementConstants.Companion.DATABASE_PORT
import ms.system.util.ManagementConstants.Companion.DATABASE_USERNAME
import java.sql.Connection
import java.sql.DriverManager
import java.sql.SQLException
/**
* Manages the sql connections.
* @author Vexia
*/
object SQLManager {
/**
* IF the sql manager is initialized.
*/
var isInitialized = false
/**
* Initializes the sql manager.
*/
@JvmStatic
fun init() {
isInitialized = true
WorldListSQLHandler.clearWorldList()
}
/**
* Gets a connection from the pool.
* @return The connection.
*/
@JvmStatic
val connection: Connection?
get() {
try {
return DriverManager.getConnection(
"jdbc:mysql://$DATABASE_HOST_ADDRESS:$DATABASE_PORT/$DATABASE_NAME?useTimezone=true&serverTimezone=UTC",
DATABASE_USERNAME,
DATABASE_PASSWORD
)
} catch (e: SQLException) {
println("Error: Mysql error message=" + e.message + ".")
}
return null
}
/**
* Releases the connection so it's available for usage.
* @param connection The connection.
*/
@JvmStatic
fun close(connection: Connection) {
try {
connection.close()
} catch (e: SQLException) {
e.printStackTrace()
}
}
}

View file

@ -0,0 +1,70 @@
package ms.system.util
import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser
import java.io.File
import java.io.FileReader
import kotlin.system.exitProcess
/**
* Class for parsing the server config, I.E default.json
* @param path the path to the JSON file to parse.
* @author Ceikry
*/
class ManagementConfigParser(path: String) {
val pathTo = parsePath(path)
val confFile = File(pathTo)
val parser = JSONParser()
var reader: FileReader? = null
var data: JSONObject? = null
init {
if(!confFile.canonicalFile.exists()){
println("Could not find ${confFile.canonicalFile} - Double check your working directory!")
exitProcess(0)
} else if(!pathTo.contains(".json")) {
println("Config file MUST be a JSON file!!")
println("(Got $pathTo)")
} else {
reader = FileReader(pathTo)
data = parser.parse(reader) as JSONObject
parseDatabaseInformation()
parseWorldTechnicalSettings()
}
}
private fun parseDatabaseInformation(){
data ?: return
val dbData = data!!["DatabaseInformation"] as JSONObject
ManagementConstants().parseDBProp(dbData)
}
private fun parseWorldTechnicalSettings(){
data ?: return
val wtiData = data!!["WorldTechnicalInformation"] as JSONObject
ManagementConstants().parseWTIProp(wtiData)
}
/**
* Parses a path string
* @author Ceikry
* @param pathString The string to parse
* @return a String with the proper file separators for the current OS.
*/
fun parsePath(pathString: String): String {
var pathTokens: List<String>? = null
if(pathString.contains("/"))
pathTokens = pathString.split("/")
else if(pathString.contains("\\"))
pathTokens = pathString.split("\\")
pathTokens ?: return pathString //return the initial pathString if path does not contain file separators.
var pathProduct = ""
for(token in pathTokens){
if(token != "")
pathProduct += "$token${File.separator}"
}
return pathProduct
}
}

View file

@ -0,0 +1,45 @@
package ms.system.util
import org.json.simple.JSONObject
class ManagementConstants {
companion object {
//MySQL main database name
var DATABASE_NAME: String = "global"
//MySQL database username
var DATABASE_USERNAME: String = "root"
//MySQL database password
var DATABASE_PASSWORD: String = ""
//MySQL host
var DATABASE_HOST_ADDRESS: String = "127.0.0.1"
//MySQL port
var DATABASE_PORT: Int = 3306
//Max amount of worlds supported on the world list
var MAX_WORLD_AMOUNT: Int = 10
//User world hop delay in seconds
var WORLD_HOP_DELAY: Long = 20_000L
}
fun parseDBProp(data: JSONObject) {
DATABASE_NAME = data["database_name"].toString()
DATABASE_USERNAME = data["database_username"].toString()
DATABASE_PASSWORD = data["database_password"].toString()
DATABASE_HOST_ADDRESS = data["database_host"].toString()
DATABASE_PORT = data["database_port"].toString().toInt()
}
fun parseWTIProp(data: JSONObject) {
MAX_WORLD_AMOUNT = data["world_limit"].toString().toInt()
WORLD_HOP_DELAY = data["worldhop_delay"].toString().toLong()
}
}

View file

@ -47,13 +47,13 @@ public class WorldDatabase {
buf.putShort((short) 0);
buf.put((byte) 1);
IoBuffer buffer = new IoBuffer();
if (updateStamp != (int) WorldDatabase.updateStamp) {
if (updateStamp == (int) WorldDatabase.updateStamp) {
buf.put((byte) 0);
} else {
buf.put((byte) 1); // Indicates an update occured.
putWorldListinfo(buffer);
} else {
buf.put((byte) 0);
}
putPlayerInfo(buffer);
putPlayerInfo(buffer);
if (buffer.toByteBuffer().position() > 0) {
buf.put((ByteBuffer) buffer.toByteBuffer().flip());
}
@ -85,18 +85,21 @@ public class WorldDatabase {
buffer.putJagString(capitalize(country.name().toLowerCase()));
}
}
/*
* Stole this from a library so we don't need the dependency
*/
/**
* Converts a string to a capitalized string
* @param name
* @return
*/
private static String capitalize(String name) {
if (name != null && name.length() != 0) {
if (name == null || name.length() == 0) {
return name;
} else {
char[] chars = name.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
} else {
return name;
}
}
}
/**
* Adds the world configuration on the packet.

View file

@ -25,7 +25,6 @@ dependencies {
implementation "org.jetbrains:markdown-jvm:0.2.0.pre-55"
implementation 'com.google.guava:guava:29.0-jre'
implementation 'mysql:mysql-connector-java:8.0.21'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
implementation 'io.github.classgraph:classgraph:4.8.98'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@


File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
ξΓιµΞέϊΕ<EFBFBD><EFBFBD>ϋ¨ά±χxόxφxχxψxχxψxάκΫαΑςοζρωθΘχώςοφγΜΩΖπ¤ισKΐBκLΜCψNζ-ύ6Φ8Μ8

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
eractionPacket%ñÙ$core.cache.def.impl.ObjectDefinition%)$core.cache.def.impl.ObjectDefinition%w$core.net.packet.in.InteractionPacketrÅ;core.game.node.entity.skill.farming.CompostBinOptionHandler5core.game.node.entity.skill.farming.InspectionHandler6u5core.game.node.entity.skill.farming.InspectionHandler685core.game.node.entity.skill.farming.InspectionHandler7Ó 6core.game.node.entity.state.newsys.states.FarmingState6r5core.game.node.entity.skill.farming.InspectionHandler<Ûø;core.game.node.entity.skill.farming.ToolLeprechaunInterface<@;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface<>;core.game.node.entity.skill.farming.ToolLeprechaunInterface

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more