UNPKG

mm_os

Version:

MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。

622 lines (571 loc) 16.4 kB
const { Drive, Manager } = require('mm_machine'); const { Scene } = require('../../scene/index.js'); const { System } = require('../../system/index.js'); const { Logic } = require('../../logic/index.js'); const { Factory } = require('../../factory/index.js'); const { Component } = require('../../component/index.js'); const { EntityAdmin } = require('../entity_admin.js'); const { GameLoop } = require('../../scene/loop.js'); const { idGen } = require('../../../ulits/id_gen.js'); /** * 游戏世界 */ class GameWorld extends Drive { static config = { // 游戏名称 'name': 'world', // 游戏标题 'title': '游戏世界', // 游戏描述 'description': '这是一个游戏世界', // 游戏主脚本 - 可自定义游戏初始化,一般情况不需要定义 'main': '', // 游戏状态 - 1 正常 0 禁用 'state': 1, // 游戏排序 - 数字越小越靠前 'sort': 100, // 游戏类型 - 角色扮演rpg、卡牌游戏card、策略游戏strategy、模拟经营simulation 'type': 'rpg', // 游戏实体类型 - 玩家player、NPC、怪物、物品等 'entity_type': 'player' }; /** * 构造函数 * @param {object} config 配置参数 */ constructor(config = {}) { super({ ...GameWorld.config, ...config }); // 游戏世界ID this.world_id = this.genId(); // 玩家ID集合 - 使用Set保证唯一性和高效查找 this._player_ids = new Set(); // 游戏实体 this.entities = new Map(); // 实体管理器 this.entityAdmin = null; // 游戏循环 this.loop = null; // 游戏场景集合 this.scene = {}; // 游戏系统集合 this.system = {}; // 游戏逻辑集合 this.logic = {}; // 游戏工厂集合 this.factory = {}; // 游戏组件集合 this.component = {}; // 管理器集合 this.manager = {}; } } /** * 获取模板目录 * @returns {string} 模板目录 */ GameWorld.prototype.getTplDir = function () { return __dirname; }; /** * 获取游戏管理器目录 * @returns {string} 游戏管理器目录 */ GameWorld.prototype.getDir = function () { return this.getGame().getDir(); }; /** * 生成游戏世界ID * @returns {string} 游戏世界ID */ GameWorld.prototype.genId = function () { return idGen.genId('world'); }; /** * 创建管理器实例 * @param {string} name 管理器名称 * @param {string} title 管理器标题 * @param {Function} cls 管理器类 * @returns {object} 管理器实例 */ GameWorld.prototype._createManager = function (name, title, cls) { var dir = this.getDir(); var manager = new Manager({ name, title, scope: this.config.name, dir: `./${name}`.fullname(dir) }, this, this[name], cls); this.manager[name] = manager; return manager; }; /** * 初始化管理器集合 * @returns {Promise<void>} 初始化完成 */ GameWorld.prototype._initManager = async function () { // 创建所有管理器实例 var component = this._createManager('component', '组件', Component); var factory = this._createManager('factory', '工厂', Factory); var logic = this._createManager('logic', '逻辑', Logic); var system = this._createManager('system', '系统', System); var scene = this._createManager('scene', '场景', Scene); // 并行执行所有管理器的初始化操作 var initPromises = [ component.do('init'), factory.do('init'), logic.do('init'), system.do('init'), scene.do('init'), ]; await Promise.all(initPromises); // 创建实体管理器 this.entityAdmin = new EntityAdmin(); }; /** * 初始化游戏循环 * @private */ GameWorld.prototype._initGameLoop = async function () { // 游戏循环 this._loop = new GameLoop(this.config.game_loop); await this._loop.do('init', this, this.getEventer(), this.getLogger()); }; /** * 加载资源 */ GameWorld.prototype._loadSources = async function () { // 加载无需依赖关系,所以可以同时加载 await Promise.all([ this.manager.component.runAll('load'), this.manager.factory.runAll('load'), this.manager.logic.runAll('load'), this.manager.system.runAll('load'), this.manager.scene.runAll('load') ]); }; /** * 初始化资源 */ GameWorld.prototype._initSources = async function () { // 初始化顺序 scene -> system -> logic -> factory -> entity -> component ,需要依赖下级,所以自下而上初始化 await this.manager.component.runAll('init', this.getLogger()); await this.manager.factory.runAll('init', this.component, this.getEventer(), this.getLogger()); await this.entityAdmin.do('init', this.entities, this.factory, this.getEventer(), this.getLogger()); await this.manager.logic.runAll('init', this.getLogger()); await this.manager.system.runAll('init', this, this.getEventer(), this.getLogger()); await this.manager.scene.runAll('init', this.system, this.getEventer(), this.getLogger()); }; /** * 初始化核心 * @param {object} channel 游戏频道 * @param {object} eventer 事件总线 * @param {object} logger 日志管理器 * @returns {void} */ GameWorld.prototype._initCore = async function (channel, eventer, logger) { // 初始化依赖项 if (logger) { this.setLogger(logger); } if (eventer) { this.getEventer = function () { return eventer; }; } if (!channel) { throw new Error('游戏世界必须绑定游戏频道'); } else if (channel) { this.getChannel = function () { return channel; }; } // 初始化管理 await this._initManager(); // 加载资源 await this._loadSources(); // 初始化资源 await this._initSources(); // 初始化游戏循环 await this._initGameLoop(); }; /** * 加载实体 * @returns {Promise<void>} */ GameWorld.prototype._loadEntities = async function () { try { // 通过事件方式加载已存在的实体数据,避免直接操作数据库 var entities = await this.emitWait('entity_load', { world_id: this.world_id, world_name: this.config.name }); if (entities && entities.length > 0) { // 遍历实体列表,恢复实体对象 for (var i = 0; i < entities.length; i++) { var info = entities[i]; // 使用工厂创建实体 var factory = this.createEntity(info.type, info.model); if (factory) { // 恢复玩家ID if (info.player_id) { this._player_ids.add(info.player_id); } } } } } catch (error) { this.log('error', `加载实体数据失败: `, error); } }; /** * 启动资源 */ GameWorld.prototype._startSources = async function () { // 并行启动游戏系统和场景 await Promise.all([ // 启动游戏系统 this.manager.system.runAll('start'), // 启动游戏场景 this.manager.scene.runAll('start') ]); }; /** * 启动核心 */ GameWorld.prototype._startCore = async function () { // 加载实体(在启动前恢复已存在的实体) await this._loadEntities(); // 启动资源 await this._startSources(); // 启动游戏循环 await this._loop.do('start'); }; /** * 游戏世界更新 */ GameWorld.prototype.update = async function () { await this.manager.system.runAll('update'); await this.manager.scene.runAll('update'); }; /** * 保存脏数据实体 * @returns {Promise<void>} */ GameWorld.prototype._saveDirtyEntities = async function () { try { var entities = []; // 遍历所有实体,收集脏数据 for (var entity of this.entities.values()) { if (entity.isDirty()) { entities.push(entity); // 触发实体数据变化事件 this.emitEvent('entity_changed', { entity: entity, world_id: this.world_id, timestamp: Date.now() }); } } if (entities.length > 0) { // 通过事件方式保存脏数据实体 await this.emitWait('entity_save', { world_id: this.world_id, world_name: this.config.name, entities: entities }); // 重置脏标记 for (var i = 0; i < entities.length; i++) { entities[i].isDirty(false); } this.log('debug', `保存脏数据实体 ${entities.length} 个`); } } catch (error) { this.log('error', `保存脏数据实体失败: `, error); } }; /** * 保存所有实体 * @returns {Promise<void>} */ GameWorld.prototype._saveAllEntities = async function () { try { var all_entities = Array.from(this.entities.values()); if (all_entities.length > 0) { // 通过事件方式保存所有实体 await this.emitWait('entity_save', { world_id: this.world_id, world_name: this.config.name, entities: all_entities }); this.log('info', `保存所有实体 ${all_entities.length} 个`); } } catch (error) { this.log('error', `保存所有实体失败: `, error); } }; /** * 销毁游戏世界 * @private * @returns {Promise<void>} 销毁完成后的Promise */ GameWorld.prototype._destroy = async function () { // 销毁前保存所有实体 await this._saveAllEntities(); await this.manager.system.runAll('destroy'); await this.manager.scene.runAll('destroy'); }; /** * 获取实体 * @param {object} id 实体ID * @returns {object|null} 实体对象,如果不存在则返回null */ GameWorld.prototype.getEntity = function (id) { return this.entities.get(id); }; /** * 获取组件相关实体 * @param {Array} types 组件类型数组 * @returns {Array} 符合条件的实体数组 */ GameWorld.prototype.getEntitiesByTypes = function (types) { // 实现实体查询逻辑 let result = []; for (let entity of this.entities.values()) { if (types.every(type => entity.hasComponent(type))) { result.push(entity); } } return result; }; /** * 获取相关标签实体 * @param {Array} tags 标签数组 * @returns {Array} 符合条件的实体数组 */ GameWorld.prototype.getEntitiesByTags = function (tags) { // 实现实体查询逻辑 let result = []; for (let entity of this.entities.values()) { if (tags.every(type => entity.hasTag(type))) { result.push(entity); } } return result; }; /** * 创建实体 * @param {string} type 实体类型 - 可选值为 玩家、NPC、怪物、物品等 * @param {object} model 实体模型 - 可选,根据实体类型定义 * @returns {object} 创建的实体对象 */ GameWorld.prototype.createEntity = function (type = 'player', model = {}) { // 使用工厂创建实体 var factory = this.factory[type]; if (!factory) { throw new Error(`${this.config.title}游戏工厂(${type})不存在`); } let entity = factory.create(model); this.entities.set(entity.entity_id, entity); // 注册实体与玩家的映射关系 if (entity.player_id) { // 尝试获取 Pusher 实例并注册映射 if ($.pusher) { $.pusher.registerEntityPlayer(entity.entity_id, entity.player_id); } } // 触发实体创建事件 this.emitEvent('entity_created', { entity: entity, world_id: this.world_id, timestamp: Date.now() }); return entity; }; /** * 玩家进入世界 * @param {string} player_id 玩家ID * @param {string} entity_type 实体类型 - 可选值为 玩家、NPC、怪物、物品等 * @returns {object} 玩家实体对象 */ GameWorld.prototype.enter = async function (player_id, entity_type) { // 参数校验 if (!player_id) { throw new TypeError('玩家ID无效'); } let player = this.getChannel().getPlayer(player_id); // 参数校验 if (!player) { throw new TypeError('玩家对象无效'); } if (this._player_ids.has(player_id)) { throw new Error(`玩家 ${player_id} 已存在`); } try { this._addPlayer(player_id); // 创建玩家实体 let entity = this.createEntity(entity_type || this.config.entity_type, player); // 触发玩家进入世界事件 this.emitEvent('player_enter_world', { world_id: this.world_id, world_name: this.config.name, player_id: player.player_id, player_level: player.level, timestamp: Date.now() }); // 将玩家添加到默认场景 let default_scene = this.scene['default']; if (default_scene) { await default_scene.addPlayer(entity); } return entity; } catch (error) { this.log('error', `玩家进入世界失败: `, error); throw error; } }; /** * 玩家离开世界 * @param {string} player_id 玩家ID * @returns {object} 离开的玩家实体 */ GameWorld.prototype.leave = async function (player_id) { // 参数校验 if (!player_id) { throw new TypeError('玩家ID无效'); } // 查找玩家实体 let entity = this.entities.get(player_id); if (!entity) { throw new Error(`玩家 ${player_id} 不存在`); } // 从默认场景移除玩家 let default_scene = this.scene['default']; if (default_scene) { await default_scene.leave(entity); } // 触发玩家离开世界事件 this.emitEvent('player_leave_world', { world_id: this.world_id, world_name: this.config.name, player_id: player_id, timestamp: Date.now() }); // 触发实体删除事件 this.emitEvent('entity_deleted', { entity_id: entity.entity_id, world_id: this.world_id, timestamp: Date.now() }); // 从实体管理器移除玩家实体 this.entities.delete(player_id); // 从玩家ID集合中移除 this._removePlayer(player_id); return entity; }; /** * 玩家进入场景 * @param {string} player_id 玩家ID * @param {string} scene_id 场景ID * @returns {boolean} 是否成功进入 */ GameWorld.prototype.enterScene = async function (player_id, scene_id) { // 参数校验 if (!player_id) { throw new TypeError('玩家ID无效'); } if (!scene_id) { throw new TypeError('场景ID无效'); } // 查找玩家实体 let entity = this.entities.get(player_id); if (!entity) { throw new Error(`玩家 ${player_id} 不存在`); } // 查找场景 let scene = this.scene[scene_id]; if (!scene) { throw new Error(`场景 ${scene_id} 不存在`); } // 触发玩家进入场景事件 this.emitEvent('player_enter_scene', { world_id: this.world_id, world_name: this.config.name, player_id: player_id, scene_id: scene_id, timestamp: Date.now() }); // 将玩家添加到场景 await scene.addPlayer(entity); return true; }; /** * 添加玩家到世界 * @param {string} player_id 玩家ID */ GameWorld.prototype._addPlayer = function (player_id) { // 参数校验 if (!player_id) { throw new TypeError('玩家ID无效'); } // 检查玩家是否已存在 if (this._player_ids.has(player_id)) { throw new Error(`玩家 ${player_id} 已存在`); } // 添加玩家ID到集合 this._player_ids.add(player_id); }; /** * 移除玩家 * @param {string} player_id 玩家ID * @returns {boolean} 是否成功移除 */ GameWorld.prototype._removePlayer = function (player_id) { // 参数校验 if (!player_id) { throw new TypeError('玩家ID无效'); } return this._player_ids.delete(player_id); }; /** * 获取世界玩家数量 * @returns {number} 玩家数量 */ GameWorld.prototype.getPlayerNum = function () { return this._player_ids.size; }; /** * 检查玩家是否在世界中 * @param {string} player_id 玩家ID * @returns {boolean} 是否存在 */ GameWorld.prototype.hasPlayer = function (player_id) { return this._player_ids.has(player_id); }; /** * 获取所有玩家ID * @returns {Array} 玩家ID数组 */ GameWorld.prototype.getAllPlayerIds = function () { return Array.from(this._player_ids); }; exports.GameWorld = GameWorld;