/*
OrpheusMS: MapleStory Private Server based on OdinMS
Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net>
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 as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
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.server;
import client.BuddyList;
import client.BuddyList.BuddyAddResult;
import client.BuddyList.BuddyOperation;
import client.BuddylistEntry;
import client.MapleCharacter;
import client.MapleFamily;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import net.MaplePacket;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleGuildSummary;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.Output;
/**
*
* @author kevintjuh93
*/
public class World {
private byte id, flag;
private int exprate, droprate, mesorate, bossdroprate;
private String eventmsg;
private List<Channel> channels = new ArrayList<Channel>();
private Map<Integer, MapleParty> parties = new HashMap<Integer, MapleParty>();
private AtomicInteger runningPartyId = new AtomicInteger();
private Map<Integer, MapleMessenger> messengers = new HashMap<Integer, MapleMessenger>();
private AtomicInteger runningMessengerId = new AtomicInteger();
private Map<Integer, MapleFamily> families = new LinkedHashMap<Integer, MapleFamily>();
private Map<Integer, MapleGuildSummary> gsStore = new HashMap<Integer, MapleGuildSummary>();
private PlayerStorage players = new PlayerStorage();
public World(byte world, byte flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
this.id = world;
this.flag = flag;
this.eventmsg = eventmsg;
this.exprate = exprate;
this.droprate = droprate;
this.mesorate = mesorate;
this.bossdroprate = bossdroprate;
runningPartyId.set(1);
runningMessengerId.set(1);
}
public List<Channel> getChannels() {
return channels;
}
public Channel getChannel(byte channel) {
return channels.get(channel - 1);
}
public void addChannel(Channel channel) {
channels.add(channel);
}
public void removeChannel(byte channel) {
channels.remove(channel);
}
public void setFlag(byte b) {
this.flag = b;
}
public byte getFlag() {
return flag;
}
public String getEventMessage() {
return eventmsg;
}
public int getExpRate() {
return exprate;
}
public void setExpRate(int exp) {
this.exprate = exp;
}
public int getDropRate() {
return droprate;
}
public void setDropRate(int drop) {
this.droprate = drop;
}
public int getMesoRate() {
return mesorate;
}
public void setMesoRate(int meso) {
this.mesorate = meso;
}
public int getBossDropRate() {
return bossdroprate;
}
public PlayerStorage getPlayerStorage() {
return players;
}
public void removePlayer(MapleCharacter chr) {
channels.get(chr.getClient().getChannel() - 1).removePlayer(chr);
players.removePlayer(chr.getId());
}
public byte getId() {
return id;
}
public void addFamily(int id, MapleFamily f) {
synchronized (families) {
if (!families.containsKey(id)) {
families.put(id, f);
}
}
}
public MapleFamily getFamily(int id) {
synchronized (families) {
if (families.containsKey(id)) {
return families.get(id);
}
return null;
}
}
public MapleGuild getGuild(MapleGuildCharacter mgc) {
int gid = mgc.getGuildId();
MapleGuild g = null;
g = Server.getInstance().getGuild(gid, mgc);
if (gsStore.get(gid) == null) {
gsStore.put(gid, new MapleGuildSummary(g));
}
return g;
}
public MapleGuildSummary getGuildSummary(int gid) {
if (gsStore.containsKey(gid)) {
return gsStore.get(gid);
} else {
MapleGuild g = Server.getInstance().getGuild(gid, null);
if (g != null) {
gsStore.put(gid, new MapleGuildSummary(g));
}
return gsStore.get(gid);
}
}
public void updateGuildSummary(int gid, MapleGuildSummary mgs) {
gsStore.put(gid, mgs);
}
public void reloadGuildSummary() {
MapleGuild g;
Server server = Server.getInstance();
for (int i : gsStore.keySet()) {
g = server.getGuild(i, null);
if (g != null) {
gsStore.put(i, new MapleGuildSummary(g));
} else {
gsStore.remove(i);
}
}
}
public void setGuildAndRank(List<Integer> cids, int guildid, int rank, int exception) {
for (int cid : cids) {
if (cid != exception) {
setGuildAndRank(cid, guildid, rank);
}
}
}
public void setOfflineGuildStatus(int guildid, byte guildrank, int cid) {
try {
PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("UPDATE characters SET guildid = ?, guildrank = ? WHERE id = ?");
ps.setInt(1, guildid);
ps.setInt(2, guildrank);
ps.setInt(3, cid);
ps.execute();
ps.close();
ps = null;
} catch (SQLException se) {
se.printStackTrace();
}
}
public void setGuildAndRank(int cid, int guildid, int rank) {
MapleCharacter mc = getPlayerStorage().getCharacterById(cid);
if (mc == null) {
return;
}
boolean bDifferentGuild;
if (guildid == -1 && rank == -1) {
bDifferentGuild = true;
} else {
bDifferentGuild = guildid != mc.getGuildId();
mc.setGuildId(guildid);
mc.setGuildRank(rank);
mc.saveGuildStatus();
}
if (bDifferentGuild) {
mc.getMap().broadcastMessage(mc, MaplePacketCreator.removePlayerFromMap(cid), false);
mc.getMap().broadcastMessage(mc, MaplePacketCreator.spawnPlayerMapobject(mc), false);
}
}
public void changeEmblem(int gid, List<Integer> affectedPlayers, MapleGuildSummary mgs) {
updateGuildSummary(gid, mgs);
sendPacket(affectedPlayers, MaplePacketCreator.guildEmblemChange(gid, mgs.getLogoBG(), mgs.getLogoBGColor(), mgs.getLogo(), mgs.getLogoColor()), -1);
setGuildAndRank(affectedPlayers, -1, -1, -1); // respawn player
}
public void sendPacket(List<Integer> targetIds, MaplePacket packet, int exception) {
MapleCharacter c;
for (int i : targetIds) {
if (i == exception) {
continue;
}
c = getPlayerStorage().getCharacterById(i);
if (c != null) {
c.getClient().getSession().write(packet);
}
}
}
public MapleParty createParty(MaplePartyCharacter chrfor) {
int partyid = runningPartyId.getAndIncrement();
MapleParty party = new MapleParty(partyid, chrfor);
parties.put(party.getId(), party);
return party;
}
public MapleParty getParty(int partyid) {
return parties.get(partyid);
}
public MapleParty disbandParty(int partyid) {
return parties.remove(partyid);
}
public void updateParty(MapleParty party, PartyOperation operation, MaplePartyCharacter target) {
for (MaplePartyCharacter partychar : party.getMembers()) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName());
if (chr != null) {
if (operation == PartyOperation.DISBAND) {
chr.setParty(null);
chr.setMPC(null);
} else {
chr.setParty(party);
chr.setMPC(partychar);
}
chr.getClient().getSession().write(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target));
}
}
switch (operation) {
case LEAVE:
case EXPEL:
MapleCharacter chr = getPlayerStorage().getCharacterByName(target.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target));
chr.setParty(null);
chr.setMPC(null);
}
}
}
public void updateParty(int partyid, PartyOperation operation, MaplePartyCharacter target) {
MapleParty party = getParty(partyid);
if (party == null) {
throw new IllegalArgumentException("no party with the specified partyid exists");
}
switch (operation) {
case JOIN:
party.addMember(target);
break;
case EXPEL:
case LEAVE:
party.removeMember(target);
break;
case DISBAND:
disbandParty(partyid);
break;
case SILENT_UPDATE:
case LOG_ONOFF:
party.updateMember(target);
break;
case CHANGE_LEADER:
party.setLeader(target);
break;
default:
Output.print("Unhandled updateParty operation " + operation.name() + ".");
}
updateParty(party, operation, target);
}
public byte find(String name) {
byte channel = -1;
MapleCharacter chr = getPlayerStorage().getCharacterByName(name);
if (chr != null) {
channel = chr.getClient().getChannel();
}
return channel;
}
public byte find(int id) {
byte channel = -1;
MapleCharacter chr = getPlayerStorage().getCharacterById(id);
if (chr != null) {
channel = chr.getClient().getChannel();
}
return channel;
}
public void partyChat(MapleParty party, String chattext, String namefrom) {
for (MaplePartyCharacter partychar : party.getMembers()) {
if (!(partychar.getName().equals(namefrom))) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.multiChat(namefrom, chattext, 1));
}
}
}
}
public void buddyChat(int[] recipientCharacterIds, int cidFrom, String nameFrom, String chattext) {
PlayerStorage playerStorage = getPlayerStorage();
for (int characterId : recipientCharacterIds) {
MapleCharacter chr = playerStorage.getCharacterById(characterId);
if (chr != null) {
if (chr.getBuddylist().containsVisible(cidFrom)) {
chr.getClient().getSession().write(MaplePacketCreator.multiChat(nameFrom, chattext, 0));
}
}
}
}
public CharacterIdChannelPair[] multiBuddyFind(int charIdFrom, int[] characterIds) {
List<CharacterIdChannelPair> foundsChars = new ArrayList<CharacterIdChannelPair>(characterIds.length);
for (Channel ch : getChannels()) {
for (int charid : ch.multiBuddyFind(charIdFrom, characterIds)) {
foundsChars.add(new CharacterIdChannelPair(charid, ch.getId()));
}
}
return foundsChars.toArray(new CharacterIdChannelPair[foundsChars.size()]);
}
public MapleMessenger getMessenger(int messengerid) {
return messengers.get(messengerid);
}
public void leaveMessenger(int messengerid, MapleMessengerCharacter target) {
MapleMessenger messenger = getMessenger(messengerid);
if (messenger == null) {
throw new IllegalArgumentException("No messenger with the specified messengerid exists");
}
int position = messenger.getPositionByName(target.getName());
messenger.removeMember(target);
removeMessengerPlayer(messenger, position);
}
public void messengerInvite(String sender, int messengerid, String target, byte fromchannel) {
if (isConnected(target)) {
MapleMessenger messenger = getPlayerStorage().getCharacterByName(target).getMessenger();
if (messenger == null) {
getPlayerStorage().getCharacterByName(target).getClient().getSession().write(MaplePacketCreator.messengerInvite(sender, messengerid));
MapleCharacter from = getChannel(fromchannel).getPlayerStorage().getCharacterByName(sender);
from.getClient().getSession().write(MaplePacketCreator.messengerNote(target, 4, 1));
} else {
MapleCharacter from = getChannel(fromchannel).getPlayerStorage().getCharacterByName(sender);
from.getClient().getSession().write(MaplePacketCreator.messengerChat(sender + " : " + target + " is already using Maple Messenger"));
}
}
}
public void addMessengerPlayer(MapleMessenger messenger, String namefrom, byte fromchannel, int position) {
for (MapleMessengerCharacter messengerchar : messenger.getMembers()) {
if (!(messengerchar.getName().equals(namefrom))) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(messengerchar.getName());
if (chr != null) {
MapleCharacter from = getChannel(fromchannel).getPlayerStorage().getCharacterByName(namefrom);
chr.getClient().getSession().write(MaplePacketCreator.addMessengerPlayer(namefrom, from, position, (byte) (fromchannel - 1)));
from.getClient().getSession().write(MaplePacketCreator.addMessengerPlayer(chr.getName(), chr, messengerchar.getPosition(), (byte) (messengerchar.getChannel() - 1)));
}
} else if ((messengerchar.getName().equals(namefrom))) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(messengerchar.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.joinMessenger(messengerchar.getPosition()));
}
}
}
}
public void removeMessengerPlayer(MapleMessenger messenger, int position) {
for (MapleMessengerCharacter messengerchar : messenger.getMembers()) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(messengerchar.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.removeMessengerPlayer(position));
}
}
}
public void messengerChat(MapleMessenger messenger, String chattext, String namefrom) {
for (MapleMessengerCharacter messengerchar : messenger.getMembers()) {
if (!(messengerchar.getName().equals(namefrom))) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(messengerchar.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.messengerChat(chattext));
}
}
}
}
public void declineChat(String target, String namefrom) {
if (isConnected(target)) {
MapleCharacter chr = getPlayerStorage().getCharacterByName(target);
if (chr != null && chr.getMessenger() != null) {
chr.getClient().getSession().write(MaplePacketCreator.messengerNote(namefrom, 5, 0));
}
}
}
public void updateMessenger(int messengerid, String namefrom, byte fromchannel) {
MapleMessenger messenger = getMessenger(messengerid);
int position = messenger.getPositionByName(namefrom);
updateMessenger(messenger, namefrom, position, fromchannel);
}
public void updateMessenger(MapleMessenger messenger, String namefrom, int position, byte fromchannel) {
for (MapleMessengerCharacter messengerchar : messenger.getMembers()) {
Channel ch = getChannel(fromchannel);
if (!(messengerchar.getName().equals(namefrom))) {
MapleCharacter chr = ch.getPlayerStorage().getCharacterByName(messengerchar.getName());
if (chr != null) {
chr.getClient().getSession().write(MaplePacketCreator.updateMessengerPlayer(namefrom, getChannel(fromchannel).getPlayerStorage().getCharacterByName(namefrom), position, (byte) (fromchannel - 1)));
}
}
}
}
public void silentLeaveMessenger(int messengerid, MapleMessengerCharacter target) {
MapleMessenger messenger = getMessenger(messengerid);
if (messenger == null) {
throw new IllegalArgumentException("No messenger with the specified messengerid exists");
}
messenger.silentRemoveMember(target);
}
public void joinMessenger(int messengerid, MapleMessengerCharacter target, String from, byte fromchannel) {
MapleMessenger messenger = getMessenger(messengerid);
if (messenger == null) {
throw new IllegalArgumentException("No messenger with the specified messengerid exists");
}
messenger.addMember(target);
addMessengerPlayer(messenger, from, fromchannel, target.getPosition());
}
public void silentJoinMessenger(int messengerid, MapleMessengerCharacter target, int position) {
MapleMessenger messenger = getMessenger(messengerid);
if (messenger == null) {
throw new IllegalArgumentException("No messenger with the specified messengerid exists");
}
messenger.silentAddMember(target, position);
}
public MapleMessenger createMessenger(MapleMessengerCharacter chrfor) {
int messengerid = runningMessengerId.getAndIncrement();
MapleMessenger messenger = new MapleMessenger(messengerid, chrfor);
messengers.put(messenger.getId(), messenger);
return messenger;
}
public boolean isConnected(String charName) {
return getPlayerStorage().getCharacterByName(charName) != null;
}
public void whisper(String sender, String target, byte channel, String message) {
if (isConnected(target)) {
getPlayerStorage().getCharacterByName(target).getClient().getSession().write(MaplePacketCreator.getWhisper(sender, channel, message));
}
}
public BuddyAddResult requestBuddyAdd(String addName, byte channelFrom, int cidFrom, String nameFrom) {
MapleCharacter addChar = getPlayerStorage().getCharacterByName(addName);
if (addChar != null) {
BuddyList buddylist = addChar.getBuddylist();
if (buddylist.isFull()) {
return BuddyAddResult.BUDDYLIST_FULL;
}
if (!buddylist.contains(cidFrom)) {
buddylist.addBuddyRequest(addChar.getClient(), cidFrom, nameFrom, channelFrom);
} else if (buddylist.containsVisible(cidFrom)) {
return BuddyAddResult.ALREADY_ON_LIST;
}
}
return BuddyAddResult.OK;
}
public void buddyChanged(int cid, int cidFrom, String name, byte channel, BuddyOperation operation) {
MapleCharacter addChar = getPlayerStorage().getCharacterById(cid);
if (addChar != null) {
BuddyList buddylist = addChar.getBuddylist();
switch (operation) {
case ADDED:
if (buddylist.contains(cidFrom)) {
buddylist.put(new BuddylistEntry(name, "Default Group", cidFrom, channel, true));
addChar.getClient().getSession().write(MaplePacketCreator.updateBuddyChannel(cidFrom, (byte) (channel - 1)));
}
break;
case DELETED:
if (buddylist.contains(cidFrom)) {
buddylist.put(new BuddylistEntry(name, "Default Group", cidFrom, (byte) -1, buddylist.get(cidFrom).isVisible()));
addChar.getClient().getSession().write(MaplePacketCreator.updateBuddyChannel(cidFrom, (byte) -1));
}
break;
}
}
}
public void loggedOff(String name, int characterId, byte channel, int[] buddies) {
updateBuddies(characterId, channel, buddies, true);
}
public void loggedOn(String name, int characterId, byte channel, int buddies[]) {
updateBuddies(characterId, channel, buddies, false);
}
private void updateBuddies(int characterId, byte channel, int[] buddies, boolean offline) {
PlayerStorage playerStorage = getPlayerStorage();
for (int buddy : buddies) {
MapleCharacter chr = playerStorage.getCharacterById(buddy);
if (chr != null) {
BuddylistEntry ble = chr.getBuddylist().get(characterId);
if (ble != null && ble.isVisible()) {
byte mcChannel;
if (offline) {
ble.setChannel((byte) -1);
mcChannel = -1;
} else {
ble.setChannel(channel);
mcChannel = (byte) (channel - 1);
}
chr.getBuddylist().put(ble);
chr.getClient().getSession().write(MaplePacketCreator.updateBuddyChannel(ble.getCharacterId(), mcChannel));
}
}
}
}
public void setServerMessage(String msg) {
for (Channel ch : channels) {
ch.setServerMessage(msg);
}
}
public void broadcastPacket(MaplePacket data) {
for (MapleCharacter chr : players.getAllCharacters()) {
chr.announce(data);
}
}
public final void shutdown() {
for (Channel ch : getChannels()) {
ch.shutdown();
}
players.disconnectAll();
}
}