import EventEmitter from 'events'; import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs'; import { parse } from 'json5'; import * as mathjs from 'mathjs'; import { join, resolve } from 'path'; import { argv, env } from 'process'; import { HttpServer, WsClient, WsServer } from 'tsrpc'; import { ServiceType as ServiceTypeCross } from './cross/protocols/serviceProto'; import { MyEvent } from './event'; import { addListener, gEventType } from './globalListener'; import localConfig from './localConfig'; import { ServiceType as ServiceTypeHttp } from './monopoly/protocols/serviceProto'; import { SchedulerManage } from './public/scheduler/scheduler'; import { _mongodb } from './setMongodb'; import { redisJsonFun } from './setRedis'; import { ResGetList } from './shared/protocols/pay/PtlGetList'; import { ServiceType as ServiceTypeWs } from './shared/protocols/serviceProto'; import { PublicShared } from './shared/public/public'; import { clusterRunOnce } from './clusterUtils'; import * as ramda from 'ramda' import Redis from 'ioredis'; declare global { var G: _G & Partial<{ /**仅类型映射 */ otherBuff: any; }>; var mathJs: typeof mathjs; var R type k_v = { [k: string]: T; }; type atn = { a: string, t: string | number | any, n: number; colour?: number; shiwuBuff?: any; }; /**类型过滤 */ type FilterConditionally = Pick< Source, { [K in keyof Source]: Source[K] extends Condition ? K : never }[keyof Source] >; interface Array { /**数组随机取值 */ random(): T; /**取一个数组在当前数组中的交集 */ intersection(other: T[]): T[]; /**取一个数组在当前数组中的差集 */ difference(other: T[]): T[]; /**数组是否存在重复元素 */ isDuplication(): boolean; /**打乱数组 */ shuffle(): this; } interface Uint8Array { /**是否已经加密 */ encrypt: boolean; } } class _G { /**游戏配置 */ gc: Partial<_gcType> = {}; /**服务启动时命令行参数解析 */ argv: { /**服务器类型 */ serverType: 'msg' | 'cross', /**服务器日志模式 error | debug*/ logModel: string; } = { serverType: 'msg', logModel: 'error' }; /**当前时间对象 */ date: Date; /**当前时间戳 */ time: number; // /**serverType==msg时记录所有玩家的uid, 剔除全局变量,转移到redis */ // uids?: string[]; /**服务器配置 */ config: Partial & k_v = {}; /**当serverType==msg时才会启动的http */ http?: HttpServer; /**当serverType!=cross时才会启动的ws */ server?: WsServer; /**当serverType==cross时才会启动的ws */ serverCross?: WsServer; /**当serverType==msg时才会启动的跨服连接 */ clientCross?: WsClient; /**redis连接对象 */ redis: redisJsonFun; /**ioredis连接对象 */ ioredis: Redis; /**mongodb连接对象 */ mongodb: _mongodb; /**crossmongodb连接对象 */ crossmongodb: _mongodb; // mongodbClient: any; /**所有玩家的充值记录 */ allPlayerPayLog: k_v = {}; private event = new EventEmitter(); /**映射开服时间 */ get openTime() { return this.config.openTime; } get getEvent(): new (...args: any) => { on(type: any, callback: any, caller?: any): any; once(type: any, callback: any): any; off(type: any, callback: any, caller?: any): void; emit(type: any, ...args: any[]): void; debug(): any; removeAllListeners(type?:any):void; } { return MyEvent as any; } constructor(argArr: string[]) { let configJson = existsSync(resolve(__dirname, 'config.json')) ? JSON.parse(readFileSync(resolve(__dirname, 'config.json'), 'utf-8')) : {}; for (let index = 0; index < argArr.length; index++) { let arg = argArr[index]; if (arg == '-serverType') { this.argv.serverType = argArr[index + 1] as any; } else if (arg == '-logModel') { this.argv.logModel = argArr[index + 1]; } } Object.assign(localConfig, configJson); this.config = localConfig; if (env.SERVER_ID) { this.config.serverId = ~~env.SERVER_ID; } this.initGc(); } on(event: T, callback: gEventType[T]) { return this.event.on(event, (...args)=>{ try{ callback.call(this, ...args); }catch(e){ console.error(e) } }); } once(event: T, callback: gEventType[T]) { return this.event.once(event, callback); } emit(event: T, ...args: Parameters) { return this.event.emit(event, ...args); } /**加载json */ initGc() { let jsonPath = join(__dirname, 'json'); readdirSync(jsonPath).forEach(file => { if (file.endsWith('.json5')) { let json = parse(readFileSync(join(jsonPath, file), 'utf-8')); this.gc[file.split('.')[0]] = json; } else if(file.endsWith('.json')) { let json = JSON.parse(readFileSync(join(jsonPath, file), 'utf-8')); this.gc[file.split('.')[0]] = json; } }); } /**更新时间 每秒刷新 */ updateTime() { if (G.config.debug && G.config.time) { try { let conf = JSON.parse(readFileSync(resolve(__dirname, 'config.json'), 'utf-8')); this.date = new Date(conf.time); this.date = new Date(this.date.getTime() + 1000); this.time = Math.round(this.date.getTime() / 1000); conf.time = this.date.format('YYYY-MM-DD hh:mm:ss'); // writeFileSync(resolve(__dirname, 'config.json'), JSON.stringify(conf, null, 2)); } catch (error) { } } else { // let date = new Date(); // let time = date.getTime(); // let offset = date.getTimezoneOffset() / 60 + this.config.utc; // this.date = new Date(time + offset * 3600 * 1000); this.date = new Date(); this.time = Math.round(this.date.getTime() / 1000); } } /**检查redis路径是否首字符为数字 */ formatRedisKey(key: string) { let firstStr = key.toString().substring(0, 1); if (!isNaN(Number(firstStr))) return '_' + key; return key; } /**改写开区时间(外部请求 games/open 改写)*/ set openTime(_opentine) { try { let conf = JSON.parse(readFileSync(resolve(__dirname, 'config.json'), 'utf-8')); G.date = new Date(_opentine); G.date = new Date(this.date.getTime() + 1000); conf.openTime = this.date.format('YYYY-MM-DD hh:mm:ss'); // this.openTime = this.date.format('YYYY-MM-DD hh:mm:ss'); // 外部调用时直接改写了,不然会无限重复调用 this.config.openTime = this.date.format('YYYY-MM-DD hh:mm:ss') // writeFileSync(resolve(__dirname, 'config.json'), JSON.stringify(conf, null, 2)); } catch (error) { } } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } } export function ctor() { globalThis.mathJs = mathjs; globalThis.G = new _G(argv); G.updateTime(); globalThis.R = ramda } Array.prototype.random = function (this: Array) { return this[PublicShared.randomNum(0, this.length)]; }; Array.prototype.intersection = function (this: Array, other: Array) { let a = new Set(this); let b = new Set(other); return Array.from(new Set([...a].filter(x => b.has(x)))); }; Array.prototype.difference = function (this: Array, other: Array) { let a = new Set(this); let b = new Set(other); return Array.from(new Set([...a].filter(x => !b.has(x)))); }; Array.prototype.isDuplication = function (this: Array) { return this.length != [...new Set(this)].length; }; Array.prototype.shuffle = function (this: Array) { this.forEach((v, k) => { let _k = 0 | (Math.random() * (k + 1)); var tmp = this[k]; this[k] = this[_k]; this[_k] = tmp; }); return this; }