Code:
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation. You may not use, modify
or distribute this program under any other version of the
GNU Affero General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.odinms.client.messages;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import net.sf.odinms.client.MapleCharacter;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.SkillFactory;
import net.sf.odinms.client.messages.commands.HelpCommand;
import net.sf.odinms.database.DatabaseConnection;
import net.sf.odinms.net.channel.ChannelServer;
import net.sf.odinms.net.channel.handler.GeneralchatHandler;
import net.sf.odinms.server.TimerManager;
import net.sf.odinms.server.maps.MapleMap;
import net.sf.odinms.tools.ClassFinder;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.MockIOSession;
import net.sf.odinms.tools.Pair;
import net.sf.odinms.tools.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CommandProcessor implements CommandProcessorMBean {
private static final Logger log = LoggerFactory.getLogger(GeneralchatHandler.class);
private static List<Pair<MapleCharacter,String>> gmlog = new LinkedList<Pair<MapleCharacter,String>>();
private Map<String, DefinitionCommandPair> commands = new LinkedHashMap<String, DefinitionCommandPair>();
private static CommandProcessor instance = new CommandProcessor();
private static Runnable persister;
private ScriptEngineFactory sef;
static {
persister = new PersistingTask();
TimerManager.getInstance().register(persister, 62000);
}
private CommandProcessor() {
ScriptEngineManager sem = new ScriptEngineManager();
sef = sem.getEngineByName("javascript").getFactory();
instance = this; // hackydihack
reloadCommands();
}
public static class PersistingTask implements Runnable {
@Override
public void run() {
synchronized (gmlog) {
Connection con = DatabaseConnection.getConnection();
try {
PreparedStatement ps = con.prepareStatement("INSERT INTO gmlog (cid, command) VALUES (?, ?)");
for (Pair<MapleCharacter,String> logentry : gmlog) {
ps.setInt(1, logentry.getLeft().getId());
ps.setString(2, logentry.getRight());
ps.executeUpdate();
}
ps.close();
} catch (SQLException e) {
log.error("error persisting cheatlog", e);
}
gmlog.clear();
}
}
}
public static void registerMBean() {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
try {
mBeanServer.registerMBean(instance, new ObjectName("net.sf.odinms.client.messages:name=CommandProcessor"));
} catch (Exception e) {
log.error("Error registering CommandProcessor MBean");
}
}
public static String joinAfterString(String splitted[], String str) {
for (int i = 1; i < splitted.length; i++) {
if (splitted[i].equalsIgnoreCase(str) && i + 1 < splitted.length) {
return StringUtil.joinStringFrom(splitted, i + 1);
}
}
return null;
}
public static int getOptionalIntArg(String splitted[], int position, int def) {
if (splitted.length > position) {
try {
return Integer.parseInt(splitted[position]);
} catch (NumberFormatException nfe) {
return def;
}
}
return def;
}
public static String getNamedArg(String splitted[], int startpos, String name) {
for (int i = startpos; i < splitted.length; i++) {
if (splitted[i].equalsIgnoreCase(name) && i + 1 < splitted.length) {
return splitted[i + 1];
}
}
return null;
}
public static Integer getNamedIntArg(String splitted[], int startpos, String name) {
String arg = getNamedArg(splitted, startpos, name);
if (arg != null) {
try {
return Integer.parseInt(arg);
} catch (NumberFormatException nfe) {
// swallow - we don't really care
}
}
return null;
}
public static int getNamedIntArg(String splitted[], int startpos, String name, int def) {
Integer ret = getNamedIntArg(splitted, startpos, name);
if (ret == null) {
return def;
}
return ret.intValue();
}
public static Double getNamedDoubleArg(String splitted[], int startpos, String name) {
String arg = getNamedArg(splitted, startpos, name);
if (arg != null) {
try {
return Double.parseDouble(arg);
} catch (NumberFormatException nfe) {
// swallow - we don't really care
}
}
return null;
}
public boolean processCommand(MapleClient c, String line) {
return instance.processCommandInternal(c, new ServernoticeMapleClientMessageCallback(c), c.getPlayer().getGMLevel(), line);
}
/* (non-Javadoc)
* @see net.sf.odinms.client.messages.CommandProcessorMBean#processCommandJMX(int, int, java.lang.String)
*/
public String processCommandJMX(int cserver, int mapid, String command) {
ChannelServer cserv = ChannelServer.getInstance(cserver);
if (cserv == null) {
return "The specified channel Server does not exist in this serverprocess";
}
MapleClient c = new MapleClient(null, null, new MockIOSession());
MapleCharacter chr = MapleCharacter.getDefault(c, 26023);
c.setPlayer(chr);
chr.setName("/---------jmxuser-------------\\"); // (name longer than maxmimum length)
MapleMap map = cserv.getMapFactory().getMap(mapid);
if (map != null) {
chr.setMap(map);
SkillFactory.getSkill(5101004).getEffect(1).applyTo(chr);
map.addPlayer(chr);
}
cserv.addPlayer(chr);
MessageCallback mc = new StringMessageCallback();
try {
processCommandInternal(c, mc, 1000, command);
} finally {
if (map != null) {
map.removePlayer(chr);
}
cserv.removePlayer(chr);
}
return mc.toString();
}
public static void forcePersisting() {
persister.run();
}
public static CommandProcessor getInstance() {
return instance;
}
public void reloadCommands() {
commands.clear();
try {
ClassFinder classFinder = new ClassFinder();
String[] classes = classFinder.listClasses("net.sf.odinms.client.messages.commands", true);
registerCommand(new HelpCommand()); // register the helpcommand first so it appears first in the list (LinkedHashMap)
for (String clazz : classes) {
Class<?> clasz = Class.forName(clazz);
if (Command.class.isAssignableFrom(clasz)) {
try {
Command newInstance = (Command) clasz.newInstance();
registerCommand(newInstance);
} catch (Exception e) {
log.error("ERROR INSTANCIATING COMMAND CLASS", e);
}
}
}
} catch (ClassNotFoundException e) {
log.error("THROW", e);
}
File scriptFolder = new File("scripts/command");
for (File file : scriptFolder.listFiles()) {
if (file.isFile() && file.canRead()) {
FileReader fr = null;
try {
ScriptEngine command = sef.getScriptEngine();
fr = new FileReader(file);
CompiledScript compiled = ((Compilable) command).compile(fr);
compiled.eval();
Command c = ((Invocable) command).getInterface(Command.class);
registerCommand(c);
} catch (ScriptException e) {
log.error("THROW", e);
} catch (IOException e) {
log.error("THROW", e);
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
log.error("ERROR CLOSING", e);
}
}
}
}
}
}
private void registerCommand(Command command) {
CommandDefinition[] definition = command.getDefinition();
for (CommandDefinition def : definition) {
commands.put(def.getCommand(), new DefinitionCommandPair(command, def));
}
}
public void dropHelp(MapleCharacter chr, MessageCallback mc, int page) {
List<DefinitionCommandPair> allCommands = new ArrayList<DefinitionCommandPair>(commands.values());
int startEntry = (page - 1) * 20;
mc.dropMessage("Command Help Page: --------" + page + "---------");
for (int i = startEntry; i < startEntry + 20 && i < allCommands.size(); i++) {
CommandDefinition commandDefinition = allCommands.get(i).getDefinition();
{
dropHelpForDefinition(chr.getClient(), commandDefinition);
}
}
}
private void dropHelpForDefinition(MapleClient c, CommandDefinition commandDefinition) {
c.getSession().write(MaplePacketCreator.yellowNotice(commandDefinition.getCommand() + " " + commandDefinition.getParameterDescription() + ": " + commandDefinition.getHelp()));
}
/* (non-Javadoc)
* @see net.sf.odinms.client.messages.CommandProcessorMBean#processCommandInstance(net.sf.odinms.client.MapleClient, java.lang.String)
*/
private boolean processCommandInternal(MapleClient c, MessageCallback mc, int gmLevel, String line) {
MapleCharacter player = c.getPlayer();
if (line.charAt(0) == '/' || line.charAt(0) == '@') {
String[] splitted = line.split(" ");
if (splitted.length > 0 && splitted[0].length() > 1) {
DefinitionCommandPair definitionCommandPair = commands.get(splitted[0]);
{
if (c.getPlayer().isGM()) { //only save to the GM log what GMs do.
synchronized (gmlog) {
gmlog.add(new Pair<MapleCharacter, String>(player, line));
}
}
try {
definitionCommandPair.getCommand().execute(c, mc, splitted);
} catch (IllegalCommandSyntaxException e) {
mc.dropMessage("IllegalCommandSyntaxException:" + e.getMessage());
dropHelpForDefinition(c, definitionCommandPair.getDefinition());
} catch (Exception e) {
mc.dropMessage("An error occured: " + e.getClass().getName() + " " + e.getMessage());
log.error("COMMAND ERROR", e);
}
return true;
}
}
}
return false;
}
}
class DefinitionCommandPair {
private Command command;
private CommandDefinition definition;
public DefinitionCommandPair(Command command, CommandDefinition definition) {
super();
this.command = command;
this.definition = definition;
}
public Command getCommand() {
return command;
}
public CommandDefinition getDefinition() {
return definition;
}
}
CharCommands
Code:
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License version 3
as published by the Free Software Foundation. You may not use, modify
or distribute this program under any other version of the
GNU Affero General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.odinms.client.messages.commands;
import java.util.Collection;
import java.util.HashMap;
import static net.sf.odinms.client.messages.CommandProcessor.getOptionalIntArg;
import net.sf.odinms.client.GameConstants;
import net.sf.odinms.client.IItem;
import net.sf.odinms.client.Item;
import net.sf.odinms.client.MapleCharacter;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.MapleInventoryType;
import net.sf.odinms.client.MapleJob;
import net.sf.odinms.client.MaplePet;
import net.sf.odinms.client.MapleRing;
import net.sf.odinms.client.MapleStat;
import net.sf.odinms.client.SkillFactory;
import net.sf.odinms.client.messages.Command;
import net.sf.odinms.client.messages.CommandDefinition;
import net.sf.odinms.client.messages.IllegalCommandSyntaxException;
import net.sf.odinms.client.messages.MessageCallback;
import net.sf.odinms.client.messages.ServernoticeMapleClientMessageCallback;
import net.sf.odinms.net.channel.ChannelServer;
import net.sf.odinms.server.MapleInventoryManipulator;
import net.sf.odinms.server.MapleItemInformationProvider;
import net.sf.odinms.server.MapleShop;
import net.sf.odinms.server.MapleShopFactory;
import net.sf.odinms.tools.MaplePacketCreator;
public class CharCommands implements Command {
@SuppressWarnings("static-access")
@Override
public void execute(MapleClient c, MessageCallback mc, String[] splitted) throws Exception,
IllegalCommandSyntaxException {
MapleCharacter player = c.getPlayer();
if (splitted[0].equals("/lowhp")) {
player.setHp(1);
player.setMp(500);
player.updateSingleStat(MapleStat.HP, 1);
player.updateSingleStat(MapleStat.MP, 500);
} else if (splitted[0].equals("/fullhp")) {
player.setHp(player.getMaxHp());
player.updateSingleStat(MapleStat.HP, player.getMaxHp());
} else if (splitted[0].equals("/heal")) {
player.setHp(player.getMaxHp());
player.updateSingleStat(MapleStat.HP, player.getMaxHp());
player.setMp(player.getMaxMp());
player.updateSingleStat(MapleStat.MP, player.getMaxMp());
} else if (splitted[0].equals("/skill")) {
int skill = Integer.parseInt(splitted[1]);
int level = getOptionalIntArg(splitted, 2, 1);
int masterlevel = getOptionalIntArg(splitted, 3, 1);
c.getPlayer().changeSkillLevel(SkillFactory.getSkill(skill), level, masterlevel);
} else if (splitted[0].equals("/sp")) {
player.setRemainingSp(getOptionalIntArg(splitted, 1, 1));
player.updateSingleStat(MapleStat.AVAILABLESP, player.getRemainingSp());
} else if (splitted[0].equals("/job")) {
c.getPlayer().changeJob(MapleJob.getById(Integer.parseInt(splitted[1])));
} else if (splitted[0].equals("/whereami")) {
new ServernoticeMapleClientMessageCallback(c).dropMessage("You are on map " +
c.getPlayer().getMap().getId());
} else if (splitted[0].equals("/shop")) {
MapleShopFactory sfact = MapleShopFactory.getInstance();
MapleShop shop = sfact.getShop(getOptionalIntArg(splitted, 1, 1));
shop.sendShop(c);
} else if (splitted[0].equals("/levelup")) {
if (c.getPlayer().getLevel() >= GameConstants.getMaxLevel(c.getPlayer().getJob()))
return;
c.getPlayer().levelUp();
int newexp = c.getPlayer().getExp();
if (newexp < 0) {
c.getPlayer().gainExp(-newexp, false, false);
}
} else if (splitted[0].equals("/gmshop")) {
MapleShopFactory sfact = MapleShopFactory.getInstance();
MapleShop shop = sfact.getShop(1337);
shop.sendShop(c);
} else if (splitted[0].equals("/mesos")){
player.gainMeso(Integer.parseInt(splitted[1]), true);
} else if (splitted[0].equals("/item")) {
short quantity = (short) getOptionalIntArg(splitted, 2, 1);
if (Integer.parseInt(splitted[1]) >= 5000000 && Integer.parseInt(splitted[1]) <= 5000100) {
if (quantity > 1) {
quantity = 1;
}
int petId = MaplePet.createPet(Integer.parseInt(splitted[1]));
//c.getPlayer().equipChanged();
MapleInventoryManipulator.addById(c, Integer.parseInt(splitted[1]), quantity, c.getPlayer().getName() +
"used !item with quantity " + quantity, player.getName(), petId);
return;
}
MapleInventoryManipulator.addById(c, Integer.parseInt(splitted[1]), quantity, c.getPlayer().getName() +
"used !item with quantity " + quantity, player.getName());
} else if (splitted[0].equals("/ring")) {
int itemId = Integer.parseInt(splitted[1]);
String partnerName = splitted[2];
int partnerId = MapleCharacter.getIdByName(partnerName, 0);
int[] ret = MapleRing.createRing(c, itemId, c.getPlayer().getId(), c.getPlayer().getName(), partnerId, partnerName);
if (ret[0] == -1 || ret[1] == -1) {
mc.dropMessage("There was an unknown error.");
mc.dropMessage("Make sure the person you are attempting to create a ring with is online.");
}
} else if (splitted[0].equals("/goto")) {
ChannelServer cserv = c.getChannelServer();
HashMap<String, Integer> maps = new HashMap<String, Integer>();
maps.put("henesys", 100000000);
maps.put("ellinia", 101000000);
maps.put("perion", 102000000);
maps.put("kerning", 103000000);
maps.put("lith", 104000000);
maps.put("sleepywood", 105040300);
maps.put("florina", 110000000);
maps.put("orbis", 200000000);
maps.put("happy", 209000000);
maps.put("elnath", 211000000);
maps.put("ludi", 220000000);
maps.put("omega", 221000000);
maps.put("korean", 222000000);
maps.put("aqua", 230000000);
maps.put("leafre", 240000000);
maps.put("mulung", 250000000);
maps.put("herb", 251000000);
maps.put("nlc", 600000000);
maps.put("shrine", 800000000);
maps.put("showa", 801000000);
maps.put("fm", 910000000);
if (maps.containsKey(splitted[1])) {
player.changeMap(cserv.getMapFactory().getMap(maps.get(splitted[1])), cserv.getMapFactory().getMap(maps.get(splitted[1])).getPortal(0));
}else{
mc.dropMessage("No map enetered do /goto <henesys|ellinia|perion|kerning|lith|sleepywood|florina|orbis|happy|elnath|ludi|omega|korean|aqua|leafre|mulung|herb|nlc|shrine|showa|fm>");
}
} else if (splitted[0].equals("/drop")) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
int itemId = Integer.parseInt(splitted[1]);
short quantity = (short) (short) getOptionalIntArg(splitted, 2, 1);
IItem toDrop;
if (ii.getInventoryType(itemId) == MapleInventoryType.EQUIP) {
toDrop = ii.getEquipById(itemId);
} else {
toDrop = new Item(itemId, (byte) 0, (short) quantity);
}
StringBuilder logMsg = new StringBuilder("Created by ");
logMsg.append(c.getPlayer().getName());
logMsg.append(" using !drop. Quantity: ");
logMsg.append(quantity);
toDrop.log(logMsg.toString(), false);
toDrop.setOwner(player.getName());
c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), toDrop, c.getPlayer().getPosition(), true, true);
} else if (splitted[0].equals("/level")) {
int quantity = Integer.parseInt(splitted[1]);
c.getPlayer().setLevel(quantity);
c.getPlayer().levelUp();
int newexp = c.getPlayer().getExp();
if (newexp < 0) {
c.getPlayer().gainExp(-newexp, false, false);
}
} else if (splitted[0].equals("/online")) {
mc.dropMessage("Characters connected to channel " + c.getChannel() + ":");
Collection<MapleCharacter> chrs = c.getChannelServer().getInstance(c.getChannel()).getPlayerStorage().getAllCharacters();
for (MapleCharacter chr : chrs) {
mc.dropMessage(chr.getName() + " at map ID: " + chr.getMapId());
}
mc.dropMessage("Total characters on channel " + c.getChannel() + ": " + chrs.size());
} else if (splitted[0].equals("/iamevil")) {
MapleCharacter victim = ChannelServer.getInstance(c.getChannel()).getPlayerStorage().getCharacterByName(splitted[1]);
boolean enable = Integer.parseInt(splitted[2]) == 1;
if (victim != null) {
victim.getClient().getSession().write(MaplePacketCreator.hideUI(enable));
} else {
c.getPlayer().dropMessage(splitted[1] + " does not exist.");
}
}
}
@Override
public CommandDefinition[] getDefinition() {
return new CommandDefinition[] {
new CommandDefinition("/lowhp", "", "", 1),
new CommandDefinition("/fullhp", "", "", 1),
new CommandDefinition("/heal", "", "", 1),
new CommandDefinition("/skill", "", "", 1),
new CommandDefinition("/sp", "", "", 1),
new CommandDefinition("/job", "", "", 1),
new CommandDefinition("/whereami", "", "", 1),
new CommandDefinition("/shop", "", "", 1),
new CommandDefinition("/gmshop", "", "", 1),
new CommandDefinition("/mesos", "", "", 1),
new CommandDefinition("/levelup", "", "", 1),
new CommandDefinition("/item", "", "", 2),
new CommandDefinition("/drop", "", "", 2),
new CommandDefinition("/level", "", "", 1),
new CommandDefinition("/online", "", "", 1),
new CommandDefinition("/ring", "", "", 1),
new CommandDefinition("/goto", "", "", 1),
new CommandDefinition("/iamevil", "<victim name> <1 == enable 0 == disable>", "You are evil. Disables/enables the victim's UI. :)", 4),
};
}
}