From 551dc6917e368a648261e80eb3308d5ddbc5836b Mon Sep 17 00:00:00 2001 From: Rogiel Date: Tue, 31 May 2011 19:03:03 -0300 Subject: [PATCH] Automatic database updates Signed-off-by: Rogiel --- .../db/dao/jdbc/JDBCCharacterDAO.java | 2 +- .../com/l2jserver/db/dao/jdbc/JDBCNPCDAO.java | 38 ++++-- src/main/java/com/l2jserver/Installer.java | 40 ------ .../game/net/packet/client/CM_RESTART.java | 28 +++++ .../game/net/packet/server/SM_CHAR_LIST.java | 16 ++- .../net/packet/server/SM_ITEM_GROUND.java | 54 ++++++++ .../com/l2jserver/model/AbstractModel.java | 23 +++- src/main/java/com/l2jserver/model/Model.java | 8 +- .../java/com/l2jserver/model/game/Fort.java | 9 ++ .../com/l2jserver/model/game/Shortcut.java | 13 +- .../java/com/l2jserver/model/game/Skill.java | 5 +- .../l2jserver/model/template/NPCTemplate.java | 8 +- .../java/com/l2jserver/model/world/Actor.java | 7 ++ .../java/com/l2jserver/model/world/Clan.java | 1 + .../java/com/l2jserver/model/world/Item.java | 4 + .../l2jserver/model/world/L2Character.java | 12 ++ .../model/world/PositionableObject.java | 2 + .../service/cache/AbstractReferenceCache.java | 25 ++++ .../com/l2jserver/service/cache/Cache.java | 2 +- .../service/cache/EhCacheService.java | 6 + .../l2jserver/service/cache/EternalCache.java | 6 + .../service/database/AbstractDAO.java | 18 ++- .../service/database/DataAccessObject.java | 16 ++- .../service/database/DatabaseService.java | 4 +- .../service/database/JDBCDatabaseService.java | 118 ++++++++++++------ .../game/character/CharacterServiceImpl.java | 3 + 26 files changed, 355 insertions(+), 113 deletions(-) delete mode 100644 src/main/java/com/l2jserver/Installer.java create mode 100644 src/main/java/com/l2jserver/game/net/packet/server/SM_ITEM_GROUND.java diff --git a/src/dao/com/l2jserver/db/dao/jdbc/JDBCCharacterDAO.java b/src/dao/com/l2jserver/db/dao/jdbc/JDBCCharacterDAO.java index f9d875f6b..b927067b2 100644 --- a/src/dao/com/l2jserver/db/dao/jdbc/JDBCCharacterDAO.java +++ b/src/dao/com/l2jserver/db/dao/jdbc/JDBCCharacterDAO.java @@ -344,7 +344,7 @@ public abstract class JDBCCharacterDAO extends return database.query(new InsertUpdateQuery(character) { @Override protected String query() { - return "UPDATE `" + TABLE + "` SET " + ACCOUNT_ID + "` = ?,`" + return "UPDATE `" + TABLE + "` SET `" + ACCOUNT_ID + "` = ?,`" + CLAN_ID + "` = ?,`" + NAME + "` = ?,`" + RACE + "` = ?,`" + CLASS + "` = ?,`" + SEX + "` = ?,`" + LEVEL + "` = ?,`" + EXPERIENCE + "` = ?,`" + SP diff --git a/src/dao/com/l2jserver/db/dao/jdbc/JDBCNPCDAO.java b/src/dao/com/l2jserver/db/dao/jdbc/JDBCNPCDAO.java index 243edcbeb..c055df766 100644 --- a/src/dao/com/l2jserver/db/dao/jdbc/JDBCNPCDAO.java +++ b/src/dao/com/l2jserver/db/dao/jdbc/JDBCNPCDAO.java @@ -67,14 +67,16 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements public static final String NPC_ID = "npc_id"; public static final String NPC_TEMPLATE_ID = "npc_template_id"; + public static final String NPC_HP = "hp"; + public static final String NPC_MP = "mp"; + public static final String POINT_X = "point_x"; public static final String POINT_Y = "point_y"; public static final String POINT_Z = "point_z"; public static final String POINT_ANGLE = "point_angle"; @Inject - public JDBCNPCDAO(DatabaseService database, - final NPCIDProvider idProvider, + public JDBCNPCDAO(DatabaseService database, final NPCIDProvider idProvider, NPCTemplateIDProvider templateIdProvider) { super(database); this.idProvider = idProvider; @@ -113,8 +115,15 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements final NPC npc = template.create(); npc.setID(id); - npc.setPoint(Point3D.fromXYZA(rs.getInt(POINT_X), rs.getInt(POINT_Y), - rs.getInt(POINT_Z), rs.getDouble(POINT_ANGLE))); + + if (rs.getString(NPC_HP) != null) + npc.setHP(rs.getDouble(NPC_HP)); + if (rs.getString(NPC_MP) != null) + npc.setMP(rs.getDouble(NPC_MP)); + + npc.setPoint(Point3D.fromXYZA(rs.getInt(POINT_X), + rs.getInt(POINT_Y), rs.getInt(POINT_Z), + rs.getDouble(POINT_ANGLE))); return npc; } @@ -198,9 +207,9 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements @Override protected String query() { return "INSERT INTO `" + TABLE + "` (`" + NPC_ID + "`,`" - + NPC_TEMPLATE_ID + "`,`" + POINT_X + "`,`" + POINT_Y - + "`,`" + POINT_Z + "`,`" + POINT_ANGLE - + "`) VALUES(?,?,?,?,?,?)"; + + NPC_TEMPLATE_ID + "`,`" + NPC_HP + "`, `" + NPC_MP + + "`,`" + POINT_X + "`,`" + POINT_Y + "`,`" + POINT_Z + + "`,`" + POINT_ANGLE + "`) VALUES(?,?,?,?,?,?,?,?)"; } @Override @@ -211,6 +220,9 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements st.setInt(i++, npc.getID().getID()); st.setInt(i++, npc.getTemplateID().getID()); + st.setDouble(i++, npc.getHP()); + st.setDouble(i++, npc.getMP()); + st.setInt(i++, npc.getPoint().getX()); st.setInt(i++, npc.getPoint().getY()); st.setInt(i++, npc.getPoint().getZ()); @@ -224,10 +236,11 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements return database.query(new InsertUpdateQuery(npc) { @Override protected String query() { - return "UPDATE `" + TABLE + "` SET " + NPC_TEMPLATE_ID - + "` = ?,`" + POINT_X + "` = ?,`" + POINT_Y + "` = ?,`" - + POINT_Z + "` = ?,`" + POINT_ANGLE + "` = ? WHERE `" - + NPC_ID + "` = ?"; + return "UPDATE `" + TABLE + "` SET `" + NPC_TEMPLATE_ID + + "` = ?,`" + NPC_HP + "` = ?, `" + NPC_MP + "` = ?,`" + + POINT_X + "` = ?,`" + POINT_Y + "` = ?,`" + POINT_Z + + "` = ?,`" + POINT_ANGLE + "` = ? WHERE `" + NPC_ID + + "` = ?"; } @Override @@ -238,6 +251,9 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO implements // SET st.setInt(i++, npc.getTemplateID().getID()); + st.setDouble(i++, npc.getHP()); + st.setDouble(i++, npc.getMP()); + st.setInt(i++, npc.getPoint().getX()); st.setInt(i++, npc.getPoint().getY()); st.setInt(i++, npc.getPoint().getZ()); diff --git a/src/main/java/com/l2jserver/Installer.java b/src/main/java/com/l2jserver/Installer.java deleted file mode 100644 index 866caf42e..000000000 --- a/src/main/java/com/l2jserver/Installer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of l2jserver . - * - * l2jserver is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * l2jserver 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with l2jserver. If not, see . - */ -package com.l2jserver; - -import com.l2jserver.service.ServiceManager; -import com.l2jserver.service.database.DatabaseService; - -/** - * @author Rogiel - * - */ -public class Installer { - public static void main(String[] args) { - final L2JGameServer server = new L2JGameServer(); - try { - final ServiceManager serviceManager = server.getInjector() - .getInstance(ServiceManager.class); - - serviceManager.start(DatabaseService.class).install(); - } catch (Exception e) { - System.out.println("GameServer could not be installed!"); - e.printStackTrace(); - System.exit(0); - } - } -} diff --git a/src/main/java/com/l2jserver/game/net/packet/client/CM_RESTART.java b/src/main/java/com/l2jserver/game/net/packet/client/CM_RESTART.java index 6aaf739c1..d2f97b7b3 100644 --- a/src/main/java/com/l2jserver/game/net/packet/client/CM_RESTART.java +++ b/src/main/java/com/l2jserver/game/net/packet/client/CM_RESTART.java @@ -18,9 +18,14 @@ package com.l2jserver.game.net.packet.client; import org.jboss.netty.buffer.ChannelBuffer; +import com.google.inject.Inject; +import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.game.net.packet.AbstractClientPacket; +import com.l2jserver.game.net.packet.server.SM_CHAR_LIST; import com.l2jserver.game.net.packet.server.SM_CHAR_RESTART; +import com.l2jserver.service.game.character.CharacterService; +import com.l2jserver.service.game.spawn.NotSpawnedServiceException; /** * Requests the list of characters to be displayed in the lobby. The list of @@ -34,13 +39,36 @@ public class CM_RESTART extends AbstractClientPacket { */ public static final int OPCODE = 0x57; + /** + * The {@link CharacterService} + */ + private final CharacterService charService; + /** + * The {@link CharacterDAO} + */ + private final CharacterDAO charDao; + + @Inject + public CM_RESTART(CharacterService charService, CharacterDAO charDao) { + this.charService = charService; + this.charDao = charDao; + } + @Override public void read(Lineage2Connection conn, ChannelBuffer buffer) { } @Override public void process(final Lineage2Connection conn) { + try { + charService.leaveWorld(conn.getCharacter()); + } catch (NotSpawnedServiceException e) { + conn.sendActionFailed(); + return; + } conn.setCharacterID(null); conn.write(SM_CHAR_RESTART.ok()); + conn.write(SM_CHAR_LIST.fromL2Session(conn.getSession(), + charDao.selectByAccount(conn.getSession().getAccountID()))); } } diff --git a/src/main/java/com/l2jserver/game/net/packet/server/SM_CHAR_LIST.java b/src/main/java/com/l2jserver/game/net/packet/server/SM_CHAR_LIST.java index faff566d7..f9e4cac32 100644 --- a/src/main/java/com/l2jserver/game/net/packet/server/SM_CHAR_LIST.java +++ b/src/main/java/com/l2jserver/game/net/packet/server/SM_CHAR_LIST.java @@ -42,6 +42,8 @@ import static com.l2jserver.model.world.character.CharacterInventory.InventoryPa import static com.l2jserver.model.world.character.CharacterInventory.InventoryPaperdoll.RIGHT_FINGER; import static com.l2jserver.model.world.character.CharacterInventory.InventoryPaperdoll.RIGHT_HAND; +import java.util.Collection; + import org.jboss.netty.buffer.ChannelBuffer; import com.l2jserver.game.net.Lineage2Connection; @@ -77,8 +79,8 @@ public class SM_CHAR_LIST extends AbstractServerPacket { */ private final L2Character[] characters; - public SM_CHAR_LIST(String loginName, int sessionId, - int lastCharacterId, L2Character... characters) { + public SM_CHAR_LIST(String loginName, int sessionId, int lastCharacterId, + L2Character... characters) { super(OPCODE); this.loginName = loginName; this.sessionId = sessionId; @@ -86,12 +88,18 @@ public class SM_CHAR_LIST extends AbstractServerPacket { this.characters = characters; } - public static SM_CHAR_LIST fromL2Session( - Lineage2Session session, L2Character... characters) { + public static SM_CHAR_LIST fromL2Session(Lineage2Session session, + L2Character... characters) { return new SM_CHAR_LIST(session.getAccountID().getID(), session.getPlayKey2(), -1, characters); } + public static SM_CHAR_LIST fromL2Session(Lineage2Session session, + Collection characters) { + return fromL2Session(session, + characters.toArray(new L2Character[characters.size()])); + } + @Override public void write(Lineage2Connection conn, ChannelBuffer buffer) { // buffer.writeByte(0x09); diff --git a/src/main/java/com/l2jserver/game/net/packet/server/SM_ITEM_GROUND.java b/src/main/java/com/l2jserver/game/net/packet/server/SM_ITEM_GROUND.java new file mode 100644 index 000000000..06ec134de --- /dev/null +++ b/src/main/java/com/l2jserver/game/net/packet/server/SM_ITEM_GROUND.java @@ -0,0 +1,54 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver.game.net.packet.server; + +import org.jboss.netty.buffer.ChannelBuffer; + +import com.l2jserver.game.net.Lineage2Connection; +import com.l2jserver.game.net.packet.AbstractServerPacket; + +/** + * This packet sends an item that is dropped on the ground + * + * @author Rogiel + */ +public class SM_ITEM_GROUND extends AbstractServerPacket { + /** + * The packet OPCODE + */ + public static final int OPCODE = 0x16; + + public SM_ITEM_GROUND() { + super(OPCODE); + } + + @Override + public void write(Lineage2Connection conn, ChannelBuffer buffer) { + buffer.writeInt(268437456); // char who dropped + buffer.writeInt(268635461); // item obj id + buffer.writeInt(57); // item template id + + buffer.writeInt(-84341); // x + buffer.writeInt(244623); // y + buffer.writeInt(-3728); // z + // only show item count if it is a stackable item + buffer.writeInt(0x01); // show count + buffer.writeLong(4001); // count + + buffer.writeInt(1); // unknown + } +} diff --git a/src/main/java/com/l2jserver/model/AbstractModel.java b/src/main/java/com/l2jserver/model/AbstractModel.java index 049f437b5..fa49f726c 100644 --- a/src/main/java/com/l2jserver/model/AbstractModel.java +++ b/src/main/java/com/l2jserver/model/AbstractModel.java @@ -32,7 +32,7 @@ public abstract class AbstractModel> implements Model { /** * The database object state */ - protected transient ObjectState state = ObjectState.NOT_STORED; + protected transient ObjectDesire desire = ObjectDesire.INSERT; @Override public T getID() { @@ -46,13 +46,26 @@ public abstract class AbstractModel> implements Model { } @Override - public ObjectState getObjectState() { - return state; + public ObjectDesire getObjectDesire() { + return desire; } @Override - public void setObjectState(ObjectState state) { - this.state = state; + public void setObjectDesire(ObjectDesire desire) { + if (desire == null) + desire = ObjectDesire.NONE; + this.desire = desire; + } + + /** + * Set this object desire to {@link ObjectDesire#UPDATE}. If the desire is + * {@link ObjectDesire#INSERT} or {@link ObjectDesire#DELETE} the desire + * will not be changed. + */ + protected void desireUpdate() { + if (this.desire != ObjectDesire.INSERT + && this.desire != ObjectDesire.DELETE) + this.desire = ObjectDesire.UPDATE; } @Override diff --git a/src/main/java/com/l2jserver/model/Model.java b/src/main/java/com/l2jserver/model/Model.java index b5ea9ed59..424e91606 100644 --- a/src/main/java/com/l2jserver/model/Model.java +++ b/src/main/java/com/l2jserver/model/Model.java @@ -37,15 +37,15 @@ public interface Model> { /** * @return the database object state */ - ObjectState getObjectState(); + ObjectDesire getObjectDesire(); /** * @param state * the database object state to set */ - void setObjectState(ObjectState state); + void setObjectDesire(ObjectDesire state); - public enum ObjectState { - STORED, NOT_STORED, ORPHAN; + public enum ObjectDesire { + NONE, INSERT, UPDATE, DELETE; } } diff --git a/src/main/java/com/l2jserver/model/game/Fort.java b/src/main/java/com/l2jserver/model/game/Fort.java index 7830226e6..e3db9166c 100644 --- a/src/main/java/com/l2jserver/model/game/Fort.java +++ b/src/main/java/com/l2jserver/model/game/Fort.java @@ -89,6 +89,7 @@ public class Fort extends AbstractModel { * the castleID to set */ public void setCastleID(CastleID castleID) { + desireUpdate(); this.castleID = castleID; } @@ -104,6 +105,7 @@ public class Fort extends AbstractModel { * the ownerID to set */ public void setOwnerID(CharacterID ownerID) { + desireUpdate(); this.ownerID = ownerID; } @@ -119,6 +121,7 @@ public class Fort extends AbstractModel { * the name to set */ public void setName(String name) { + desireUpdate(); this.name = name; } @@ -134,6 +137,7 @@ public class Fort extends AbstractModel { * the siegeDate to set */ public void setSiegeDate(Date siegeDate) { + desireUpdate(); this.siegeDate = siegeDate; } @@ -149,6 +153,7 @@ public class Fort extends AbstractModel { * the lastOwnedTime to set */ public void setLastOwnedTime(Date lastOwnedTime) { + desireUpdate(); this.lastOwnedTime = lastOwnedTime; } @@ -164,6 +169,7 @@ public class Fort extends AbstractModel { * the fortType to set */ public void setFortType(FortType fortType) { + desireUpdate(); this.fortType = fortType; } @@ -179,6 +185,7 @@ public class Fort extends AbstractModel { * the state to set */ public void setState(boolean state) { + desireUpdate(); this.state = state; } @@ -194,6 +201,7 @@ public class Fort extends AbstractModel { * the blood to set */ public void setBlood(boolean blood) { + desireUpdate(); this.blood = blood; } @@ -209,6 +217,7 @@ public class Fort extends AbstractModel { * the supplyLvL to set */ public void setSupplyLvL(int supplyLvL) { + desireUpdate(); this.supplyLvL = supplyLvL; } } diff --git a/src/main/java/com/l2jserver/model/game/Shortcut.java b/src/main/java/com/l2jserver/model/game/Shortcut.java index 83cd6313e..371bf925d 100644 --- a/src/main/java/com/l2jserver/model/game/Shortcut.java +++ b/src/main/java/com/l2jserver/model/game/Shortcut.java @@ -16,6 +16,7 @@ */ package com.l2jserver.model.game; +import com.l2jserver.model.AbstractModel; import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.ItemID; import com.l2jserver.model.id.template.SkillTemplateID; @@ -24,9 +25,10 @@ import com.l2jserver.model.world.L2Character; /** * An shortcut in Lineage II game interface * - * @author Rogiel + * @author Rogiel
+ * TODO create the shortcut id */ -public class Shortcut { +public class Shortcut extends AbstractModel { /** * The character id */ @@ -179,6 +181,7 @@ public class Shortcut { * the skillID to set */ public void setSkillID(SkillTemplateID skillID) { + desireUpdate(); this.skillID = skillID; } @@ -194,6 +197,7 @@ public class Shortcut { * the itemID to set */ public void setItemID(ItemID itemID) { + desireUpdate(); this.itemID = itemID; } @@ -209,6 +213,7 @@ public class Shortcut { * the slot to set */ public void setSlot(int slot) { + desireUpdate(); this.slot = slot; } @@ -224,6 +229,7 @@ public class Shortcut { * the page to set */ public void setPage(int page) { + desireUpdate(); this.page = page; } @@ -239,6 +245,7 @@ public class Shortcut { * the type to set */ public void setType(ShortcutType type) { + desireUpdate(); this.type = type; } @@ -254,6 +261,7 @@ public class Shortcut { * the level to set */ public void setLevel(int level) { + desireUpdate(); this.level = level; } @@ -269,6 +277,7 @@ public class Shortcut { * the characterType to set */ public void setCharacterType(int characterType) { + desireUpdate(); this.characterType = characterType; } diff --git a/src/main/java/com/l2jserver/model/game/Skill.java b/src/main/java/com/l2jserver/model/game/Skill.java index 61874990d..45343c4d8 100644 --- a/src/main/java/com/l2jserver/model/game/Skill.java +++ b/src/main/java/com/l2jserver/model/game/Skill.java @@ -16,6 +16,7 @@ */ package com.l2jserver.model.game; +import com.l2jserver.model.AbstractModel; import com.l2jserver.model.id.object.ActorID; import com.l2jserver.model.id.template.SkillTemplateID; import com.l2jserver.model.template.SkillTemplate; @@ -26,7 +27,7 @@ import com.l2jserver.model.world.Actor; * * @author Rogiel */ -public class Skill { +public class Skill extends AbstractModel { /** * The skill template ID */ @@ -90,6 +91,7 @@ public class Skill { * the actor ID to set */ public void setActorID(ActorID actorID) { + desireUpdate(); this.actorID = actorID; } @@ -105,6 +107,7 @@ public class Skill { * the level to set */ public void setLevel(int level) { + desireUpdate(); this.level = level; } diff --git a/src/main/java/com/l2jserver/model/template/NPCTemplate.java b/src/main/java/com/l2jserver/model/template/NPCTemplate.java index f5abf5fe1..7eb31420a 100644 --- a/src/main/java/com/l2jserver/model/template/NPCTemplate.java +++ b/src/main/java/com/l2jserver/model/template/NPCTemplate.java @@ -268,7 +268,13 @@ public class NPCTemplate extends ActorTemplate { @Override protected NPC createInstance() { - return new NPC(this.id); + final NPC npc = new NPC(this.id); + + // new npcs are full hp/mp + npc.setHP(getMaximumHP()); + npc.setMP(getMaximumMP()); + + return npc; } /** diff --git a/src/main/java/com/l2jserver/model/world/Actor.java b/src/main/java/com/l2jserver/model/world/Actor.java index ae658b38a..7b22a93dc 100644 --- a/src/main/java/com/l2jserver/model/world/Actor.java +++ b/src/main/java/com/l2jserver/model/world/Actor.java @@ -148,6 +148,7 @@ public abstract class Actor extends PositionableObject { * the race to set */ public void setRace(ActorRace race) { + desireUpdate(); this.race = race; } @@ -163,6 +164,7 @@ public abstract class Actor extends PositionableObject { * the sex to set */ public void setSex(ActorSex sex) { + desireUpdate(); this.sex = sex; } @@ -178,6 +180,7 @@ public abstract class Actor extends PositionableObject { * the level to set */ public void setLevel(int level) { + desireUpdate(); this.level = level; } @@ -193,6 +196,7 @@ public abstract class Actor extends PositionableObject { * the hP to set */ public void setHP(double hP) { + desireUpdate(); HP = hP; } @@ -208,6 +212,7 @@ public abstract class Actor extends PositionableObject { * the mP to set */ public void setMP(double mP) { + desireUpdate(); MP = mP; } @@ -223,6 +228,7 @@ public abstract class Actor extends PositionableObject { * the experience to set */ public void setExperience(long experience) { + desireUpdate(); this.experience = experience; } @@ -238,6 +244,7 @@ public abstract class Actor extends PositionableObject { * the sp to set */ public void setSP(int sp) { + desireUpdate(); this.sp = sp; } diff --git a/src/main/java/com/l2jserver/model/world/Clan.java b/src/main/java/com/l2jserver/model/world/Clan.java index aa4b4c78d..55c7d3df1 100644 --- a/src/main/java/com/l2jserver/model/world/Clan.java +++ b/src/main/java/com/l2jserver/model/world/Clan.java @@ -58,6 +58,7 @@ public class Clan extends AbstractObject implements Iterable { * the leaderID to set */ public void setLeaderID(CharacterID leaderID) { + desireUpdate(); this.leaderID = leaderID; } diff --git a/src/main/java/com/l2jserver/model/world/Item.java b/src/main/java/com/l2jserver/model/world/Item.java index 0ca4e92e1..7f0daa224 100644 --- a/src/main/java/com/l2jserver/model/world/Item.java +++ b/src/main/java/com/l2jserver/model/world/Item.java @@ -85,6 +85,7 @@ public class Item extends PositionableObject { * the count to set */ public void setCount(long count) { + desireUpdate(); this.count = count; } @@ -100,6 +101,7 @@ public class Item extends PositionableObject { * the location to set */ public void setLocation(InventoryLocation location) { + desireUpdate(); this.location = location; if (location != InventoryLocation.PAPERDOLL) this.paperdoll = null; @@ -117,6 +119,7 @@ public class Item extends PositionableObject { * the paperdoll to set */ public void setPaperdoll(InventoryPaperdoll paperdoll) { + desireUpdate(); this.paperdoll = paperdoll; } @@ -146,6 +149,7 @@ public class Item extends PositionableObject { * the ownerID to set */ public void setOwnerID(CharacterID ownerID) { + desireUpdate(); this.ownerID = ownerID; } } diff --git a/src/main/java/com/l2jserver/model/world/L2Character.java b/src/main/java/com/l2jserver/model/world/L2Character.java index aa6763a89..b37b4dbb4 100644 --- a/src/main/java/com/l2jserver/model/world/L2Character.java +++ b/src/main/java/com/l2jserver/model/world/L2Character.java @@ -203,6 +203,7 @@ public class L2Character extends Player { * the account ID to set */ public void setAccountID(AccountID accountID) { + desireUpdate(); this.accountID = accountID; } @@ -227,6 +228,7 @@ public class L2Character extends Player { * the clanID to set */ public void setClanID(ClanID clanID) { + desireUpdate(); this.clanID = clanID; } @@ -251,6 +253,7 @@ public class L2Character extends Player { * the petID to set */ public void setPetID(PetID petID) { + desireUpdate(); this.petID = petID; } @@ -266,6 +269,7 @@ public class L2Character extends Player { * the name to set */ public void setName(String name) { + desireUpdate(); this.name = name; } @@ -281,6 +285,7 @@ public class L2Character extends Player { * the title to set */ public void setTitle(String title) { + desireUpdate(); this.title = title; } @@ -296,6 +301,7 @@ public class L2Character extends Player { * the characterClass to set */ public void setCharacterClass(CharacterClass characterClass) { + desireUpdate(); this.characterClass = characterClass; } @@ -311,6 +317,7 @@ public class L2Character extends Player { * the character CP to set */ public void setCP(double CP) { + desireUpdate(); this.CP = CP; } @@ -326,6 +333,7 @@ public class L2Character extends Player { * the online to set */ public void setOnline(boolean online) { + desireUpdate(); this.online = online; } @@ -341,6 +349,7 @@ public class L2Character extends Player { * the lastAccess to set */ public void setLastAccess(Date lastAccess) { + desireUpdate(); this.lastAccess = lastAccess; } @@ -363,6 +372,7 @@ public class L2Character extends Player { * the character karma points to set */ public void setKarma(int karma) { + desireUpdate(); this.karma = karma; } @@ -378,6 +388,7 @@ public class L2Character extends Player { * the character PK kills to set */ public void setPkKills(int pkKills) { + desireUpdate(); this.pkKills = pkKills; } @@ -393,6 +404,7 @@ public class L2Character extends Player { * the character PVP kills to set */ public void setPvpKills(int pvpKills) { + desireUpdate(); this.pvpKills = pvpKills; } diff --git a/src/main/java/com/l2jserver/model/world/PositionableObject.java b/src/main/java/com/l2jserver/model/world/PositionableObject.java index c75d9839c..6c60cda23 100644 --- a/src/main/java/com/l2jserver/model/world/PositionableObject.java +++ b/src/main/java/com/l2jserver/model/world/PositionableObject.java @@ -43,6 +43,7 @@ public abstract class PositionableObject extends AbstractObject { * the coordinate point to set */ public void setPoint(Point3D point) { + desireUpdate(); this.point = point; } @@ -51,6 +52,7 @@ public abstract class PositionableObject extends AbstractObject { } public void setPosition(Coordinate coord) { + desireUpdate(); this.point = new Point3D(coord, (point != null ? point.getAngle() : 0)); } } diff --git a/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java b/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java index d4119a5cc..b4e4af4b7 100644 --- a/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java +++ b/src/main/java/com/l2jserver/service/cache/AbstractReferenceCache.java @@ -18,6 +18,7 @@ package com.l2jserver.service.cache; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; +import java.util.Iterator; import java.util.Map; import org.slf4j.Logger; @@ -108,6 +109,30 @@ abstract class AbstractReferenceCache implements Cache { log.debug("{}: cleared", cacheName); } + @Override + public Iterator iterator() { + cleanQueue(); + return new Iterator() { + private final Iterator> iterator = cacheMap.values() + .iterator(); + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public V next() { + return iterator.next().get(); + } + + @Override + public void remove() { + iterator.remove(); + } + }; + } + protected abstract Reference newReference(K key, V value, ReferenceQueue queue); } diff --git a/src/main/java/com/l2jserver/service/cache/Cache.java b/src/main/java/com/l2jserver/service/cache/Cache.java index 370b2e69f..fced38ad0 100644 --- a/src/main/java/com/l2jserver/service/cache/Cache.java +++ b/src/main/java/com/l2jserver/service/cache/Cache.java @@ -21,7 +21,7 @@ package com.l2jserver.service.cache; * * @author Rogiel */ -public interface Cache { +public interface Cache extends Iterable { /** * Adds a pair to cache.
*
diff --git a/src/main/java/com/l2jserver/service/cache/EhCacheService.java b/src/main/java/com/l2jserver/service/cache/EhCacheService.java index 88ebf2c4c..e73c3328f 100644 --- a/src/main/java/com/l2jserver/service/cache/EhCacheService.java +++ b/src/main/java/com/l2jserver/service/cache/EhCacheService.java @@ -20,6 +20,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.Iterator; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; @@ -217,5 +218,10 @@ public class EhCacheService extends AbstractService implements CacheService { public void clear() { cache.removeAll(); } + + @Override + public Iterator iterator() { + return null; + } } } diff --git a/src/main/java/com/l2jserver/service/cache/EternalCache.java b/src/main/java/com/l2jserver/service/cache/EternalCache.java index 41d55da7d..0931f4e7b 100644 --- a/src/main/java/com/l2jserver/service/cache/EternalCache.java +++ b/src/main/java/com/l2jserver/service/cache/EternalCache.java @@ -16,6 +16,7 @@ */ package com.l2jserver.service.cache; +import java.util.Iterator; import java.util.Map; import org.slf4j.Logger; @@ -84,4 +85,9 @@ class EternalCache implements Cache { cacheMap.clear(); log.debug("{}: cleared", cacheName); } + + @Override + public Iterator iterator() { + return cacheMap.values().iterator(); + } } diff --git a/src/main/java/com/l2jserver/service/database/AbstractDAO.java b/src/main/java/com/l2jserver/service/database/AbstractDAO.java index 6dbf0efd6..7d8d19f62 100644 --- a/src/main/java/com/l2jserver/service/database/AbstractDAO.java +++ b/src/main/java/com/l2jserver/service/database/AbstractDAO.java @@ -48,15 +48,23 @@ public abstract class AbstractDAO, I extends ID> @Override public boolean save(T object) { - switch (object.getObjectState()) { - case NOT_STORED: + return save(object, false); + } + + @Override + public boolean save(T object, boolean force) { + switch (object.getObjectDesire()) { + case INSERT: return insert(object); - case STORED: + case UPDATE: return update(object); - case ORPHAN: + case DELETE: return delete(object); + case NONE: + return (force ? update(object) : false); + default: + return false; } - return false; } @Override diff --git a/src/main/java/com/l2jserver/service/database/DataAccessObject.java b/src/main/java/com/l2jserver/service/database/DataAccessObject.java index 711951636..08a68009b 100644 --- a/src/main/java/com/l2jserver/service/database/DataAccessObject.java +++ b/src/main/java/com/l2jserver/service/database/DataAccessObject.java @@ -60,15 +60,29 @@ public interface DataAccessObject, I extends ID> extends /** * Save the instance to the database. If a new database entry was created - * returns true. + * returns true. This method will only save if the object has changed. * * @param object * the object * @return true if the row was inserted or updated + * @see DataAccessObject#save(Model, boolean) */ @IgnoreCaching boolean save(O object); + /** + * Save the instance to the database. If a new database entry was created + * returns true. + * + * @param object + * the object + * @param force + * will force an save, even if the object has not changed + * @return true if the row was inserted or updated + */ + @IgnoreCaching + boolean save(O object, boolean force); + /** * Inserts the instance in the database. * diff --git a/src/main/java/com/l2jserver/service/database/DatabaseService.java b/src/main/java/com/l2jserver/service/database/DatabaseService.java index 5bb965d38..a02d41acf 100644 --- a/src/main/java/com/l2jserver/service/database/DatabaseService.java +++ b/src/main/java/com/l2jserver/service/database/DatabaseService.java @@ -16,6 +16,8 @@ */ package com.l2jserver.service.database; +import com.l2jserver.model.Model; +import com.l2jserver.model.id.ID; import com.l2jserver.service.Service; /** @@ -25,5 +27,5 @@ import com.l2jserver.service.Service; * @author Rogiel */ public interface DatabaseService extends Service { - void install(); + , I extends ID> DataAccessObject getDAO(Class model); } diff --git a/src/main/java/com/l2jserver/service/database/JDBCDatabaseService.java b/src/main/java/com/l2jserver/service/database/JDBCDatabaseService.java index 3c2a236df..54b410fe2 100644 --- a/src/main/java/com/l2jserver/service/database/JDBCDatabaseService.java +++ b/src/main/java/com/l2jserver/service/database/JDBCDatabaseService.java @@ -16,15 +16,13 @@ */ package com.l2jserver.service.database; -import java.io.File; -import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.sql.DataSource; @@ -32,17 +30,27 @@ import org.apache.commons.dbcp.ConnectionFactory; import org.apache.commons.dbcp.DriverManagerConnectionFactory; import org.apache.commons.dbcp.PoolableConnectionFactory; import org.apache.commons.dbcp.PoolingDataSource; -import org.apache.commons.io.FileUtils; import org.apache.commons.pool.impl.GenericObjectPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.google.inject.Inject; +import com.google.inject.Injector; +import com.l2jserver.db.dao.CharacterDAO; +import com.l2jserver.db.dao.ClanDAO; +import com.l2jserver.db.dao.ItemDAO; +import com.l2jserver.db.dao.NPCDAO; +import com.l2jserver.db.dao.PetDAO; import com.l2jserver.model.Model; -import com.l2jserver.model.Model.ObjectState; +import com.l2jserver.model.Model.ObjectDesire; import com.l2jserver.model.id.ID; import com.l2jserver.model.id.object.allocator.IDAllocator; +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.model.world.NPC; +import com.l2jserver.model.world.Pet; import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.ServiceStartException; @@ -51,8 +59,11 @@ import com.l2jserver.service.cache.Cache; import com.l2jserver.service.cache.CacheService; import com.l2jserver.service.configuration.ConfigurationService; import com.l2jserver.service.core.LoggingService; +import com.l2jserver.service.core.threading.ScheduledAsyncFuture; +import com.l2jserver.service.core.threading.ThreadService; import com.l2jserver.service.game.template.TemplateService; import com.l2jserver.util.ArrayIterator; +import com.l2jserver.util.ClassUtils; import com.l2jserver.util.factory.CollectionFactory; /** @@ -61,7 +72,7 @@ import com.l2jserver.util.factory.CollectionFactory; * @author Rogiel */ @Depends({ LoggingService.class, CacheService.class, - ConfigurationService.class, TemplateService.class }) + ConfigurationService.class, TemplateService.class, ThreadService.class }) public class JDBCDatabaseService extends AbstractService implements DatabaseService { /** @@ -71,13 +82,22 @@ public class JDBCDatabaseService extends AbstractService implements /** * The logger */ - private final Logger logger = LoggerFactory + private final Logger log = LoggerFactory .getLogger(JDBCDatabaseService.class); + /** + * The Google Guice {@link Injector}. It is used to get DAO instances. + */ + private final Injector injector; + /** * The cache service */ private final CacheService cacheService; + /** + * The thread service + */ + private final ThreadService threadService; /** * The database connection pool @@ -100,13 +120,21 @@ public class JDBCDatabaseService extends AbstractService implements /** * An cache object */ - private Cache objectCache; + private Cache> objectCache; + /** + * Future for the auto-save task. Each object that has changed is auto saved + * every 1 minute. + */ + private ScheduledAsyncFuture autoSaveFuture; @Inject public JDBCDatabaseService(ConfigurationService configService, - CacheService cacheService) { + Injector injector, CacheService cacheService, + ThreadService threadService) { config = configService.get(JDBCDatabaseConfiguration.class); + this.injector = injector; this.cacheService = cacheService; + this.threadService = threadService; } @Override @@ -130,29 +158,45 @@ public class JDBCDatabaseService extends AbstractService implements // duplication... this would endanger non-persistent states objectCache = cacheService.createEternalCache("database-service", IDAllocator.ALLOCABLE_IDS); + + // start the auto save task + autoSaveFuture = threadService.async(60, TimeUnit.SECONDS, 60, + new Runnable() { + @Override + public void run() { + log.debug("Auto save task started"); + int objects = 0; + for (final Model object : objectCache) { + @SuppressWarnings("unchecked") + final DataAccessObject, ?> dao = getDAO(object + .getClass()); + if (dao.save(object)) { + objects++; + } + } + log.info( + "{} objects have been saved by the auto save task", + objects); + } + }); } @Override - public void install() { - Collection files = FileUtils.listFiles(new File("dist/sql/h2"), - new String[] { "sql" }, false); - try { - final Connection conn = dataSource.getConnection(); - try { - for (final File file : files) { - conn.createStatement().execute( - FileUtils.readFileToString(file)); - } - } finally { - conn.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - return; - } catch (IOException e) { - e.printStackTrace(); - return; + @SuppressWarnings({ "unchecked", "rawtypes" }) + public , I extends ID> DataAccessObject getDAO( + Class model) { + if (ClassUtils.isSubclass(model, L2Character.class)) { + return (DataAccessObject) injector.getInstance(CharacterDAO.class); + } else if (ClassUtils.isSubclass(model, Clan.class)) { + return (DataAccessObject) injector.getInstance(ClanDAO.class); + } else if (ClassUtils.isSubclass(model, Item.class)) { + return (DataAccessObject) injector.getInstance(ItemDAO.class); + } else if (ClassUtils.isSubclass(model, NPC.class)) { + return (DataAccessObject) injector.getInstance(NPCDAO.class); + } else if (ClassUtils.isSubclass(model, Pet.class)) { + return (DataAccessObject) injector.getInstance(PetDAO.class); } + return null; } /** @@ -171,13 +215,13 @@ public class JDBCDatabaseService extends AbstractService implements try { return query.query(conn); } catch (SQLException e) { - logger.error("Error executing query", e); + log.error("Error executing query", e); return null; } finally { conn.close(); } } catch (SQLException e) { - logger.error("Could not open database connection", e); + log.error("Could not open database connection", e); return null; } } @@ -192,7 +236,7 @@ public class JDBCDatabaseService extends AbstractService implements return objectCache.contains(id); } - public void updateCache(Object key, Object value) { + public void updateCache(ID key, Model value) { Preconditions.checkNotNull(key, "key"); Preconditions.checkNotNull(value, "value"); objectCache.put(key, value); @@ -205,6 +249,8 @@ public class JDBCDatabaseService extends AbstractService implements @Override protected void doStop() throws ServiceStopException { + autoSaveFuture.cancel(true); + autoSaveFuture = null; cacheService.dispose(objectCache); objectCache = null; @@ -212,7 +258,7 @@ public class JDBCDatabaseService extends AbstractService implements if (connectionPool != null) connectionPool.close(); } catch (Exception e) { - logger.error("Error stopping database service", e); + log.error("Error stopping database service", e); throw new ServiceStopException(e); } finally { connectionPool = null; @@ -289,9 +335,9 @@ public class JDBCDatabaseService extends AbstractService implements this.parametize(st, object); rows += st.executeUpdate(); - // update object state + // update object desire --it has been realized if (object instanceof Model) - ((Model) object).setObjectState(ObjectState.STORED); + ((Model) object).setObjectDesire(ObjectDesire.NONE); final Mapper mapper = keyMapper(object); if (mapper == null) @@ -358,7 +404,7 @@ public class JDBCDatabaseService extends AbstractService implements if (obj == null) continue; if (obj instanceof Model) - ((Model) obj).setObjectState(ObjectState.STORED); + ((Model) obj).setObjectDesire(ObjectDesire.NONE); list.add(obj); } return list; @@ -415,7 +461,7 @@ public class JDBCDatabaseService extends AbstractService implements while (rs.next()) { final T object = mapper().map(rs); if (object instanceof Model) - ((Model) object).setObjectState(ObjectState.STORED); + ((Model) object).setObjectDesire(ObjectDesire.NONE); return object; } return null; diff --git a/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java b/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java index ba707087b..19f08fcdf 100644 --- a/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java @@ -25,6 +25,7 @@ import com.l2jserver.game.net.packet.server.SM_CHAR_INFO; import com.l2jserver.game.net.packet.server.SM_CHAR_INFO_EXTRA; import com.l2jserver.game.net.packet.server.SM_CHAR_INVENTORY; import com.l2jserver.game.net.packet.server.SM_CHAT; +import com.l2jserver.game.net.packet.server.SM_ITEM_GROUND; import com.l2jserver.game.net.packet.server.SM_MOVE; import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE; import com.l2jserver.game.net.packet.server.SM_TARGET; @@ -204,6 +205,8 @@ public class CharacterServiceImpl extends AbstractService implements // start broadcasting -- will broadcast all nearby objects broadcastService.broadcast(conn); + + conn.write(new SM_ITEM_GROUND()); // characters start in run mode try {