diff --git a/java/net/sf/l2j/Config.java b/java/net/sf/l2j/Config.java
index 4b7181f..68f70b7 100644
--- a/java/net/sf/l2j/Config.java
+++ b/java/net/sf/l2j/Config.java
@@ -35,6 +35,7 @@
public static final String PLAYERS_FILE = "./config/players.properties";
public static final String SERVER_FILE = "./config/server.properties";
public static final String SIEGE_FILE = "./config/siege.properties";
+ public static final String OFFLINEMOD = "./config/CustomMods/OfflineShop.ini";
// --------------------------------------------------
// Clans settings
@@ -380,7 +381,15 @@
public static int ENCHANT_MAX_ARMOR;
public static int ENCHANT_SAFE_MAX;
public static int ENCHANT_SAFE_MAX_FULL;
-
+ /** Offline Shop */
+ public static boolean OFFLINE_TRADE_ENABLE;
+ public static boolean OFFLINE_CRAFT_ENABLE;
+ public static boolean OFFLINE_MODE_IN_PEACE_ZONE;
+ public static boolean OFFLINE_MODE_NO_DAMAGE;
+ public static boolean RESTORE_OFFLINERS;
+ public static int OFFLINE_MAX_DAYS;
+ public static boolean OFFLINE_DISCONNECT_FINISHED;
+ public static boolean OFFLINE_SET_SLEEP;
/** Augmentations */
public static int AUGMENTATION_NG_SKILL_CHANCE;
public static int AUGMENTATION_NG_GLOW_CHANCE;
@@ -1088,6 +1097,19 @@
STORE_SKILL_COOLTIME = players.getProperty("StoreSkillCooltime", true);
}
+ private static final void loadOff()
+ {
+ final ExProperties offlineshop = initProperties(Config.OFFLINEMOD);
+ OFFLINE_TRADE_ENABLE = offlineshop.getProperty("OfflineTradeEnable", false);
+ OFFLINE_CRAFT_ENABLE = offlineshop.getProperty("OfflineCraftEnable", false);
+ OFFLINE_MODE_IN_PEACE_ZONE = offlineshop.getProperty("OfflineModeInPeaceZone", false);
+ OFFLINE_MODE_NO_DAMAGE = offlineshop.getProperty("OfflineModeNoDamage", false);
+ OFFLINE_SET_SLEEP = offlineshop.getProperty("OfflineSetSleepEffect", false);
+ RESTORE_OFFLINERS = offlineshop.getProperty("RestoreOffliners", false);
+ OFFLINE_MAX_DAYS = offlineshop.getProperty("OfflineMaxDays", 10);
+ OFFLINE_DISCONNECT_FINISHED = offlineshop.getProperty("OfflineDisconnectFinished", true);
+
+ }
/**
* Loads siege settings.
*/
@@ -1307,6 +1329,9 @@
// siege settings
loadSieges();
+ // OffShop settings
+ loadOff();
+
// server settings
loadServer();
}
diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/GameServer.java
index 41a9f92..402a66a 100644
--- a/java/net/sf/l2j/gameserver/GameServer.java
+++ b/java/net/sf/l2j/gameserver/GameServer.java
@@ -71,6 +71,7 @@
import net.sf.l2j.gameserver.data.xml.SummonItemData;
import net.sf.l2j.gameserver.data.xml.TeleportLocationData;
import net.sf.l2j.gameserver.data.xml.WalkerRouteData;
+import net.sf.l2j.gameserver.enums.actors.OfflineStoresData;
import net.sf.l2j.gameserver.geoengine.GeoEngine;
import net.sf.l2j.gameserver.handler.AdminCommandHandler;
import net.sf.l2j.gameserver.handler.ChatHandler;
@@ -243,6 +244,10 @@
Olympiad.getInstance();
HeroManager.getInstance();
+ StringUtil.printSection("OfflineShop Started");
+ if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
+ OfflineStoresData.getInstance().restoreOfflineTraders();
+
StringUtil.printSection("Four Sepulchers");
FourSepulchersManager.getInstance();
diff --git a/java/net/sf/l2j/gameserver/LoginServerThread.java b/java/net/sf/l2j/gameserver/LoginServerThread.java
index 477d0af..0eb4fd2 100644
--- a/java/net/sf/l2j/gameserver/LoginServerThread.java
+++ b/java/net/sf/l2j/gameserver/LoginServerThread.java
@@ -295,6 +295,8 @@
public void addClient(String account, GameClient client)
{
final GameClient existingClient = _clients.putIfAbsent(account, client);
+ if (client.isDetached())
+ return;
if (existingClient == null)
{
try
diff --git a/java/net/sf/l2j/gameserver/Shutdown.java b/java/net/sf/l2j/gameserver/Shutdown.java
index 88a3dc4..f90b31e 100644
--- a/java/net/sf/l2j/gameserver/Shutdown.java
+++ b/java/net/sf/l2j/gameserver/Shutdown.java
@@ -18,6 +18,7 @@
import net.sf.l2j.gameserver.data.manager.SevenSignsManager;
import net.sf.l2j.gameserver.data.manager.ZoneManager;
import net.sf.l2j.gameserver.data.sql.ServerMemoTable;
+import net.sf.l2j.gameserver.enums.actors.OfflineStoresData;
import net.sf.l2j.gameserver.model.World;
import net.sf.l2j.gameserver.model.actor.Player;
import net.sf.l2j.gameserver.model.olympiad.Olympiad;
@@ -77,7 +78,18 @@
if (this == SingletonHolder.INSTANCE)
{
StringUtil.printSection("Under " + MODE_TEXT[_shutdownMode] + " process");
-
+ try
+ {
+ if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
+ {
+ OfflineStoresData.getInstance().storeOffliners();
+ LOGGER.info("Offline Traders Table: Offline shops stored.");
+ }
+ }
+ catch (Throwable t)
+ {
+
+ }
// disconnect players
try
{
diff --git a/java/net/sf/l2j/gameserver/enums/actors/OfflineStoresData.java b/java/net/sf/l2j/gameserver/enums/actors/OfflineStoresData.java
new file mode 100644
index 0000000..47a48b3
--- /dev/null
+++ b/java/net/sf/l2j/gameserver/enums/actors/OfflineStoresData.java
@@ -0,0 +1,276 @@
+package net.sf.l2j.gameserver.enums.actors;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Calendar;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+import net.sf.l2j.Config;
+import net.sf.l2j.L2DatabaseFactory;
+import net.sf.l2j.gameserver.LoginServerThread;
+import net.sf.l2j.gameserver.enums.ZoneId;
+import net.sf.l2j.gameserver.model.World;
+import net.sf.l2j.gameserver.model.actor.Player;
+import net.sf.l2j.gameserver.model.craft.ManufactureItem;
+import net.sf.l2j.gameserver.model.craft.ManufactureList;
+import net.sf.l2j.gameserver.model.tradelist.TradeItem;
+import net.sf.l2j.gameserver.network.GameClient;
+import net.sf.l2j.gameserver.network.GameClient.GameClientState;
+
+public class OfflineStoresData
+{
+ private static final Logger LOGGER = Logger.getLogger(OfflineStoresData.class.getName());
+
+ // SQL DEFINITIONS
+ private static final String SAVE_OFFLINE_STATUS = "INSERT INTO character_offline_trade (`charId`,`time`,`type`,`title`) VALUES (?,?,?,?)";
+ private static final String SAVE_ITEMS = "INSERT INTO character_offline_trade_items (`charId`,`item`,`count`,`price`,`enchant`) VALUES (?,?,?,?,?)";
+ private static final String CLEAR_OFFLINE_TABLE = "DELETE FROM character_offline_trade";
+ private static final String CLEAR_OFFLINE_TABLE_ITEMS = "DELETE FROM character_offline_trade_items";
+ private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
+ private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE charId = ?";
+
+ public void storeOffliners()
+ {
+ try (Connection con = L2DatabaseFactory.getInstance().getConnection(); PreparedStatement save_offline_status = con.prepareStatement(SAVE_OFFLINE_STATUS); PreparedStatement save_items = con.prepareStatement(SAVE_ITEMS))
+ {
+ try (Statement stm = con.createStatement())
+ {
+ stm.execute(CLEAR_OFFLINE_TABLE);
+ stm.execute(CLEAR_OFFLINE_TABLE_ITEMS);
+ }
+ for (Player pc : World.getInstance().getPlayers())
+ {
+ try
+ {
+ if (pc.getStoreType() != StoreType.NONE && (pc.getClient() == null || pc.getClient().isDetached()))
+ {
+ save_offline_status.setInt(1, pc.getObjectId());
+ save_offline_status.setLong(2, pc.getOfflineStartTime());
+ save_offline_status.setInt(3, pc.getStoreType().getId());
+ switch (pc.getStoreType())
+ {
+ case BUY:
+ if (!Config.OFFLINE_TRADE_ENABLE)
+ continue;
+
+ save_offline_status.setString(4, pc.getBuyList().getTitle());
+ for (TradeItem i : pc.getBuyList().getItems())
+ {
+ save_items.setInt(1, pc.getObjectId());
+ save_items.setInt(2, i.getItem().getItemId());
+ save_items.setLong(3, i.getCount());
+ save_items.setLong(4, i.getPrice());
+ save_items.setLong(5, i.getEnchant());
+ save_items.addBatch();
+ }
+ break;
+ case SELL:
+ case PACKAGE_SELL:
+ if (!Config.OFFLINE_TRADE_ENABLE)
+ continue;
+
+ save_offline_status.setString(4, pc.getSellList().getTitle());
+ pc.getSellList().updateItems();
+ for (TradeItem i : pc.getSellList().getItems())
+ {
+ save_items.setInt(1, pc.getObjectId());
+ save_items.setInt(2, i.getObjectId());
+ save_items.setLong(3, i.getCount());
+ save_items.setLong(4, i.getPrice());
+ save_items.setLong(5, i.getEnchant());
+ save_items.addBatch();
+ }
+ break;
+ case MANUFACTURE:
+ if (!Config.OFFLINE_CRAFT_ENABLE)
+ continue;
+
+ save_offline_status.setString(4, pc.getCreateList().getStoreName());
+ for (ManufactureItem i : pc.getCreateList().getList())
+ {
+ save_items.setInt(1, pc.getObjectId());
+ save_items.setInt(2, i.getId());
+ save_items.setLong(3, 0L);
+ save_items.setLong(4, i.getValue());
+ save_items.setLong(5, 0L);
+ save_items.addBatch();
+ }
+ break;
+ }
+ save_items.executeBatch();
+ save_offline_status.execute();
+ }
+ }
+ catch (Exception e)
+ {
+ LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while saving offline trader: " + pc.getObjectId() + " " + e, e);
+ }
+ }
+
+ LOGGER.info(getClass().getSimpleName() + ": Offline traders stored.");
+ }
+ catch (Exception e)
+ {
+ LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while saving offline traders: " + e, e);
+ }
+ }
+
+ public void restoreOfflineTraders()
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Loading offline traders...");
+ try (Connection con = L2DatabaseFactory.getInstance().getConnection(); Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery(LOAD_OFFLINE_STATUS))
+ {
+ int nTraders = 0;
+ while (rs.next())
+ {
+ final long time = rs.getLong("time");
+ if (Config.OFFLINE_MAX_DAYS > 0)
+ {
+ final Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(time);
+ cal.add(Calendar.DAY_OF_YEAR, Config.OFFLINE_MAX_DAYS);
+ if (cal.getTimeInMillis() <= System.currentTimeMillis())
+ continue;
+ }
+
+ StoreType type = null;
+ for (StoreType t : StoreType.values())
+ {
+ if (t.getId() == rs.getInt("type"))
+ {
+ type = t;
+ break;
+ }
+ }
+ if (type == null)
+ {
+ LOGGER.warning(getClass().getSimpleName() + ": PrivateStoreType with id " + rs.getInt("type") + " could not be found.");
+ continue;
+ }
+ if (type == StoreType.NONE)
+ continue;
+
+ final Player player = Player.restore(rs.getInt("charId"));
+ if (player == null)
+ continue;
+
+ try (PreparedStatement stm_items = con.prepareStatement(LOAD_OFFLINE_ITEMS))
+ {
+ player.isRunning();
+ player.sitDown();
+ player.setOnlineStatus(true, false);
+
+ World.getInstance().addPlayer(player);
+
+ final GameClient client = new GameClient(null);
+ client.setDetached(true);
+ player.setClient(client);
+ client.setPlayer(player);
+ client.setAccountName(player.getAccountNamePlayer());
+ player.setOnlineStatus(true, true);
+ client.setState(GameClientState.IN_GAME);
+ player.setOfflineStartTime(time);
+ player.spawnMe();
+
+ LoginServerThread.getInstance().addClient(player.getAccountName(), client);
+
+ stm_items.setInt(1, player.getObjectId());
+ try (ResultSet items = stm_items.executeQuery())
+ {
+ switch (type)
+ {
+ case BUY:
+ while (items.next())
+ {
+ player.getBuyList().addItemByItemId(items.getInt(2), items.getInt(3), items.getInt(4));
+ }
+
+ player.getBuyList().setTitle(rs.getString("title"));
+ break;
+ case SELL:
+ case PACKAGE_SELL:
+ while (items.next())
+ if (player.getSellList().addItem(items.getInt(2), items.getInt(3), items.getInt(4)) == null)
+ throw new NullPointerException("NPE at SELL of offlineShop " + player.getObjectId() + " " + items.getInt(2) + " " + items.getInt(3) + " " + items.getInt(4));
+
+ player.getSellList().setTitle(rs.getString("title"));
+ player.getSellList().setPackaged(type == StoreType.PACKAGE_SELL);
+ break;
+ case MANUFACTURE:
+ final ManufactureList createList = new ManufactureList();
+ createList.setStoreName(rs.getString("title"));
+ while (items.next())
+ createList.add(new ManufactureItem(items.getInt(2), items.getInt(4)));
+ //player.setCreateList(createList);
+ break;
+ }
+ }
+
+ if (Config.OFFLINE_SET_SLEEP)
+ player.startAbnormalEffect(0x000080);
+
+ player.setStoreType(type);
+ player.restoreEffects();
+ player.broadcastUserInfo();
+
+ nTraders++;
+ }
+ catch (Exception e)
+ {
+ LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading trader: " + player, e);
+
+ player.deleteMe();
+ }
+ }
+
+ LOGGER.info(getClass().getSimpleName() + ": Loaded: " + nTraders + " offline trader(s)");
+
+ try (Statement stm1 = con.createStatement())
+ {
+ stm1.execute(CLEAR_OFFLINE_TABLE);
+ stm1.execute(CLEAR_OFFLINE_TABLE_ITEMS);
+ }
+ }
+ catch (Exception e)
+ {
+ LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while loading offline traders: ", e);
+ }
+ }
+
+ public static boolean offlineMode(Player player)
+ {
+ if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isInJail() || player.getBoat() != null)
+ return false;
+
+ boolean canSetShop = false;
+ switch (player.getStoreType())
+ {
+ case SELL:
+ case PACKAGE_SELL:
+ case BUY:
+ canSetShop = Config.OFFLINE_TRADE_ENABLE;
+ break;
+ case MANUFACTURE:
+ canSetShop = Config.OFFLINE_CRAFT_ENABLE;
+ break;
+ }
+ if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
+ canSetShop = false;
+
+ return canSetShop;
+ }
+
+ public static OfflineStoresData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final OfflineStoresData _instance = new OfflineStoresData();
+ }
+}
\ No newline at end of file
diff --git a/java/net/sf/l2j/gameserver/enums/actors/StoreType.java b/java/net/sf/l2j/gameserver/enums/actors/StoreType.java
index b7da1c6..dca591f 100644
--- a/java/net/sf/l2j/gameserver/enums/actors/StoreType.java
+++ b/java/net/sf/l2j/gameserver/enums/actors/StoreType.java
@@ -21,4 +21,13 @@
{
return _id;
}
+ public static StoreType findById(int id)
+ {
+ for (StoreType privateStoreType : values())
+ {
+ if (privateStoreType.getId() == id)
+ return privateStoreType;
+ }
+ return null;
+ }
}
\ No newline at end of file
diff --git a/java/net/sf/l2j/gameserver/model/actor/Player.java b/java/net/sf/l2j/gameserver/model/actor/Player.java
index 9436ef0..dad3cc4 100644
--- a/java/net/sf/l2j/gameserver/model/actor/Player.java
+++ b/java/net/sf/l2j/gameserver/model/actor/Player.java
@@ -2607,9 +2607,14 @@
public String getAccountName()
{
+ if (getClient() == null)
+ return getAccountNamePlayer();
return _accountName;
}
-
+ public String getAccountNamePlayer()
+ {
+ return _accountName;
+ }
public Map<Integer, String> getAccountChars()
{
return _chars;
@@ -4113,6 +4118,8 @@
public void setStoreType(StoreType type)
{
_storeType = type;
+ if (Config.OFFLINE_DISCONNECT_FINISHED && type == StoreType.NONE && (getClient() == null || getClient().isDetached()))
+ deleteMe();
}
/**
@@ -4122,7 +4129,16 @@
{
return _storeType;
}
+ private long _offlineShopStart;
+ public long getOfflineStartTime()
+ {
+ return _offlineShopStart;
+ }
+ public void setOfflineStartTime(long time)
+ {
+ _offlineShopStart = time;
+ }
/**
* @return true if the {@link Player} can use dwarven recipes.
*/
diff --git a/java/net/sf/l2j/gameserver/network/GameClient.java b/java/net/sf/l2j/gameserver/network/GameClient.java
index 5218e60..823728e 100644
--- a/java/net/sf/l2j/gameserver/network/GameClient.java
+++ b/java/net/sf/l2j/gameserver/network/GameClient.java
@@ -21,9 +21,12 @@
import net.sf.l2j.gameserver.LoginServerThread;
import net.sf.l2j.gameserver.data.sql.ClanTable;
import net.sf.l2j.gameserver.data.sql.PlayerInfoTable;
+import net.sf.l2j.gameserver.enums.MessageType;
+import net.sf.l2j.gameserver.enums.ZoneId;
import net.sf.l2j.gameserver.model.CharSelectSlot;
import net.sf.l2j.gameserver.model.World;
import net.sf.l2j.gameserver.model.actor.Player;
+import net.sf.l2j.gameserver.model.olympiad.OlympiadManager;
import net.sf.l2j.gameserver.model.pledge.Clan;
import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
import net.sf.l2j.gameserver.network.serverpackets.L2GameServerPacket;
@@ -208,6 +211,29 @@
if (getPlayer() != null && !isDetached())
{
setDetached(true);
+ if (offlineMode(getPlayer()))
+ {
+ if (getPlayer().getParty() != null)
+ getPlayer().getParty().removePartyMember(getPlayer(), MessageType.EXPELLED);
+ OlympiadManager.getInstance().unRegisterNoble(getPlayer());
+
+ // If the Character has Pet, unsummon it
+ if (getPlayer().hasPet())
+ {
+ getPlayer().getSummon().unSummon(getPlayer());
+ // Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
+ if (getPlayer().getSummon() != null)
+ getPlayer().getSummon().updateAndBroadcastStatus(0);
+ }
+
+ if (Config.OFFLINE_SET_SLEEP)
+ getPlayer().startAbnormalEffect(0x000080);
+
+ if (getPlayer().getOfflineStartTime() == 0)
+ getPlayer().setOfflineStartTime(System.currentTimeMillis());
+
+ return;
+ }
fast = !getPlayer().isInCombat() && !getPlayer().isLocked();
}
cleanMe(fast);
@@ -218,6 +244,44 @@
}
}
+ /**
+ * @param player the player to be check.
+ * @return {@code true} if the player is allowed to remain as off-line shop.
+ */
+ public static boolean offlineMode(Player player)
+ {
+ if (player.isInOlympiadMode() || player.isFestivalParticipant() || player.isInJail() || player.getBoat() != null)
+ return false;
+
+ boolean canSetShop = false;
+ switch (player.getStoreType())
+ {
+ case SELL:
+ case PACKAGE_SELL:
+ case BUY:
+ {
+ canSetShop = Config.OFFLINE_TRADE_ENABLE;
+ break;
+ }
+ case MANUFACTURE:
+ {
+ canSetShop = Config.OFFLINE_TRADE_ENABLE;
+ break;
+ }
+ default:
+ {
+ canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isCrafting();
+ break;
+ }
+ }
+
+ if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
+ canSetShop = false;
+
+ return canSetShop;
+ }
+
+
@Override
protected void onForcedDisconnection()
{
@@ -580,6 +644,8 @@
public void close(L2GameServerPacket gsp)
{
+ if (getConnection() == null)
+ return;
getConnection().close(gsp);
}
Criar Tabela SQL
+character_offline_trade_items
+CREATE TABLE IF NOT EXISTS `character_offline_trade_items` (
+ `charId` int(10) NOT NULL DEFAULT 0,
+ `item` int(10) NOT NULL DEFAULT 0,
+ `count` int(20) NOT NULL DEFAULT 0,
+ `price` int(20) NOT NULL DEFAULT 0,
+ `enchant` int(20) NOT NULL DEFAULT 0
+);
+character_offline_trade
+CREATE TABLE IF NOT EXISTS `character_offline_trade` (
+ `charId` int(11) NOT NULL,
+ `time` bigint(20) unsigned NOT NULL DEFAULT 0,
+ `type` tinyint(4) NOT NULL DEFAULT 0,
+ `title` varchar(100) DEFAULT NULL,
+ PRIMARY KEY (`charId`)
+);
TOOLS
database_installer.bat
%mysqlPath% -h %gshost% -u %gsuser% --password=%gspass% -D %gsdb% < ../sql/character_memo.sql
+%mysqlPath% -h %gshost% -u %gsuser% --password=%gspass% -D %gsdb% < ../sql/character_offline_trade.sql
+%mysqlPath% -h %gshost% -u %gsuser% --password=%gspass% -D %gsdb% < ../sql/character_offline_trade_items.sql
%mysqlPath% -h %gshost% -u %gsuser% --password=%gspass% -D %gsdb% < ../sql/character_quests.sql
database_installer.sh
$MYG < ../sql/character_memo.sql &> /dev/null
+$MYG < ../sql/character_offline_trade.sql &> /dev/null
+$MYG < ../sql/character_offline_trade_items.sql &> /dev/null
$MYG < ../sql/character_quests.sql &> /dev/null
full_instal.sql
DROP TABLE IF EXISTS character_memo;
+DROP TABLE IF EXISTS character_offline_trade;
+DROP TABLE IF EXISTS character_offline_trade_items;
DROP TABLE IF EXISTS character_quests;
Index: DataPack
+# =================================================================
+# Offline trade/craft
+# =================================================================
+
+# Option to enable or disable offline trade feature.
+# Enable -> true, Disable -> false
+OfflineTradeEnable = True
+
+# Option to enable or disable offline craft feature.
+# Enable -> true, Disable -> false
+OfflineCraftEnable = True
+
+# If set to True, off-line shops will be possible only in peace zones.
+# Default: False
+OfflineModeInPeaceZone = True
+
+# If set to True, players in off-line shop mode will not take any damage, thus they cannot be killed.
+# Default: False
+OfflineModeNoDamage = False
+
+# Restore offline traders/crafters after restart/shutdown.
+# Default: False
+RestoreOffliners = True
+
+# Do not restore offline characters, after OfflineMaxDays days spent from first restore.
+# Require server restart to disconnect expired shops.
+# 0 = disabled (always restore).
+# Default: 7
+OfflineMaxDays = 7
+
+# Disconnect shop after finished selling, buying.
+# Default: True
+OfflineDisconnectFinished = True
+
+#Offline Effect Sleep
+OfflineSetSleepEffect = True