mm_os
Version:
MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。
622 lines (571 loc) • 16.4 kB
JavaScript
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;