/**
* License
* THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
* CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE").
* THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.
* ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR
* COPYRIGHT LAW IS PROHIBITED.
*
* BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
* AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE
* MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
* HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
*
*/
package l1j.server.server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.logging.Logger;
import l1j.server.Config;
import l1j.server.L1Message;
import l1j.server.console.ConsoleProcess;
import l1j.server.server.datatables.CastleTable;
import l1j.server.server.datatables.CharacterTable;
import l1j.server.server.datatables.ChatLogTable;
import l1j.server.server.datatables.ClanTable;
import l1j.server.server.datatables.DoorTable;
import l1j.server.server.datatables.DropTable;
import l1j.server.server.datatables.DropItemTable;
import l1j.server.server.datatables.FurnitureItemTable;
import l1j.server.server.datatables.FurnitureSpawnTable;
import l1j.server.server.datatables.GetBackRestartTable;
import l1j.server.server.datatables.InnTable;
import l1j.server.server.datatables.IpTable;
import l1j.server.server.datatables.ItemTable;
import l1j.server.server.datatables.MagicDollTable;
import l1j.server.server.datatables.MailTable;
import l1j.server.server.datatables.MapsTable;
import l1j.server.server.datatables.MobGroupTable;
import l1j.server.server.datatables.NpcActionTable;
import l1j.server.server.datatables.NpcChatTable;
import l1j.server.server.datatables.NpcSpawnTable;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.datatables.NPCTalkDataTable;
import l1j.server.server.datatables.PetTable;
import l1j.server.server.datatables.PetTypeTable;
import l1j.server.server.datatables.PolyTable;
import l1j.server.server.datatables.RaceTicketTable;
import l1j.server.server.datatables.ResolventTable;
import l1j.server.server.datatables.ShopTable;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.datatables.SpawnTable;
import l1j.server.server.datatables.SprTable;
import l1j.server.server.datatables.UBSpawnTable;
import l1j.server.server.datatables.WeaponSkillTable;
import l1j.server.server.model.Dungeon;
import l1j.server.server.model.ElementalStoneGenerator;
import l1j.server.server.model.Getback;
import l1j.server.server.model.L1BossCycle;
import l1j.server.server.model.L1CastleLocation;
import l1j.server.server.model.L1DeleteItemOnGround;
import l1j.server.server.model.L1NpcRegenerationTimer;
import l1j.server.server.model.L1World;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.game.L1BugBearRace;
import l1j.server.server.model.gametime.L1GameTimeClock;
import l1j.server.server.model.item.L1TreasureBox;
import l1j.server.server.model.map.L1WorldMap;
import l1j.server.server.model.npc.action.L1NpcDefaultAction;
import l1j.server.server.model.trap.L1WorldTraps;
import l1j.server.server.storage.mysql.MysqlAutoBackup;
import l1j.server.server.utils.MysqlAutoBackupTimer;
import l1j.server.server.utils.SystemUtil;
// Referenced classes of package l1j.server.server:
// ClientThread, Logins, RateTable, IdFactory,
// LoginController, GameTimeController, Announcements,
// MobTable, SpawnTable, SkillsTable, PolyTable,
// TeleportLocations, ShopTable, NPCTalkDataTable, NpcSpawnTable,
// IpTable, Shutdown, NpcTable, MobGroupTable, NpcShoutTable
public class GameServer extends Thread {
private ServerSocket _serverSocket;
private static Logger _log = Logger.getLogger(GameServer.class.getName());
private static int YesNoCount = 0;
private int _port;
// private Logins _logins;
private LoginController _loginController;
private int chatlvl;
@Override
public void run() {
System.out.println(L1Message.memoryUse + SystemUtil.getUsedMemoryMB()
+ L1Message.memory);
System.out.println(L1Message.waitingforuser);
while (true) {
try {
Socket socket = _serverSocket.accept();
System.out.println(L1Message.from + socket.getInetAddress()+ L1Message.attempt);
String host = socket.getInetAddress().getHostAddress();
if (IpTable.getInstance().isBannedIp(host)) {
_log.info("banned IP(" + host + ")");
} else {
ClientThread client = new ClientThread(socket);
GeneralThreadPool.getInstance().execute(client);
}
} catch (IOException ioexception) {
}
}
}
private static GameServer _instance;
private GameServer() {
super("GameServer");
}
public static GameServer getInstance() {
if (_instance == null) {
_instance = new GameServer();
}
return _instance;
}
public void initialize() throws Exception {
String s = Config.GAME_SERVER_HOST_NAME;
double rateXp = Config.RATE_XP;
double LA = Config.RATE_LA;
double rateKarma = Config.RATE_KARMA;
double rateDropItems = Config.RATE_DROP_ITEMS;
double rateDropAdena = Config.RATE_DROP_ADENA;
// Locale 多國語系
L1Message.getInstance();
chatlvl = Config.GLOBAL_CHAT_LEVEL;
_port = Config.GAME_SERVER_PORT;
if (!"*".equals(s)) {
InetAddress inetaddress = InetAddress.getByName(s);
inetaddress.getHostAddress();
_serverSocket = new ServerSocket(_port, 50, inetaddress);
System.out.println(L1Message.setporton + _port);
} else {
_serverSocket = new ServerSocket(_port);
System.out.println(L1Message.setporton + _port);
}
System.out.println("┌───────────────────────────────┐");
System.out.println("│ " + L1Message.ver + "\t" + "\t" + "│");
System.out.println("└───────────────────────────────┘" + "\n");
System.out.println(L1Message.settingslist + "\n");
System.out.println("┌" + L1Message.exp + ": " + (rateXp) + L1Message.x
+ "\n\r├" + L1Message.justice + ": " + (LA) + L1Message.x
+ "\n\r├" + L1Message.karma + ": " + (rateKarma) + L1Message.x
+ "\n\r├" + L1Message.dropitems + ": " + (rateDropItems)+ L1Message.x
+ "\n\r├" + L1Message.dropadena + ": "+ (rateDropAdena) + L1Message.x
+ "\n\r├"+ L1Message.enchantweapon + ": "+ (Config.ENCHANT_CHANCE_WEAPON) + "%"
+ "\n\r├"+ L1Message.enchantarmor + ": " + (Config.ENCHANT_CHANCE_ARMOR)+ "%");
System.out.println("├" + L1Message.chatlevel + ": " + (chatlvl)+ L1Message.level);
if (Config.ALT_NONPVP) { // Non-PvP設定
System.out.println("└" + L1Message.nonpvpNo + "\n");
} else {
System.out.println("└" + L1Message.nonpvpYes + "\n");
}
int maxOnlineUsers = Config.MAX_ONLINE_USERS;
System.out.println(L1Message.maxplayer + (maxOnlineUsers)
+ L1Message.player);
System.out.println("┌───────────────────────────────┐");
System.out.println("│ " + L1Message.ver + "\t" + "\t" + "│");
System.out.println("└───────────────────────────────┘" + "\n");
IdFactory.getInstance();
L1WorldMap.getInstance();
_loginController = LoginController.getInstance();
_loginController.setMaxAllowedOnlinePlayers(maxOnlineUsers);
// 讀取所有角色名稱
CharacterTable.getInstance().loadAllCharName();
// 初始化角色的上線狀態
CharacterTable.clearOnlineStatus();
// 初始化遊戲時間
L1GameTimeClock.init();
// 初始化無限大戰
UbTimeController ubTimeContoroller = UbTimeController.getInstance();
GeneralThreadPool.getInstance().execute(ubTimeContoroller);
// 初始化攻城
WarTimeController warTimeController = WarTimeController.getInstance();
GeneralThreadPool.getInstance().execute(warTimeController);
// 設定精靈石的產生
if (Config.ELEMENTAL_STONE_AMOUNT > 0) {
ElementalStoneGenerator elementalStoneGenerator = ElementalStoneGenerator.getInstance();
GeneralThreadPool.getInstance().execute(elementalStoneGenerator);
}
// 初始化 HomeTown 時間
HomeTownTimeController.getInstance();
// 初始化盟屋拍賣
AuctionTimeController auctionTimeController = AuctionTimeController.getInstance();
GeneralThreadPool.getInstance().execute(auctionTimeController);
// 初始化盟屋的稅金
HouseTaxTimeController houseTaxTimeController = HouseTaxTimeController.getInstance();
GeneralThreadPool.getInstance().execute(houseTaxTimeController);
// 初始化釣魚
FishingTimeController fishingTimeController = FishingTimeController.getInstance();
GeneralThreadPool.getInstance().execute(fishingTimeController);
// 初始化 NPC 聊天
NpcChatTimeController npcChatTimeController = NpcChatTimeController.getInstance();
GeneralThreadPool.getInstance().execute(npcChatTimeController);
// 初始化 Light
LightTimeController lightTimeController = LightTimeController.getInstance();
GeneralThreadPool.getInstance().execute(lightTimeController);
// 初始化遊戲公告
Announcements.getInstance();
// 初始化遊戲循環公告
AnnouncementsCycle.getInstance();
// 初始化MySQL自動備份程序
MysqlAutoBackup.getInstance();
// 開始 MySQL自動備份程序 計時器
MysqlAutoBackupTimer.TimerStart();
// 初始化帳號使用狀態
Account.InitialOnlineStatus();
NpcTable.getInstance();
L1DeleteItemOnGround deleteitem = new L1DeleteItemOnGround();
deleteitem.initialize();
if (!NpcTable.getInstance().isInitialized()) {
throw new Exception("Could not initialize the npc table");
}
L1NpcDefaultAction.getInstance();
DoorTable.initialize();
SpawnTable.getInstance();
MobGroupTable.getInstance();
SkillsTable.getInstance();
PolyTable.getInstance();
ItemTable.getInstance();
DropTable.getInstance();
DropItemTable.getInstance();
ShopTable.getInstance();
NPCTalkDataTable.getInstance();
L1World.getInstance();
L1WorldTraps.getInstance();
Dungeon.getInstance();
NpcSpawnTable.getInstance();
IpTable.getInstance();
MapsTable.getInstance();
UBSpawnTable.getInstance();
PetTable.getInstance();
ClanTable.getInstance();
CastleTable.getInstance();
L1CastleLocation.setCastleTaxRate(); // 必須在 CastleTable 初始化之後
GetBackRestartTable.getInstance();
GeneralThreadPool.getInstance();
L1NpcRegenerationTimer.getInstance();
ChatLogTable.getInstance();
WeaponSkillTable.getInstance();
NpcActionTable.load();
GMCommandsConfig.load();
Getback.loadGetBack();
PetTypeTable.load();
L1BossCycle.load();
L1TreasureBox.load();
SprTable.getInstance();
ResolventTable.getInstance();
FurnitureSpawnTable.getInstance();
NpcChatTable.getInstance();
MailTable.getInstance();
RaceTicketTable.getInstance();
L1BugBearRace.getInstance();
InnTable.getInstance();
MagicDollTable.getInstance();
FurnitureItemTable.getInstance();
System.out.println(L1Message.initialfinished);
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
// cmd互動指令
Thread cp = new ConsoleProcess();
cp.start();
this.start();
}
/**
* 踢掉世界地圖中所有的玩家與儲存資料。
*/
public void disconnectAllCharacters() {
Collection<L1PcInstance> players = L1World.getInstance()
.getAllPlayers();
for (L1PcInstance pc : players) {
pc.getNetConnection().setActiveChar(null);
pc.getNetConnection().kick();
}
// 踢除所有在線上的玩家
for (L1PcInstance pc : players) {
ClientThread.quitGame(pc);
L1World.getInstance().removeObject(pc);
Account account = Account.load(pc.getAccountName());
Account.online(account, false);
}
}
private class ServerShutdownThread extends Thread {
private final int _secondsCount;
public ServerShutdownThread(int secondsCount) {
_secondsCount = secondsCount;
}
@Override
public void run() {
L1World world = L1World.getInstance();
try {
int secondsCount = _secondsCount;
world.broadcastServerMessage("伺服器即將關閉。");
world.broadcastServerMessage("請玩家移動到安全區域先行登出");
while (0 < secondsCount) {
if (secondsCount <= 30) {
world.broadcastServerMessage("伺服器將在" + secondsCount
+ "秒後關閉,請玩家移動到安全區域先行登出。");
} else {
if (secondsCount % 60 == 0) {
world.broadcastServerMessage("伺服器將在" + secondsCount
/ 60 + "分鐘後關閉。");
}
}
Thread.sleep(1000);
secondsCount--;
}
shutdown();
} catch (InterruptedException e) {
world.broadcastServerMessage("已取消伺服器關機。伺服器將會正常運作。");
return;
}
}
}
private ServerShutdownThread _shutdownThread = null;
public synchronized void shutdownWithCountdown(int secondsCount) {
if (_shutdownThread != null) {
// 如果正在關閉
// TODO 可能要有錯誤通知之類的
return;
}
_shutdownThread = new ServerShutdownThread(secondsCount);
GeneralThreadPool.getInstance().execute(_shutdownThread);
}
public void shutdown() {
disconnectAllCharacters();
System.exit(0);
}
public synchronized void abortShutdown() {
if (_shutdownThread == null) {
// 如果正在關閉
// TODO 可能要有錯誤通知之類的
return;
}
_shutdownThread.interrupt();
_shutdownThread = null;
}
/**
* 取得世界中發送YesNo總次數
* @return YesNo總次數
*/
public static int getYesNoCount() {
YesNoCount += 1;
return YesNoCount;
}
}