GameServerManager.ts
1 import { L2GameServerClient } from './GameServerClient' 2 import { ConnectedGameServer } from '../models/RegisteredGameServer' 3 import { AvailableServerNames } from '../config/serverNames' 4 import { BanManager } from '../cache/BanManager' 5 import { L2GameServerParameters, L2LoginRegisterServerEvent } from '../rpc/interface/LoginServerOperations' 6 import { Socket } from 'net' 7 import _ from 'lodash' 8 import { ServerLog } from '../logger/Logger' 9 import { IPCache, IPCacheConnectionType, IPCacheListType } from '../cache/IPCache' 10 import { AddressInfo } from 'node:net' 11 import chalk from 'chalk' 12 13 const allPossibleServerIds: Array<number> = Object.keys( AvailableServerNames ).map( value => parseInt( value ) ) 14 15 class Manager { 16 connectedClients: { [ key: string ]: L2GameServerClient } = {} 17 registeredGameServers: Array<ConnectedGameServer> = [] 18 19 addClient( client: L2GameServerClient ) : void { 20 this.connectedClients[ client.getConnectionHash() ] = client 21 } 22 23 registerServer( client: L2GameServerClient, event: L2LoginRegisterServerEvent ): boolean { 24 this.removeRegisteredServer( event.serverId ) 25 return this.registerWithSpecifiedId( client, event ) 26 } 27 28 /* 29 TODO: is prefetch really needed? 30 */ 31 prefetchCharactersOnAccount( accountName: string ) : void { 32 this.registeredGameServers.forEach( ( currentServer: ConnectedGameServer ) => { 33 if ( currentServer.client && currentServer.client.getServerProperties().isServerAcceptingPlayers ) { 34 currentServer.client.requestServerCharacters( accountName ) 35 } 36 } ) 37 } 38 39 getRegisteredGameServerById( serverId: number ): ConnectedGameServer { 40 return this.registeredGameServers.find( server => server.serverId === serverId ) 41 } 42 43 getRegisteredGameServers(): ReadonlyArray<ConnectedGameServer> { 44 return this.registeredGameServers 45 } 46 47 isAllowed( connection : Socket ) : boolean { 48 if ( !IPCache.isInList( connection, IPCacheConnectionType.GameServer, IPCacheListType.Allow ) ) { 49 return false 50 } 51 52 const address = connection.address() as AddressInfo 53 const remoteAddress = address.address ?? connection.remoteAddress 54 55 return BanManager.isAllowed( remoteAddress ) 56 } 57 58 canRegister( id: number ): boolean { 59 return !this.getRegisteredGameServerById( id ) 60 } 61 62 registerWithSpecifiedId( client: L2GameServerClient, event: L2LoginRegisterServerEvent ): boolean { 63 const existingServer: ConnectedGameServer = this.getRegisteredGameServerById( event.serverId ) 64 65 if ( !existingServer && AvailableServerNames[ event.serverId ] ) { 66 const server: ConnectedGameServer = { 67 serverId: event.serverId, 68 serverName: AvailableServerNames[ event.serverId ], 69 host: event.ip.join( '.' ), 70 client, 71 port: event.port, 72 } 73 74 this.registeredGameServers.push( server ) 75 76 ServerLog.info( 'Registered game server %s[%s] on %s:%d', chalk.greenBright( server.serverName ), chalk.red( server.serverId ), server.host, server.port ) 77 return true 78 } 79 80 return false 81 } 82 83 registerWithFirstAvailableId( client: L2GameServerClient, serverProperties: L2LoginRegisterServerEvent ): number { 84 const usedServerIds = new Set<number>( allPossibleServerIds ) 85 this.registeredGameServers.forEach( server => usedServerIds.delete( server.serverId ) ) 86 87 if ( usedServerIds.size === 0 ) { 88 ServerLog.warn( 'No server registration ids left!' ) 89 return 0 90 } 91 92 const values = usedServerIds.values() 93 const nextFreeId : number = values.next().value 94 95 const server: ConnectedGameServer = { 96 serverId: nextFreeId, 97 serverName: AvailableServerNames[ nextFreeId ], 98 host: serverProperties.ip.join( '.' ), 99 client, 100 port: serverProperties.port, 101 } 102 103 this.registeredGameServers.push( server ) 104 105 ServerLog.info( 'Auto-registered game server %s[%s] on %s:%d', chalk.greenBright( server.serverName ), chalk.red( server.serverId ), server.host, server.port ) 106 return nextFreeId 107 } 108 109 removeClient( connectionHash : string ) { 110 const client = this.connectedClients[ connectionHash ] 111 if ( client ) { 112 const parameters: L2GameServerParameters = client.getServerProperties() 113 if ( parameters ) { 114 this.removeRegisteredServer( parameters.serverId ) 115 } 116 } 117 118 delete this.connectedClients[ connectionHash ] 119 } 120 121 removeRegisteredServer( serverId : number ) { 122 _.remove( this.registeredGameServers, ( server : ConnectedGameServer ) => server.serverId === serverId ) 123 } 124 125 getClientByAccountName( accountName : string ) : L2GameServerClient { 126 const server : ConnectedGameServer = this.registeredGameServers.find( ( currentServer: ConnectedGameServer ) : boolean => { 127 return currentServer.client && currentServer.client.hasAccountOnGameServer( accountName ) 128 } ) 129 130 return server.client 131 } 132 } 133 134 export const GameServerManager = new Manager()