From 9dce22dc968aa78c1d7174b835de66121a652e17 Mon Sep 17 00:00:00 2001 From: Neon Date: Sun, 1 Dec 2024 00:13:08 +0100 Subject: [PATCH] LegionHistory memory optimizations Old legions had tens of thousands of history entries, all permanently loaded into memory. Limited legion warehouse and reward logs to one year to remove most of the entries. As these two views only show the month and day but not the year, they shouldn't hold several years of data anyway. Also reduced the memory footprint of history entries by optimizing fields/types and interning common strings. --- game-server/sql/aion_gs.sql | 1 - game-server/sql/update.sql | 5 +- .../com/aionemu/gameserver/dao/LegionDAO.java | 70 +++++++++++++------ .../gameserver/model/team/legion/Legion.java | 40 +++++++---- .../model/team/legion/LegionHistory.java | 43 ------------ .../team/legion/LegionHistoryAction.java | 42 +++++++++++ .../model/team/legion/LegionHistoryEntry.java | 15 ++++ .../model/team/legion/LegionHistoryType.java | 39 ----------- .../network/aion/AionClientPacketFactory.java | 2 +- .../network/aion/ServerPacketsOpcodes.java | 2 +- .../aion/clientpackets/CM_APPEARANCE.java | 4 +- .../aion/clientpackets/CM_LEGION_HISTORY.java | 38 ++++++++++ .../aion/clientpackets/CM_LEGION_TABS.java | 45 ------------ .../clientpackets/CM_LEGION_WH_KINAH.java | 6 +- .../aion/serverpackets/SM_LEGION_HISTORY.java | 57 +++++++++++++++ .../aion/serverpackets/SM_LEGION_TABS.java | 65 ----------------- .../gameserver/services/LegionService.java | 46 ++++++------ .../services/siege/FortressSiege.java | 4 +- 18 files changed, 258 insertions(+), 266 deletions(-) delete mode 100644 game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistory.java create mode 100644 game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryAction.java create mode 100644 game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryEntry.java delete mode 100644 game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryType.java create mode 100644 game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_HISTORY.java delete mode 100644 game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_TABS.java create mode 100644 game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_HISTORY.java delete mode 100644 game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_TABS.java diff --git a/game-server/sql/aion_gs.sql b/game-server/sql/aion_gs.sql index 00f5ed3c7..266927d7d 100644 --- a/game-server/sql/aion_gs.sql +++ b/game-server/sql/aion_gs.sql @@ -471,7 +471,6 @@ CREATE TABLE `legion_history` ( `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `history_type` enum('CREATE','JOIN','KICK','APPOINTED','EMBLEM_REGISTER','EMBLEM_MODIFIED','ITEM_DEPOSIT','ITEM_WITHDRAW','KINAH_DEPOSIT','KINAH_WITHDRAW','LEVEL_UP','DEFENSE','OCCUPATION','LEGION_RENAME','CHARACTER_RENAME') NOT NULL, `name` varchar(50) NOT NULL, - `tab_id` smallint(3) NOT NULL DEFAULT '0', `description` varchar(30) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `legion_id` (`legion_id`), diff --git a/game-server/sql/update.sql b/game-server/sql/update.sql index fe620d704..78ef84c46 100644 --- a/game-server/sql/update.sql +++ b/game-server/sql/update.sql @@ -1,6 +1,5 @@ /* -* DB changes since 249c4e14 (10.08.2024) +* DB changes since 9556a4b (30.11.2024) */ --- remove old event items -DELETE FROM inventory WHERE item_id IN (182006999, 185000128, 188052166, 188600199); \ No newline at end of file +ALTER TABLE `legion_history` DROP COLUMN `tab_id`; \ No newline at end of file diff --git a/game-server/src/com/aionemu/gameserver/dao/LegionDAO.java b/game-server/src/com/aionemu/gameserver/dao/LegionDAO.java index 7e9ba4d82..af7150ef9 100644 --- a/game-server/src/com/aionemu/gameserver/dao/LegionDAO.java +++ b/game-server/src/com/aionemu/gameserver/dao/LegionDAO.java @@ -1,6 +1,10 @@ package com.aionemu.gameserver.dao; import java.sql.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +17,7 @@ import com.aionemu.gameserver.model.gameobjects.Persistable.PersistentState; import com.aionemu.gameserver.model.items.storage.StorageType; import com.aionemu.gameserver.model.team.legion.*; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction.Type; /** * Class that is responsible for storing/loading legion data @@ -40,8 +45,9 @@ public class LegionDAO { /** Storage Queries **/ private static final String SELECT_STORAGE_QUERY = "SELECT * FROM `inventory` WHERE `item_owner`=? AND `item_location`=? AND `is_equipped`=?"; /** History Queries **/ - private static final String INSERT_HISTORY_QUERY = "INSERT INTO legion_history(`legion_id`, `date`, `history_type`, `name`, `tab_id`, `description`) VALUES (?, ?, ?, ?, ?, ?)"; - private static final String SELECT_HISTORY_QUERY = "SELECT * FROM `legion_history` WHERE legion_id=? ORDER BY date ASC;"; + private static final String INSERT_HISTORY_QUERY = "INSERT INTO legion_history(`legion_id`, `date`, `history_type`, `name`, `description`) VALUES (?, ?, ?, ?, ?)"; + private static final String SELECT_HISTORY_QUERY = "SELECT * FROM `legion_history` WHERE legion_id=? ORDER BY date DESC, id DESC"; + private static final String DELETE_HISTORY_QUERY = "DELETE FROM `legion_history` WHERE id IN (%s)"; private static final String CLEAR_LEGION_SIEGE = "UPDATE siege_locations SET legion_id=0 WHERE legion_id=?"; public static boolean isNameUsed(String name) { @@ -378,33 +384,53 @@ public void handleRead(ResultSet rset) throws SQLException { return inventory; } - public static void loadLegionHistory(Legion legion) { + public static void loadHistory(Legion legion) { + Map> history = new EnumMap<>(Type.class); + for (Type type : Type.values()) + history.put(type, new ArrayList<>()); try (Connection con = DatabaseFactory.getConnection(); PreparedStatement stmt = con.prepareStatement(SELECT_HISTORY_QUERY)) { stmt.setInt(1, legion.getLegionId()); ResultSet resultSet = stmt.executeQuery(); - while (resultSet.next()) - legion.addHistory(new LegionHistory(LegionHistoryType.valueOf(resultSet.getString("history_type")), resultSet.getString("name"), - resultSet.getTimestamp("date"), resultSet.getInt("tab_id"), resultSet.getString("description"))); + while (resultSet.next()) { + int id = resultSet.getInt("id"); + int epochSeconds = (int) (resultSet.getTimestamp("date").getTime() / 1000); + LegionHistoryAction action = LegionHistoryAction.valueOf(resultSet.getString("history_type")); + String name = resultSet.getString("name"); + String description = resultSet.getString("description"); + history.get(action.getType()).add(new LegionHistoryEntry(id, epochSeconds, action, name, description)); + } } catch (Exception e) { - log.error("Error loading legion history of " + legion, e); + log.error("Could not load history of legion " + legion, e); } + legion.setHistory(history); } - public static boolean saveNewLegionHistory(int legionId, LegionHistory legionHistory) { - boolean success = DB.insertUpdate(INSERT_HISTORY_QUERY, new IUStH() { - - @Override - public void handleInsertUpdate(PreparedStatement preparedStatement) throws SQLException { - preparedStatement.setInt(1, legionId); - preparedStatement.setTimestamp(2, legionHistory.getTime()); - preparedStatement.setString(3, legionHistory.getLegionHistoryType().toString()); - preparedStatement.setString(4, legionHistory.getName()); - preparedStatement.setInt(5, legionHistory.getTabId()); - preparedStatement.setString(6, legionHistory.getDescription()); - preparedStatement.execute(); - } - }); - return success; + public static LegionHistoryEntry insertHistory(int legionId, LegionHistoryAction action, String name, String description) { + try (Connection con = DatabaseFactory.getConnection(); PreparedStatement stmt = con.prepareStatement(INSERT_HISTORY_QUERY, Statement.RETURN_GENERATED_KEYS)) { + long nowMillis = System.currentTimeMillis(); + stmt.setInt(1, legionId); + stmt.setTimestamp(2, new Timestamp(nowMillis)); + stmt.setString(3, action.toString()); + stmt.setString(4, name); + stmt.setString(5, description); + stmt.execute(); + ResultSet result = stmt.getGeneratedKeys(); + result.next(); + return new LegionHistoryEntry(result.getInt(1), (int) (nowMillis / 1000), action, name, description); + } catch (Exception e) { + log.error("Could not add history entry for legion " + legionId, e); + return null; + } } + public static void deleteHistory(int legionId, List entries) { + String placeholders = ",?".repeat(entries.size()).substring(1); + try (Connection con = DatabaseFactory.getConnection(); PreparedStatement stmt = con.prepareStatement(DELETE_HISTORY_QUERY.formatted(placeholders))) { + for (int i = 0; i < entries.size(); i++) + stmt.setInt(i + 1, entries.get(i).id()); + stmt.executeUpdate(); + } catch (Exception e) { + log.error("Could not delete " + entries.size() + " history entries for legion " + legionId, e); + } + } } diff --git a/game-server/src/com/aionemu/gameserver/model/team/legion/Legion.java b/game-server/src/com/aionemu/gameserver/model/team/legion/Legion.java index a1b88974b..824625275 100644 --- a/game-server/src/com/aionemu/gameserver/model/team/legion/Legion.java +++ b/game-server/src/com/aionemu/gameserver/model/team/legion/Legion.java @@ -1,16 +1,17 @@ package com.aionemu.gameserver.model.team.legion; import java.sql.Timestamp; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; import com.aionemu.gameserver.configs.main.LegionConfig; import com.aionemu.gameserver.model.gameobjects.AionObject; import com.aionemu.gameserver.model.gameobjects.player.Player; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction.Type; import com.aionemu.gameserver.network.aion.serverpackets.SM_ICON_INFO; import com.aionemu.gameserver.services.LegionService; import com.aionemu.gameserver.utils.PacketSendUtility; @@ -34,7 +35,7 @@ public class Legion extends AionObject { private Announcement announcement; private LegionEmblem legionEmblem = new LegionEmblem(); private LegionWarehouse legionWarehouse; - private final List legionHistory = new ArrayList<>(); + private Map> legionHistoryByType; private AtomicBoolean hasBonus = new AtomicBoolean(false); private int occupiedLegionDominion = 0; private int currentLegionDominion = 0; @@ -419,24 +420,33 @@ public int getWarehouseLevel() { return getLegionLevel() - 1; } - public List getLegionHistoryByTabId(int tabType) { - synchronized (legionHistory) { - if (legionHistory.isEmpty()) - return Collections.emptyList(); - return legionHistory.stream().filter(h -> h.getTabId() == tabType).collect(Collectors.toList()); + public List getHistory(Type type) { + List history = legionHistoryByType.get(type); + synchronized (history) { + return new ArrayList<>(history); } } /** - * Adds history entries sorted descending by their timestamps. + * Adds the history entry at the top of the list and removes entries older than a year (except the ones on the first page) */ - public void addHistory(LegionHistory history) { - synchronized (legionHistory) { - int index = 0; - while (index < legionHistory.size() && history.getTime().before(legionHistory.get(index).getTime())) - index++; - legionHistory.add(index, history); + public List addHistory(LegionHistoryEntry entry) { + List removedEntries = new ArrayList<>(); + Type type = entry.action().getType(); + List history = legionHistoryByType.get(type); + synchronized (history) { + history.addFirst(entry); + if (type == Type.REWARD || type == Type.WAREHOUSE) { + long maxMillis = System.currentTimeMillis() / 1000 - Duration.ofDays(365).toSeconds(); + while (history.getLast().epochSeconds() < maxMillis) + removedEntries.add(history.removeLast()); + } } + return removedEntries; + } + + public void setHistory(Map> history) { + legionHistoryByType = history; } public void addBonus() { diff --git a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistory.java b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistory.java deleted file mode 100644 index 5da281acf..000000000 --- a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistory.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.aionemu.gameserver.model.team.legion; - -import java.sql.Timestamp; - -/** - * @author Simple, xTz - */ -public class LegionHistory { - - private LegionHistoryType legionHistoryType; - private String name; - private Timestamp time; - private int tabId; - private String description; - - public LegionHistory(LegionHistoryType legionHistoryType, String name, Timestamp time, int tabId, String description) { - this.legionHistoryType = legionHistoryType; - this.name = name; - this.time = time; - this.tabId = tabId; - this.description = description; - } - - public LegionHistoryType getLegionHistoryType() { - return legionHistoryType; - } - - public String getName() { - return name; - } - - public Timestamp getTime() { - return time; - } - - public int getTabId() { - return tabId; - } - - public String getDescription() { - return description; - } -} diff --git a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryAction.java b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryAction.java new file mode 100644 index 000000000..150bad172 --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryAction.java @@ -0,0 +1,42 @@ +package com.aionemu.gameserver.model.team.legion; + +/** + * @author Simple + */ +public enum LegionHistoryAction { + + CREATE(0, Type.LEGION), // No parameters + JOIN(1, Type.LEGION), // Parameter: name + KICK(2, Type.LEGION), // Parameter: name + LEVEL_UP(3, Type.LEGION), // Parameter: legion level + APPOINTED(4, Type.LEGION), // Parameter: legion level + EMBLEM_REGISTER(5, Type.LEGION), // No parameters + EMBLEM_MODIFIED(6, Type.LEGION), // No parameters + // 7 to 10 are not used anymore or never implemented + DEFENSE(11, Type.REWARD), // Parameter: name = kinah amount, description = fortress id + OCCUPATION(12, Type.REWARD), // Parameter: name = kinah amount, description = fortress id + LEGION_RENAME(13, Type.LEGION), // Parameter: old name, new name + CHARACTER_RENAME(14, Type.LEGION), // Parameter: old name, new name + ITEM_DEPOSIT(15, Type.WAREHOUSE), // Parameter: name + ITEM_WITHDRAW(16, Type.WAREHOUSE), // Parameter: name + KINAH_DEPOSIT(17, Type.WAREHOUSE), // Parameter: name + KINAH_WITHDRAW(18, Type.WAREHOUSE); // Parameter: name + + private final byte id; + private final Type type; + + LegionHistoryAction(int id, Type type) { + this.id = (byte) id; + this.type = type; + } + + public byte getId() { + return id; + } + + public Type getType() { + return type; + } + + public enum Type { LEGION, REWARD, WAREHOUSE } +} diff --git a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryEntry.java b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryEntry.java new file mode 100644 index 000000000..78e97cb9d --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryEntry.java @@ -0,0 +1,15 @@ +package com.aionemu.gameserver.model.team.legion; + +/** + * @author Simple, xTz + */ +public record LegionHistoryEntry(int id, int epochSeconds, LegionHistoryAction action, String name, String description) { + + public LegionHistoryEntry(int id, int epochSeconds, LegionHistoryAction action, String name, String description) { + this.id = id; + this.epochSeconds = epochSeconds; + this.action = action; + this.name = name.intern(); + this.description = description.intern(); + } +} diff --git a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryType.java b/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryType.java deleted file mode 100644 index de6c269cc..000000000 --- a/game-server/src/com/aionemu/gameserver/model/team/legion/LegionHistoryType.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.aionemu.gameserver.model.team.legion; - -/** - * @author Simple - */ -public enum LegionHistoryType { - - CREATE(0), // No parameters - JOIN(1), // Parameter: name - KICK(2), // Parameter: name - LEVEL_UP(3), // Parameter: legion level - APPOINTED(4), // Parameter: legion level - EMBLEM_REGISTER(5), // No parameters - EMBLEM_MODIFIED(6), // No parameters - // 7 to 10 are not used anymore or never implemented - DEFENSE(11), // Parameter: name = kinah amount, description = fortress id - OCCUPATION(12), // Parameter: name = kinah amount, description = fortress id - LEGION_RENAME(13), // Parameter: old name, new name - CHARACTER_RENAME(14), // Parameter: old name, new name - ITEM_DEPOSIT(15), // Parameter: name - ITEM_WITHDRAW(16), // Parameter: name - KINAH_DEPOSIT(17), // Parameter: name - KINAH_WITHDRAW(18); // Parameter: name - - private final byte historyType; - - LegionHistoryType(int historyType) { - this.historyType = (byte) historyType; - } - - /** - * Returns client-side id for this - * - * @return byte - */ - public byte getId() { - return historyType; - } -} diff --git a/game-server/src/com/aionemu/gameserver/network/aion/AionClientPacketFactory.java b/game-server/src/com/aionemu/gameserver/network/aion/AionClientPacketFactory.java index 6afd4d7c9..b39a09846 100644 --- a/game-server/src/com/aionemu/gameserver/network/aion/AionClientPacketFactory.java +++ b/game-server/src/com/aionemu/gameserver/network/aion/AionClientPacketFactory.java @@ -80,7 +80,7 @@ public class AionClientPacketFactory { packets[52] = new PacketInfo<>(CM_SHOW_DIALOG.class, State.IN_GAME); // [C_START_DIALOG (StartDialogPacket)] packets[53] = new PacketInfo<>(CM_CLOSE_DIALOG.class, State.IN_GAME); // [C_END_DIALOG (EndDialogPacket)] packets[54] = new PacketInfo<>(CM_DIALOG_SELECT.class, State.IN_GAME); // [C_HACTION (HActionPacket)] - packets[55] = new PacketInfo<>(CM_LEGION_TABS.class, State.IN_GAME); // [C_REQUEST_GUILD_HISTORY (RequestGuildHistoryPacket)] + packets[55] = new PacketInfo<>(CM_LEGION_HISTORY.class, State.IN_GAME); // [C_REQUEST_GUILD_HISTORY (RequestGuildHistoryPacket)] // packets[56] = [C_BOOKMARK (BookmarkPacket)] // packets[57] = [C_DELETE_BOOKMARK (DeleteBookmarkPacket)] packets[58] = new PacketInfo<>(CM_SET_NOTE.class, State.IN_GAME); // [C_TODAY_WORDS (TodayWordsPacket)] diff --git a/game-server/src/com/aionemu/gameserver/network/aion/ServerPacketsOpcodes.java b/game-server/src/com/aionemu/gameserver/network/aion/ServerPacketsOpcodes.java index f9145db47..4432c7eaf 100644 --- a/game-server/src/com/aionemu/gameserver/network/aion/ServerPacketsOpcodes.java +++ b/game-server/src/com/aionemu/gameserver/network/aion/ServerPacketsOpcodes.java @@ -27,7 +27,7 @@ public class ServerPacketsOpcodes { // addPacketOpcode(9, ); // [S_LOGIN_CHECK] addPacketOpcode(10, SM_NPC_ASSEMBLER.class); // [S_CUTSCENE_NPC_INFO] addPacketOpcode(11, SM_LEGION_UPDATE_NICKNAME.class); // [S_CHANGE_GUILD_MEMBER_NICKNAME] - addPacketOpcode(12, SM_LEGION_TABS.class); // [S_GUILD_HISTORY] + addPacketOpcode(12, SM_LEGION_HISTORY.class); // [S_GUILD_HISTORY] addPacketOpcode(13, SM_ENTER_WORLD_CHECK.class); // [S_ENTER_WORLD_CHECK] addPacketOpcode(14, SM_NPC_INFO.class); // [S_PUT_NPC] addPacketOpcode(15, SM_PLAYER_SPAWN.class); // [S_WORLD] diff --git a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_APPEARANCE.java b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_APPEARANCE.java index 75140bd24..70dcbaab4 100644 --- a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_APPEARANCE.java +++ b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_APPEARANCE.java @@ -7,7 +7,7 @@ import com.aionemu.gameserver.model.gameobjects.Item; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.team.legion.Legion; -import com.aionemu.gameserver.model.team.legion.LegionHistoryType; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction; import com.aionemu.gameserver.model.templates.item.actions.AbstractItemAction; import com.aionemu.gameserver.model.templates.item.actions.CosmeticItemAction; import com.aionemu.gameserver.network.aion.AionClientPacket; @@ -91,7 +91,7 @@ public static void onPlayerNameChanged(Player player, String oldName) { World.getInstance().updateCachedPlayerName(oldName, player); if (player.isLegionMember()) { LegionService.getInstance().updateCachedPlayerName(oldName, player); - LegionService.getInstance().addHistory(player.getLegion(), oldName, LegionHistoryType.CHARACTER_RENAME, 0, player.getName()); + LegionService.getInstance().addHistory(player.getLegion(), oldName, LegionHistoryAction.CHARACTER_RENAME, player.getName()); } PacketSendUtility.broadcastToWorld(new SM_RENAME(player, oldName)); // broadcast to world to update all friendlists, housing npcs, etc. } diff --git a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_HISTORY.java b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_HISTORY.java new file mode 100644 index 000000000..b62cabfff --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_HISTORY.java @@ -0,0 +1,38 @@ +package com.aionemu.gameserver.network.aion.clientpackets; + +import java.util.Set; + +import com.aionemu.gameserver.model.gameobjects.player.Player; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction.Type; +import com.aionemu.gameserver.network.aion.AionClientPacket; +import com.aionemu.gameserver.network.aion.AionConnection.State; +import com.aionemu.gameserver.network.aion.serverpackets.SM_LEGION_HISTORY; + +/** + * @author Simple, xTz, Sykra + */ +public class CM_LEGION_HISTORY extends AionClientPacket { + + private int page; + private Type type; + + public CM_LEGION_HISTORY(int opcode, Set validStates) { + super(opcode, validStates); + } + + @Override + protected void readImpl() { + page = readD(); + type = Type.values()[readUC()]; + } + + @Override + protected void runImpl() { + Player player = getConnection().getActivePlayer(); + if (player.getLegion() == null) + return; + if (type == Type.REWARD && !player.getLegionMember().isBrigadeGeneral()) + return; + sendPacket(new SM_LEGION_HISTORY(player.getLegion().getHistory(type), page, type)); + } +} diff --git a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_TABS.java b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_TABS.java deleted file mode 100644 index bde563310..000000000 --- a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_TABS.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.aionemu.gameserver.network.aion.clientpackets; - -import java.util.List; -import java.util.Set; - -import com.aionemu.gameserver.model.gameobjects.player.Player; -import com.aionemu.gameserver.model.team.legion.LegionHistory; -import com.aionemu.gameserver.network.aion.AionClientPacket; -import com.aionemu.gameserver.network.aion.AionConnection.State; -import com.aionemu.gameserver.network.aion.serverpackets.SM_LEGION_TABS; -import com.aionemu.gameserver.utils.PacketSendUtility; - -/** - * @author Simple, xTz, Sykra - */ -public class CM_LEGION_TABS extends AionClientPacket { - - private int page; - private int tabId; - - public CM_LEGION_TABS(int opcode, Set validStates) { - super(opcode, validStates); - } - - @Override - protected void readImpl() { - page = readD(); - tabId = readUC(); - } - - @Override - protected void runImpl() { - Player player = getConnection().getActivePlayer(); - if (player.getLegion() == null) - return; - // invalid tab ids - if (tabId < 0 || tabId > 2) - return; - // restrict legion reward tab to brigade general - if (tabId == 1 && !player.getLegionMember().isBrigadeGeneral()) - return; - List history = player.getLegion().getLegionHistoryByTabId(tabId); - PacketSendUtility.sendPacket(player, new SM_LEGION_TABS(history, page, tabId)); - } -} diff --git a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_WH_KINAH.java b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_WH_KINAH.java index fea4f8636..e8d3e428c 100644 --- a/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_WH_KINAH.java +++ b/game-server/src/com/aionemu/gameserver/network/aion/clientpackets/CM_LEGION_WH_KINAH.java @@ -5,7 +5,7 @@ import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.model.items.storage.StorageType; import com.aionemu.gameserver.model.team.legion.Legion; -import com.aionemu.gameserver.model.team.legion.LegionHistoryType; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction; import com.aionemu.gameserver.model.team.legion.LegionMember; import com.aionemu.gameserver.model.team.legion.LegionPermissionsMask; import com.aionemu.gameserver.network.aion.AionClientPacket; @@ -47,7 +47,7 @@ protected void runImpl() { } if (activePlayer.getStorage(StorageType.LEGION_WAREHOUSE.getId()).tryDecreaseKinah(amount)) { activePlayer.getInventory().increaseKinah(amount); - LegionService.getInstance().addHistory(legion, activePlayer.getName(), LegionHistoryType.KINAH_WITHDRAW, 2, Long.toString(amount)); + LegionService.getInstance().addHistory(legion, activePlayer.getName(), LegionHistoryAction.KINAH_WITHDRAW, Long.toString(amount)); } break; case 1: @@ -58,7 +58,7 @@ protected void runImpl() { } if (activePlayer.getInventory().tryDecreaseKinah(amount)) { activePlayer.getStorage(StorageType.LEGION_WAREHOUSE.getId()).increaseKinah(amount); - LegionService.getInstance().addHistory(legion, activePlayer.getName(), LegionHistoryType.KINAH_DEPOSIT, 2, Long.toString(amount)); + LegionService.getInstance().addHistory(legion, activePlayer.getName(), LegionHistoryAction.KINAH_DEPOSIT, Long.toString(amount)); } break; } diff --git a/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_HISTORY.java b/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_HISTORY.java new file mode 100644 index 000000000..ae829eb8d --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_HISTORY.java @@ -0,0 +1,57 @@ +package com.aionemu.gameserver.network.aion.serverpackets; + +import java.util.Collections; +import java.util.List; + +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction.Type; +import com.aionemu.gameserver.model.team.legion.LegionHistoryEntry; +import com.aionemu.gameserver.network.aion.AionConnection; +import com.aionemu.gameserver.network.aion.AionServerPacket; + +/** + * @author Simple, KID, xTz + */ +public class SM_LEGION_HISTORY extends AionServerPacket { + + private static final int ENTRIES_PER_PAGE = 8; + + private final int totalEntries; + private final int page; + private final List pageEntries; + private final Type type; + + public SM_LEGION_HISTORY(List history, Type type) { + this(history, 0, type); + } + + public SM_LEGION_HISTORY(List history, int page, Type type) { + this.totalEntries = history.size(); + this.page = page; + this.pageEntries = findEntriesForCurrentPage(history); + this.type = type; + } + + @Override + protected void writeImpl(AionConnection con) { + writeD(totalEntries); + writeD(page); // current page + writeD(pageEntries.size()); + for (LegionHistoryEntry entry : pageEntries) { + writeD(entry.epochSeconds()); + writeC(entry.action().getId()); + writeC(0); // unk + writeS(entry.name(), 32); + writeS(entry.description(), 32); + writeH(0); + } + writeH(type.ordinal()); + } + + private List findEntriesForCurrentPage(List legionHistory) { + int startIndex = page * ENTRIES_PER_PAGE; + if (startIndex < 0 || startIndex >= legionHistory.size()) + return Collections.emptyList(); + int endIndex = Math.min(startIndex + ENTRIES_PER_PAGE, legionHistory.size()); + return legionHistory.subList(startIndex, endIndex); + } +} diff --git a/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_TABS.java b/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_TABS.java deleted file mode 100644 index e260cdb3d..000000000 --- a/game-server/src/com/aionemu/gameserver/network/aion/serverpackets/SM_LEGION_TABS.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.aionemu.gameserver.network.aion.serverpackets; - -import java.util.Collections; -import java.util.List; - -import com.aionemu.gameserver.model.team.legion.LegionHistory; -import com.aionemu.gameserver.network.aion.AionConnection; -import com.aionemu.gameserver.network.aion.AionServerPacket; - -/** - * @author Simple, KID, xTz - */ -public class SM_LEGION_TABS extends AionServerPacket { - - private static final int ENTRIES_PER_PAGE = 8; - - private final int totalEntries; - private final int page; - private final List pageEntries; - private final int tabId; - - public SM_LEGION_TABS(List legionHistory, int tabId) { - this(legionHistory, 0, tabId); - } - - /** - * @param legionHistory - * whole history entries for given tab - * @param page - * current viewed page on this tab - * @param tabId - * 0 = general legion history, 1 = legion siege reward history, 2 = legion warehouse history - */ - public SM_LEGION_TABS(List legionHistory, int page, int tabId) { - this.totalEntries = legionHistory.size(); - this.page = page; - this.pageEntries = findEntriesForCurrentPage(legionHistory); - this.tabId = tabId; - } - - @Override - protected void writeImpl(AionConnection con) { - writeD(totalEntries); - writeD(page); // current page - writeD(pageEntries.size()); - for (LegionHistory entry : pageEntries) { - writeD((int) (entry.getTime().getTime() / 1000)); - writeC(entry.getLegionHistoryType().getId()); - writeC(0); // unk - writeS(entry.getName(), 32); - writeS(entry.getDescription(), 32); - writeH(0); - } - writeC(tabId); - writeC(0); - } - - private List findEntriesForCurrentPage(List legionHistory) { - int startIndex = page * ENTRIES_PER_PAGE; - if (startIndex >= legionHistory.size()) - return Collections.emptyList(); - int endIndex = Math.min(startIndex + ENTRIES_PER_PAGE, legionHistory.size()); - return legionHistory.subList(startIndex, endIndex); - } -} diff --git a/game-server/src/com/aionemu/gameserver/services/LegionService.java b/game-server/src/com/aionemu/gameserver/services/LegionService.java index dd125fc65..7153a0286 100644 --- a/game-server/src/com/aionemu/gameserver/services/LegionService.java +++ b/game-server/src/com/aionemu/gameserver/services/LegionService.java @@ -134,7 +134,7 @@ private void deleteLegionMemberFromDB(LegionMemberEx legionMember) { LegionMemberDAO.deleteLegionMember(legionMember.getObjectId()); Legion legion = legionMember.getLegion(); legion.deleteLegionMember(legionMember.getObjectId()); - addHistory(legion, legionMember.getName(), LegionHistoryType.KICK); + addHistory(legion, legionMember.getName(), LegionHistoryAction.KICK); } public Legion getLegion(String legionName) { @@ -167,7 +167,7 @@ private void loadLegionInfo(Legion legion) { legion.setLegionEmblem(LegionDAO.loadLegionEmblem(legion.getLegionId())); legion.setLegionWarehouse(LegionDAO.loadLegionStorage(legion)); ItemService.loadItemStones(legion.getLegionWarehouse().getItems()); - LegionDAO.loadLegionHistory(legion); + LegionDAO.loadHistory(legion); } public LegionMember getLegionMember(int playerObjId) { @@ -263,8 +263,8 @@ public void createLegion(Player activePlayer, String legionName) { storeLegion(legion, true); addLegionMember(legion, activePlayer, LegionRank.BRIGADE_GENERAL); - addHistory(legion, "", LegionHistoryType.CREATE); - addHistory(legion, activePlayer.getName(), LegionHistoryType.JOIN); + addHistory(legion, "", LegionHistoryAction.CREATE); + addHistory(legion, activePlayer.getName(), LegionHistoryAction.JOIN); PacketSendUtility.sendPacket(activePlayer, SM_SYSTEM_MESSAGE.STR_GUILD_CREATED(legion.getName())); } @@ -280,7 +280,7 @@ public boolean addToLegion(Legion legion, Player invited, Player inviter) { displayLegionAnnouncement(invited, legion.getAnnouncement()); // Add to history of legion - addHistory(legion, invited.getName(), LegionHistoryType.JOIN); + addHistory(legion, invited.getName(), LegionHistoryAction.JOIN); return true; } PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_GUILD_INVITE_CAN_NOT_ADD_MEMBER_ANY_MORE()); @@ -396,7 +396,7 @@ public void appointBrigadeGeneral(Player player) { player.getLegionMember().setRank(LegionRank.BRIGADE_GENERAL); PacketSendUtility.broadcastToLegion(legion, new SM_LEGION_UPDATE_MEMBER(player, 1300273, player.getName())); PacketSendUtility.broadcastToLegion(legion, new SM_LEGION_EDIT(0x08)); - addHistory(legion, player.getName(), LegionHistoryType.APPOINTED); + addHistory(legion, player.getName(), LegionHistoryAction.APPOINTED); } /** @@ -486,7 +486,7 @@ public void requestChangeLevel(Player activePlayer) { Legion legion = activePlayer.getLegion(); activePlayer.getInventory().decreaseKinah(legion.getKinahPrice()); changeLevel(legion, legion.getLegionLevel() + 1, false); - addHistory(legion, legion.getLegionLevel() + "", LegionHistoryType.LEVEL_UP); + addHistory(legion, legion.getLegionLevel() + "", LegionHistoryAction.LEVEL_UP); } } @@ -570,7 +570,7 @@ private void updateMembersOfRecreateLegion(Legion legion) { public void storeLegionEmblem(Player activePlayer, int emblemId, int color_a, int color_r, int color_g, int color_b, LegionEmblemType emblemType) { if (legionRestrictions.canStoreLegionEmblem(activePlayer, emblemId)) { Legion legion = activePlayer.getLegion(); - addHistory(legion, "", LegionHistoryType.EMBLEM_MODIFIED); + addHistory(legion, "", LegionHistoryAction.EMBLEM_MODIFIED); activePlayer.getInventory().decreaseKinah(PricesService.getPriceForService(LegionConfig.LEGION_EMBLEM_REQUIRED_KINAH, activePlayer.getRace())); legion.getLegionEmblem().setEmblem(emblemId, color_a, color_r, color_g, color_b, emblemType, null); updateMembersEmblem(legion); @@ -695,7 +695,7 @@ public void uploadEmblemData(Player activePlayer, int size, byte[] data) { // Finished legionEmblem.setCustomEmblemData(legionEmblem.getUploadData()); LegionDAO.storeLegionEmblem(activePlayer.getLegion().getLegionId(), legionEmblem); - addHistory(activePlayer.getLegion(), "", LegionHistoryType.EMBLEM_REGISTER); + addHistory(activePlayer.getLegion(), "", LegionHistoryAction.EMBLEM_REGISTER); updateMembersEmblem(activePlayer.getLegion()); PacketSendUtility.sendPacket(activePlayer, SM_SYSTEM_MESSAGE.STR_GUILD_WARN_SUCCESS_UPLOAD_EMBLEM()); legionEmblem.resetUploadSettings(); @@ -768,27 +768,25 @@ public void changeAnnouncement(Player activePlayer, String message) { } } - private void addHistory(Legion legion, String text, LegionHistoryType legionHistoryType) { - addHistory(legion, text, legionHistoryType, 0, ""); + private void addHistory(Legion legion, String text, LegionHistoryAction action) { + addHistory(legion, text, action, ""); } - public void addRewardHistory(Legion legion, long kinahAmount, LegionHistoryType lht, int fortressId) { - addHistory(legion, String.valueOf(kinahAmount), lht, 1, String.valueOf(fortressId)); + public void addRewardHistory(Legion legion, long kinahAmount, LegionHistoryAction action, int fortressId) { + addHistory(legion, String.valueOf(kinahAmount), action, String.valueOf(fortressId)); } /** * This method will add a new history for a legion * - * @param text in case of reward: kinah amount + * @param name in case of reward: kinah amount * @param description in case of reward: fortress id */ - public void addHistory(Legion legion, String text, LegionHistoryType legionHistoryType, int tabId, String description) { - LegionHistory legionHistory = new LegionHistory(legionHistoryType, text, new Timestamp(System.currentTimeMillis()), tabId, description); - - legion.addHistory(legionHistory); - LegionDAO.saveNewLegionHistory(legion.getLegionId(), legionHistory); - - PacketSendUtility.broadcastToLegion(legion, new SM_LEGION_TABS(legion.getLegionHistoryByTabId(tabId), tabId)); + public void addHistory(Legion legion, String name, LegionHistoryAction action, String description) { + LegionHistoryEntry historyEntry = LegionDAO.insertHistory(legion.getLegionId(), action, name, description); + List removedEntries = legion.addHistory(historyEntry); + LegionDAO.deleteHistory(legion.getLegionId(), removedEntries); + PacketSendUtility.broadcastToLegion(legion, new SM_LEGION_HISTORY(legion.getHistory(action.getType()), action.getType())); } /** @@ -1224,9 +1222,9 @@ public void addWHItemHistory(Player player, int itemId, long count, IStorage sou if (legion != null) { String description = Integer.toString(itemId) + ":" + Long.toString(count); if (sourceStorage.getStorageType() == StorageType.LEGION_WAREHOUSE) { - LegionService.getInstance().addHistory(legion, player.getName(), LegionHistoryType.ITEM_WITHDRAW, 2, description); + LegionService.getInstance().addHistory(legion, player.getName(), LegionHistoryAction.ITEM_WITHDRAW, description); } else if (destStorage.getStorageType() == StorageType.LEGION_WAREHOUSE) { - LegionService.getInstance().addHistory(legion, player.getName(), LegionHistoryType.ITEM_DEPOSIT, 2, description); + LegionService.getInstance().addHistory(legion, player.getName(), LegionHistoryAction.ITEM_DEPOSIT, description); } } } @@ -1292,7 +1290,7 @@ public boolean tryRename(Legion legion, String name, Player player, Integer legi String oldName = legion.getName(); legion.setName(name); LegionDAO.storeLegion(legion); - addHistory(legion, oldName, LegionHistoryType.LEGION_RENAME, 0, name); + addHistory(legion, oldName, LegionHistoryAction.LEGION_RENAME, name); PacketSendUtility.broadcastToWorld(new SM_RENAME(legion, oldName)); // broadcast to world to update all keeps, member's tags, etc. return true; } diff --git a/game-server/src/com/aionemu/gameserver/services/siege/FortressSiege.java b/game-server/src/com/aionemu/gameserver/services/siege/FortressSiege.java index 11ff5b742..d2ea5426d 100644 --- a/game-server/src/com/aionemu/gameserver/services/siege/FortressSiege.java +++ b/game-server/src/com/aionemu/gameserver/services/siege/FortressSiege.java @@ -23,7 +23,7 @@ import com.aionemu.gameserver.model.siege.SiegeModType; import com.aionemu.gameserver.model.siege.SiegeRace; import com.aionemu.gameserver.model.team.legion.Legion; -import com.aionemu.gameserver.model.team.legion.LegionHistoryType; +import com.aionemu.gameserver.model.team.legion.LegionHistoryAction; import com.aionemu.gameserver.model.templates.npc.AbyssNpcType; import com.aionemu.gameserver.model.templates.npc.NpcRating; import com.aionemu.gameserver.model.templates.siegelocation.SiegeLegionReward; @@ -370,7 +370,7 @@ private void distributeLegionRewards(Legion legion) { if (item.getItemId() == ItemId.KINAH) { long kinah = isBossKilled() ? item.getItemCount() : Math.round(item.getItemCount() * 0.7f); legion.getLegionWarehouse().increaseKinah(kinah); - LegionService.getInstance().addRewardHistory(legion, kinah, isBossKilled() ? LegionHistoryType.OCCUPATION : LegionHistoryType.DEFENSE, + LegionService.getInstance().addRewardHistory(legion, kinah, isBossKilled() ? LegionHistoryAction.OCCUPATION : LegionHistoryAction.DEFENSE, getSiegeLocationId()); totalKinah += kinah; } else {