/ login-server / source / service / GameServerManager.ts
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()