001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server;
019
020import net.tridentsdk.*;
021import net.tridentsdk.config.Config;
022import net.tridentsdk.entity.living.Player;
023import net.tridentsdk.plugin.Plugin;
024import net.tridentsdk.registry.Registered;
025import net.tridentsdk.server.command.TridentConsole;
026import net.tridentsdk.server.concurrent.ConcurrentTaskExecutor;
027import net.tridentsdk.server.concurrent.MainThread;
028import net.tridentsdk.server.concurrent.ThreadsHandler;
029import net.tridentsdk.server.concurrent.TridentTaskScheduler;
030import net.tridentsdk.server.netty.protocol.Protocol;
031import net.tridentsdk.server.player.TridentPlayer;
032import net.tridentsdk.server.service.Statuses;
033import net.tridentsdk.server.world.TridentWorld;
034import net.tridentsdk.server.world.TridentWorldLoader;
035import net.tridentsdk.util.TridentLogger;
036import net.tridentsdk.world.World;
037
038import javax.annotation.concurrent.ThreadSafe;
039import java.io.IOException;
040import java.net.InetAddress;
041
042/**
043 * The access base to internal workings of the server
044 *
045 * @author The TridentSDK Team
046 */
047@ThreadSafe
048public final class TridentServer implements Server {
049    // TODO this is temporary for testing
050    public static TridentWorld WORLD;
051    private final MainThread mainThread;
052
053    private final Config config;
054    private final Protocol protocol;
055    private final TridentLogger logger;
056
057    private final TridentConsole console;
058
059    final TridentWorldLoader rootWorldLoader;
060    private volatile PingInfo pingInfo;
061
062    private TridentServer(Config config) {
063        this.config = config;
064        this.protocol = new Protocol();
065        this.logger = TridentLogger.get(getClass());
066        this.mainThread = new MainThread(20);
067        this.rootWorldLoader = new TridentWorldLoader();
068        this.console = new TridentConsole();
069        this.pingInfo = new PingInfo();
070    }
071
072    /**
073     * Creates the server access base, distributing information to the fields available
074     *
075     * @param config the configuration to use for option lookup
076     */
077    public static TridentServer createServer(Config config) {
078        TridentServer server = new TridentServer(config);
079        Trident.setServer(server);
080        server.mainThread.start();
081        return server;
082        // We CANNOT let the "this" instance escape during creation, else we lose thread-safety
083    }
084
085    /**
086     * Gets the instance of the server
087     *
088     * @return the server singleton
089     */
090    public static TridentServer instance() {
091        return (TridentServer) Trident.instance();
092    }
093
094    /**
095     * Get the protocol base of the server
096     *
097     * @return the access to server protocol
098     */
099    public Protocol protocol() {
100        return this.protocol;
101    }
102
103    public int compressionThreshold() {
104        return this.config.getInt("compression-threshold", Defaults.COMPRESSION_THRESHOLD);
105    }
106
107    public MainThread mainThread() {
108        return mainThread;
109    }
110
111    @Override
112    public Console console() {
113        return console;
114    }
115
116    /**
117     * Gets the port the server currently runs on
118     *
119     * @return the port occupied by the server
120     */
121    @Override
122    public int port() {
123        return this.config.getInt("port", 25565);
124    }
125
126    @Override
127    public Config config() {
128        return this.config;
129    }
130
131    /**
132     * Performs the shutdown procedure on the server, ending with the exit of the JVM
133     */
134    @Override
135    public void shutdown() {
136        try {
137            TridentLogger.get().log("Saving files...");
138            try {
139                ((Statuses) Registered.statuses()).saveAll();
140            } catch (IOException e) {
141                e.printStackTrace();
142            }
143
144            TridentLogger.get().log("Kicking players...");
145            for (Player player : TridentPlayer.players()) {
146                ((TridentPlayer) player).kickPlayer("Server shutting down");
147                ((TridentPlayer) player).connection().logout();
148            }
149
150            TridentLogger.get().log("Saving worlds...");
151            for (World world : rootWorldLoader.worlds())
152                ((TridentWorld) world).save();
153
154            TridentLogger.get().log("Shutting down scheduler...");
155            ((TridentTaskScheduler) Registered.tasks()).shutdown();
156
157            TridentLogger.get().log("Shutting down server process...");
158            ThreadsHandler.shutdownAll();
159
160            //TODO: Cleanup stuff...
161            TridentLogger.get().log("Shutting down plugins...");
162            for (Plugin plugin : Registered.plugins())
163                Registered.plugins().disable(plugin);
164
165            TridentLogger.get().log("Shutting down thread pools...");
166            ConcurrentTaskExecutor.executors().forEach(ConcurrentTaskExecutor::shutdown);
167
168            TridentLogger.get().log("Shutting down server connections...");
169            TridentStart.close();
170        } catch (Exception e) {
171            TridentLogger.get().error("Server failed to shutdown correctly");
172            TridentLogger.get().error(e);
173            return;
174        }
175
176        TridentLogger.get().log("Server shutdown successfully.");
177    }
178
179    @Override
180    public InetAddress ip() {
181        return null;
182    }
183
184    @Override
185    public String version() {
186        // TODO: Make this more eloquent
187        return "0.3-alpha-DP";
188    }
189
190    @Override
191    public PingInfo info() {
192        return pingInfo;
193    }
194
195    @Override
196    public TridentLogger logger() {
197        return logger;
198    }
199}