/** * Copyright (C) 2013-2014 Project-Vethrfolnir * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package com.vethrfolnir.login.services; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; import com.vethrfolnir.logging.MuLogger; import com.vethrfolnir.login.network.game.GamePackets; import com.vethrfolnir.login.network.game.send.KillPacket.KillType; import com.vethrfolnir.login.templates.MuGameServerTemplate; import com.vethrfolnir.network.NetworkClient; import com.vethrfolnir.network.WritePacket; import com.vethrfolnir.services.DataMappingService; import corvus.corax.Corax; import corvus.corax.inject.Inject; /** * @author Vlad * */ public class GameNameService { private static final MuLogger _log = MuLogger.getLogger(GameNameService.class); private final HashMap<MuGameServerTemplate, HashMap<Integer, GameServer>> serverPool = new HashMap<>(10); private AtomicInteger liveServers = new AtomicInteger(); @Inject private void load(DataMappingService service) { try { ArrayList<MuGameServerTemplate> data = service.asArrayList(MuGameServerTemplate.class, "server-names.json"); for (MuGameServerTemplate t : data) { serverPool.put(t, new HashMap<Integer, GameServer>()); } data.clear(); } catch (Exception e) { _log.fatal("Unable to load name server data!", e); } _log.info("Loaded "+serverPool.size()+" game server name(s)!"); } public void registerNewServer(GameServer gns, String password) { String serverPws = Corax.config().getProperty("GameServer.Password", "root"); boolean allow = serverPws.equals(password); if(allow) { MuGameServerTemplate serv = gns.getTemplate(); if(serv != null) { if(serverPool.get(gns.getTemplate()).containsKey(gns.getServerId())) { gns.sendPacket(GamePackets.KillServer, KillType.ID_TAKEN); _log.info("Server with Host: "+gns.channel()+" tryed to connect on the same id with another one id: "+gns.getServerId()+"."); return; } else if (gns.isAcceptAnyId()) { int id = getFreeId(serv); gns.setServerId(id); if(id <= -1) { _log.warn("Failed finding available id for server with Host: "+gns.getHost()); gns.sendPacket(GamePackets.KillServer, KillType.NO_AVIALIABLE_ID); return; } } serverPool.get(serv).put(gns.getServerId(), gns); _log.info("Server with Host: "+gns.getHost()+" connected as "+serv.getName()+" id: "+gns.getServerId()+"."); liveServers.incrementAndGet(); } else { _log.warn("Server with Host: "+gns.getHost()+" tryed to connect with a invalid server id: "+gns.getServerId()); gns.sendPacket(GamePackets.KillServer, KillType.INCORRECT_ID); } } else { gns.sendPacket(GamePackets.KillServer, KillType.INCORRECT_PASSWORD); } } public int liveServerSize() { return liveServers.get(); } private int getFreeId(MuGameServerTemplate template) { for (int i = template.getX(); i < template.getY(); i++) { if(!serverPool.get(template).containsKey(i)) { return i; } } return -1; } public MuGameServerTemplate getServer(int id) { for(MuGameServerTemplate serv : serverPool.keySet()) { if(id >= serv.getX() && id <= serv.getY()) return serv; } return null; } public int getServerIndex(int id) { for(MuGameServerTemplate serv : serverPool.keySet()) { if(id >= serv.getX() && id <= serv.getY()) { return (serv.getX()) / 2; } } return 0; } public void removeServer(GameServer info) { liveServers.decrementAndGet(); serverPool.get(info.getTemplate()).remove(info.getServerId()); _log.info("Removed server "+info.getTemplate().getName()+" with id "+info.getServerId()); } public GameServer create(ChannelHandlerContext context, int serverId, String host, int port) { GameServer gs = new GameServer(context, getServer(serverId), host, port); gs.setServerId(serverId); return gs; } public final class GameServer extends NetworkClient { private final String host; private final int port; private final ChannelHandlerContext context; private final MuGameServerTemplate template; private boolean acceptAnyId; private int serverId; private int onlinePlayers; private int cap; /** * @param context */ public GameServer(ChannelHandlerContext context, MuGameServerTemplate template, String host, int port) { super(context.channel()); this.context = context; this.host = host; this.port = port; this.template = template; } /** * Should only be called by netty's handler! */ public void remove() { GameNameService.this.serverPool.get(template).remove(serverId); _log.info("Game Server with host["+host+"/"+port+"] has been removed."); } /** * @return the template */ public MuGameServerTemplate getTemplate() { return template; } /** * @param serverId the serverId to set */ public void setServerId(int serverId) { this.serverId = serverId; } /** * @return the serverId */ public int getServerId() { return serverId; } /** * @return the context */ public Channel getChannel() { return context.channel(); } /** * @return the host */ public String getHost() { return host; } /** * @return the port */ public int getPort() { return port; } /** * @return the acceptAnyId */ public boolean isAcceptAnyId() { return acceptAnyId; } /** * @param acceptAnyId the acceptAnyId to set */ public void setAcceptAnyId(boolean acceptAnyId) { this.acceptAnyId = acceptAnyId; } /** * @return the onlinePlayers */ public int getOnlinePlayers() { return onlinePlayers; } /** * @param onlinePlayers the onlinePlayers to set */ public void setOnlinePlayers(int onlinePlayers) { this.onlinePlayers = onlinePlayers; } /** * @return the cap */ public int getCap() { return cap; } /** * @param cap the cap to set */ public void setCap(int cap) { this.cap = cap; } public void sendPacket(WritePacket packet, Object... params) { ByteBuf buff = context.alloc().buffer(); packet.write(this, buff, params); packet.markLength(buff); context.writeAndFlush(buff); } } public HashMap<MuGameServerTemplate, HashMap<Integer, GameServer>> getLiveServers() { return serverPool; } /** * TODO: Improve this * @param channel * @return */ public GameServer getServer(Channel channel) { for(HashMap<Integer, GameServer> ss : getLiveServers().values()) { for (GameServer s : ss.values()) { if(s.channel() == channel) return s; } } return null; } }