SHOW:
|
|
- or go back to the newest paste.
1 | ### Eclipse Workspace Patch 1.0 | |
2 | #P aCis_gameserver | |
3 | diff --git config/players.properties | |
4 | +++ config/players.properties | |
5 | @@ -255,7 +255,46 @@ | |
6 | #============================================================= | |
7 | ||
8 | # Maximum number of buffs. Remember that Divine Inspiration will give 4 additional buff slots on top of the number specified. Default: 20 | |
9 | MaxBuffsAmount = 20 | |
10 | ||
11 | # Store buffs/debuffs on user logout. Default: True | |
12 | StoreSkillCooltime = True | |
13 | ||
14 | +# ================================================================= | |
15 | +# Offline trade/craft | |
16 | +# ================================================================= | |
17 | + | |
18 | +# Option to enable or disable offline trade feature. | |
19 | +# Enable -> true, Disable -> false | |
20 | +OfflineTradeEnable = True | |
21 | + | |
22 | +# Option to enable or disable offline craft feature. | |
23 | +# Enable -> true, Disable -> false | |
24 | +OfflineCraftEnable = True | |
25 | + | |
26 | +# If set to True, off-line shops will be possible only in peace zones. | |
27 | +# Default: False | |
28 | +OfflineModeInPeaceZone = True | |
29 | + | |
30 | +# If set to True, players in off-line shop mode will not take any damage, thus they cannot be killed. | |
31 | +# Default: False | |
32 | +OfflineModeNoDamage = False | |
33 | + | |
34 | +# Restore offline traders/crafters after restart/shutdown. | |
35 | +# Default: False | |
36 | +RestoreOffliners = True | |
37 | + | |
38 | +# Do not restore offline characters, after OfflineMaxDays days spent from first restore. | |
39 | +# Require server restart to disconnect expired shops. | |
40 | +# 0 = disabled (always restore). | |
41 | +# Default: 7 | |
42 | +OfflineMaxDays = 7 | |
43 | + | |
44 | +# Disconnect shop after finished selling, buying. | |
45 | +# Default: True | |
46 | +OfflineDisconnectFinished = True | |
47 | + | |
48 | +#Offline Effect Sleep | |
49 | +OfflineSetSleepEffect = True | |
50 | + | |
51 | + | |
52 | diff --git java/net/sf/l2j/Config.java | |
53 | +++ java/net/sf/l2j/Config.java | |
54 | @@ -341,12 +341,23 @@ | |
55 | public static int MAX_PVTSTORE_SLOTS_DWARF; | |
56 | public static int MAX_PVTSTORE_SLOTS_OTHER; | |
57 | public static boolean DEEPBLUE_DROP_RULES; | |
58 | public static boolean ALLOW_DELEVEL; | |
59 | public static int DEATH_PENALTY_CHANCE; | |
60 | ||
61 | + /** Offline Shop */ | |
62 | + public static boolean OFFLINE_TRADE_ENABLE; | |
63 | + public static boolean OFFLINE_CRAFT_ENABLE; | |
64 | + public static boolean OFFLINE_MODE_IN_PEACE_ZONE; | |
65 | + public static boolean OFFLINE_MODE_NO_DAMAGE; | |
66 | + public static boolean RESTORE_OFFLINERS; | |
67 | + public static int OFFLINE_MAX_DAYS; | |
68 | + public static boolean OFFLINE_DISCONNECT_FINISHED; | |
69 | + public static boolean OFFLINE_SET_SLEEP; | |
70 | + | |
71 | /** Inventory & WH */ | |
72 | public static int INVENTORY_MAXIMUM_NO_DWARF; | |
73 | public static int INVENTORY_MAXIMUM_DWARF; | |
74 | public static int INVENTORY_MAXIMUM_PET; | |
75 | public static int MAX_ITEM_IN_PACKET; | |
76 | public static double WEIGHT_LIMIT; | |
77 | @@ -970,12 +981,21 @@ | |
78 | MAX_PVTSTORE_SLOTS_DWARF = players.getProperty("MaxPvtStoreSlotsDwarf", 5); | |
79 | MAX_PVTSTORE_SLOTS_OTHER = players.getProperty("MaxPvtStoreSlotsOther", 4); | |
80 | DEEPBLUE_DROP_RULES = players.getProperty("UseDeepBlueDropRules", true); | |
81 | ALLOW_DELEVEL = players.getProperty("AllowDelevel", true); | |
82 | DEATH_PENALTY_CHANCE = players.getProperty("DeathPenaltyChance", 20); | |
83 | ||
84 | + OFFLINE_TRADE_ENABLE = players.getProperty("OfflineTradeEnable", false); | |
85 | + OFFLINE_CRAFT_ENABLE = players.getProperty("OfflineCraftEnable", false); | |
86 | + OFFLINE_MODE_IN_PEACE_ZONE = players.getProperty("OfflineModeInPeaceZone", false); | |
87 | + OFFLINE_MODE_NO_DAMAGE = players.getProperty("OfflineModeNoDamage", false); | |
88 | + OFFLINE_SET_SLEEP = players.getProperty("OfflineSetSleepEffect", false); | |
89 | + RESTORE_OFFLINERS = players.getProperty("RestoreOffliners", false); | |
90 | + OFFLINE_MAX_DAYS = players.getProperty("OfflineMaxDays", 10); | |
91 | + OFFLINE_DISCONNECT_FINISHED = players.getProperty("OfflineDisconnectFinished", true); | |
92 | ||
93 | INVENTORY_MAXIMUM_NO_DWARF = players.getProperty("MaximumSlotsForNoDwarf", 80); | |
94 | INVENTORY_MAXIMUM_DWARF = players.getProperty("MaximumSlotsForDwarf", 100); | |
95 | INVENTORY_MAXIMUM_PET = players.getProperty("MaximumSlotsForPet", 12); | |
96 | MAX_ITEM_IN_PACKET = Math.max(INVENTORY_MAXIMUM_NO_DWARF, INVENTORY_MAXIMUM_DWARF); | |
97 | WEIGHT_LIMIT = players.getProperty("WeightLimit", 1.); | |
98 | WAREHOUSE_SLOTS_NO_DWARF = players.getProperty("MaximumWarehouseSlotsForNoDwarf", 100); | |
99 | diff --git java/net/sf/l2j/gameserver/GameServer.java | |
100 | +++ java/net/sf/l2j/gameserver/GameServer.java | |
101 | @@ -70,12 +70,13 @@ | |
102 | import net.sf.l2j.gameserver.data.xml.SoulCrystalData; | |
103 | import net.sf.l2j.gameserver.data.xml.SpellbookData; | |
104 | import net.sf.l2j.gameserver.data.xml.StaticObjectData; | |
105 | import net.sf.l2j.gameserver.data.xml.SummonItemData; | |
106 | import net.sf.l2j.gameserver.data.xml.TeleportData; | |
107 | import net.sf.l2j.gameserver.data.xml.WalkerRouteData; | |
108 | +import net.sf.l2j.gameserver.enums.actors.OfflineStoresData; | |
109 | import net.sf.l2j.gameserver.geoengine.GeoEngine; | |
110 | import net.sf.l2j.gameserver.handler.AdminCommandHandler; | |
111 | import net.sf.l2j.gameserver.handler.ChatHandler; | |
112 | import net.sf.l2j.gameserver.handler.ItemHandler; | |
113 | import net.sf.l2j.gameserver.handler.SkillHandler; | |
114 | import net.sf.l2j.gameserver.handler.TargetHandler; | |
115 | @@ -235,12 +236,23 @@ | |
116 | TeleportData.getInstance(); | |
117 | ||
118 | StringUtil.printSection("Olympiads & Heroes"); | |
119 | OlympiadGameManager.getInstance(); | |
120 | Olympiad.getInstance(); | |
121 | HeroManager.getInstance(); | |
122 | ||
123 | + StringUtil.printSection("OfflineShop Started"); | |
124 | + if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) | |
125 | + { | |
126 | + OfflineStoresData.getInstance().restoreOfflineTraders(); | |
127 | + } | |
128 | + else | |
129 | + { | |
130 | + LOGGER.info("Offline Shop is disabled."); | |
131 | + } | |
132 | ||
133 | StringUtil.printSection("Four Sepulchers"); | |
134 | FourSepulchersManager.getInstance(); | |
135 | ||
136 | StringUtil.printSection("Quests & Scripts"); | |
137 | ScriptData.getInstance(); | |
138 | diff --git java/net/sf/l2j/gameserver/LoginServerThread.java | |
139 | +++ java/net/sf/l2j/gameserver/LoginServerThread.java | |
140 | @@ -292,12 +292,14 @@ | |
141 | } | |
142 | } | |
143 | ||
144 | public void addClient(String account, GameClient client) | |
145 | { | |
146 | final GameClient existingClient = _clients.putIfAbsent(account, client); | |
147 | + if (client.isDetached()) | |
148 | + return; | |
149 | if (existingClient == null) | |
150 | { | |
151 | try | |
152 | { | |
153 | sendPacket(new PlayerAuthRequest(client.getAccountName(), client.getSessionId())); | |
154 | } | |
155 | diff --git java/net/sf/l2j/gameserver/Shutdown.java | |
156 | +++ java/net/sf/l2j/gameserver/Shutdown.java | |
157 | @@ -15,12 +15,13 @@ | |
158 | import net.sf.l2j.gameserver.data.manager.GrandBossManager; | |
159 | import net.sf.l2j.gameserver.data.manager.HeroManager; | |
160 | import net.sf.l2j.gameserver.data.manager.PetitionManager; | |
161 | import net.sf.l2j.gameserver.data.manager.RaidBossManager; | |
162 | import net.sf.l2j.gameserver.data.manager.SevenSignsManager; | |
163 | import net.sf.l2j.gameserver.data.manager.ZoneManager; | |
164 | +import net.sf.l2j.gameserver.enums.actors.OfflineStoresData; | |
165 | import net.sf.l2j.gameserver.model.World; | |
166 | import net.sf.l2j.gameserver.model.actor.Player; | |
167 | import net.sf.l2j.gameserver.model.olympiad.Olympiad; | |
168 | import net.sf.l2j.gameserver.network.GameClient; | |
169 | import net.sf.l2j.gameserver.network.SystemMessageId; | |
170 | import net.sf.l2j.gameserver.network.gameserverpackets.ServerStatus; | |
171 | @@ -74,13 +75,24 @@ | |
172 | @Override | |
173 | public void run() | |
174 | { | |
175 | if (this == SingletonHolder.INSTANCE) | |
176 | { | |
177 | StringUtil.printSection("Under " + MODE_TEXT[_shutdownMode] + " process"); | |
178 | ||
179 | + try | |
180 | + { | |
181 | + if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) | |
182 | + { | |
183 | + OfflineStoresData.getInstance().storeOffliners(); | |
184 | + LOGGER.info("Offline Traders Table: Offline shops stored."); | |
185 | + } | |
186 | + } | |
187 | + catch (Throwable t) | |
188 | + { | |
189 | + | |
190 | + } | |
191 | // disconnect players | |
192 | try | |
193 | { | |
194 | disconnectAllPlayers(); | |
195 | LOGGER.info("All players have been disconnected."); | |
196 | } | |
197 | diff --git java/net/sf/l2j/gameserver/enums/actors/OfflineStoresData.java | |
198 | +++ java/net/sf/l2j/gameserver/enums/actors/OfflineStoresData.java | |
199 | @@ -0,0 +1,274 @@ | |
200 | +package net.sf.l2j.gameserver.enums.actors; | |
201 | + | |
202 | +import java.sql.Connection; | |
203 | +import java.sql.PreparedStatement; | |
204 | +import java.sql.ResultSet; | |
205 | +import java.sql.Statement; | |
206 | +import java.util.Calendar; | |
207 | +import java.util.logging.Level; | |
208 | +import java.util.logging.Logger; | |
209 | + | |
210 | +import net.sf.l2j.commons.pool.ConnectionPool; | |
211 | + | |
212 | +import net.sf.l2j.Config; | |
213 | +import net.sf.l2j.gameserver.LoginServerThread; | |
214 | +import net.sf.l2j.gameserver.enums.ZoneId; | |
215 | +import net.sf.l2j.gameserver.model.World; | |
216 | +import net.sf.l2j.gameserver.model.actor.Player; | |
217 | +import net.sf.l2j.gameserver.model.craft.ManufactureItem; | |
218 | +import net.sf.l2j.gameserver.model.craft.ManufactureList; | |
219 | +import net.sf.l2j.gameserver.model.trade.TradeItem; | |
220 | +import net.sf.l2j.gameserver.network.GameClient; | |
221 | +import net.sf.l2j.gameserver.network.GameClient.GameClientState; | |
222 | + | |
223 | +public class OfflineStoresData | |
224 | +{ | |
225 | + private static final Logger LOGGER = Logger.getLogger(OfflineStoresData.class.getName()); | |
226 | + | |
227 | + // SQL DEFINITIONS | |
228 | + private static final String SAVE_OFFLINE_STATUS = "INSERT INTO character_offline_trade (`charId`,`time`,`type`,`title`) VALUES (?,?,?,?)"; | |
229 | + private static final String SAVE_ITEMS = "INSERT INTO character_offline_trade_items (`charId`,`item`,`count`,`price`,`enchant`) VALUES (?,?,?,?,?)"; | |
230 | + private static final String CLEAR_OFFLINE_TABLE = "DELETE FROM character_offline_trade"; | |
231 | + private static final String CLEAR_OFFLINE_TABLE_ITEMS = "DELETE FROM character_offline_trade_items"; | |
232 | + private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade"; | |
233 | + private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE charId = ?"; | |
234 | + | |
235 | + public void storeOffliners() | |
236 | + { | |
237 | + try (Connection con = ConnectionPool.getConnection(); PreparedStatement save_offline_status = con.prepareStatement(SAVE_OFFLINE_STATUS); PreparedStatement save_items = con.prepareStatement(SAVE_ITEMS)) | |
238 | + { | |
239 | + try (Statement stm = con.createStatement()) | |
240 | + { | |
241 | + stm.execute(CLEAR_OFFLINE_TABLE); | |
242 | + stm.execute(CLEAR_OFFLINE_TABLE_ITEMS); | |
243 | + } | |
244 | + for (Player pc : World.getInstance().getPlayers()) | |
245 | + { | |
246 | + try | |
247 | + { | |
248 | + if (pc.getOperateType() != OperateType.NONE && (pc.getClient() == null || pc.getClient().isDetached())) | |
249 | + { | |
250 | + save_offline_status.setInt(1, pc.getObjectId()); | |
251 | + save_offline_status.setLong(2, pc.getOfflineStartTime()); | |
252 | + save_offline_status.setInt(3, pc.getOperateType().getId()); | |
253 | + switch (pc.getOperateType()) | |
254 | + { | |
255 | + case BUY: | |
256 | + if (!Config.OFFLINE_TRADE_ENABLE) | |
257 | + continue; | |
258 | + | |
259 | + save_offline_status.setString(4, pc.getBuyList().getTitle()); | |
260 | + for (TradeItem i : pc.getBuyList()) | |
261 | + { | |
262 | + save_items.setInt(1, pc.getObjectId()); | |
263 | + save_items.setInt(2, i.getItem().getItemId()); | |
264 | + save_items.setLong(3, i.getCount()); | |
265 | + save_items.setLong(4, i.getPrice()); | |
266 | + save_items.setLong(5, i.getEnchant()); | |
267 | + save_items.addBatch(); | |
268 | + } | |
269 | + break; | |
270 | + case SELL: | |
271 | + case PACKAGE_SELL: | |
272 | + if (!Config.OFFLINE_TRADE_ENABLE) | |
273 | + continue; | |
274 | + | |
275 | + save_offline_status.setString(4, pc.getSellList().getTitle()); | |
276 | + pc.getSellList().updateItems(); | |
277 | + for (TradeItem i : pc.getSellList()) | |
278 | + { | |
279 | + save_items.setInt(1, pc.getObjectId()); | |
280 | + save_items.setInt(2, i.getObjectId()); | |
281 | + save_items.setLong(3, i.getCount()); | |
282 | + save_items.setLong(4, i.getPrice()); | |
283 | + save_items.setLong(5, i.getEnchant()); | |
284 | + save_items.addBatch(); | |
285 | + } | |
286 | + break; | |
287 | + case MANUFACTURE: | |
288 | + if (!Config.OFFLINE_CRAFT_ENABLE) | |
289 | + continue; | |
290 | + | |
291 | + save_offline_status.setString(4, pc.getManufactureList().getStoreName()); | |
292 | + for (final ManufactureItem i : pc.getManufactureList()) | |
293 | + { | |
294 | + save_items.setInt(1, pc.getObjectId()); | |
295 | + save_items.setInt(2, i.getId()); | |
296 | + save_items.setLong(3, 0L); | |
297 | + save_items.setLong(4, i.getValue()); | |
298 | + save_items.setLong(5, 0L); | |
299 | + save_items.addBatch(); | |
300 | + } | |
301 | + break; | |
302 | + } | |
303 | + save_items.executeBatch(); | |
304 | + save_offline_status.execute(); | |
305 | + } | |
306 | + } | |
307 | + catch (Exception e) | |
308 | + { | |
309 | + LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while saving offline trader: " + pc.getObjectId() + " " + e, e); | |
310 | + } | |
311 | + } | |
312 | + | |
313 | + LOGGER.info(getClass().getSimpleName() + ": Offline traders stored."); | |
314 | + } | |
315 | + catch (Exception e) | |
316 | + { | |
317 | + LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while saving offline traders: " + e, e); | |
318 | + } | |
319 | + } | |
320 | + | |
321 | + public void restoreOfflineTraders() | |
322 | + { | |
323 | + LOGGER.info(getClass().getSimpleName() + ": Loading offline traders..."); | |
324 | + try (Connection con = ConnectionPool.getConnection(); Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery(LOAD_OFFLINE_STATUS)) | |
325 | + { | |
326 | + int nTraders = 0; | |
327 | + while (rs.next()) | |
328 | + { | |
329 | + final long time = rs.getLong("time"); | |
330 | + if (Config.OFFLINE_MAX_DAYS > 0) | |
331 | + { | |
332 | + final Calendar cal = Calendar.getInstance(); | |
333 | + cal.setTimeInMillis(time); | |
334 | + cal.add(Calendar.DAY_OF_YEAR, Config.OFFLINE_MAX_DAYS); | |
335 | + if (cal.getTimeInMillis() <= System.currentTimeMillis()) | |
336 | + continue; | |
337 | + } | |
338 | + | |
339 | + OperateType type = null; | |
340 | + for (OperateType t : OperateType.values()) | |
341 | + { | |
342 | + if (t.getId() == rs.getInt("type")) | |
343 | + { | |
344 | + type = t; | |
345 | + break; | |
346 | + } | |
347 | + } | |
348 | + if (type == null) | |
349 | + { | |
350 | + LOGGER.warning(getClass().getSimpleName() + ": PrivateStoreType with id " + rs.getInt("type") + " could not be found."); | |
351 | + continue; | |
352 | + } | |
353 | + if (type == OperateType.NONE) | |
354 | + continue; | |
355 | + | |
356 | + final Player player = Player.restore(rs.getInt("charId")); | |
357 | + if (player == null) | |
358 | + continue; | |
359 | + | |
360 | + try (PreparedStatement stm_items = con.prepareStatement(LOAD_OFFLINE_ITEMS)) | |
361 | + { | |
362 | + player.isRunning(); | |
363 | + player.sitDown(); | |
364 | + player.setOnlineStatus(true, false); | |
365 | + | |
366 | + World.getInstance().addPlayer(player); | |
367 | + | |
368 | + final GameClient client = new GameClient(null); | |
369 | + client.setDetached(true); | |
370 | + player.setClient(client); | |
371 | + client.setPlayer(player); | |
372 | + client.setAccountName(player.getAccountNamePlayer()); | |
373 | + player.setOnlineStatus(true, true); | |
374 | + client.setState(GameClientState.IN_GAME); | |
375 | + player.setOfflineStartTime(time); | |
376 | + player.spawnMe(); | |
377 | + | |
378 | + LoginServerThread.getInstance().addClient(player.getAccountName(), client); | |
379 | + | |
380 | + stm_items.setInt(1, player.getObjectId()); | |
381 | + try (ResultSet items = stm_items.executeQuery()) | |
382 | + { | |
383 | + switch (type) | |
384 | + { | |
385 | + case BUY: | |
386 | + while (items.next()) | |
387 | + { | |
388 | + player.getBuyList().addItemByItemId(items.getInt(2), items.getInt(3), items.getInt(4), items.getInt(5)); | |
389 | + } | |
390 | + | |
391 | + player.getBuyList().setTitle(rs.getString("title")); | |
392 | + break; | |
393 | + case SELL: | |
394 | + case PACKAGE_SELL: | |
395 | + while (items.next()) | |
396 | + if (player.getSellList().addItem(items.getInt(2), items.getInt(3), items.getInt(4)) == null) | |
397 | + throw new NullPointerException("NPE at SELL of offlineShop " + player.getObjectId() + " " + items.getInt(2) + " " + items.getInt(3) + " " + items.getInt(4)); | |
398 | + | |
399 | + player.getSellList().setTitle(rs.getString("title")); | |
400 | + player.getSellList().setPackaged(type == OperateType.PACKAGE_SELL); | |
401 | + break; | |
402 | + case MANUFACTURE: | |
403 | + while (items.next()) | |
404 | + player.getManufactureList().add(new ManufactureItem(items.getInt(2), items.getInt(4))); | |
405 | + player.getManufactureList().setStoreName(rs.getString("title")); | |
406 | + break; | |
407 | + } | |
408 | + } | |
409 | + | |
410 | + if (Config.OFFLINE_SET_SLEEP) | |
411 | + player.startAbnormalEffect(0x000080); | |
412 | + | |
413 | + player.setOperateType(type); | |
414 | + player.restoreEffects(); | |
415 | + player.broadcastUserInfo(); | |
416 | + | |
417 | + nTraders++; | |
418 | + } | |
419 | + catch (Exception e) | |
420 | + { | |
421 | + LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading trader: " + player, e); | |
422 | + | |
423 | + player.deleteMe(); | |
424 | + } | |
425 | + } | |
426 | + | |
427 | + LOGGER.info(getClass().getSimpleName() + ": Loaded: " + nTraders + " offline trader(s)"); | |
428 | + | |
429 | + try (Statement stm1 = con.createStatement()) | |
430 | + { | |
431 | + stm1.execute(CLEAR_OFFLINE_TABLE); | |
432 | + stm1.execute(CLEAR_OFFLINE_TABLE_ITEMS); | |
433 | + } | |
434 | + } | |
435 | + catch (Exception e) | |
436 | + { | |
437 | + LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while loading offline traders: ", e); | |
438 | + } | |
439 | + } | |
440 | + | |
441 | + public static boolean offlineMode(Player player) | |
442 | + { | |
443 | + if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isInJail() || player.getBoat() != null) | |
444 | + return false; | |
445 | + | |
446 | + boolean canSetShop = false; | |
447 | + switch (player.getOperateType()) | |
448 | + { | |
449 | + case SELL: | |
450 | + case PACKAGE_SELL: | |
451 | + case BUY: | |
452 | + canSetShop = Config.OFFLINE_TRADE_ENABLE; | |
453 | + break; | |
454 | + case MANUFACTURE: | |
455 | + canSetShop = Config.OFFLINE_CRAFT_ENABLE; | |
456 | + break; | |
457 | + } | |
458 | + if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE)) | |
459 | + canSetShop = false; | |
460 | + | |
461 | + return canSetShop; | |
462 | + } | |
463 | + | |
464 | + public static OfflineStoresData getInstance() | |
465 | + { | |
466 | + return SingletonHolder._instance; | |
467 | + } | |
468 | + | |
469 | + private static class SingletonHolder | |
470 | + { | |
471 | + protected static final OfflineStoresData _instance = new OfflineStoresData(); | |
472 | + } | |
473 | +} | |
474 | \ No newline at end of file | |
475 | diff --git java/net/sf/l2j/gameserver/enums/actors/OperateType.java | |
476 | +++ java/net/sf/l2j/gameserver/enums/actors/OperateType.java | |
477 | @@ -15,12 +15,20 @@ | |
478 | private int _id; | |
479 | ||
480 | private OperateType(int id) | |
481 | { | |
482 | _id = id; | |
483 | } | |
484 | + public static OperateType findById(int id) | |
485 | + { | |
486 | + for (OperateType privateStoreType : values()) | |
487 | + { | |
488 | + if (privateStoreType.getId() == id) | |
489 | + return privateStoreType; | |
490 | + } | |
491 | + return null; | |
492 | + } | |
493 | public int getId() | |
494 | { | |
495 | return _id; | |
496 | } | |
497 | } | |
498 | \ No newline at end of file | |
499 | diff --git java/net/sf/l2j/gameserver/model/actor/Player.java | |
500 | +++ java/net/sf/l2j/gameserver/model/actor/Player.java | |
501 | @@ -2240,15 +2240,20 @@ | |
502 | { | |
503 | _client = client; | |
504 | } | |
505 | ||
506 | public String getAccountName() | |
507 | { | |
508 | + if (getClient() == null) | |
509 | + return getAccountNamePlayer(); | |
510 | return _accountName; | |
511 | } | |
512 | ||
513 | + public String getAccountNamePlayer() | |
514 | + { | |
515 | + return _accountName; | |
516 | + } | |
517 | public Map<Integer, String> getAccountChars() | |
518 | { | |
519 | return _chars; | |
520 | } | |
521 | ||
522 | /** | |
523 | @@ -3275,14 +3280,26 @@ | |
524 | * Set the {@link OperateType} of this {@link Player}. | |
525 | * @param type : The new {@link OperateType} state to set. | |
526 | */ | |
527 | public void setOperateType(OperateType type) | |
528 | { | |
529 | _operateType = type; | |
530 | + if (Config.OFFLINE_DISCONNECT_FINISHED && type == OperateType.NONE && (getClient() == null || getClient().isDetached())) | |
531 | + deleteMe(); | |
532 | } | |
533 | ||
534 | + private long _offlineShopStart; | |
535 | + public long getOfflineStartTime() | |
536 | + { | |
537 | + return _offlineShopStart; | |
538 | + } | |
539 | + public void setOfflineStartTime(long time) | |
540 | + { | |
541 | + _offlineShopStart = time; | |
542 | + } | |
543 | + | |
544 | /** | |
545 | * @return True if this {@link Player} is set on any store mode, or false otherwise. | |
546 | */ | |
547 | public boolean isInStoreMode() | |
548 | { | |
549 | return _operateType == OperateType.BUY || _operateType == OperateType.SELL || _operateType == OperateType.PACKAGE_SELL || _operateType == OperateType.MANUFACTURE; | |
550 | diff --git java/net/sf/l2j/gameserver/network/GameClient.java | |
551 | +++ java/net/sf/l2j/gameserver/network/GameClient.java | |
552 | @@ -19,15 +19,18 @@ | |
553 | ||
554 | import net.sf.l2j.Config; | |
555 | import net.sf.l2j.gameserver.LoginServerThread; | |
556 | import net.sf.l2j.gameserver.data.sql.ClanTable; | |
557 | import net.sf.l2j.gameserver.data.sql.PlayerInfoTable; | |
558 | import net.sf.l2j.gameserver.enums.FloodProtector; | |
559 | +import net.sf.l2j.gameserver.enums.MessageType; | |
560 | +import net.sf.l2j.gameserver.enums.ZoneId; | |
561 | import net.sf.l2j.gameserver.model.CharSelectSlot; | |
562 | import net.sf.l2j.gameserver.model.World; | |
563 | import net.sf.l2j.gameserver.model.actor.Player; | |
564 | +import net.sf.l2j.gameserver.model.olympiad.OlympiadManager; | |
565 | import net.sf.l2j.gameserver.model.pledge.Clan; | |
566 | import net.sf.l2j.gameserver.network.serverpackets.ActionFailed; | |
567 | import net.sf.l2j.gameserver.network.serverpackets.L2GameServerPacket; | |
568 | import net.sf.l2j.gameserver.network.serverpackets.ServerClose; | |
569 | ||
570 | /** | |
571 | @@ -206,22 +209,82 @@ | |
572 | ThreadPool.execute(() -> | |
573 | { | |
574 | boolean fast = true; | |
575 | if (getPlayer() != null && !isDetached()) | |
576 | { | |
577 | setDetached(true); | |
578 | + if (offlineMode(getPlayer())) | |
579 | + { | |
580 | + if (getPlayer().getParty() != null) | |
581 | + getPlayer().getParty().removePartyMember(getPlayer(), MessageType.EXPELLED); | |
582 | + OlympiadManager.getInstance().unRegisterNoble(getPlayer()); | |
583 | + | |
584 | + // If the Character has Pet, unsummon it | |
585 | + if (getPlayer().hasPet()) | |
586 | + { | |
587 | + getPlayer().getSummon().unSummon(getPlayer()); | |
588 | + // Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline) | |
589 | + if (getPlayer().getSummon() != null) | |
590 | + getPlayer().getSummon().updateAndBroadcastStatus(0); | |
591 | + } | |
592 | + | |
593 | + if (Config.OFFLINE_SET_SLEEP) | |
594 | + getPlayer().startAbnormalEffect(0x000080); | |
595 | + | |
596 | + if (getPlayer().getOfflineStartTime() == 0) | |
597 | + getPlayer().setOfflineStartTime(System.currentTimeMillis()); | |
598 | + | |
599 | + return; | |
600 | + } | |
601 | fast = !getPlayer().isInCombat() && !getPlayer().isLocked(); | |
602 | } | |
603 | cleanMe(fast); | |
604 | }); | |
605 | } | |
606 | catch (RejectedExecutionException e) | |
607 | { | |
608 | } | |
609 | } | |
610 | ||
611 | + /** | |
612 | + * @param player | |
613 | + * @return | |
614 | + */ | |
615 | + public static boolean offlineMode(Player player) | |
616 | + { | |
617 | + if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isInJail() || player.getBoat() != null) | |
618 | + return false; | |
619 | + | |
620 | + boolean canSetShop = false; | |
621 | + switch (player.getOperateType()) | |
622 | + { | |
623 | + case SELL: | |
624 | + case PACKAGE_SELL: | |
625 | + case BUY: | |
626 | + { | |
627 | + canSetShop = Config.OFFLINE_TRADE_ENABLE; | |
628 | + break; | |
629 | + } | |
630 | + case MANUFACTURE: | |
631 | + { | |
632 | + canSetShop = Config.OFFLINE_TRADE_ENABLE; | |
633 | + break; | |
634 | + } | |
635 | + default: | |
636 | + { | |
637 | + canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isCrafting(); | |
638 | + break; | |
639 | + } | |
640 | + } | |
641 | + | |
642 | + if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE)) | |
643 | + canSetShop = false; | |
644 | + | |
645 | + return canSetShop; | |
646 | + } | |
647 | + | |
648 | @Override | |
649 | protected void onForcedDisconnection() | |
650 | { | |
651 | LOGGER.debug("{} disconnected abnormally.", toString()); | |
652 | } | |
653 | ||
654 | @@ -578,12 +641,14 @@ | |
655 | { | |
656 | _slots = list; | |
657 | } | |
658 | ||
659 | public void close(L2GameServerPacket gsp) | |
660 | { | |
661 | + if (getConnection() == null) | |
662 | + return; | |
663 | getConnection().close(gsp); | |
664 | } | |
665 | ||
666 | /** | |
667 | * @param slot : The slot to test. | |
668 | * @return the objectId of the character associated to that slot, or -1 if not found. | |
669 |