package handling.world.family; import client.MapleCharacter; import database.DatabaseConnection; import handling.world.World; import handling.world.World.Broadcast; import handling.world.World.Family; import java.io.PrintStream; import java.io.Serializable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import tools.packet.CWvsContext; import tools.packet.CWvsContext.FamilyPacket; public class MapleFamily implements Serializable { public static final long serialVersionUID = 6322150443228168192L; private final Map<Integer, MapleFamilyCharacter> members = new ConcurrentHashMap(); private String leadername = null; private String notice; private int id; private int leaderid; private boolean proper = true; private boolean bDirty = false; private boolean changed = false; public MapleFamily(int fid) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM families WHERE familyid = ?"); ps.setInt(1, fid); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); this.id = -1; this.proper = false; return; } this.id = fid; this.leaderid = rs.getInt("leaderid"); this.notice = rs.getString("notice"); rs.close(); ps.close(); ps = con.prepareStatement("SELECT id, name, level, job, seniorid, junior1, junior2, currentrep, totalrep FROM characters WHERE familyid = ?", 1008); ps.setInt(1, fid); rs = ps.executeQuery(); while (rs.next()) { if (rs.getInt("id") == this.leaderid) { this.leadername = rs.getString("name"); } this.members.put(Integer.valueOf(rs.getInt("id")), new MapleFamilyCharacter(rs.getInt("id"), rs.getShort("level"), rs.getString("name"), -1, rs.getInt("job"), fid, rs.getInt("seniorid"), rs.getInt("junior1"), rs.getInt("junior2"), rs.getInt("currentrep"), rs.getInt("totalrep"), false)); } rs.close(); ps.close(); if ((this.leadername == null) || (this.members.size() < 2)) { System.err.println("Leader " + this.leaderid + " isn't in family " + this.id + ". Members: " + this.members.size() + ". Impossible... family is disbanding."); writeToDB(true); this.proper = false; return; } for (MapleFamilyCharacter mfc : this.members.values()) { if ((mfc.getJunior1() > 0) && ((getMFC(mfc.getJunior1()) == null) || (mfc.getId() == mfc.getJunior1()))) { mfc.setJunior1(0); } if ((mfc.getJunior2() > 0) && ((getMFC(mfc.getJunior2()) == null) || (mfc.getId() == mfc.getJunior2()) || (mfc.getJunior1() == mfc.getJunior2()))) { mfc.setJunior2(0); } if ((mfc.getSeniorId() > 0) && ((getMFC(mfc.getSeniorId()) == null) || (mfc.getId() == mfc.getSeniorId()))) { mfc.setSeniorId(0); } if ((mfc.getJunior2() > 0) && (mfc.getJunior1() <= 0)) { mfc.setJunior1(mfc.getJunior2()); mfc.setJunior2(0); } if (mfc.getJunior1() > 0) { MapleFamilyCharacter mfc2 = getMFC(mfc.getJunior1()); if (mfc2.getJunior1() == mfc.getId()) { mfc2.setJunior1(0); } if (mfc2.getJunior2() == mfc.getId()) { mfc2.setJunior2(0); } if (mfc2.getSeniorId() != mfc.getId()) { mfc2.setSeniorId(mfc.getId()); } } if (mfc.getJunior2() > 0) { MapleFamilyCharacter mfc2 = getMFC(mfc.getJunior2()); if (mfc2.getJunior1() == mfc.getId()) { mfc2.setJunior1(0); } if (mfc2.getJunior2() == mfc.getId()) { mfc2.setJunior2(0); } if (mfc2.getSeniorId() != mfc.getId()) { mfc2.setSeniorId(mfc.getId()); } } } resetPedigree(); resetDescendants(); } catch (SQLException se) { System.err.println("unable to read family information from sql"); se.printStackTrace(); } } public void resetPedigree() { for (MapleFamilyCharacter mfc : this.members.values()) { mfc.resetPedigree(this); } this.bDirty = true; } public void resetDescendants() { MapleFamilyCharacter mfc = getMFC(this.leaderid); if (mfc != null) { mfc.resetDescendants(this); } this.bDirty = true; } public boolean isProper() { return this.proper; } public static final void loadAll() { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT familyid FROM families"); ResultSet rs = ps.executeQuery(); while (rs.next()) { World.Family.addLoadedFamily(new MapleFamily(rs.getInt("familyid"))); } rs.close(); ps.close(); } catch (SQLException se) { System.err.println("unable to read family information from sql"); se.printStackTrace(); } } public static final void loadAll(Object toNotify) { try { boolean cont = false; Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT familyid FROM families"); ResultSet rs = ps.executeQuery(); while (rs.next()) { FamilyLoad.QueueFamilyForLoad(rs.getInt("familyid")); cont = true; } rs.close(); ps.close(); if (!cont) { return; } } catch (SQLException se) { System.err.println("unable to read family information from sql"); se.printStackTrace(); } AtomicInteger FinishedThreads = new AtomicInteger(0); FamilyLoad.Execute(toNotify); synchronized (toNotify) { try { toNotify.wait(); } catch (InterruptedException ex) { ex.printStackTrace(); } } while (FinishedThreads.incrementAndGet() != 8) { synchronized (toNotify) { try { toNotify.wait(); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } public final void writeToDB(boolean bDisband) { try { Connection con = DatabaseConnection.getConnection(); if (!bDisband) { if (this.changed) { PreparedStatement ps = con.prepareStatement("UPDATE families SET notice = ? WHERE familyid = ?"); ps.setString(1, this.notice); ps.setInt(2, this.id); ps.execute(); ps.close(); } this.changed = false; } else { if ((this.leadername == null) || (this.members.size() < 2)) { broadcast(null, -1, FCOp.DISBAND, null); } PreparedStatement ps = con.prepareStatement("DELETE FROM families WHERE familyid = ?"); ps.setInt(1, this.id); ps.execute(); ps.close(); } } catch (SQLException se) { System.err.println("Error saving family to SQL"); se.printStackTrace(); } } public final int getId() { return this.id; } public final int getLeaderId() { return this.leaderid; } public final String getNotice() { if (this.notice == null) { return ""; } return this.notice; } public final String getLeaderName() { return this.leadername; } public final void broadcast(byte[] packet, List<Integer> cids) { broadcast(packet, -1, FCOp.NONE, cids); } public final void broadcast(byte[] packet, int exception, List<Integer> cids) { broadcast(packet, exception, FCOp.NONE, cids); } public final void broadcast(byte[] packet, int exceptionId, FCOp bcop, List<Integer> cids) { buildNotifications(); if (this.members.size() < 2) { this.bDirty = true; return; } for (MapleFamilyCharacter mgc : this.members.values()) { if ((cids == null) || (cids.contains(Integer.valueOf(mgc.getId())))) { if (bcop == FCOp.DISBAND) { if (mgc.isOnline()) { World.Family.setFamily(0, 0, 0, 0, mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } else { setOfflineFamilyStatus(0, 0, 0, 0, mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } } else if ((mgc.isOnline()) && (mgc.getId() != exceptionId)) { World.Broadcast.sendFamilyPacket(mgc.getId(), packet, exceptionId, this.id); } } } } private final void buildNotifications() { if (!this.bDirty) { return; } Iterator toRemove = this.members.entrySet().iterator(); while (toRemove.hasNext()) { MapleFamilyCharacter mfc = (MapleFamilyCharacter) ((Map.Entry) toRemove.next()).getValue(); if ((mfc.getJunior1() > 0) && (getMFC(mfc.getJunior1()) == null)) { mfc.setJunior1(0); } if ((mfc.getJunior2() > 0) && (getMFC(mfc.getJunior2()) == null)) { mfc.setJunior2(0); } if ((mfc.getSeniorId() > 0) && (getMFC(mfc.getSeniorId()) == null)) { mfc.setSeniorId(0); } if (mfc.getFamilyId() != this.id) { toRemove.remove(); } } if ((this.members.size() < 2) && (World.Family.getFamily(this.id) != null)) { World.Family.disbandFamily(this.id); } this.bDirty = false; } public final void setOnline(int cid, boolean online, int channel) { MapleFamilyCharacter mgc = getMFC(cid); if ((mgc != null) && (mgc.getFamilyId() == this.id)) { if (mgc.isOnline() != online) { broadcast(CWvsContext.FamilyPacket.familyLoggedIn(online, mgc.getName()), cid, mgc.getId() == this.leaderid ? null : mgc.getPedigree()); } mgc.setOnline(online); mgc.setChannel((byte) channel); } this.bDirty = true; } public final int setRep(int cid, int addrep, long oldLevel, String oldName) { MapleFamilyCharacter mgc = getMFC(cid); if ((mgc != null) && (mgc.getFamilyId() == this.id)) { if (oldLevel > mgc.getLevel()) { addrep /= 2; } if (mgc.isOnline()) { List dummy = new ArrayList(); dummy.add(Integer.valueOf(mgc.getId())); broadcast(CWvsContext.FamilyPacket.changeRep(addrep, oldName), -1, dummy); World.Family.setFamily(this.id, mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep() + addrep, mgc.getTotalRep() + addrep, mgc.getId()); } else { mgc.setCurrentRep(mgc.getCurrentRep() + addrep); mgc.setTotalRep(mgc.getTotalRep() + addrep); setOfflineFamilyStatus(this.id, mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } return mgc.getSeniorId(); } return 0; } public final MapleFamilyCharacter addFamilyMemberInfo(MapleCharacter mc, int seniorid, int junior1, int junior2) { MapleFamilyCharacter ret = new MapleFamilyCharacter(mc, this.id, seniorid, junior1, junior2); this.members.put(Integer.valueOf(mc.getId()), ret); ret.resetPedigree(this); this.bDirty = true; List toRemove = new ArrayList(); for (int i = 0; i < ret.getPedigree().size(); i++) { if (((Integer) ret.getPedigree().get(i)).intValue() != ret.getId()) { MapleFamilyCharacter mfc = getMFC(((Integer) ret.getPedigree().get(i)).intValue()); if (mfc == null) { toRemove.add(Integer.valueOf(i)); } else { mfc.resetPedigree(this); } } } for (Iterator i$ = toRemove.iterator(); i$.hasNext();) { int i = ((Integer) i$.next()).intValue(); ret.getPedigree().remove(i); } return ret; } public final int addFamilyMember(MapleFamilyCharacter mgc) { mgc.setFamilyId(this.id); this.members.put(Integer.valueOf(mgc.getId()), mgc); mgc.resetPedigree(this); this.bDirty = true; for (Iterator i$ = mgc.getPedigree().iterator(); i$.hasNext();) { int i = ((Integer) i$.next()).intValue(); getMFC(i).resetPedigree(this); } return 1; } public final void leaveFamily(int id) { leaveFamily(getMFC(id), true); } public final void leaveFamily(MapleFamilyCharacter mgc, boolean skipLeader) { this.bDirty = true; if ((mgc.getId() == this.leaderid) && (!skipLeader)) { this.leadername = null; World.Family.disbandFamily(this.id); } else { if (mgc.getJunior1() > 0) { MapleFamilyCharacter j = getMFC(mgc.getJunior1()); if (j != null) { j.setSeniorId(0); splitFamily(j.getId(), j); } } if (mgc.getJunior2() > 0) { MapleFamilyCharacter j = getMFC(mgc.getJunior2()); if (j != null) { j.setSeniorId(0); splitFamily(j.getId(), j); } } if (mgc.getSeniorId() > 0) { MapleFamilyCharacter mfc = getMFC(mgc.getSeniorId()); if (mfc != null) { if (mfc.getJunior1() == mgc.getId()) { mfc.setJunior1(0); } else { mfc.setJunior2(0); } } } List dummy = new ArrayList(); dummy.add(Integer.valueOf(mgc.getId())); broadcast(null, -1, FCOp.DISBAND, dummy); resetPedigree(); } this.members.remove(Integer.valueOf(mgc.getId())); this.bDirty = true; } public final void setNotice(String notice) { this.changed = true; this.notice = notice; } public final void memberLevelJobUpdate(MapleCharacter mgc) { MapleFamilyCharacter member = getMFC(mgc.getId()); if (member != null) { int old_level = member.getLevel(); int old_job = member.getJobId(); member.setJobId(mgc.getJob()); member.setLevel(mgc.getLevel()); if (old_level != mgc.getLevel()) { broadcast(CWvsContext.sendLevelup(true, mgc.getLevel(), mgc.getName()), mgc.getId(), mgc.getId() == this.leaderid ? null : member.getPedigree()); } if (old_job != mgc.getJob()) { broadcast(CWvsContext.sendJobup(true, mgc.getJob(), mgc.getName()), mgc.getId(), mgc.getId() == this.leaderid ? null : member.getPedigree()); } } } public final void disbandFamily() { writeToDB(true); } public final MapleFamilyCharacter getMFC(int cid) { return (MapleFamilyCharacter) this.members.get(Integer.valueOf(cid)); } public int getMemberSize() { return this.members.size(); } public static void setOfflineFamilyStatus(int familyid, int seniorid, int junior1, int junior2, int currentrep, int totalrep, int cid) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE characters SET familyid = ?, seniorid = ?, junior1 = ?, junior2 = ?, currentrep = ?, totalrep = ? WHERE id = ?"); ps.setInt(1, familyid); ps.setInt(2, seniorid); ps.setInt(3, junior1); ps.setInt(4, junior2); ps.setInt(5, currentrep); ps.setInt(6, totalrep); ps.setInt(7, cid); ps.execute(); ps.close(); } catch (SQLException se) { System.out.println("SQLException: " + se.getLocalizedMessage()); se.printStackTrace(); } } public static int createFamily(int leaderId) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO families (`leaderid`) VALUES (?)", 1); ps.setInt(1, leaderId); ps.executeUpdate(); ResultSet rs = ps.getGeneratedKeys(); if (!rs.next()) { rs.close(); ps.close(); return 0; } int ret = rs.getInt(1); rs.close(); ps.close(); return ret; } catch (Exception e) { e.printStackTrace(); } return 0; } public static void mergeFamily(MapleFamily newfam, MapleFamily oldfam) { for (MapleFamilyCharacter mgc : oldfam.members.values()) { mgc.setFamilyId(newfam.getId()); if (mgc.isOnline()) { World.Family.setFamily(newfam.getId(), mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } else { setOfflineFamilyStatus(newfam.getId(), mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } newfam.members.put(Integer.valueOf(mgc.getId()), mgc); newfam.setOnline(mgc.getId(), mgc.isOnline(), mgc.getChannel()); } newfam.resetPedigree(); World.Family.disbandFamily(oldfam.getId()); } public boolean splitFamily(int splitId, MapleFamilyCharacter def) { MapleFamilyCharacter leader = getMFC(splitId); if (leader == null) { leader = def; if (leader == null) { return false; } } try { List<MapleFamilyCharacter> all = leader.getAllJuniors(this); if (all.size() <= 1) { leaveFamily(leader, false); return true; } int newId = createFamily(leader.getId()); if (newId <= 0) { return false; } for (MapleFamilyCharacter mgc : all) { mgc.setFamilyId(newId); setOfflineFamilyStatus(newId, mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); this.members.remove(Integer.valueOf(mgc.getId())); } MapleFamily newfam = World.Family.getFamily(newId); for (MapleFamilyCharacter mgc : all) { if (mgc.isOnline()) { World.Family.setFamily(newId, mgc.getSeniorId(), mgc.getJunior1(), mgc.getJunior2(), mgc.getCurrentRep(), mgc.getTotalRep(), mgc.getId()); } newfam.setOnline(mgc.getId(), mgc.isOnline(), mgc.getChannel()); } if (this.members.size() <= 1) { World.Family.disbandFamily(this.id); return true; } } finally { if (this.members.size() <= 1) { World.Family.disbandFamily(this.id); return true; } } this.bDirty = true; return false; } public static enum FCOp { NONE, DISBAND; } }