diff --git a/README.md b/README.md
index 9abdaf4f8..0e2529272 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,10 @@ While the current stage of the platform is tailored for developers, ongoing impr
---
+## [Check our website for the latest news!](https://www.reldens.com/ "Check our website for the latest news")
+
+---
+
## [Features Overview](https://www.reldens.com/features)
[First to mention, if the feature you need is not available, you can request a feature here: https://www.reldens.com/features-request](https://www.reldens.com/features-request)
@@ -43,11 +47,9 @@ As for the latest version released the platform will provide you with the follow
---
-## [Check our website for the latest news!](https://www.reldens.com/ "Check our website for the latest news")
-
----
+## [Installation](https://www.reldens.com/documentation/installation "Installation")
-## [Installation Guide](https://www.reldens.com/installation "Installation Guide")
+Please follow the Installation Guide: https://www.reldens.com/documentation/installation.
---
diff --git a/lib/actions/client/player-selector.js b/lib/actions/client/player-selector.js
index bd8e9208f..6a19f48b1 100644
--- a/lib/actions/client/player-selector.js
+++ b/lib/actions/client/player-selector.js
@@ -92,7 +92,9 @@ class PlayerSelector
let avatarKey = select.options[select.selectedIndex].dataset.key;
avatar.classList.add('class-path-select-avatar');
avatar.style.backgroundImage = `url('/assets/custom/sprites/${avatarKey}${GameConst.FILES.EXTENSIONS.PNG}')`;
- avatar.style.width = playersConfig.size.width+'px';
+ let widthInPx = playersConfig.size.width+'px';
+ avatar.style.backgroundPositionX = '-'+widthInPx;
+ avatar.style.width = widthInPx;
avatar.style.height = playersConfig.size.height+'px';
select.addEventListener('change', () => {
let avatarKey = select.options[select.selectedIndex].dataset.key;
diff --git a/lib/actions/client/preloader-handler.js b/lib/actions/client/preloader-handler.js
index a6198d375..d26e94918 100644
--- a/lib/actions/client/preloader-handler.js
+++ b/lib/actions/client/preloader-handler.js
@@ -2,48 +2,6 @@
*
* Reldens - PreloaderHandler.
*
- * Main functionalities:
- * The PreloaderHandler class is responsible for handling the preloading and creation of animations and assets used in
- * the game. It loads HTML templates, spritesheets, and creates animations based on the configuration data provided by
- * the game manager. It also handles the preparation and creation of animations with multiple directions and the
- * creation of avatars animations.
- *
- * Methods:
- * - constructor(props): initializes the class with the game manager and events manager objects, and sets the
- * properties.
- * - setProperties(props): sets the properties of the class, such as the game DOM, initial game data, and animations
- * configuration.
- * - loadContents(uiScene): loads HTML templates and preloads animations based on the configuration data.
- * - preloadClassPaths(uiScene): preloads spritesheets for class paths based on the initial game data.
- * - createAnimations(preloadScene): creates animations based on the configuration data.
- * - createAvatarsAnimations(preloadScene): creates animations for avatars based on the initial game data.
- * - loopAnimationsAnd(animations, command, uiScene): loops through the animations and executes the specified command
- * (preload or create) for each animation.
- * - preloadAnimation(data, uiScene): preloads animations based on the configuration data, including animations with
- * multiple directions.
- * - preloadAnimationsInDirections(data, uiScene): preloads animations in different directions based on the
- * configuration data.
- * - preloadSpriteInDirection(uiScene, data, direction): preloads a sprite in a specific direction based on the
- * configuration data.
- * - createAnimation(data, uiScene): creates animations based on the configuration data, including animations with
- * multiple directions.
- * - createWithMultipleDirections(uiScene, data, animDir): creates animations with multiple directions based on the
- * configuration data.
- * - createWithDirection(data, uiScene, direction = false): creates animations in a specific direction based on the
- * configuration data.
- * - prepareAnimationData(data, uiScene, direction = false): prepares the animation data based on the configuration
- * data and direction.
- * - getAnimationKey(data, direction = false): gets the animation key based on the configuration data and direction.
- *
- * Fields:
- * - gameManager: the game manager object.
- * - events: the events manager object.
- * - gameDom: the game DOM object.
- * - initialGameData: the initial game data object.
- * - levelsAnimConfig: the levels animations configuration object.
- * - skillsAnimConfig: the skills animations configuration object.
- * - assetsCustomActionsSpritesPath: the path to the custom actions sprites assets.
- *
*/
const { Logger, sc } = require('@reldens/utils');
@@ -79,7 +37,12 @@ class PreloaderHandler
'assetsCustomActionsSpritesPath',
'assets/custom/actions/sprites/'
);
- this.gameManager.loadedAssets = {};
+ if(!this.gameManager.loadedAssets){
+ this.gameManager.loadedAssets = {};
+ }
+ if(!this.gameManager.createdAnimations){
+ this.gameManager.createdAnimations = {};
+ }
}
loadContents(uiScene)
@@ -127,34 +90,38 @@ class PreloaderHandler
{
let classesData = sc.get(this.initialGameData, 'classesData', false);
if(!classesData){
+ Logger.debug('Classes data not found. Fallback to player avatar.');
return false;
}
if(!this.gameManager.mappedAvatars){
this.gameManager.mappedAvatars = {};
}
+ Logger.debug({availableClassesData: classesData});
for(let i of Object.keys(classesData)){
let avatarKey = classesData[i].key;
if(!this.gameManager.loadedAssets[avatarKey]){
+ avatarKey = GameConst.IMAGE_PLAYER;
Logger.info('Avatar for class path "'+avatarKey+'" not found in assets. Fallback to player avatar.');
- this.gameManager.mappedAvatars[avatarKey] = GameConst.IMAGE_PLAYER;
- continue;
}
this.gameManager.mappedAvatars[avatarKey] = avatarKey;
- return preloadScene.createPlayerAnimations(avatarKey);
+ preloadScene.createPlayerAnimations(avatarKey);
}
+ return this.gameManager.mappedAvatars;
}
loopAnimationsAnd(animations, command, uiScene)
{
if(!animations){
+ Logger.warning('Animations not found.', animations);
return false;
}
for(let i of Object.keys(animations)){
let data = animations[i];
if(!data.animationData.enabled){
+ Logger.debug('Animation "'+i+'" not enabled, skipping.', data);
continue;
}
- // preloadAnimation or createAnimation
+ Logger.debug({[command+'Animation']: data});
this[command+'Animation'](data, uiScene);
}
}
@@ -242,19 +209,24 @@ class PreloaderHandler
}
}
- createWithDirection(data, uiScene, direction = false)
+ createWithDirection(data, uiScene, direction = '')
{
let animationCreateData = this.prepareAnimationData(data, uiScene, direction);
- let animation = uiScene.anims.create(animationCreateData);
+ if(this.gameManager.createdAnimations[animationCreateData.key]){
+ return this.gameManager.createdAnimations[animationCreateData.key];
+ }
+ let newAnimation = uiScene.anims.create(animationCreateData);
if(sc.hasOwn(data.animationData, 'destroyTime')){
- animation.destroyTime = data.animationData.destroyTime;
+ newAnimation.destroyTime = data.animationData.destroyTime;
}
if(sc.hasOwn(data.animationData, 'depthByPlayer')){
- animation.depthByPlayer = data.animationData.depthByPlayer;
+ newAnimation.depthByPlayer = data.animationData.depthByPlayer;
}
+ this.gameManager.createdAnimations[animationCreateData.key] = newAnimation;
+ return this.gameManager.createdAnimations[animationCreateData.key];
}
- prepareAnimationData(data, uiScene, direction = false)
+ prepareAnimationData(data, uiScene, direction = '')
{
// @NOTE: here we use have two keys, the animation key and the animationData.img, this is because we could have
// a single sprite with multiple attacks, and use the start and end frame to run the required one.
@@ -275,9 +247,9 @@ class PreloaderHandler
return animationCreateData;
}
- getAnimationKey(data, direction = false)
+ getAnimationKey(data, direction = '')
{
- return (data.skillKey ? data.skillKey+'_' : '')+data.key+(direction ? '_'+direction : '');
+ return (data.skillKey ? data.skillKey+'_' : '')+data.key+(direction && '' !== direction ? '_'+direction : '');
}
}
diff --git a/lib/actions/client/receiver-wrapper.js b/lib/actions/client/receiver-wrapper.js
index fb43fc8e2..aaef470ee 100644
--- a/lib/actions/client/receiver-wrapper.js
+++ b/lib/actions/client/receiver-wrapper.js
@@ -156,9 +156,7 @@ class ReceiverWrapper extends Receiver
targetSprite.moveSprites[hitAnimKey + '_' + targetSpriteId] = hitSprite;
}
let animData = allAnimations[hitAnimKey];
- let depth = 'above' === sc.get(animData.animationData, 'depthByPlayer', '')
- ? targetSprite.depth + 100
- : targetSprite.depth - 0.1;
+ let depth = targetSprite.depth+('above' === sc.get(animData.animationData, 'depthByPlayer', '') ? 100 : -0.1);
hitSprite.depthByPlayer = animData.animationData.depthByPlayer;
hitSprite.setDepth(depth);
return hitSprite;
@@ -270,7 +268,10 @@ class ReceiverWrapper extends Receiver
let sceneAnimation = currentScene.getAnimationByKey(animationKey);
if(!sceneAnimation){
if(-1 === animationKey.indexOf('default')){
- Logger.error('Animation sprite not found', animationKey);
+ Logger.error(
+ 'Animation sprite not found for "'+animationKey+'".',
+ this.gameManager.config.client.skills.animations
+ );
}
return false;
}
diff --git a/lib/actions/server/battle.js b/lib/actions/server/battle.js
index b1a4d7e31..2e447a380 100644
--- a/lib/actions/server/battle.js
+++ b/lib/actions/server/battle.js
@@ -32,17 +32,20 @@ class Battle
async runBattle(playerSchema, target)
{
if(GameConst.STATUS.ACTIVE !== playerSchema.inState){
- Logger.info('Battle inactive player.', playerSchema.inState);
+ Logger.error('Battle inactive player with ID "'+playerSchema.player_id+'".', playerSchema.inState);
return false;
}
- if(target.inState && GameConst.STATUS.ACTIVE !== target.inState){
- Logger.info('Battle inactive target.', target.inState);
+ if(target.inState && GameConst.STATUS.ACTIVE.toString() !== target.inState.toString()){
+ Logger.error(
+ 'Inactive target ID "'+(target.uid || target.player_id)
+ +'" in state "'+target.inState+'"/"'+GameConst.STATUS.ACTIVE+'".'
+ );
return false;
}
// @NOTE: each attack will have different properties to validate like range, delay, etc.
let currentAction = this.getCurrentAction(playerSchema);
if(!currentAction){
- Logger.error(['Actions not defined for this player.', 'ID:', playerSchema.player_id]);
+ Logger.error('Actions not defined for this player with ID "'+playerSchema.player_id+'".');
return false;
}
currentAction.currentBattle = this;
@@ -92,6 +95,10 @@ class Battle
async clientDeathUpdate(targetSchema, room, targetClient, affectedProperty)
{
+ if(!targetSchema.player_id){
+ Logger.error('Target is not a player.', targetSchema.player_id);
+ return false;
+ }
targetSchema.inState = GameConst.STATUS.DEATH;
let actionData = new BattleEndAction(
targetSchema.state.x,
@@ -105,14 +112,20 @@ class Battle
await room.savePlayerState(targetSchema.sessionId);
targetClient.send('*', {act: GameConst.GAME_OVER});
await room.savePlayerStats(targetSchema, targetClient);
- setTimeout(async () => {
- room.roomWorld.addBody(body);
- targetSchema.inState = GameConst.STATUS.ACTIVE;
- // player is dead! reinitialize the stats using its base value:
- targetSchema.stats[affectedProperty] = targetSchema.statsBase[affectedProperty];
- await room.savePlayerStats(targetSchema, targetClient);
- room.broadcast('*', {act: GameConst.REVIVED, t: targetSchema.sessionId});
- }, (room.config.get('server/players/gameOver/timeOut') || 1));
+ targetSchema.setPrivate(
+ 'playerDeathTimer',
+ setTimeout(
+ async () => {
+ room.roomWorld.addBody(body);
+ targetSchema.inState = GameConst.STATUS.ACTIVE;
+ // player is dead! reinitialize the stats using its base value:
+ targetSchema.stats[affectedProperty] = targetSchema.statsBase[affectedProperty];
+ await room.savePlayerStats(targetSchema, targetClient);
+ room.broadcast('*', {act: GameConst.REVIVED, t: targetSchema.sessionId});
+ },
+ (room.config.get('server/players/gameOver/timeOut') || 1)
+ )
+ );
return false;
}
}
diff --git a/lib/actions/server/event-listeners.js b/lib/actions/server/event-listeners.js
index 7a084fa9b..760d5128a 100644
--- a/lib/actions/server/event-listeners.js
+++ b/lib/actions/server/event-listeners.js
@@ -5,7 +5,7 @@
*/
const { SkillsEvents } = require('@reldens/skills');
-const { sc } = require('@reldens/utils');
+const { Logger, sc } = require('@reldens/utils');
class EventListeners
{
@@ -13,6 +13,10 @@ class EventListeners
static async attachCastMovementEvents(props)
{
let {classPath, events, actionsPlugin} = props;
+ if(!classPath || !events || !actionsPlugin){
+ Logger.critical('EventListeners: classPath, events or actionsPlugin undefined.', props);
+ return;
+ }
let ownerId = classPath.getOwnerEventKey();
classPath.listenEvent(
SkillsEvents.SKILL_BEFORE_CAST,
@@ -22,7 +26,7 @@ class EventListeners
}
skill.owner.physicalBody.isBlocked = true;
},
- 'skillBeforeCastPack',
+ classPath.getOwnerUniqueEventKey('skillBeforeCastPack'),
ownerId
);
classPath.listenEvent(
@@ -33,7 +37,7 @@ class EventListeners
}
skill.owner.physicalBody.isBlocked = false;
},
- 'skillAfterCastPack',
+ classPath.getOwnerUniqueEventKey('skillAfterCastPack'),
ownerId
);
await events.emit('reldens.actionsPrepareEventsListeners', actionsPlugin, classPath);
diff --git a/lib/actions/server/player-enricher.js b/lib/actions/server/player-enricher.js
index 44f88711c..f6d3d7c11 100644
--- a/lib/actions/server/player-enricher.js
+++ b/lib/actions/server/player-enricher.js
@@ -45,10 +45,13 @@ class PlayerEnricher
currentPlayer.getSkillExtraData = (params) => {
return SkillsExtraData.extractSkillExtraData(params);
};
- currentPlayer.executePhysicalSkill = this.playerExecutePhysicalSkillCallback(currentPlayer, room);
+ currentPlayer.executePhysicalSkill = this.playerExecutePhysicalSkillCallback(
+ currentPlayer,
+ room.config.client.skills.animations
+ );
}
- static playerExecutePhysicalSkillCallback(currentPlayer, room)
+ static playerExecutePhysicalSkillCallback(currentPlayer, skillsAnimationsData)
{
return async (target, executedSkill) => {
let messageData = Object.assign({skillKey: executedSkill.key}, executedSkill.owner.getPosition());
@@ -64,7 +67,7 @@ class PlayerEnricher
);
let from = {x: currentPlayer.state.x, y: currentPlayer.state.y};
executedSkill.initialPosition = from;
- let animData = sc.get(room.config.client.skills.animations, executedSkill.key + '_bullet', false);
+ let animData = sc.get(skillsAnimationsData, executedSkill.key + '_bullet', false);
if(animData){
executedSkill.animDir = sc.get(animData.animationData, 'dir', false);
}
diff --git a/lib/actions/server/plugin.js b/lib/actions/server/plugin.js
index ff00e9a0d..3b6b77cde 100644
--- a/lib/actions/server/plugin.js
+++ b/lib/actions/server/plugin.js
@@ -36,39 +36,54 @@ class ActionsPlugin extends PluginInterface
if(!this.events){
return false;
}
- this.events.on('reldens.serverReady', async (event) => {
- await DataLoader.enrichConfig(event.serverManager.configManager, this.skillsModelsManager, this.dataServer);
- });
- this.events.on('reldens.beforeSuperInitialGameData', async (superInitialGameData, roomGame) => {
- await InitialGameDataEnricher.withClassPathLabels(roomGame, superInitialGameData);
- await PlayerEnricher.withClassPath(roomGame, superInitialGameData, this.dataServer);
- });
- this.events.on('reldens.roomsMessageActionsByRoom', async (roomMessageActions) => {
- roomMessageActions.actions = new ActionsMessageActions();
+ this.events.on('reldens.serverReady', this.serverReadyDataLoaderEnrichConfig.bind(this));
+ this.events.on('reldens.beforeSuperInitialGameData', this.enrichInitialGameDataWithClassPathData.bind(this));
+ this.events.on('reldens.roomsMessageActionsByRoom', this.appendRoomActions.bind(this));
+ this.events.on('reldens.createdPlayerSchema', this.enrichPlayerWithSkillsAndActions.bind(this));
+ this.events.on('reldens.createdNewPlayer', this.createPlayerClassPath.bind(this));
+ }
+
+ async serverReadyDataLoaderEnrichConfig(event)
+ {
+ await DataLoader.enrichConfig(event.serverManager.configManager, this.skillsModelsManager, this.dataServer);
+ }
+
+ async enrichInitialGameDataWithClassPathData(superInitialGameData, roomGame)
+ {
+ await InitialGameDataEnricher.withClassPathLabels(roomGame, superInitialGameData);
+ await PlayerEnricher.withClassPath(roomGame, superInitialGameData, this.dataServer);
+ }
+
+ async appendRoomActions(roomMessageActions)
+ {
+ roomMessageActions.actions = new ActionsMessageActions();
+ }
+
+ async enrichPlayerWithSkillsAndActions(client, userModel, currentPlayer, room)
+ {
+ await PlayerEnricher.withActions(currentPlayer, room, this.events);
+ await PlayerEnricher.withSkillsServerAndClassPath({
+ client,
+ room,
+ skillsModelsManager: this.skillsModelsManager,
+ currentPlayer,
+ dataServer: this.dataServer,
+ events: this.events
});
- this.events.on('reldens.createdPlayerSchema', async (client, userModel, currentPlayer, room) => {
- await PlayerEnricher.withActions(currentPlayer, room, this.events);
- await PlayerEnricher.withSkillsServerAndClassPath({
- client,
- currentPlayer,
- room,
- skillsModelsManager: this.skillsModelsManager,
- dataServer: this.dataServer,
- events: this.events
- });
- await EventListeners.attachCastMovementEvents({
- classPath: currentPlayer.skillsServer.classPath,
- events: this.events,
- actionsPlugin: this
- });
+ await EventListeners.attachCastMovementEvents({
+ classPath: currentPlayer.skillsServer.classPath,
+ events: this.events,
+ actionsPlugin: this
});
- this.events.on('reldens.createdNewPlayer', async (player, loginData, loginManager) => {
- return PlayerClassPathHandler.createFromLoginData({
- loginManager,
- loginData,
- player,
- dataServer: this.dataServer
- });
+ }
+
+ async createPlayerClassPath(player, loginData, loginManager)
+ {
+ return PlayerClassPathHandler.createFromLoginData({
+ loginManager,
+ loginData,
+ player,
+ dataServer: this.dataServer
});
}
diff --git a/lib/actions/server/pve.js b/lib/actions/server/pve.js
index beb682216..f926a65c8 100644
--- a/lib/actions/server/pve.js
+++ b/lib/actions/server/pve.js
@@ -51,14 +51,23 @@ class Pve extends Battle
async startBattleWith(playerSchema, room)
{
- // @TODO - BETA - Yeah... a lot could happen and this could be improved by cleaning the timers on specific
- // actions like when player disconnects.
+ if(!this.targetObject){
+ Logger.critical('Target Object reference removed.');
+ return false;
+ }
+ let thisWorldKey = this.targetObject?.objectBody?.world?.worldKey;
+ let targetWorldKey = playerSchema?.physicalBody?.world?.worldKey;
+ if(!thisWorldKey || !targetWorldKey || thisWorldKey !== targetWorldKey){
+ Logger.debug('World keys check failed.', {thisWorldKey, targetWorldKey});
+ return false;
+ }
if(
!room?.roomWorld
|| !room?.state
|| !playerSchema
|| !room.playerBySessionIdFromState(playerSchema.sessionId)
){
+ Logger.debug('Room or player missing references.');
// @NOTE: leaveBattle is used for when the player can't be reached anymore or disconnected.
this.leaveBattle(playerSchema);
return false;
@@ -156,13 +165,18 @@ class Pve extends Battle
leaveBattle(playerSchema)
{
this.removeInBattlePlayer(playerSchema);
+ if(!this.targetObject){
+ Logger.critical('Target Object reference not found.');
+ return false;
+ }
this.targetObject.objectBody.moveToOriginalPoint();
}
async battleEnded(playerSchema, room)
{
// @TODO - BETA - Implement battle end in both PvE and PvP.
- this.targetObject.inState = GameConst.STATUS.DEATH;
+ this.targetObject.objectBody.bodyState.inState = GameConst.STATUS.DEATH;
+ Logger.debug('Battle ended, set target with ID "'+this.targetObject.uid+'" state to "DEATH".');
this.removeInBattlePlayer(playerSchema);
let actionData = new BattleEndAction(
this.targetObject.objectBody.position[0],
diff --git a/lib/actions/server/skills/skills-extra-data.js b/lib/actions/server/skills/skills-extra-data.js
index 54f04bf3d..eb8c0d8b9 100644
--- a/lib/actions/server/skills/skills-extra-data.js
+++ b/lib/actions/server/skills/skills-extra-data.js
@@ -9,6 +9,7 @@ const { sc } = require('@reldens/utils');
class SkillsExtraData
{
+
static extractSkillExtraData(params)
{
let extraData = {};
diff --git a/lib/actions/server/skills/type-attack.js b/lib/actions/server/skills/type-attack.js
index 8d3c66c12..b8a509f14 100644
--- a/lib/actions/server/skills/type-attack.js
+++ b/lib/actions/server/skills/type-attack.js
@@ -13,6 +13,7 @@ class TypeAttack extends Attack
constructor(props)
{
super(props);
+ // @TODO - BETA - Refactor and extract room reference.
this.room = false;
this.currentBattle = false;
}
diff --git a/lib/actions/server/skills/type-effect.js b/lib/actions/server/skills/type-effect.js
index 1d4a424e5..6b8021d78 100644
--- a/lib/actions/server/skills/type-effect.js
+++ b/lib/actions/server/skills/type-effect.js
@@ -13,6 +13,7 @@ class TypeEffect extends Effect
constructor(props)
{
super(props);
+ // @TODO - BETA - Refactor and extract room reference.
this.room = false;
this.currentBattle = false;
}
diff --git a/lib/actions/server/skills/type-physical-attack.js b/lib/actions/server/skills/type-physical-attack.js
index e21b97a1f..b751736d4 100644
--- a/lib/actions/server/skills/type-physical-attack.js
+++ b/lib/actions/server/skills/type-physical-attack.js
@@ -13,6 +13,7 @@ class TypePhysicalAttack extends PhysicalAttack
constructor(props)
{
super(props);
+ // @TODO - BETA - Refactor and extract room reference.
this.room = false;
this.currentBattle = false;
// @NOTE: hit priority is something specifically from reldens physics engine, in order to change this value you
@@ -87,6 +88,9 @@ class TypePhysicalAttack extends PhysicalAttack
async restartBattle(validDefender)
{
if(!this.validateTargetOnHit && sc.hasOwn(validDefender, 'battle')){
+ if(!validDefender.battle){
+ return;
+ }
// if target validation is disabled then any target could start the battle (pve):
validDefender.battle.targetObject = validDefender;
await validDefender.battle.startBattleWith(this.owner, this.room);
@@ -126,7 +130,7 @@ class TypePhysicalAttack extends PhysicalAttack
{
body.world.removeBodies.push(body);
// @TODO - BETA - Refactor and extract Colyseus into a driver.
- this.room.state.bodies.delete(this.key+'_bullet_'+body.id);
+ this.room.state.removeBody(this.key+'_bullet_'+body.id);
}
}
diff --git a/lib/actions/server/skills/type-physical-effect.js b/lib/actions/server/skills/type-physical-effect.js
index 223770d03..6979ae122 100644
--- a/lib/actions/server/skills/type-physical-effect.js
+++ b/lib/actions/server/skills/type-physical-effect.js
@@ -13,6 +13,7 @@ class TypePhysicalEffect extends PhysicalEffect
constructor(props)
{
super(props);
+ // @TODO - BETA - Refactor and extract room reference.
this.room = false;
this.currentBattle = false;
// @NOTE: hit priority is something specifically from reldens physics engine, in order to change this value you
@@ -76,6 +77,9 @@ class TypePhysicalEffect extends PhysicalEffect
async restartBattle(validDefender)
{
if(!this.validateTargetOnHit && sc.hasOwn(validDefender, 'battle')){
+ if(!validDefender.battle){
+ return;
+ }
// if target validation is disabled then any target could start the battle (pve):
validDefender.battle.targetObject = validDefender;
await validDefender.battle.startBattleWith(this.owner, this.room);
@@ -112,7 +116,7 @@ class TypePhysicalEffect extends PhysicalEffect
{
body.world.removeBodies.push(body);
// @TODO - BETA - Refactor and extract Colyseus into a driver.
- this.room.state.bodies.delete(this.key+'_bullet_'+body.id);
+ this.room.state.removeBody(this.key+'_bullet_'+body.id);
}
}
diff --git a/lib/ads/client/plugin.js b/lib/ads/client/plugin.js
index e9a7bc0dd..266f3c41e 100644
--- a/lib/ads/client/plugin.js
+++ b/lib/ads/client/plugin.js
@@ -52,13 +52,13 @@ class AdsPlugin extends PluginInterface
let providers = sc.get(this.config, 'providers', {});
let providersKeys = Object.keys(providers);
if(0 === providersKeys.length){
- Logger.info('None ads providers configured.', this.config);
+ Logger.debug('None ads providers configured.', this.config);
return false;
}
for(let i of providersKeys){
let provider = providers[i];
if(!provider.enabled){
- Logger.info({'Provider disabled': providers});
+ Logger.debug({'Provider disabled': providers});
continue;
}
provider.classDefinition = sc.get(ProvidersList, i, false);
diff --git a/lib/ads/client/sdk-handler.js b/lib/ads/client/sdk-handler.js
index 308b4782e..3f701b089 100644
--- a/lib/ads/client/sdk-handler.js
+++ b/lib/ads/client/sdk-handler.js
@@ -21,12 +21,12 @@ class SdkHandler
return false;
}
if(!sc.isObject(providers)){
- Logger.info('Providers not available.');
+ Logger.debug('Providers not available.');
return false;
}
let keys = Object.keys(providers);
if(0 === keys.length){
- Logger.info('Providers not found.');
+ Logger.debug('Providers not found.');
return false;
}
for(let i of keys){
@@ -41,7 +41,7 @@ class SdkHandler
{
let sdkUrl = sc.get(provider, 'sdkUrl', '');
if('' === sdkUrl){
- Logger.info('Provider does not have an SDK URL.', provider);
+ Logger.debug('Provider does not have an SDK URL.', provider);
return false;
}
let body = this.gameDom.getElement('body');
diff --git a/lib/chat/server/event-listener/npc-skills.js b/lib/chat/server/event-listener/npc-skills.js
index 15244ae60..f31c47b51 100644
--- a/lib/chat/server/event-listener/npc-skills.js
+++ b/lib/chat/server/event-listener/npc-skills.js
@@ -4,11 +4,11 @@
*
*/
-const { SkillsEvents, SkillConst } = require('@reldens/skills');
-const { sc } = require('@reldens/utils');
const { NpcDamageCallback } = require('../messages/npc-damage-callback');
const { NpcModifiersCallback } = require('../messages/npc-modifiers-callback');
const { NpcDodgeCallback } = require('../messages/npc-dodge-callback');
+const { SkillsEvents, SkillConst } = require('@reldens/skills');
+const { sc } = require('@reldens/utils');
class NpcSkills
{
@@ -16,8 +16,8 @@ class NpcSkills
static listenEvents(props, chatConfig, chatManager)
{
let skillsByType = this.fetchSkillsByType(props, chatConfig);
- let attackSkill = sc.get(skillsByType, SkillConst.SKILL_TYPE_ATTACK, null);
- let effectSkill = sc.get(skillsByType, SkillConst.SKILL_TYPE_EFFECT, null);
+ let attackSkill = sc.get(skillsByType, SkillConst.SKILL.TYPE.ATTACK, null);
+ let effectSkill = sc.get(skillsByType, SkillConst.SKILL.TYPE.EFFECT, null);
this.listenDamageEvent(attackSkill, chatConfig, chatManager);
this.listenModifiersEvent(effectSkill, chatConfig, chatManager);
this.listenAfterRunLogicEvent((attackSkill || effectSkill), chatConfig, chatManager);
@@ -36,7 +36,8 @@ class NpcSkills
}
await NpcDamageCallback.sendMessage({skill, target, damage, chatManager});
},
- 'skillAttackApplyDamageChat',
+ attackSkill.getOwnerUniqueEventKey('skillAttackApplyDamageChat'),
+ // @NOTE: objects ownerIdProperty is their uid and that's used as master key for the object event listeners.
attackSkill.owner[attackSkill.ownerIdProperty]
);
}
@@ -51,7 +52,8 @@ class NpcSkills
async (skill) => {
await NpcModifiersCallback.sendMessage({skill, chatManager});
},
- 'skillApplyModifiersChat',
+ effectSkill.getOwnerUniqueEventKey('skillApplyModifiersChat'),
+ // @NOTE: objects ownerIdProperty is their uid and that's used as master key for the object event listeners.
effectSkill.owner[effectSkill.ownerIdProperty]
);
}
@@ -69,7 +71,8 @@ class NpcSkills
}
await NpcDodgeCallback.sendMessage({skill, chatManager});
},
- 'skillDodgeChat',
+ skillForLogic.getOwnerUniqueEventKey('skillDodgeChat'),
+ // @NOTE: objects ownerIdProperty is their uid and that's used as master key for the object event listeners.
skillForLogic.owner[skillForLogic.ownerIdProperty]
);
}
@@ -87,11 +90,11 @@ class NpcSkills
if(sc.hasOwn(skillsByType, skill.type)){
continue;
}
- if(SkillConst.SKILL_TYPE_ATTACK === skill.type || SkillConst.SKILL_TYPE_ATTACK === skill.parentType){
- skillsByType[SkillConst.SKILL_TYPE_ATTACK] = skill;
+ if(SkillConst.SKILL.TYPE.ATTACK === skill.type || SkillConst.SKILL.TYPE.ATTACK === skill.parentType){
+ skillsByType[SkillConst.SKILL.TYPE.ATTACK] = skill;
}
- if(SkillConst.SKILL_TYPE_EFFECT === skill.type || SkillConst.SKILL_TYPE_EFFECT === skill.parentType){
- skillsByType[SkillConst.SKILL_TYPE_EFFECT] = skill;
+ if(SkillConst.SKILL.TYPE.EFFECT === skill.type || SkillConst.SKILL.TYPE.EFFECT === skill.parentType){
+ skillsByType[SkillConst.SKILL.TYPE.EFFECT] = skill;
}
let totalValidTypes = sc.get(chatConfig, 'totalValidTypes', 2);
if(totalValidTypes === Object.keys(skillsByType).length){
diff --git a/lib/chat/server/event-listener/player-skills.js b/lib/chat/server/event-listener/player-skills.js
index 560714b0a..478914e4c 100644
--- a/lib/chat/server/event-listener/player-skills.js
+++ b/lib/chat/server/event-listener/player-skills.js
@@ -4,10 +4,10 @@
*
*/
-const { SkillsEvents, SkillConst } = require('@reldens/skills');
const { PlayerDamageCallback } = require('../messages/player-damage-callback');
const { PlayerModifiersCallback } = require('../messages/player-modifiers-callback');
const { PlayerDodgeCallback } = require('../messages/player-dodge-callback');
+const { SkillsEvents, SkillConst } = require('@reldens/skills');
class PlayerSkills
{
@@ -38,8 +38,8 @@ class PlayerSkills
chatManager: chatManager
});
},
- 'skillAttackApplyDamageChat',
- classPath.owner[classPath.ownerIdProperty]
+ classPath.getOwnerUniqueEventKey('skillAttackApplyDamageChat'),
+ classPath.getOwnerEventKey()
);
}
@@ -57,8 +57,8 @@ class PlayerSkills
chatManager: chatManager
});
},
- 'skillApplyModifiersChat',
- classPath.owner[classPath.ownerIdProperty]
+ classPath.getOwnerUniqueEventKey('skillApplyModifiersChat'),
+ classPath.getOwnerEventKey()
);
}
@@ -79,8 +79,8 @@ class PlayerSkills
chatManager: chatManager
});
},
- 'skillDodgeChat',
- classPath.owner[classPath.ownerIdProperty]
+ classPath.getOwnerUniqueEventKey('skillDodgeChat'),
+ classPath.getOwnerEventKey()
);
}
diff --git a/lib/chat/server/messages/npc-modifiers-callback.js b/lib/chat/server/messages/npc-modifiers-callback.js
index 7e0aad01b..f0ed0c1a2 100644
--- a/lib/chat/server/messages/npc-modifiers-callback.js
+++ b/lib/chat/server/messages/npc-modifiers-callback.js
@@ -39,7 +39,7 @@ class NpcModifiersCallback
for(let i of appliedModifiersKeys){
let value = lastAppliedModifiers[i];
let property = i.split('/').pop();
- messageData.push({[property]: value});
+ messageData[property] = value;
}
let isObjectOwner = sc.hasOwn(skill.owner, 'key');
let from = isObjectOwner ? skill.owner.title : skill.owner.playerName;
diff --git a/lib/chat/server/messages/player-modifiers-callback.js b/lib/chat/server/messages/player-modifiers-callback.js
index eb0a960bb..b0339c321 100644
--- a/lib/chat/server/messages/player-modifiers-callback.js
+++ b/lib/chat/server/messages/player-modifiers-callback.js
@@ -34,7 +34,7 @@ class PlayerModifiersCallback
for(let i of appliedModifiersKeys){
let value = lastAppliedModifiers[i];
let property = i.split('/').pop();
- messageData.push({[property]: value});
+ messageData[property] = value;
}
let messageObject = MessageFactory.create(ChatConst.TYPES.SKILL, message, messageData, skill.owner.playerName);
client.send(messageObject);
diff --git a/lib/game/client/room-events.js b/lib/game/client/room-events.js
index 2535c6366..98889ca5e 100644
--- a/lib/game/client/room-events.js
+++ b/lib/game/client/room-events.js
@@ -159,7 +159,9 @@ class RoomEvents
{
// do not move the player if it is changing the scene:
if(player.state.scene !== this.roomName){
- Logger.info('Player scene miss match.', {playerScene: player.state.scene, currentScene: this.roomName});
+ if(!this.gameManager.isChangingScene){
+ Logger.info('Player scene miss match.', {playerScene: player.state.scene, currentScene: this.roomName});
+ }
return;
}
let currentScene = this.getActiveScene();
diff --git a/lib/game/client/scene-dynamic.js b/lib/game/client/scene-dynamic.js
index 366887f87..5235463ad 100644
--- a/lib/game/client/scene-dynamic.js
+++ b/lib/game/client/scene-dynamic.js
@@ -304,10 +304,7 @@ class SceneDynamic extends Scene
}
let newX = Phaser.Math.Linear(entity.x, (entityState.x - this.player.leftOff), this.interpolationSpeed);
let newY = Phaser.Math.Linear(entity.y, (entityState.y - this.player.topOff), this.interpolationSpeed);
- this.player.updateSpritePosition(entity, newX, newY);
- this.player.playPlayerAnimation(entity, Object.assign({}, entityState, {x: newX, y: newY}));
- this.player.stopPlayerAnimation(entity, entityState);
- this.player.updatePlayerState(entity, entity, i);
+ this.player.processPlayerPositionAnimationUpdate(entity, entityState, i, newX, newY);
delete this.interpolatePlayersPosition[i];
}
}
@@ -499,7 +496,8 @@ class SceneDynamic extends Scene
getAnimationByKey(key)
{
- if(!this.anims || !this.anims.anims || !this.anims.anims.entries){
+ if(!this.anims || !this.anims?.anims || !this.anims?.anims?.entries){
+ Logger.error('Animations not loaded.', this.anims);
return false;
}
return sc.get(this.anims.anims.entries, key, false);
diff --git a/lib/game/client/scene-preloader.js b/lib/game/client/scene-preloader.js
index efe00d281..b0c8a2e9c 100644
--- a/lib/game/client/scene-preloader.js
+++ b/lib/game/client/scene-preloader.js
@@ -32,6 +32,9 @@ class ScenePreloader extends Scene
this.preloadAssets = props.preloadAssets;
this.directionalAnimations = {};
this.objectsAnimations = {};
+ if(!this.gameManager.createdAnimations){
+ this.gameManager.createdAnimations = {};
+ }
let currentScene = this.gameManager.activeRoomEvents.getActiveScene();
currentScene.objectsAnimationsData = props.objectsAnimationsData;
this.playerSpriteSize = {
@@ -77,8 +80,10 @@ class ScenePreloader extends Scene
if(!this.gameManager.config.get('client/ui/pointer/show')){
return;
}
- // @TODO - BETA - Make pointer sprite data configurable.
- let pointerData = {frameWidth: 32, frameHeight: 32};
+ let pointerData = {
+ frameWidth: this.gameManager.config.getWithoutLogs('client/general/assets/arrowDownFrameWidth', 32),
+ frameHeight: this.gameManager.config.getWithoutLogs('client/general/assets/arrowDownFrameHeight', 32)
+ };
this.load.spritesheet(
GameConst.ARROW_DOWN,
this.gameManager.config.get('client/general/assets/arrowDownPath', '/assets/sprites/arrow-down.png'),
@@ -363,13 +368,17 @@ class ScenePreloader extends Scene
createAnimationWith(anim)
{
- this.anims.create({
+ if(this.gameManager.createdAnimations[anim.k]){
+ return;
+ }
+ this.gameManager.createdAnimations[anim.k] = this.anims.create({
key: anim.k,
frames: this.anims.generateFrameNumbers(anim.img, {start: anim.start, end: anim.end}),
frameRate: sc.hasOwn(anim, 'rate') ? anim.rate : this.configuredFrameRate,
repeat: anim.repeat,
hideOnComplete: sc.hasOwn(anim, 'hide') ? anim.hide : true,
});
+ return this.gameManager.createdAnimations[anim.k];
}
registerControllers(controllersBox)
diff --git a/lib/game/server/install-templates/.env.dist b/lib/game/server/install-templates/.env.dist
index a27f28b8c..19827db16 100644
--- a/lib/game/server/install-templates/.env.dist
+++ b/lib/game/server/install-templates/.env.dist
@@ -37,8 +37,8 @@ RELDENS_DB_LIMIT=0
# If you don't want to specify the string you can pass options to be append to the automatically generated string.
# RELDENS_DB_CONNECT_STRING_OPTIONS=authSource=reldens&readPreference=primary&appname=MongoDB%20Compass&ssl=false
# Logs:
-RELDENS_LOG_LEVEL=9
-RELDENS_ENABLE_TRACE_FOR=emergency,alert,critical,error,warning
+RELDENS_LOG_LEVEL=7
+RELDENS_ENABLE_TRACE_FOR=emergency,alert,critical
# Mailer:
RELDENS_MAILER_ENABLE={{&mailer-enable}}
RELDENS_MAILER_SERVICE={{&mailer-service}}
diff --git a/lib/game/server/theme-manager.js b/lib/game/server/theme-manager.js
index 065753bb3..75fc9db12 100644
--- a/lib/game/server/theme-manager.js
+++ b/lib/game/server/theme-manager.js
@@ -365,7 +365,7 @@ class ThemeManager
sourceMaps: false,
distEntry: entryPath,
distDir: this.distPath,
- isLibrary: true,
+ isLibrary: false,
outputFormat: 'esmodule'
}
};
diff --git a/lib/inventory/client/inventory-receiver.js b/lib/inventory/client/inventory-receiver.js
index c9ee315f6..e15c1783c 100644
--- a/lib/inventory/client/inventory-receiver.js
+++ b/lib/inventory/client/inventory-receiver.js
@@ -20,6 +20,7 @@ class InventoryReceiver extends Receiver
super(props);
this.gameManager = props.gameManager;
this.itemSprites = {};
+ this.itemsAnimations = {};
}
onExecuting(message)
@@ -27,16 +28,28 @@ class InventoryReceiver extends Receiver
// @TODO - BETA - Improve, split in several classes, methods and functionalities.
let item = message.item;
if(!sc.hasOwn(item, 'animationData')){
+ Logger.warning('Item does not contain animation data.', message);
return false;
}
let animKey = InventoryConst.ANIMATION_KEY_PREFIX+item.key;
let currentScene = this.gameManager.getActiveScene();
+ let existentAnimation = this.itemSprites[animKey]
+ && this.itemSprites[animKey].anims
+ && currentScene.anims.get(animKey);
+ if(existentAnimation){
+ Logger.debug('Animation already exists, playing: '+animKey);
+ this.playSpriteAnimation(animKey, item);
+ return false;
+ }
// @TODO - BETA - Remove hardcoded file extension.
currentScene.load.spritesheet(animKey, '/assets/custom/sprites/'+item.key+GameConst.FILES.EXTENSIONS.PNG, {
frameWidth: item.animationData.frameWidth || 64,
frameHeight: item.animationData.frameHeight || 64
+ }).on('loaderror', (event) => {
+ Logger.error('Sprite load error: '+animKey, event);
});
currentScene.load.on('complete', () => {
+ Logger.debug('Scene load complete, playing: '+animKey);
this.createItemSprites(animKey, item, message, currentScene);
});
currentScene.load.start();
@@ -44,14 +57,6 @@ class InventoryReceiver extends Receiver
createItemSprites(animKey, item, message, currentScene)
{
- if(this.itemSprites[animKey] && sc.hasOwn(this.itemSprites, animKey)){
- if(!item.animationData.destroyOnComplete){
- this.itemSprites[animKey].anims.play(animKey, false);
- return;
- }
- Logger.info('Sprite already running for item: '+animKey);
- return false;
- }
let targetId = this.extractTargetId(item, message, currentScene);
if(!targetId){
Logger.error('Target ID not found.');
@@ -63,51 +68,74 @@ class InventoryReceiver extends Receiver
return false;
}
// @TODO - BETA - Make all the defaults configurable.
- currentScene.anims.create({
- key: animKey,
- frames: currentScene.anims.generateFrameNumbers(animKey, {
- start: item.animationData.start || 0,
- end: item.animationData.end || 1
- }),
- frameRate: sc.get(item.animationData, 'rate', currentScene.configuredFrameRate),
- repeat: item.animationData.repeat || 3,
- hideOnComplete: sc.get(item.animationData, 'hide', true),
- });
- if(item.animationData.closeInventoryOnUse){
- this.gameManager.gameDom.getElement('#inventory-close').click();
+ let animationFromScene = currentScene.anims.get(animKey);
+ if(!animationFromScene){
+ Logger.debug('Creating new animation on scene: '+animKey);
+ animationFromScene = currentScene.anims.create({
+ key: animKey,
+ frames: currentScene.anims.generateFrameNumbers(animKey, {
+ start: item.animationData.start || 0,
+ end: item.animationData.end || 1
+ }),
+ frameRate: sc.get(item.animationData, 'rate', currentScene.configuredFrameRate),
+ repeat: item.animationData.repeat || 3,
+ hideOnComplete: sc.get(item.animationData, 'hide', true),
+ showOnStart: sc.get(item.animationData, 'showOnStart', true),
+ });
}
+ this.itemsAnimations[animKey] = animationFromScene;
let x = sc.get(item.animationData, 'fixedX', (item.animationData.usePlayerPosition ? playerSprite.x : 0));
let y = sc.get(item.animationData, 'fixedY', (item.animationData.usePlayerPosition ? playerSprite.y : 0));
this.itemSprites[animKey] = currentScene.physics.add.sprite(x, y, animKey);
- this.itemSprites[animKey].setDepth(1000000);
+ this.itemSprites[animKey] = this.itemSprites[animKey].setDepth(90000);
+ this.itemSprites[animKey].depthByPlayer = 'above';
if(item.animationData.followPlayer){
playerSprite.moveSprites[animKey] = this.itemSprites[animKey];
}
// @TODO - BETA - Make auto-destroy configurable.
- this.itemSprites[animKey].anims.play(animKey, false).on('animationcomplete', () => {
- this.destroyAnimation(item, animKey, playerSprite);
+ Logger.debug('Playing sprite: '+animKey);
+ this.playSpriteAnimation(animKey, item).on('animationcomplete', () => {
+ if(item.animationData.destroyOnComplete){
+ this.destroyAnimation(item, animKey, playerSprite);
+ }
});
}
- extractTargetId(item, message, currentScene)
+ playSpriteAnimation(animKey, item)
{
- if(item.animationData.startsOnTarget && message.target?.playerId){
- return message.target.playerId;
+ // @TODO - BETA - Make closeInventoryOnUse and ignoreIfPlaying default values configurable.
+ let closeInventoryOnUse = sc.get(item.animationData, 'closeInventoryOnUse', false);
+ if(closeInventoryOnUse){
+ this.gameManager.gameDom.getElement('#inventory-close')?.click();
}
- return currentScene.player?.playerId || false;
+ let spriteAnims = this.itemSprites[animKey].anims;
+ if(!spriteAnims){
+ Logger.error('Sprite animation not found: '+animKey);
+ return false;
+ }
+ spriteAnims.visible = true;
+ return spriteAnims.play(animKey, sc.get(item.animationData, 'ignoreIfPlaying', true));
}
destroyAnimation(item, animKey, playerSprite)
{
- if(!item.animationData.destroyOnComplete){
- return;
- }
this.itemSprites[animKey].destroy();
delete this.itemSprites[animKey];
+ delete this.itemsAnimations[animKey];
if(item.animationData.followPlayer){
delete playerSprite.moveSprites[animKey];
}
+ Logger.debug('Animation and sprite destroyed: '+animKey);
}
+
+ extractTargetId(item, message, currentScene)
+ {
+ if(item.animationData.startsOnTarget && message.target?.playerId){
+ return message.target.playerId;
+ }
+ return currentScene.player?.playerId || false;
+ }
+
}
module.exports.InventoryReceiver = InventoryReceiver;
diff --git a/lib/inventory/client/plugin.js b/lib/inventory/client/plugin.js
index 9c8f490f0..3e572b415 100644
--- a/lib/inventory/client/plugin.js
+++ b/lib/inventory/client/plugin.js
@@ -14,9 +14,9 @@ const { TemplatesHandler } = require('./templates-handler');
const { TranslationsMapper } = require('../../snippets/client/translations-mapper');
const Translations = require('./snippets/en_US');
const { InventoryConst } = require('../constants');
+const { ItemsEvents, ItemsConst } = require('@reldens/items-system');
const { GameConst } = require('../../game/constants');
const { Logger, sc } = require('@reldens/utils');
-const { ItemsEvents, ItemsConst } = require('@reldens/items-system');
class InventoryPlugin extends PluginInterface
{
@@ -160,49 +160,84 @@ class InventoryPlugin extends PluginInterface
listenInventoryEvents(uiScene, inventoryPanel, equipmentPanel)
{
let gameManager = uiScene.gameManager;
- let masterKey = 'p'+gameManager.inventory.manager.getOwnerId();
- gameManager.inventory.manager.listenEvent(ItemsEvents.ADD_ITEM, (inventory, item) => {
- let output = this.createItemBox(item, 'inventoryItem', gameManager, uiScene);
- gameManager.gameDom.appendToElement('#'+InventoryConst.INVENTORY_ITEMS, output);
- this.setupButtonsActions(inventoryPanel, item.getInventoryId(), item, uiScene);
- }, 'addItemPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.SET_ITEMS, (props) => {
- inventoryPanel.innerHTML = '';
- for(let i of Object.keys(props.items)){
- let item = props.items[i];
- this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, i);
- }
- }, 'setItemsPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.MODIFY_ITEM_QTY, (item) => {
- let qtyBox = uiScene.getUiElement('inventory').getChildByID('item-qty-'+item.getInventoryId());
- qtyBox.innerHTML = item.qty;
- }, 'modifyItemQtyPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.REMOVE_ITEM, (inventory, itemKey) => {
- uiScene.getUiElement('inventory').getChildByID('item-'+itemKey).remove();
- }, 'removeItemPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.SET_GROUPS, (props) => {
- // @TODO - BETA - If groups are re-set or updated we will need to update the items as well.
- let reEquipItems = false;
- let equipmentItemsGroups = gameManager.gameDom.getElement('#'+InventoryConst.EQUIPMENT_ITEMS);
- if(equipmentItemsGroups.innerHTML !== ''){
- reEquipItems = true;
- }
- equipmentItemsGroups.innerHTML = '';
- let orderedGroups = this.sortGroups(props.groups);
- for(let i of orderedGroups){
- let output = this.createGroupBox(props.groups[i], gameManager, uiScene);
- gameManager.gameDom.appendToElement('#'+InventoryConst.EQUIPMENT_ITEMS, output);
- }
- if(reEquipItems){
- this.resetEquippedItemsDisplay(gameManager, uiScene, equipmentPanel, inventoryPanel);
- }
- }, 'setGroupsPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.EQUIP_ITEM, (item) => {
- this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, item.getInventoryId());
- }, 'equipItemPack', masterKey);
- gameManager.inventory.manager.listenEvent(ItemsEvents.UNEQUIP_ITEM, (item) => {
- this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, item.getInventoryId());
- }, 'unequipItemPack', masterKey);
+ let masterKey = gameManager.inventory.manager.getOwnerEventKey();
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.ADD_ITEM,
+ (inventory, item) => {
+ let output = this.createItemBox(item, 'inventoryItem', gameManager, uiScene);
+ gameManager.gameDom.appendToElement('#'+InventoryConst.INVENTORY_ITEMS, output);
+ this.setupButtonsActions(inventoryPanel, item.getInventoryId(), item, uiScene);
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('addItemPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.SET_ITEMS,
+ (props) => {
+ inventoryPanel.innerHTML = '';
+ for(let i of Object.keys(props.items)){
+ let item = props.items[i];
+ this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, i);
+ }
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('setItemsPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.MODIFY_ITEM_QTY,
+ (item) => {
+ let qtyBox = uiScene.getUiElement('inventory').getChildByID('item-qty-'+item.getInventoryId());
+ qtyBox.innerHTML = item.qty;
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('modifyItemQtyPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.REMOVE_ITEM,
+ (inventory, itemKey) => {
+ uiScene.getUiElement('inventory').getChildByID('item-'+itemKey).remove();
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('removeItemPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.SET_GROUPS,
+ (props) => {
+ // @TODO - BETA - If groups are re-set or updated we will need to update the items as well.
+ let reEquipItems = false;
+ let equipmentItemsGroups = gameManager.gameDom.getElement('#'+InventoryConst.EQUIPMENT_ITEMS);
+ if(equipmentItemsGroups.innerHTML !== ''){
+ reEquipItems = true;
+ }
+ equipmentItemsGroups.innerHTML = '';
+ let orderedGroups = this.sortGroups(props.groups);
+ for(let i of orderedGroups){
+ let output = this.createGroupBox(props.groups[i], gameManager, uiScene);
+ gameManager.gameDom.appendToElement('#'+InventoryConst.EQUIPMENT_ITEMS, output);
+ }
+ if(reEquipItems){
+ this.resetEquippedItemsDisplay(gameManager, uiScene, equipmentPanel, inventoryPanel);
+ }
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('setGroupsPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.EQUIP_ITEM,
+ (item) => {
+ this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, item.getInventoryId());
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('equipItemPack'),
+ masterKey
+ );
+ gameManager.inventory.manager.listenEvent(
+ ItemsEvents.UNEQUIP_ITEM,
+ (item) => {
+ this.displayItem(item, uiScene, equipmentPanel, inventoryPanel, item.getInventoryId());
+ },
+ gameManager.inventory.manager.getOwnerUniqueEventKey('unequipItemPack'),
+ masterKey
+ );
}
resetEquippedItemsDisplay(gameManager, uiScene, equipmentPanel, inventoryPanel)
diff --git a/lib/objects/client/animation-engine.js b/lib/objects/client/animation-engine.js
index 9afbafa31..ef5dd090d 100644
--- a/lib/objects/client/animation-engine.js
+++ b/lib/objects/client/animation-engine.js
@@ -4,14 +4,14 @@
*
* Objects flow:
*
- * When you create an NpcObject this can/should be set as "interactive", around line 92, after the validation
+ * When you create an NpcObject this can/should be set as "interactive", after the validation
* if(this.isInteractive){
* This will activate the onpointerdown event so when you click on the object it will send the action
* ObjectsConst.OBJECT_INTERACTION
* Along with its own ID and type.
- * The server will pick up this information and validate it on the NpcObject.executeMessageActions method around
- * line 60, and return a UI message to open a UI dialog box, updated with the information coming in the message, see
- * RoomEvents.initUi method.
+ * The server will pick up this information and validate it on the NpcObject.executeMessageActions method, and return
+ * a UI message to open a UI dialog box, updated with the information coming in the message.
+ * See RoomEvents.initUi method.
*
*/
@@ -25,6 +25,7 @@ class AnimationEngine
constructor(gameManager, props, currentPreloader)
{
this.currentPreloader = currentPreloader;
+ this.currentAnimation = false;
this.gameManager = gameManager;
this.enabled = props.enabled || false;
this.key = props.key;
@@ -40,6 +41,9 @@ class AnimationEngine
this.y = props.y || 0;
this.repeat = isNaN(props.repeat) ? -1 : props.repeat;
this.hideOnComplete = props.hideOnComplete || false;
+ if(!this.gameManager.createdAnimations){
+ this.gameManager.createdAnimations = {};
+ }
// @NOTE: you cannot combine destroyOnComplete with repeat = -1, because an animation with infinite
// repetitions will never trigger the complete event.
this.destroyOnComplete = props.destroyOnComplete || false;
@@ -109,19 +113,24 @@ class AnimationEngine
if(this.zeroPad !== false){
animationData.zeroPad = this.zeroPad;
}
- this.frameNumbers = this.currentPreloader.anims.generateFrameNumbers(this.asset_key, animationData);
+ let frameNumbers = this.currentPreloader.anims.generateFrameNumbers(this.asset_key, animationData);
let createData = {
key: this.key,
- frames: this.frameNumbers,
+ frames: frameNumbers,
frameRate: this.frameRate,
repeat: this.repeat,
hideOnComplete: this.hideOnComplete
};
- this.currentAnimation = this.currentPreloader.anims.create(createData);
+ this.currentAnimation = this.gameManager.createdAnimations[this.key];
+ if(!this.currentAnimation){
+ Logger.debug('Creating animation: '+this.key);
+ this.currentAnimation = this.currentPreloader.anims.create(createData);
+ }
this.currentPreloader.objectsAnimations[this.key] = this.currentAnimation;
+ this.gameManager.createdAnimations[this.key] = this.currentAnimation;
let spriteX = this.positionFix ? this.animPos.x : this.x;
let spriteY = this.positionFix ? this.animPos.y : this.y;
- // This is where the animation is actually been created and stored.
+ // this is where the animation is actually been created and stored:
this.sceneSprite = currentScene.physics.add.sprite(spriteX, spriteY, this.asset_key);
if(this.autoStart){
this.sceneSprite.anims.play(this.key, true);
@@ -144,7 +153,7 @@ class AnimationEngine
return;
}
this.sceneSprite.on('animationcomplete', () => {
- this.currentAnimation.destroy();
+ this.currentAnimation?.destroy();
this.sceneSprite.destroy();
}, this);
}
@@ -220,7 +229,12 @@ class AnimationEngine
return;
}
for(let i of animationsKeys){
+ if(this.gameManager.createdAnimations[i]){
+ this.currentPreloader.objectsAnimations[i] = this.gameManager.createdAnimations[i];
+ continue;
+ }
if(sc.hasOwn(this.currentPreloader.objectsAnimations, i)){
+ // @TODO - BETA - Clean up, can objectsAnimations be removed?
continue;
}
let animData = animations[i];
@@ -239,6 +253,7 @@ class AnimationEngine
asset_key: animData['asset_key'] || this.asset_key
};
this.currentPreloader.objectsAnimations[i] = this.currentPreloader.anims.create(createData);
+ this.gameManager.createdAnimations[i] = this.currentPreloader.objectsAnimations[i];
}
}
diff --git a/lib/objects/client/plugin.js b/lib/objects/client/plugin.js
index e9fde1bbe..16f528eb5 100644
--- a/lib/objects/client/plugin.js
+++ b/lib/objects/client/plugin.js
@@ -113,8 +113,9 @@ class ObjectsPlugin extends PluginInterface
Logger.warning('Could not create bullet sprite.', currentScene);
return false;
}
- bulletSprite.setDepth(300000);
+ bulletSprite.setDepth(11000);
this.bullets[key] = bulletSprite;
+ Logger.debug({createdBulletSprite: skillBullet, shootFrom: body, bulletSprite});
}
setOnChangeBodyCallback(body, key, room, gameManager)
@@ -217,7 +218,7 @@ class ObjectsPlugin extends PluginInterface
let deathKey = sc.get(gameManager.config.client.skills.animations, message.k + '_death', 'default_death');
let currentScene = gameManager.activeRoomEvents.getActiveScene();
let skeletonSprite = currentScene.physics.add.sprite(message.x, message.y, deathKey);
- skeletonSprite.setDepth(200000);
+ skeletonSprite.setDepth(10500);
skeletonSprite.anims.play(deathKey, true).on('animationcomplete', () => {
skeletonSprite.destroy();
});
diff --git a/lib/objects/constants.js b/lib/objects/constants.js
index acad20a2f..5d1e42215 100644
--- a/lib/objects/constants.js
+++ b/lib/objects/constants.js
@@ -21,6 +21,14 @@ module.exports.ObjectsConst = {
NAMESPACE: 'objects'
}
},
+ EVENT_PREFIX: {
+ BASE: 'bo',
+ ANIMATION: 'ao',
+ DROP: 'dep',
+ ENEMY: 'eo',
+ NPC: 'npc',
+ TRADER: 'tnpc'
+ },
SNIPPETS: {
PREFIX: snippetsPrefix,
NPC_INVALID: snippetsPrefix+'npcInvalid',
diff --git a/lib/objects/server/manager.js b/lib/objects/server/manager.js
index 1949b9b3f..436b47ed7 100644
--- a/lib/objects/server/manager.js
+++ b/lib/objects/server/manager.js
@@ -13,6 +13,8 @@ class ObjectsManager
{
this.config = props.config;
this.events = sc.get(props, 'events', false);
+ this.roomId = sc.get(props, 'roomId', false);
+ this.roomName = sc.get(props, 'roomName', false);
if(!this.events){
Logger.error('EventsManager undefined in ObjectsManager.');
}
diff --git a/lib/objects/server/object/type/animation-object.js b/lib/objects/server/object/type/animation-object.js
index 08b6f4242..200bb364c 100644
--- a/lib/objects/server/object/type/animation-object.js
+++ b/lib/objects/server/object/type/animation-object.js
@@ -16,11 +16,10 @@ class AnimationObject extends BaseObject
constructor(props)
{
super(props);
- // object type:
this.type = ObjectsConst.TYPE_ANIMATION;
this.isAnimation = true;
- this.eventsPrefix = 'ao';
- // assign extra public params:
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.ANIMATION;
+ // the clientParams are all public params broadcast to the client:
this.clientParams = {
type: this.type,
enabled: true,
diff --git a/lib/objects/server/object/type/base-object.js b/lib/objects/server/object/type/base-object.js
index abf29dca0..fca152fad 100644
--- a/lib/objects/server/object/type/base-object.js
+++ b/lib/objects/server/object/type/base-object.js
@@ -2,9 +2,6 @@
*
* Reldens - BaseObject
*
- * Every object created will have a position.
- * Objects are just an internal platform definition, different from game items which are in a different module.
- *
*/
const { ObjectsConst } = require('../../../constants');
@@ -16,7 +13,7 @@ class BaseObject extends InteractionArea
constructor(props)
{
super();
- // then we will assign all the properties from the storage automatically as part of this object.
+ // assign all the properties from the storage automatically as part of this object:
Object.assign(this, props);
if(!this.events){
Logger.error('EventsManager undefined in BaseObject.');
@@ -28,17 +25,21 @@ class BaseObject extends InteractionArea
Logger.error('Data Server undefined in BaseObject.');
}
this.appendIndex = sc.get(props, 'tile_index', props.id);
- this.objectIndex = props.layer_name + this.appendIndex;
+ this.objectIndex = props.layer_name + (this.appendIndex || '-idx-1');
// we will use the client_key has the object key:
this.key = props.client_key;
- this.uid = this.key + Date.now();
- this.eventsPrefix = 'bo';
- // defaults:
+ this.uid = this.key +'-'+ Date.now();
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.BASE;
this.setDefaultProperties();
this.mapClientParams(props);
this.mapPrivateParams(props);
}
+ eventUniqueKey(suffix)
+ {
+ return this.eventsPrefix+'.'+(new Date()).getTime()+(suffix ? '.'+suffix : '');
+ }
+
setDefaultProperties()
{
this.runOnHit = false;
diff --git a/lib/objects/server/object/type/drop-object.js b/lib/objects/server/object/type/drop-object.js
index a69ce44fb..e00f06cdc 100644
--- a/lib/objects/server/object/type/drop-object.js
+++ b/lib/objects/server/object/type/drop-object.js
@@ -5,6 +5,7 @@
*/
const { AnimationObject } = require('./animation-object');
+const { ObjectsConst } = require('../../../constants');
const { RewardsConst } = require('../../../../rewards/constants');
class DropObject extends AnimationObject
@@ -14,7 +15,7 @@ class DropObject extends AnimationObject
{
super(props);
this.type = RewardsConst.REWARDS_PICK_UP_ACT;
- this.eventsPrefix = RewardsConst.DROP_EVENT_PREFIX;
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.DROP;
this.listenMessages = true;
this.clientParams.type = RewardsConst.REWARDS_PICK_UP_ACT;
this.clientParams.isInteractive = true;
diff --git a/lib/objects/server/object/type/enemy-object.js b/lib/objects/server/object/type/enemy-object.js
index d36089cec..482c574b5 100644
--- a/lib/objects/server/object/type/enemy-object.js
+++ b/lib/objects/server/object/type/enemy-object.js
@@ -24,7 +24,7 @@ class EnemyObject extends NpcObject
this.stats = Object.assign({}, configStats);
this.statsBase = Object.assign({}, configStats);
this.type = ObjectsConst.TYPE_ENEMY;
- this.eventsPrefix = 'eo';
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.ENEMY;
// @NOTE: we could run different actions and enemies reactions based on the player action.
// this.runOnAction = true;
// run on hit will make the enemy aggressive when the player enter the in the enemy-object interactive area.
@@ -62,7 +62,10 @@ class EnemyObject extends NpcObject
this.setupDefaultAction();
this.respawnTime = false;
this.respawnTimer = false;
+ this.respawnTimerInterval = false;
+ this.respawnStateTimer = false;
this.respawnLayer = false;
+ this.postBroadPhaseListener = [];
this.mapClientParams(props);
this.mapPrivateParams(props);
}
@@ -76,11 +79,10 @@ class EnemyObject extends NpcObject
this.events.onWithKey(
this.getBattleEndEvent(),
await this.onBattleEnd.bind(this),
- this.getEventRemoveKey(),
- this.getEventMasterKey()
+ this.eventUniqueKey('battleEnd'),
+ // @NOTE: objects use their uid as master key for the event listeners.
+ this.uid
);
- let dataArr = this.events.listeners('reldens.battleEnded');
- this.battleEndListener = dataArr[dataArr.length -1];
}
setupAggressiveBehavior()
@@ -88,13 +90,24 @@ class EnemyObject extends NpcObject
if(!this.isAggressive){
return;
}
- this.events.on('reldens.sceneRoomOnCreate', (room) => {
- room.roomWorld.on('postBroadphase', (event) => {
- if(0 === this.battle.inBattleWithPlayer.length){
- this.waitForPlayersToEnterRespawnArea(event, room);
- }
- });
- });
+ this.events.onWithKey(
+ 'reldens.sceneRoomOnCreate',
+ this.attachAggressiveBehaviorEvent.bind(this),
+ this.eventUniqueKey('attachAggressiveBehavior'),
+ // @NOTE: objects use their uid as master key for the event listeners.
+ this.uid
+ );
+ }
+
+ attachAggressiveBehaviorEvent(room)
+ {
+ let newPostBroadPhaseListener = (event) => {
+ if(0 === this.battle.inBattleWithPlayer.length){
+ this.waitForPlayersToEnterRespawnArea(event, room);
+ }
+ };
+ this.postBroadPhaseListener.push(newPostBroadPhaseListener);
+ room.roomWorld.on('postBroadphase', newPostBroadPhaseListener);
}
waitForPlayersToEnterRespawnArea(event, room)
@@ -152,6 +165,26 @@ class EnemyObject extends NpcObject
async executePhysicalSkill(target, executedSkill)
{
+ let targetBody = target.physicalBody || target.objectBody;
+ if(!targetBody){
+ Logger.info('Target body is missing or do not have a body to be hit by a physical object.');
+ return false;
+ }
+ if(!targetBody.world){
+ Logger.error('Target body world is missing. Body ID: '+ targetBody.id);
+ return false;
+ }
+ let thisWorldKey = this.objectBody?.world?.worldKey;
+ let targetWorldKey = targetBody?.world?.worldKey;
+ let enemyObjectUid = this.uid;
+ if(thisWorldKey && targetWorldKey && thisWorldKey !== targetWorldKey){
+ Logger.critical('Garbage enemy instance found.', {
+ enemyObjectUid,
+ thisWorldKey,
+ targetWorldKey
+ });
+ return false;
+ }
let messageData = Object.assign({skillKey: executedSkill.key}, executedSkill.owner.getPosition());
if(sc.isObjectFunction(executedSkill.owner, 'getSkillExtraData')){
let params = {skill: executedSkill, target};
@@ -170,15 +203,6 @@ class EnemyObject extends NpcObject
if(animData){
executedSkill.animDir = sc.get(animData.animationData, 'dir', false);
}
- let targetBody = target.physicalBody || target.objectBody;
- if(!targetBody){
- Logger.info('Target body is missing.');
- return false;
- }
- if(!targetBody.world){
- Logger.error('Target body world is missing. Body ID: '+ targetBody.id);
- return false;
- }
targetBody.world.shootBullet(from, to, executedSkill);
}
@@ -193,17 +217,14 @@ class EnemyObject extends NpcObject
if(!skillData){
return false;
}
- let skillInstance = new skillData['class'](
- Object.assign(
- {
- owner: this,
- ownerIdProperty: 'uid',
- affectedProperty: this.defaultAffectedProperty,
- events: this.events
- },
- skillData['data']
- )
- );
+ let skillOwnerData = Object.assign({
+ owner: this,
+ ownerIdProperty: 'uid',
+ eventsPrefix: this.eventsPrefix,
+ affectedProperty: this.defaultAffectedProperty,
+ events: this.events
+ }, skillData['data']);
+ let skillInstance = new skillData['class'](skillOwnerData);
this.actionsKeys.push(skillKey);
this.actions[skillKey] = skillInstance;
this.actionsTargets[skillKey] = skillTarget;
@@ -212,17 +233,7 @@ class EnemyObject extends NpcObject
getBattleEndEvent()
{
- return this.key+'.reldens.battleEnded';
- }
-
- getEventRemoveKey()
- {
- return this.key+'battleEnd';
- }
-
- getEventMasterKey()
- {
- return 'battleRoom';
+ return this.eventUniqueKey()+'emittedBattleEnded';
}
async respawn(room)
@@ -240,19 +251,35 @@ class EnemyObject extends NpcObject
restoreOnTimeOut(room)
{
+ let respawnStartTime = Date.now();
+ this.respawnTimerInterval = setInterval(() => {
+ const elapsedTime = Date.now() - respawnStartTime;
+ const remainingTime = Math.max(0, (this.respawnTime - elapsedTime) / 1000);
+ Logger.debug(`Respawn Object "${this.uid}" in: ${remainingTime.toFixed(2)} seconds`);
+ }, 1000);
this.respawnTimer = setTimeout(async () => {
+ clearInterval(this.respawnTimerInterval);
await this.restoreObject(room);
- }, this.respawnTime*0.9);
+ }, this.respawnTime);
}
async restoreObject(room)
{
this.stats = Object.assign({}, this.initialStats);
if(!this.objectBody.world){
- Logger.error('ObjectBody world is null on restoreObject method.', this.objectBody.id);
+ Logger.error('ObjectBody world is null on restoreObject method for object UID: "'+this.uid+'".');
return;
}
- this.objectBody.bodyState.inState = GameConst.STATUS.AVOID_INTERPOLATION;
+ let interpolationStatus = GameConst.STATUS.AVOID_INTERPOLATION;
+ this.objectBody.bodyState.inState = interpolationStatus;
+ if(interpolationStatus !== this.battle.targetObject.objectBody.bodyState.inState){
+ Logger.warning('Battle target object state miss match, set it to avoid interpolation.');
+ this.battle.targetObject.objectBody.bodyState.inState = interpolationStatus;
+ }
+ if(interpolationStatus !== room.objectsManager.roomObjects[this.objectIndex].objectBody.bodyState.inState){
+ Logger.warning('Objects Manager room object state miss match, set it to avoid interpolation.');
+ room.objectsManager.roomObjects[this.objectIndex].objectBody.bodyState.inState = interpolationStatus;
+ }
let respawnArea = this.objectBody.world.respawnAreas[this.respawnLayer];
delete respawnArea.usedTiles[this.randomTileIndex];
let {randomTileIndex, tileData} = respawnArea.getRandomTile(this.objectIndex);
@@ -261,14 +288,27 @@ class EnemyObject extends NpcObject
Object.assign(this, tileData);
let { x, y } = tileData;
this.objectBody.position = [x, y];
- this.objectBody.originalCol = x;
- this.objectBody.originalRow = y;
this.objectBody.bodyState.x = x;
this.objectBody.bodyState.y = y;
+ let {currentCol, currentRow} = this.objectBody.positionToTiles(x, y);
+ this.objectBody.originalCol = currentCol;
+ this.objectBody.originalRow = currentRow;
await this.events.emit('reldens.restoreObjectAfter', {enemyObject: this, room});
- setTimeout(()=> {
- this.objectBody.bodyState.inState = GameConst.STATUS.ACTIVE;
- }, (this.respawnTime || 1000)*0.1);
+ let respawnTime = this.respawnTime || 1000;
+ Logger.debug('Respawn: '+this.uid+ ' - Time: '+respawnTime+' - Position x/y: '+x+' / '+y);
+ this.respawnStateTimer = setTimeout(()=> {
+ Logger.debug('Activated object after respawn: '+this.uid);
+ let activeStatus = GameConst.STATUS.ACTIVE;
+ this.objectBody.bodyState.inState = activeStatus;
+ if(activeStatus !== this.battle.targetObject.objectBody.bodyState.inState){
+ Logger.warning('Battle target object state miss match, set it to active.');
+ this.battle.targetObject.objectBody.bodyState.inState = activeStatus;
+ }
+ if(activeStatus !== room.objectsManager.roomObjects[this.objectIndex].objectBody.bodyState.inState){
+ Logger.warning('Objects Manager room object state miss match, set it to active.');
+ room.objectsManager.roomObjects[this.objectIndex].objectBody.bodyState.inState = activeStatus;
+ }
+ }, 1);
}
onHit(props)
@@ -282,7 +322,6 @@ class EnemyObject extends NpcObject
{
let playerBody = sc.hasOwn(props.bodyA, 'playerId') ? props.bodyA : props.bodyB;
if(!props.room || !playerBody){
- // this shouldn't happen :P
Logger.error('Required properties room and playerBody not found.');
return;
}
@@ -299,6 +338,7 @@ class EnemyObject extends NpcObject
getPosition()
{
+ // @TODO - BETA - Check if we need to update and return this.x, this.y or these are just the initial position.
return {
x: this.state.x,
y: this.state.y
@@ -307,7 +347,7 @@ class EnemyObject extends NpcObject
async onBattleEnd()
{
- Logger.info('Battle end method not implemented for EnemyObject.', this.key, this.title);
+ Logger.debug('BattleEnd method not implemented for EnemyObject.', this.uid, this.title);
}
}
diff --git a/lib/objects/server/object/type/npc-object.js b/lib/objects/server/object/type/npc-object.js
index 564b9d43f..e988825d3 100644
--- a/lib/objects/server/object/type/npc-object.js
+++ b/lib/objects/server/object/type/npc-object.js
@@ -19,7 +19,7 @@ class NpcObject extends AnimationObject
this.type = ObjectsConst.TYPE_NPC;
this.hasAnimation = true;
this.collisionResponse = true;
- this.eventsPrefix = 'npc';
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.NPC;
this.listenMessages = true;
// interactive objects will react on click:
this.clientParams.type = ObjectsConst.TYPE_NPC;
diff --git a/lib/objects/server/object/type/trader-object.js b/lib/objects/server/object/type/trader-object.js
index 375dcf2b8..cf2159696 100644
--- a/lib/objects/server/object/type/trader-object.js
+++ b/lib/objects/server/object/type/trader-object.js
@@ -24,7 +24,7 @@ class TraderObject extends NpcObject
{
super(props);
this.type = ObjectsConst.TYPE_TRADER;
- this.eventsPrefix = 'tnpc';
+ this.eventsPrefix = this.uid+'.'+ObjectsConst.EVENT_PREFIX.TRADER;
this.clientParams.type = ObjectsConst.TYPE_TRADER;
this.sendInvalidOptionMessage = true;
this.inventory = false;
diff --git a/lib/objects/server/plugin.js b/lib/objects/server/plugin.js
index bfb23c18d..121b100b6 100644
--- a/lib/objects/server/plugin.js
+++ b/lib/objects/server/plugin.js
@@ -13,6 +13,7 @@ class ObjectsPlugin extends PluginInterface
setup(props)
{
+ this.objectsClassTypeHandler = false;
this.events = sc.get(props, 'events', false);
if(!this.events){
ErrorManager.error('EventsManager undefined in RewardsPlugin.');
diff --git a/lib/prediction/client/prediction-world-creator.js b/lib/prediction/client/prediction-world-creator.js
index 95f6b9a43..a69c9bf85 100644
--- a/lib/prediction/client/prediction-world-creator.js
+++ b/lib/prediction/client/prediction-world-creator.js
@@ -49,7 +49,6 @@ class PredictionWorldCreator
predictionBody.updateBodyState = this.updateBodyStateOverride(predictionBody, currentPlayer);
currentPlayer.predictionBody = predictionBody;
scene.worldPredictionTimer = new WorldTimer({
- world: scene.worldPrediction,
callbacks: [() => {
if(!scene.worldPrediction){
Logger.error('Scene World not longer exists.', scene.roomWorld);
@@ -58,7 +57,7 @@ class PredictionWorldCreator
scene.worldPrediction.removeBodiesFromWorld();
}]
});
- scene.worldPredictionTimer.startWorldSteps();
+ scene.worldPredictionTimer.startWorldSteps(scene.worldPrediction);
scene.collisionsManager = new CollisionsManager({roomWorld: scene.worldPrediction});
currentPlayer.pointsValidator = new WorldPointsValidator(mapJson.width, mapJson.height);
}
diff --git a/lib/respawn/server/plugin.js b/lib/respawn/server/plugin.js
index fc2870088..2e5717c23 100644
--- a/lib/respawn/server/plugin.js
+++ b/lib/respawn/server/plugin.js
@@ -31,6 +31,7 @@ class RespawnPlugin extends PluginInterface
listenEvents()
{
if(!this.events){
+ Logger.critical('Undefined events on RespawnPlugin.');
return false;
}
this.events.on('reldens.parsingMapLayerBefore', async (eventData = {}) => {
@@ -45,9 +46,7 @@ class RespawnPlugin extends PluginInterface
}
await this.createRoomRespawnArea(layer, world);
});
- this.events.on('reldens.sceneRoomOnCreate', async (room) => {
- return this.createRespawnObjectsInstances(room);
- });
+ this.events.on('reldens.sceneRoomOnCreate', this.createRespawnObjectsInstances.bind(this));
}
createRespawnObjectsInstances(room)
@@ -75,7 +74,7 @@ class RespawnPlugin extends PluginInterface
continue;
}
// @TODO - BETA - Refactor and extract Colyseus into a driver.
- room.state.bodies.set(objInstance.client_key, objInstance.state);
+ room.state.addBodyToState(objInstance.state, objInstance.client_key);
}
}
}
diff --git a/lib/respawn/server/room-respawn.js b/lib/respawn/server/room-respawn.js
index cece58db3..8038398f8 100644
--- a/lib/respawn/server/room-respawn.js
+++ b/lib/respawn/server/room-respawn.js
@@ -115,6 +115,7 @@ class RoomRespawn
objInstance.objectIndex = objectIndex;
objInstance.randomTileIndex = randomTileIndex;
this.instancesCreated[respawnArea.id].push(objInstance);
+ Logger.debug({respawnCreatedWorldObject: objInstance.uid});
}
getObjectAssets(multipleObj)
@@ -129,6 +130,10 @@ class RoomRespawn
generateObjectIndex(respawnArea)
{
let newIndex = this.instancesCreated[respawnArea.id].length;
+ Logger.debug(
+ 'Generating new object index.',
+ {layerName: this.layer.name, newIndex, respawnAreaId: respawnArea.id}
+ );
return this.layer.name + '-' + respawnArea.id + '-' + newIndex;
}
diff --git a/lib/rewards/constants.js b/lib/rewards/constants.js
index d59ae1d30..02d3411f0 100644
--- a/lib/rewards/constants.js
+++ b/lib/rewards/constants.js
@@ -13,7 +13,6 @@ module.exports.RewardsConst = {
REWARDS_PARAMS: 'rp',
REWARDS_PATH: '/assets/custom/sprites/',
REWARDS_PICK_UP_ACT: 'rpu',
- DROP_EVENT_PREFIX: 'dep',
REMOVE_DROP: 'rd',
SPLIT_EXPERIENCE: {
ALL: 0,
diff --git a/lib/rewards/server/plugin.js b/lib/rewards/server/plugin.js
index 0611f366a..0ea773b3e 100644
--- a/lib/rewards/server/plugin.js
+++ b/lib/rewards/server/plugin.js
@@ -10,7 +10,7 @@ const { RewardMessageActions } = require('./message-actions');
const { RewardsDropsProcessor } = require('./rewards-drops-processor');
const { TargetDeterminer } = require('./target-determiner');
const { PluginInterface } = require('../../features/plugin-interface');
-const { ErrorManager, sc } = require('@reldens/utils');
+const { Logger, sc } = require('@reldens/utils');
class RewardsPlugin extends PluginInterface
{
@@ -18,33 +18,56 @@ class RewardsPlugin extends PluginInterface
setup(props)
{
this.events = sc.get(props, 'events', false);
+ this.listenEvents();
+ }
+
+ listenEvents()
+ {
if(!this.events){
- ErrorManager.error('EventsManager undefined in RewardsPlugin.');
+ Logger.critical('EventsManager undefined in RewardsPlugin.');
+ return false;
}
- this.events.on('reldens.featuresManagerLoadFeaturesAfter', (event) => {
- this.rewardsSubscriber = new RewardsSubscriber(event);
- this.targetDeterminer = new TargetDeterminer(event?.featuresManager?.featuresList?.teams.package);
- });
- this.events.on('reldens.afterRunAdditionalRespawnSetup', async (event) => {
- await ObjectSubscriber.enrichWithRewards(event.objInstance);
- });
- this.events.on('reldens.battleEnded', async (event) => {
- await this.rewardsSubscriber.giveRewards(
- event.playerSchema,
- event.pve?.targetObject,
- this.events
- );
- });
- this.events.on('reldens.sceneRoomOnCreate', async (roomScene) => {
- this.events.on('reldens.afterGiveRewards', async (rewardEventData) => {
- await RewardsDropsProcessor.processRewardsDrops(roomScene, rewardEventData);
- });
- });
- this.events.on('reldens.roomsMessageActionsGlobal', (roomMessageActions) => {
- roomMessageActions.rewards = new RewardMessageActions(
- this.targetDeterminer
- );
- });
+ this.events.on('reldens.featuresManagerLoadFeaturesAfter', this.appendPluginClasses.bind(this));
+ this.events.on('reldens.afterRunAdditionalRespawnSetup', this.enrichObjectWithRewards.bind(this));
+ this.events.on('reldens.battleEnded', this.battleEndedGiveRewards.bind(this));
+ this.events.on('reldens.sceneRoomOnCreate', this.attachGiveRewardsEvent.bind(this));
+ this.events.on('reldens.roomsMessageActionsGlobal', this.attachRewardMessageActions.bind(this));
+ }
+
+ async attachGiveRewardsEvent(roomScene)
+ {
+ this.events.onWithKey(
+ 'reldens.afterGiveRewards',
+ this.processRewardsDrops.bind(this, roomScene),
+ roomScene.roomName+'-'+roomScene.roomId+'-afterGiveRewards-'+sc.getTime(),
+ roomScene.roomName+'-'+roomScene.roomId
+ );
+ }
+
+ async processRewardsDrops(roomScene, rewardEventData)
+ {
+ await RewardsDropsProcessor.processRewardsDrops(roomScene, rewardEventData);
+ }
+
+ attachRewardMessageActions(roomMessageActions)
+ {
+ roomMessageActions.rewards = new RewardMessageActions(this.targetDeterminer);
+ }
+
+ async appendPluginClasses(event)
+ {
+ this.rewardsSubscriber = new RewardsSubscriber(event);
+ this.targetDeterminer = new TargetDeterminer(event?.featuresManager?.featuresList?.teams.package);
+ }
+
+ async enrichObjectWithRewards(event)
+ {
+ await ObjectSubscriber.enrichWithRewards(event.objInstance);
+ }
+
+ async battleEndedGiveRewards(event)
+ {
+ await this.rewardsSubscriber.giveRewards(event.playerSchema, event.pve?.targetObject, this.events);
}
}
diff --git a/lib/rewards/server/subscribers/object-subscriber.js b/lib/rewards/server/subscribers/object-subscriber.js
index 14c3299ce..671212536 100644
--- a/lib/rewards/server/subscribers/object-subscriber.js
+++ b/lib/rewards/server/subscribers/object-subscriber.js
@@ -11,6 +11,9 @@ class ObjectSubscriber
static async enrichWithRewards(objectInstance)
{
+ if(!objectInstance){
+ return;
+ }
objectInstance['rewards'] = RewardsMapper.fromModels(
await objectInstance.dataServer.getEntity('rewards').loadByWithRelations(
'object_id',
diff --git a/lib/rewards/server/subscribers/rewards-subscriber.js b/lib/rewards/server/subscribers/rewards-subscriber.js
index cc126a00e..5b55a8837 100644
--- a/lib/rewards/server/subscribers/rewards-subscriber.js
+++ b/lib/rewards/server/subscribers/rewards-subscriber.js
@@ -23,6 +23,9 @@ class RewardsSubscriber
async giveRewards(playerSchema, targetObject, eventsManager)
{
+ if(!targetObject){
+ return;
+ }
let eventDrop = {playerSchema, targetObject, continueEvent: true};
await eventsManager.emit('reldens.beforeGiveRewards', eventDrop);
if(!eventDrop.continueEvent){
diff --git a/lib/rewards/server/world-drop-handler.js b/lib/rewards/server/world-drop-handler.js
index 99150d0c6..61cc35d41 100644
--- a/lib/rewards/server/world-drop-handler.js
+++ b/lib/rewards/server/world-drop-handler.js
@@ -45,7 +45,8 @@ class WorldDropHandler
continue;
}
roomScene.addObjectStateSceneData(rewardObjectBody);
- this.setRewardTimeDisappear(rewardObjectBody, roomScene);
+ // @TODO - BETA - Clear timeout (possible bug if the timeout is not cleared).
+ newReward.autoDestroyTimeout = this.setRewardTimeDisappear(rewardObjectBody, roomScene);
newReward['objectBody'] = rewardObjectBody;
rewards.push(newReward);
}
@@ -151,7 +152,7 @@ class WorldDropHandler
static setRewardTimeDisappear(dropObject, roomScene)
{
- setTimeout(() => {
+ return setTimeout(() => {
if(!roomScene.objectsManager.getObjectData(dropObject.objectIndex)){
return false;
}
diff --git a/lib/rooms/server/game.js b/lib/rooms/server/game.js
index ad5213fd5..85b6fd515 100644
--- a/lib/rooms/server/game.js
+++ b/lib/rooms/server/game.js
@@ -52,7 +52,7 @@ class RoomGame extends RoomLogin
message.formData.user_id = client.auth.id;
let result = await this.loginManager.createNewPlayer(message.formData);
result.act = GameConst.CREATE_PLAYER_RESULT;
- client.send('*', result);
+ return client.send('*', result);
}
}
diff --git a/lib/rooms/server/login.js b/lib/rooms/server/login.js
index 15a02430b..3dc48ea00 100644
--- a/lib/rooms/server/login.js
+++ b/lib/rooms/server/login.js
@@ -28,9 +28,7 @@ class RoomLogin extends Room
this.validateRoomData = false;
options.roomsManager.createdInstances[this.roomId] = this;
this.events.emitSync('reldens.roomLoginOnCreate', {roomLogin: this, options});
- this.onMessage('*', async (client, message) => {
- await this.handleReceivedMessage(client, message);
- });
+ this.onMessage('*', this.handleReceivedMessage.bind(this));
}
async handleReceivedMessage(client, message)
@@ -86,7 +84,8 @@ class RoomLogin extends Room
onDispose()
{
- Logger.info('ON-DISPOSE Room: ' + this.roomName);
+ this.events.emitSync('reldens.onRoomDispose', {roomName: this.roomName, roomId: this.roomId});
+ Logger.info('ON-DISPOSE Room: '+this.roomName);
}
}
diff --git a/lib/rooms/server/manager.js b/lib/rooms/server/manager.js
index c5a1f2bba..cd6eef11f 100644
--- a/lib/rooms/server/manager.js
+++ b/lib/rooms/server/manager.js
@@ -37,7 +37,7 @@ class RoomsManager
if(!this.defineExtraRooms.length){
Logger.info('None extra rooms to be defined.');
}
- // dispatch event to get the global message actions (that will be listen by every room):
+ // dispatch event to get the global message actions (that will be listened by every room):
let globalMessageActions = {};
await this.events.emit('reldens.roomsMessageActionsGlobal', globalMessageActions);
// lobby room:
diff --git a/lib/rooms/server/plugin.js b/lib/rooms/server/plugin.js
index f1b6d2ad0..648c5b26f 100644
--- a/lib/rooms/server/plugin.js
+++ b/lib/rooms/server/plugin.js
@@ -16,19 +16,40 @@ class RoomsPlugin extends PluginInterface
if(!this.events){
Logger.error('EventsManager undefined in RoomsPlugin.');
}
- this.events.on('reldens.beforeSuperInitialGameData', async (superInitialGameData, roomGame) => {
- await this.onBeforeSuperInitialGameData(superInitialGameData, roomGame);
- });
+ this.listenEvents();
}
- async onBeforeSuperInitialGameData(superInitialGameData, roomGame)
+ listenEvents()
+ {
+ if(!this.events){
+ return false;
+ }
+ this.events.on('reldens.serverBeforeListen', this.attachRoomsManager.bind(this));
+ this.events.on('reldens.beforeSuperInitialGameData', this.attachRoomSelectionAndInstancesRemoval.bind(this));
+ this.events.on('reldens.onRoomDispose', this.removeRoomCreatedInstanceFromManager.bind(this));
+ }
+
+ attachRoomsManager(event)
+ {
+ this.roomsManager = event?.serverManager?.roomsManager;
+ }
+
+ async attachRoomSelectionAndInstancesRemoval(superInitialGameData, roomGame)
{
let config = roomGame.config.get('client/rooms/selection');
+ if(!config){
+ Logger.critical('Missing configuration on RoomsPlugin.');
+ return false;
+ }
+ if(!this.roomsManager){
+ Logger.critical('Missing RoomsManager on RoomsPlugin.');
+ return false;
+ }
if(config.allowOnRegistration || config.allowOnLogin){
- let isRegistration = (!superInitialGameData.players || superInitialGameData.players.length === 0);
+ let isRegistration = (!superInitialGameData.players || 0 === superInitialGameData.players.length);
let configuredRooms = (isRegistration ? config.registrationAvailableRooms : config.loginAvailableRooms);
- let currentRooms = roomGame.loginManager.roomsManager.loadedRoomsByName;
- let availableRooms = configuredRooms === '*' ? Object.keys(currentRooms) : (await this.filterValidRooms(
+ let currentRooms = this.roomsManager.loadedRoomsByName;
+ let availableRooms = '*' === configuredRooms ? Object.keys(currentRooms) : (await this.filterValidRooms(
configuredRooms.split(','),
currentRooms
));
@@ -39,6 +60,11 @@ class RoomsPlugin extends PluginInterface
}
}
+ removeRoomCreatedInstanceFromManager(roomData)
+ {
+ delete this.roomsManager.createdInstances[roomData.roomId];
+ }
+
async filterValidRooms(configuredRooms, createdRooms)
{
let validRooms = [];
diff --git a/lib/rooms/server/scene.js b/lib/rooms/server/scene.js
index b28e998ea..7af660600 100644
--- a/lib/rooms/server/scene.js
+++ b/lib/rooms/server/scene.js
@@ -21,18 +21,26 @@ class RoomScene extends RoomLogin
async onCreate(options)
{
+ super.onCreate(options);
+ this.autoDispose = sc.get(options.roomData, 'autoDispose', true);
+ this.roomWorld = {};
this.activePlayers = {};
this.messageActions = {};
this.movementInterval = {};
- super.onCreate(options);
+ this.worldTimerCallback = false;
this.roomType = RoomsConst.ROOM_TYPE_SCENE;
- // override super prop:
this.validateRoomData = true;
- Logger.info('Created RoomScene: '+this.roomName+' - ID: '+this.roomId);
+ Logger.info(
+ 'Created RoomScene: '+this.roomName+' - ID: '+this.roomId
+ +' - With AutoDispose Enabled: '+(this.autoDispose ? 'Yes' : 'No')
+ );
this.sceneId = this.roomId;
// @NOTE: we create an instance of the objects manager for each room-scene, this is on purpose so all the
// related object instances will be removed when the room is disposed.
- let objectsManagerConfig = Object.assign({events: this.events}, options);
+ let objectsManagerConfig = Object.assign(
+ {events: this.events, roomName: this.roomName, roomId: this.roomId},
+ options
+ );
this.objectsManager = new ObjectsManager(objectsManagerConfig);
await this.objectsManager.loadObjectsByRoomId(options.roomData.roomId);
if(this.objectsManager.roomObjectsData){
@@ -42,7 +50,6 @@ class RoomScene extends RoomLogin
if(this.objectsManager.listenMessages){
Object.assign(this.messageActions, this.objectsManager.listenMessagesObjects);
}
- // world data:
this.lastCallTime = Date.now() / 1000;
this.paused = false;
this.customData = options.roomData.customData || {};
@@ -163,6 +170,7 @@ class RoomScene extends RoomLogin
if(updatedPlayer){
currentPlayer.syncPlayer(updatedPlayer);
}
+ // @TODO - BETA - Remove this callbacks and provide a player container that will executed the required methods.
currentPlayer.persistData = async (params) => {
await this.events.emit('reldens.playerPersistDataBefore', client, userModel, currentPlayer, params, this);
await this.savePlayedTime(currentPlayer);
@@ -213,8 +221,8 @@ class RoomScene extends RoomLogin
async handleReceivedMessage(client, messageData)
{
if(!messageData){
- Logger.error(['Empty message data:', messageData]);
- return false;
+ Logger.error('Empty message data on room "'+this.roomName+'" ID "'+this.roomId+'".', messageData);
+ return;
}
// only process the message if the player exists and has a body:
let playerSchema = this.playerBySessionIdFromState(client.sessionId);
@@ -331,6 +339,7 @@ class RoomScene extends RoomLogin
}
clearInterval(this.movementInterval[i]);
delete this.movementInterval[i];
+ Logger.debug('Cleared movement interval: '+i);
}
}
@@ -367,20 +376,26 @@ class RoomScene extends RoomLogin
this.pointsValidator = new WorldPointsValidator(this.roomWorld.worldWidth, this.roomWorld.worldHeight);
this.roomWorld.createLimits();
await this.roomWorld.createWorldContent(roomData);
- // start world movement from the config or with the default value:
+ this.initializeWorldTimer();
+ Logger.info('World created in Room: ' + this.roomName);
+ }
+
+ initializeWorldTimer()
+ {
+ this.worldTimerCallback = () => {
+ if(!this.roomWorld){
+ Logger.error('Room World not longer exists.', this.roomWorld);
+ return;
+ }
+ this.roomWorld.removeBodiesFromWorld();
+ };
this.worldTimer = new WorldTimer({
- clockInstance: this.clock,
+ // @TODO - BETA - Create a single class/point for setIntervals or timeOuts instances creation.
+ // clockInstance: this.clock,
world: this.roomWorld,
- callbacks: [() => {
- if(!this.roomWorld){
- Logger.error('Room World not longer exists.', this.roomWorld);
- return;
- }
- this.roomWorld.removeBodiesFromWorld();
- }]
+ callbacks: [this.worldTimerCallback]
});
- this.worldTimer.startWorldSteps();
- Logger.info('World created in Room: ' + this.roomName);
+ this.worldTimer.startWorldSteps(this.roomWorld);
}
createWorldInstance(data)
@@ -478,11 +493,37 @@ class RoomScene extends RoomLogin
removeAllPlayerReferences(playerSchema, sessionId)
{
+ this.events.offByMasterKey(playerSchema.eventsPrefix);
let bodyToRemove = playerSchema.physicalBody;
if(bodyToRemove){
this.roomWorld.removeBody(bodyToRemove);
}
- this.events.offByMasterKey(playerSchema.eventsPrefix + playerSchema.player_id);
+ playerSchema.physicalBody = null;
+ let itemsList = playerSchema?.inventory?.manager?.items || {};
+ let itemsKeys = Object.keys(itemsList);
+ if(0 < itemsKeys.length){
+ for(let i of itemsKeys){
+ let item = itemsList[i];
+ if(item.useTimer){
+ clearTimeout(item.useTimer);
+ }
+ if(item.execTimer){
+ clearTimeout(item.execTimer);
+ }
+ }
+ }
+ this.clearEntityActions(playerSchema);
+ // these contain references to the room:
+ delete playerSchema.skillsServer?.client;
+ delete playerSchema.inventory?.client;
+ playerSchema.executePhysicalSkill = null;
+ playerSchema.persistData = null;
+ playerSchema.skillsServer = null;
+ playerSchema.inventory = null;
+ let playerDeathTimer = playerSchema.getPrivate('playerDeathTimer');
+ if(playerDeathTimer){
+ clearTimeout(playerDeathTimer);
+ }
this.state.removePlayer(sessionId);
}
@@ -584,30 +625,151 @@ class RoomScene extends RoomLogin
onDispose()
{
- Logger.info('ON-DISPOSE Room: ' + this.roomName);
+ Logger.info('ON-DISPOSE Room: '+this.roomName);
+ this.logEventsData('before');
this.clearMovementIntervals();
- clearInterval(this.roomWorld.worldTimer);
+ this.clearWorldTimers();
+ this.cleanUpRoomWorld();
// @TODO - BETA - Replace this by a master key related to the room ID and just remove all the events related
// to this room.
+ this.handleRespawnOnRoomDispose();
+ this.handleObjectsManagerOnRoomDispose();
+ delete this.objectsManager;
+ delete this.roomWorld;
+ this.roomWorld = {};
+ this.events.offByMasterKey(this.roomName+'-'+this.roomId);
+ super.onDispose();
+ this.logEventsData('after');
+ }
+
+ cleanUpRoomWorld()
+ {
+ this.roomWorld.removeBodies.push(this.objectBody);
+ this.roomWorld._listeners['postBroadphase'] = [];
+ this.roomWorld._listeners['preSolve'] = [];
+ this.roomWorld._listeners['beginContact'] = [];
+ this.roomWorld._listeners['endContact'] = [];
+ this.roomWorld.clear();
+ }
+
+ clearWorldTimers()
+ {
+ clearInterval(this.roomWorld.worldDateTimeInterval);
+ this.worldTimer.callbacks = [];
+ this.worldTimer.clockInstance ? this.worldTimer.worldTimer.clear() : clearInterval(this.worldTimer.worldTimer);
+ clearInterval(this.worldTimer.worldTimer);
+ delete this.worldTimerCallback;
+ this.worldTimerCallback = () => {
+ Logger.debug('World timer callback still executed for room "' + this.roomName + '".');
+ };
+ Logger.debug(
+ 'Cleared world timer and world date time intervals.',
+ {
+ worldTimerDestroyed: this.worldTimer.worldTimer._destroyed,
+ worldDateTimeDestroyed: this.roomWorld.worldDateTimeInterval._destroyed
+ }
+ );
+ this.worldTimer.world = null;
+ this.worldTimer = null;
+ delete this.worldTimer;
+ }
+
+ handleObjectsManagerOnRoomDispose()
+ {
+ if(!this.objectsManager.roomObjects){
+ Logger.debug('None roomObjects defined for room: '+this.roomName);
+ return;
+ }
+ for(let i of Object.keys(this.objectsManager.roomObjects)){
+ let objectInstance = this.objectsManager.roomObjects[i];
+ objectInstance.postBroadPhaseListener = [];
+ this.clearEntityActions(objectInstance);
+ if(objectInstance.battle){
+ clearTimeout(objectInstance.battle.battleTimer);
+ clearTimeout(objectInstance.battle.respawnStateTimer);
+ objectInstance.battle.targetObject = null;
+ }
+ clearTimeout(objectInstance.respawnTimer);
+ clearInterval(objectInstance.respawnTimerInterval);
+ clearTimeout(objectInstance.isCasting);
+ Logger.debug('Cleared timers for: ' + objectInstance.key + ' / ' + i);
+ delete this.objectsManager.roomObjects[i];
+ }
+ }
+
+ clearEntityActions(entityInstance)
+ {
+ let actions = entityInstance?.actions || {};
+ let actionsKeys = Object.keys(actions);
+ if(0 < actionsKeys){
+ for(let i of actionsKeys){
+ if(actions[i].room){
+ actions[i].room = null;
+ }
+ }
+ }
+ }
+
+ handleRespawnOnRoomDispose()
+ {
if(!this.roomWorld.respawnAreas){
- return true;
+ Logger.debug('None respawn areas defined for room: '+this.roomName);
+ return;
+ }
+ this.removeRespawnObjectsSubscribers();
+ this.deleteRespawnObjectInstances();
+ }
+
+ deleteRespawnObjectInstances()
+ {
+ if(!this.roomWorld.respawnAreas){
+ return;
+ }
+ for (let rI of Object.keys(this.roomWorld.respawnAreas)) {
+ let respawnInstancesCreated = this.roomWorld.respawnAreas[rI].instancesCreated;
+ for (let i of Object.keys(respawnInstancesCreated)) {
+ delete respawnInstancesCreated[i];
+ Logger.debug('Deleted respawn instances created: ' + i);
+ }
+ delete this.roomWorld.respawnAreas[rI];
+ Logger.debug('Deleted respawn area created: ' + rI);
}
- // clean up the listeners!
- // @TODO - BETA - Emit a new event for the room dispose and use listeners on each other core-plugin.
- for(let rI of Object.keys(this.roomWorld.respawnAreas)){
- let instC = this.roomWorld.respawnAreas[rI].instancesCreated;
- for(let i of Object.keys(instC)){
- let res = instC[i];
- for(let obj of res){
- if(!sc.hasOwn(obj, 'battleEndListener')){
- continue;
- }
- this.events.offWithKey(obj.key+'battleEnd', 'battleRoom');
+ delete this.roomWorld.respawnAreas;
+ Logger.debug('Deleted respawn areas for room: ' + this.roomName);
+ }
+
+ removeRespawnObjectsSubscribers()
+ {
+ if(!this.roomWorld.respawnAreas){
+ return;
+ }
+ for (let rI of Object.keys(this.roomWorld.respawnAreas)) {
+ let respawnInstancesCreated = this.roomWorld.respawnAreas[rI].instancesCreated;
+ for (let i of Object.keys(respawnInstancesCreated)) {
+ let respawnInstance = respawnInstancesCreated[i];
+ for (let respawnObject of respawnInstance) {
+ Logger.debug('Setting "battleEnd" listener off: ' + respawnObject.uid);
+ this.events.offByMasterKey(respawnObject.uid);
}
}
}
}
+ logEventsData(eventKey)
+ {
+ let endSubscribersCount = 0;
+ let keysData = {};
+ for (let i of Object.keys(this.events._events)) {
+ endSubscribersCount += this.events._events[i].length;
+ keysData[i] = {keys: []};
+ for (let event of this.events._events[i]) {
+ keysData[i].keys.push((event.fn.name || 'anonymous').replace('bound ', ''));
+ }
+ keysData[i].keys = keysData[i].keys.join(', ');
+ }
+ Logger.debug('Subscribers count '+eventKey+':', endSubscribersCount, keysData);
+ }
+
addObjectStateSceneData(object)
{
let sceneData = sc.toJson(this.state.sceneData);
diff --git a/lib/rooms/server/state.js b/lib/rooms/server/state.js
index 258359cc3..184656c36 100644
--- a/lib/rooms/server/state.js
+++ b/lib/rooms/server/state.js
@@ -62,6 +62,26 @@ class State extends Schema
this.players.delete(id);
}
+ fetchBody(id)
+ {
+ return this.bodies.get(id);
+ }
+
+ addBodyToState(body, bodyId)
+ {
+ // @TODO - BETA - Refactor and extract Colyseus into a driver.
+ this.bodies.set(bodyId, body);
+ return this.bodies.get(bodyId);
+ }
+
+ removeBody(id)
+ {
+ if(!this.fetchBody(id)){
+ return false;
+ }
+ return this.bodies.delete(id);
+ }
+
}
type('string')(State.prototype, 'sceneData');
diff --git a/lib/rooms/server/world-config.js b/lib/rooms/server/world-config.js
index f8c9182c1..cd2de9895 100644
--- a/lib/rooms/server/world-config.js
+++ b/lib/rooms/server/world-config.js
@@ -35,12 +35,12 @@ class WorldConfig
let applyGravity = sc.get(room.customData, 'applyGravity', globalConfig.applyGravity);
let defaultsVariations = {
useFixedWorldStep: null !== globalConfig.useFixedWorldStep ? globalConfig.useFixedWorldStep : !applyGravity,
- timeStep: null !== globalConfig.timeStep ? globalConfig.timeStep : (applyGravity ? 0.012 : 0.04),
- maxSubSteps: null !== globalConfig.maxSubSteps ? globalConfig.maxSubSteps : (applyGravity ? 5 : 1),
- movementSpeed: null !== globalConfig.movementSpeed
- ? globalConfig.movementSpeed : (applyGravity ? 200 : 180),
+ timeStep: applyGravity ? 0.012 : (null !== globalConfig.timeStep ? globalConfig.timeStep : 0.04),
+ maxSubSteps: applyGravity ? 2 : (null !== globalConfig.maxSubSteps ? globalConfig.maxSubSteps : 1),
+ movementSpeed: applyGravity ? 160 : (null !== globalConfig.movementSpeed ? globalConfig.movementSpeed : 180),
allowPassWallsFromBelow: null !== globalConfig.allowPassWallsFromBelow
- ? globalConfig.allowPassWallsFromBelow : false,
+ ? globalConfig.allowPassWallsFromBelow
+ : false,
};
let worldConfig = {
applyGravity,
diff --git a/lib/teams/server/event-handlers/end-player-hit-change-point-team-handler.js b/lib/teams/server/event-handlers/end-player-hit-change-point-team-handler.js
index bb1c33b3b..a53f07403 100644
--- a/lib/teams/server/event-handlers/end-player-hit-change-point-team-handler.js
+++ b/lib/teams/server/event-handlers/end-player-hit-change-point-team-handler.js
@@ -13,7 +13,7 @@ class EndPlayerHitChangePointTeamHandler
{
let teamId = playerSchema.currentTeam;
if(!teamId){
- Logger.info('Player "'+playerSchema?.playerName+'" (ID "'+playerSchema?.player_id+'"), team not saved.');
+ Logger.debug('Player "'+playerSchema?.playerName+'" (ID "'+playerSchema?.player_id+'"), team not saved.');
return false;
}
teamsPlugin.teamChangingRoomPlayers[playerSchema.player_id] = {
diff --git a/lib/users/client/player-engine.js b/lib/users/client/player-engine.js
index 644db1f7a..6b8e254ac 100644
--- a/lib/users/client/player-engine.js
+++ b/lib/users/client/player-engine.js
@@ -35,6 +35,7 @@ class PlayerEngine
this.pointsValidator = false;
// @TODO - BETA - Set all the configs in a single config property.
this.animationBasedOnPress = this.config.get('client/players/animations/basedOnPress');
+ // @TODO - BETA - Make size configurations depend on class-paths assets if present.
this.topOff = this.gameManager.config.get('client/players/size/topOffset');
this.leftOff = this.gameManager.config.get('client/players/size/leftOffset');
this.collideWorldBounds = this.gameManager.config.get('client/players/animations/collideWorldBounds');
@@ -73,6 +74,7 @@ class PlayerEngine
}
let {x, y, dir, playerName, avatarKey, playedTime, player_id} = addPlayerData;
let mappedAvatarKey = this.gameManager.mappedAvatars[avatarKey];
+ Logger.debug({mappedAvatarKey, avatarKey, mappedAvatars: this.gameManager.mappedAvatars});
this.players[id] = this.scene.physics.add.sprite(x, (y - this.topOff), mappedAvatarKey);
this.players[id].playerName = playerName;
this.players[id].playedTime = playedTime;
@@ -151,32 +153,58 @@ class PlayerEngine
this.scene.interpolatePlayersPosition[playerId] = player.state;
return;
}
- this.playPlayerAnimation(playerSprite, player.state);
- this.stopPlayerAnimation(playerSprite, player.state);
- this.updateSpritePosition(playerSprite, (player.state.x - this.leftOff), (player.state.y - this.topOff));
- this.updatePlayerState(playerSprite, player.state, playerId);
+ this.processPlayerPositionAnimationUpdate(
+ playerSprite,
+ player.state,
+ playerId,
+ player.state.x - this.leftOff,
+ player.state.y - this.topOff
+ );
+ }
+
+ processPlayerPositionAnimationUpdate(playerSprite, playerState, playerId, newX = 0, newY = 0)
+ {
+ Logger.debug('Process player position animation update.', {playerSprite, playerState, playerId, newX, newY});
+ if(!playerSprite){
+ Logger.error('Missing player sprite to process animation update.', playerSprite, playerState, playerId);
+ return;
+ }
+ if(!playerState){
+ Logger.error('Missing player state to process animation update.', playerSprite, playerState, playerId);
+ return;
+ }
+ if(!playerId){
+ Logger.error('Missing player ID to process animation update.', playerSprite, playerState, playerId);
+ return;
+ }
+ this.playPlayerAnimation(playerSprite, playerState);
+ this.stopPlayerAnimation(playerSprite, playerState);
+ this.updateSpritePosition(playerSprite, newX, newY);
+ this.updatePlayerState(playerSprite, playerState, playerId);
}
updatePlayerState(playerSprite, playerState, playerId)
{
// @NOTE: depth has to be set dynamically, this way the player will be above or below other objects.
- let playerNewDepth = this.updateSpriteDepth(playerSprite);
+ let playerNewDepth = playerSprite.y + playerSprite.body.height;
+ if(playerSprite.depth === playerNewDepth){
+ Logger.debug('Player state has not changed.', playerState, playerSprite);
+ return false;
+ }
+ playerSprite.setDepth(playerNewDepth);
this.events.emitSync('reldens.runPlayerAnimation', this, playerId, playerState, playerSprite);
this.updateNamePosition(playerSprite);
this.moveAttachedSprites(playerSprite, playerNewDepth);
}
- updateSpriteDepth(sprite)
- {
- let playerNewDepth = sprite.y + sprite.body.height;
- sprite.setDepth(playerNewDepth);
- return playerNewDepth;
- }
-
updateSpritePosition(sprite, newX, newY)
{
- sprite.x = newX;
- sprite.y = newY;
+ if(sprite.x !== newX){
+ sprite.x = newX;
+ }
+ if(sprite.y !== newY){
+ sprite.y = newY;
+ }
}
updateNamePosition(playerSprite)
@@ -202,10 +230,15 @@ class PlayerEngine
}
for(let i of playersKeys){
let sprite = playerSprite.moveSprites[i];
+ if(sprite.x === playerSprite.x && sprite.y === playerSprite.y){
+ continue;
+ }
sprite.x = playerSprite.x;
sprite.y = playerSprite.y;
// by default moving sprites will be always below the player:
- sprite.setDepth((sc.get(sprite, 'depthByPlayer', '') === 'above' ? playerNewDepth+1 : playerNewDepth-0.1));
+ let newSpriteDepth = playerNewDepth + (sc.get(sprite, 'depthByPlayer', '') === 'above' ? 1 : -0.1);
+ Logger.debug('Sprite "'+i+'" new depth: '+newSpriteDepth+'.', sprite);
+ sprite.setDepth(newSpriteDepth);
}
}
@@ -214,7 +247,13 @@ class PlayerEngine
// @NOTE: player speed is defined by the server.
let activeAvatarKey = this.gameManager.mappedAvatars[playerSprite.avatarKey];
if(this.animationBasedOnPress){
- playerSprite.anims.play(activeAvatarKey+'_'+playerState.dir, true);
+ let directionKey = activeAvatarKey+'_'+playerState.dir;
+ if(playerState.x === playerSprite.x && playerState.y === playerSprite.y){
+ Logger.debug('Player has not changed, skipped animation "'+directionKey+'".');
+ return false;
+ }
+ Logger.debug('Animation played based on press active.', activeAvatarKey);
+ playerSprite.anims.play(directionKey, true);
return;
}
if(playerState.x !== playerSprite.x){
diff --git a/lib/users/server/entities/users-entity.js b/lib/users/server/entities/users-entity.js
index 0fe0cac63..ef81946e6 100644
--- a/lib/users/server/entities/users-entity.js
+++ b/lib/users/server/entities/users-entity.js
@@ -44,20 +44,22 @@ class UsersEntity extends EntityProperties
}
};
- let listPropertiesKeys = Object.keys(properties);
- let editPropertiesKeys = sc.removeFromArray(listPropertiesKeys, [
+ let showProperties = Object.keys(properties);
+ let listProperties = [...showProperties];
+ let editProperties = sc.removeFromArray([...listProperties], [
'id',
'created_at',
'updated_at'
]);
- listPropertiesKeys.splice(listPropertiesKeys.indexOf('password'), 1);
+ showProperties.splice(listProperties.indexOf('password'), 1);
+ listProperties.splice(listProperties.indexOf('password'), 1);
return Object.assign({
- listProperties: listPropertiesKeys,
- showProperties: Object.keys(properties),
- filterProperties: listPropertiesKeys,
- editProperties: editPropertiesKeys,
+ listProperties,
+ showProperties,
+ filterProperties: listProperties,
+ editProperties,
properties
}, extraProps);
}
diff --git a/lib/users/server/player.js b/lib/users/server/player.js
index 67cc6ba30..589f4c827 100644
--- a/lib/users/server/player.js
+++ b/lib/users/server/player.js
@@ -63,6 +63,11 @@ class Player extends Schema
return this.customData[key] = data;
}
+ eventUniqueKey()
+ {
+ return this.eventsPrefix+'.'+(new Date()).getTime();
+ }
+
getPosition()
{
return {
diff --git a/lib/users/server/plugin.js b/lib/users/server/plugin.js
index 047f8f8db..14d4f4d11 100644
--- a/lib/users/server/plugin.js
+++ b/lib/users/server/plugin.js
@@ -7,9 +7,9 @@
const { PluginInterface } = require('../../features/plugin-interface');
const { UsersConst } = require('../constants');
const { ObjectsConst } = require('../../objects/constants');
-const { Logger, sc } = require('@reldens/utils');
-const { SkillsEvents } = require('@reldens/skills');
const { ActionsConst } = require('../../actions/constants');
+const { SkillsEvents } = require('@reldens/skills');
+const { Logger, sc } = require('@reldens/utils');
class UsersPlugin extends PluginInterface
{
@@ -54,41 +54,57 @@ class UsersPlugin extends PluginInterface
async activateLifeBar(configProcessor)
{
+ if(!this.events){
+ return false;
+ }
if(!this.lifeBarConfig){
this.lifeBarConfig = configProcessor.get('client/ui/lifeBar');
}
if(!this.lifeProp){
this.lifeProp = configProcessor.get('client/actions/skills/affectedProperty');
}
- this.events.on('reldens.createPlayerStatsAfter', async (client, userModel, playerSchema, roomScene) => {
- await this.updatePlayersLifebar(roomScene, client, playerSchema);
- await this.updateEnemiesLifebar(roomScene);
- });
- this.events.on('reldens.savePlayerStatsUpdateClient', async (client, playerSchema, roomScene) => {
- await this.onSavePlayerStatsUpdateClient(client, playerSchema, roomScene);
- });
- this.events.on('reldens.runBattlePveAfter', async (event) => {
- return this.sendLifeBarUpdate(event);
- });
- this.events.on('reldens.actionsPrepareEventsListeners', async (actionsPack, classPath) => {
- // @TODO - BETA - Make sure lifebar is updated on every stats change and not only after damage was applied.
- classPath.listenEvent(SkillsEvents.SKILL_ATTACK_APPLY_DAMAGE, async (skill, target) => {
+ this.events.on('reldens.createPlayerStatsAfter', this.updateLifeBars.bind(this));
+ this.events.on('reldens.savePlayerStatsUpdateClient', this.updateClientsWithPlayerStats.bind(this));
+ this.events.on('reldens.runBattlePveAfter', this.sendLifeBarUpdate.bind(this));
+ this.events.on(
+ 'reldens.actionsPrepareEventsListeners',
+ this.addEventListenerOnSkillAttackApplyDamage.bind(this)
+ );
+ this.events.on('reldens.restoreObjectAfter', this.broadcastObjectUpdateAfterRestore.bind(this));
+ }
+
+ async addEventListenerOnSkillAttackApplyDamage(actionsPack, classPath)
+ {
+ // @TODO - BETA - Make sure lifebar is updated on every stats change and not only after damage was applied.
+ classPath.listenEvent(
+ SkillsEvents.SKILL_ATTACK_APPLY_DAMAGE,
+ async (skill, target) => {
let client = skill.owner.skillsServer.client.client;
if(sc.hasOwn(target, 'player_id')){
await this.updatePlayersLifebar(client.room, client, target);
return;
}
- this.broadcastObjectUpdate(client, target);
- }, 'skillAttackApplyDamageLifebar', classPath.owner[classPath.ownerIdProperty]);
- });
- this.events.on('reldens.restoreObjectAfter', (event) => {
- this.broadcastObjectUpdate(event.room, event.enemyObject);
- });
+ await this.broadcastObjectUpdate(client, target);
+ },
+ classPath.getOwnerUniqueEventKey('skillAttackApplyDamageLifebar'),
+ classPath.getOwnerEventKey()
+ );
+ }
+
+ async broadcastObjectUpdateAfterRestore(event)
+ {
+ await this.broadcastObjectUpdate(event.room, event.enemyObject);
+ }
+
+ async updateLifeBars(client, userModel, playerSchema, roomScene)
+ {
+ await this.updatePlayersLifebar(roomScene, client, playerSchema);
+ await this.updateEnemiesLifebar(roomScene);
}
- broadcastObjectUpdate(room, enemyObject)
+ async broadcastObjectUpdate(room, enemyObject)
{
- room.broadcast('*', {
+ return room.broadcast('*', {
act: UsersConst.ACTION_LIFEBAR_UPDATE,
[ActionsConst.DATA_OWNER_TYPE]: ActionsConst.DATA_TYPE_VALUE_OBJECT,
[ActionsConst.DATA_OWNER_KEY]: enemyObject.broadcastKey,
@@ -97,7 +113,7 @@ class UsersPlugin extends PluginInterface
});
}
- sendLifeBarUpdate(event)
+ async sendLifeBarUpdate(event)
{
if(!this.lifeBarConfig.showEnemies && !this.lifeBarConfig.showOnClick){
return false;
@@ -106,7 +122,7 @@ class UsersPlugin extends PluginInterface
if(!target.stats[this.lifeProp]){
return false;
}
- this.broadcastObjectUpdate(roomScene, target)
+ await this.broadcastObjectUpdate(roomScene, target)
}
async updatePlayersLifebar(roomScene, client, playerSchema)
@@ -114,7 +130,7 @@ class UsersPlugin extends PluginInterface
if(this.lifeBarConfig.showAllPlayers || this.lifeBarConfig.showOnClick){
return await this.updateAllPlayersLifeBars(roomScene);
}
- return await this.onSavePlayerStatsUpdateClient(client, playerSchema, roomScene);
+ return await this.updateClientsWithPlayerStats(client, playerSchema, roomScene);
}
async updateEnemiesLifebar(roomScene)
@@ -129,8 +145,8 @@ class UsersPlugin extends PluginInterface
}
let updateData = {
act: UsersConst.ACTION_LIFEBAR_UPDATE,
- oT: ActionsConst.DATA_TYPE_VALUE_OBJECT,
- oK: obj.broadcastKey,
+ [ActionsConst.DATA_OWNER_TYPE]: ActionsConst.DATA_TYPE_VALUE_OBJECT,
+ [ActionsConst.DATA_OWNER_KEY]: obj.broadcastKey,
newValue: obj.stats[this.lifeProp],
totalValue: obj.initialStats[this.lifeProp]
};
@@ -147,8 +163,8 @@ class UsersPlugin extends PluginInterface
let player = roomScene.playerBySessionIdFromState(i);
let updateData = {
act: UsersConst.ACTION_LIFEBAR_UPDATE,
- oT: ActionsConst.DATA_TYPE_VALUE_PLAYER,
- oK: player.sessionId,
+ [ActionsConst.DATA_OWNER_TYPE]: ActionsConst.DATA_TYPE_VALUE_PLAYER,
+ [ActionsConst.DATA_OWNER_KEY]: player.sessionId,
newValue: player.stats[this.lifeProp],
totalValue: player.statsBase[this.lifeProp]
};
@@ -184,6 +200,7 @@ class UsersPlugin extends PluginInterface
let playerSpeed = Number(currentPlayer.stats?.speed || 0);
if(usePlayerSpeedProperty && 0 < playerSpeed){
currentPlayer.physicalBody.movementSpeed = playerSpeed;
+ Logger.debug('Use player speed: '+playerSpeed);
}
this.events.emit('reldens.createPlayerStatsAfter', client, userModel, currentPlayer, roomScene);
}
@@ -204,7 +221,7 @@ class UsersPlugin extends PluginInterface
return {stats, statsBase};
}
- async onSavePlayerStatsUpdateClient(client, playerSchema, roomScene)
+ async updateClientsWithPlayerStats(client, playerSchema, roomScene)
{
if(
client.sessionId !== playerSchema.sessionId
@@ -213,11 +230,10 @@ class UsersPlugin extends PluginInterface
){
return false;
}
- // @TODO - BETA - Replace "oT", "oK" by constants.
let updateData = {
act: UsersConst.ACTION_LIFEBAR_UPDATE,
- oT: 'p',
- oK: playerSchema.sessionId,
+ [ActionsConst.DATA_OWNER_TYPE]: ActionsConst.DATA_TYPE_VALUE_PLAYER,
+ [ActionsConst.DATA_OWNER_KEY]: playerSchema.sessionId,
newValue: playerSchema.stats[this.lifeProp],
totalValue: playerSchema.statsBase[this.lifeProp]
};
diff --git a/lib/world/client/debug-world-creator.js b/lib/world/client/debug-world-creator.js
index dd1f3117d..5a781e065 100644
--- a/lib/world/client/debug-world-creator.js
+++ b/lib/world/client/debug-world-creator.js
@@ -30,7 +30,6 @@ class DebugWorldCreator
scene.debugWorld.createLimits();
await scene.debugWorld.createWorldContent({});
scene.debugWorldTimer = new WorldTimer({
- world: scene.debugWorld,
callbacks: [() => {
if(!scene.debugWorld){
Logger.error('Scene World not longer exists.', scene.roomWorld);
@@ -39,7 +38,7 @@ class DebugWorldCreator
scene.debugWorld.removeBodiesFromWorld();
}]
});
- scene.debugWorldTimer.startWorldSteps();
+ scene.debugWorldTimer.startWorldSteps(scene.debugWorld);
scene.debugWorldRenderer = new Renderer(scene);
}
diff --git a/lib/world/client/plugin.js b/lib/world/client/plugin.js
index 8e5e2b450..d7ca7b960 100644
--- a/lib/world/client/plugin.js
+++ b/lib/world/client/plugin.js
@@ -15,9 +15,9 @@ class WorldPlugin extends PluginInterface
{
this.gameManager = sc.get(props, 'gameManager', false);
this.events = sc.get(props, 'events', false);
- this.debugWorldCreator = new DebugWorldCreator();
+ this.debugWorldCreator = false;
if(this.validateProperties()){
- this.listenEvents();
+ this.setupDebugMode();
}
}
@@ -34,11 +34,12 @@ class WorldPlugin extends PluginInterface
return true;
}
- listenEvents()
+ setupDebugMode()
{
if(!this.gameManager.config.getWithoutLogs('client/world/debug/enabled', false)){
return false;
}
+ this.debugWorldCreator = new DebugWorldCreator();
this.events.on('reldens.createEngineSceneDone', async (props) => {
await this.debugWorldCreator.createSceneWorld(props.currentScene);
});
diff --git a/lib/world/server/collisions-manager.js b/lib/world/server/collisions-manager.js
index 53b5b9f7d..e4643cf25 100644
--- a/lib/world/server/collisions-manager.js
+++ b/lib/world/server/collisions-manager.js
@@ -70,11 +70,8 @@ class CollisionsManager
this.room.roomWorld.removeBulletsStateIds.indexOf(stateId),
1
);
- if(!this.room.state.bodies[stateId]){
- continue;
- }
// @TODO - BETA - Refactor and extract Colyseus into a driver.
- this.room.state.bodies.delete(stateId);
+ this.room.state.removeBody(stateId);
}
}
@@ -204,13 +201,14 @@ class CollisionsManager
let isChangingScene = sc.get(playerBody, 'isChangingScene', false);
if(isChangingScene){
// @NOTE: if the player is already changing scene do nothing.
- Logger.info('Player is busy for a change point: ' + playerBody.playerId);
+ Logger.info('Player is busy for a change point: '+playerBody.playerId);
return false;
}
let playerPosition = {x: playerBody.position[0], y: playerBody.position[1]};
this.room.state.positionPlayer(playerBody.playerId, playerPosition);
let playerSchema = this.room.playerBySessionIdFromState(playerBody.playerId);
let changeData = {prev: playerSchema.state.scene, next: changePoint.changeScenePoint};
+ Logger.debug('Player "'+playerBody.playerId+'" hit change point.', changeData);
playerBody.isChangingScene = true;
let contactClient = this.room.getClientById(playerBody.playerId);
// @NOTE: we do not need to change back the isChangingScene property back to false since in the new
diff --git a/lib/world/server/p2world.js b/lib/world/server/p2world.js
index 09640abc0..38495a982 100644
--- a/lib/world/server/p2world.js
+++ b/lib/world/server/p2world.js
@@ -59,6 +59,8 @@ class P2world extends World
this.totalBodiesCreated = 0;
this.queueBodies = [];
this.enablePathFinder();
+ this.enableWorldDateTime();
+ this.worldKey = sc.randomChars(16);
}
saveMapData(options)
@@ -68,11 +70,25 @@ class P2world extends World
this.mapJson = sc.get(this.config.server.maps, this.sceneTiledMapFile, false);
}
if(!this.mapJson){
- Logger.critical('Map "'+this.sceneTiledMapFile+'" not found in server maps.', this.config.server.maps);
+ Logger.critical(
+ 'Map "'+this.sceneTiledMapFile+'" not found in server maps.',
+ Object.keys(this.config.server.maps)
+ );
ErrorManager.error('Map "'+this.sceneTiledMapFile+'" not found in server maps.');
}
}
+ enableWorldDateTime()
+ {
+ this.worldDateTime = new Date();
+ this.worldDateTimeInterval = setInterval(() => {
+ this.worldDateTime = new Date();
+ Logger.debug(
+ 'World "'+this.worldKey+'" time: '+this.worldDateTime.toISOString().slice(0, 19).replace('T', ' ')
+ );
+ }, 1000);
+ }
+
enablePathFinder()
{
if(!this.usePathFinder){
@@ -383,12 +399,12 @@ class P2world extends World
if(this.usePathFinder && pathFinder){
bodyObject.pathFinder = pathFinder;
}
- Logger.info('Created object for objectIndex: ' + objectIndex);
// try to get object instance from project root:
this.addBody(bodyObject);
// set data on room object:
roomObject.state = bodyObject.bodyState;
roomObject.objectBody = bodyObject;
+ Logger.info('Created object for objectIndex: '+objectIndex+' - At x/y: '+posX+' / '+posY+'.');
await this.events.emit('reldens.createdWorldObject', {
p2world: this,
roomObject,
@@ -528,13 +544,17 @@ class P2world extends World
return boxBody;
}
- fetchPlayerSpeed()
+ fetchPlayerSpeed(playerSpeed)
{
- let usePlayerSpeedConfig = this.config.get('server/players/physicsBody/usePlayerSpeedConfig');
- if(usePlayerSpeedConfig){
- return this.config.get('server/players/physicsBody/speed', this.movementSpeed);
+ let movementSpeed = this.movementSpeed;
+ if(this.config.get('server/players/physicsBody/usePlayerSpeedConfig')){
+ let configSpeed = this.config.get('server/players/physicsBody/speed', playerSpeed);
+ if(0 < configSpeed){
+ movementSpeed = configSpeed;
+ }
}
- return this.movementSpeed;
+ Logger.debug('Use movement speed: '+movementSpeed);
+ return movementSpeed;
}
shootBullet(fromPosition, toPosition, bulletObject)
@@ -575,7 +595,7 @@ class P2world extends World
let bodyStateId = bulletKey+'_bullet_'+bulletBody.id;
bulletBody.bodyStateId = bodyStateId;
// @TODO - BETA - Refactor and extract Colyseus into a driver.
- bulletObject.room.state.bodies.set(bodyStateId, bulletBody.bodyState);
+ bulletObject.room.state.addBodyToState(bulletBody.bodyState, bodyStateId);
// then speed up in the target direction:
bulletBody.angle = Math.atan2(y, x) * 180 / Math.PI;
bulletBody.velocity[0] = bulletObject.magnitude * Math.cos(angleByVelocity);
diff --git a/lib/world/server/physical-body.js b/lib/world/server/physical-body.js
index 56fbb82d3..f7cfbbf00 100644
--- a/lib/world/server/physical-body.js
+++ b/lib/world/server/physical-body.js
@@ -26,7 +26,7 @@ class PhysicalBody extends Body
this.originalRow = false;
this.jumpSpeed = sc.get(options, 'jumpSpeed', 540);
this.jumpTimeMs = sc.get(options, 'jumpTimeMs', 180);
- this.movementSpeed = sc.get(options, 'movementSpeed', 120);
+ this.movementSpeed = sc.get(options, 'movementSpeed', 180);
}
integrate(dt)
diff --git a/lib/world/world-timer.js b/lib/world/world-timer.js
index 03e0b768f..aa5a58aef 100644
--- a/lib/world/world-timer.js
+++ b/lib/world/world-timer.js
@@ -4,14 +4,13 @@
*
*/
-const { ErrorManager, sc } = require('@reldens/utils');
+const { Logger, sc } = require('@reldens/utils');
class WorldTimer
{
constructor(props)
{
- this.world = props.world;
this.clockInstance = sc.get(props, 'clockInstance', false);
this.callbacks = sc.get(props, 'callbacks', []);
this.worldTimer = {};
@@ -20,47 +19,45 @@ class WorldTimer
this.stepTime = 0;
this.startedTime = (new Date()).getTime();
this.currentTime = this.startedTime;
- this.validateProperties();
}
- validateProperties()
+ startWorldSteps(world)
{
- if(!this.world){
- ErrorManager.error('Missing world parameter.');
+ if(!world){
+ Logger.error('World instance invalid.', {world});
+ return;
}
- }
-
- startWorldSteps()
- {
- this.stepTime = 1000 * this.world.timeStep;
+ this.stepTime = 1000 * world.timeStep;
if(this.clockInstance){
+ Logger.debug('WorldTimes using clock instance.');
this.worldTimer = this.clockInstance.setInterval(() => {
- this.setIntervalCallback();
+ this.setIntervalCallback(world);
}, this.stepTime);
return;
}
+ Logger.debug('WorldTimes using setInterval.');
this.worldTimer = setInterval(() => {
- this.setIntervalCallback();
+ this.setIntervalCallback(world);
}, this.stepTime);
}
- setIntervalCallback()
+ setIntervalCallback(world)
{
if(this.paused){
return;
}
this.currentTime += this.stepTime;
- this.stepWorld();
+ this.stepWorld(world);
this.executeCallbacks();
}
- stepWorld()
+ stepWorld(world)
{
- if(this.world.useFixedWorldStep){
- this.world.step(this.world.timeStep);
+ if(world.useFixedWorldStep){
+ world.step(world.timeStep);
return;
}
- this.stepWorldWithSubSteps();
+ this.stepWorldWithSubSteps(world);
}
executeCallbacks()
@@ -73,11 +70,11 @@ class WorldTimer
}
}
- stepWorldWithSubSteps()
+ stepWorldWithSubSteps(world)
{
let now = Date.now() / 1000;
let timeSinceLastCall = now - this.lastCallTime;
- this.world.step(this.world.timeStep, timeSinceLastCall, this.world.maxSubSteps);
+ world.step(world.timeStep, timeSinceLastCall, world.maxSubSteps);
}
}
diff --git a/migrations/development/beta.30-sql-update.sql b/migrations/development/beta.30-sql-update.sql
index be6639bdb..6135f4d7b 100644
--- a/migrations/development/beta.30-sql-update.sql
+++ b/migrations/development/beta.30-sql-update.sql
@@ -9,7 +9,6 @@ UPDATE `rooms` SET
`map_filename` = CONCAT(`map_filename`, '.json'),
`scene_images` = REPLACE(CONCAT(`scene_images`, '.png'), ',', '.png,');
-
#######################################################################################################################
SET FOREIGN_KEY_CHECKS = 1;
diff --git a/migrations/development/beta.31-sql-update.sql b/migrations/development/beta.31-sql-update.sql
new file mode 100644
index 000000000..912e90eab
--- /dev/null
+++ b/migrations/development/beta.31-sql-update.sql
@@ -0,0 +1,40 @@
+#######################################################################################################################
+
+SET FOREIGN_KEY_CHECKS = 0;
+
+#######################################################################################################################
+
+# Sample player fix:
+REPLACE INTO `players_state` (`id`, `player_id`, `room_id`, `x`, `y`, `dir`) VALUES
+ (1, 1, 5, 332, 288, 'down');
+
+REPLACE INTO `players_stats` (`id`, `player_id`, `stat_id`, `base_value`, `value`) VALUES
+ (1, 1, 1, 280, 81),
+ (2, 1, 2, 280, 85),
+ (3, 1, 3, 280, 400),
+ (4, 1, 4, 280, 280),
+ (5, 1, 5, 100, 100),
+ (6, 1, 6, 100, 100),
+ (7, 1, 7, 100, 100),
+ (8, 1, 8, 100, 100),
+ (9, 1, 9, 100, 100),
+ (10, 1, 10, 100, 100);
+
+# Config:
+SET @boolean_id = (SELECT `id` FROM `config_types` WHERE `label` = 'boolean');
+INSERT INTO `config` (`scope`, `path`, `value`, `type`) VALUES ('server', 'players/physicsBody/usePlayerSpeedConfig', '0', @boolean_id);
+INSERT INTO `config` (`scope`, `path`, `value`, `type`) VALUES ('server', 'players/physicsBody/usePlayerSpeedProperty', '0', @boolean_id);
+
+# Rooms:
+UPDATE `rooms` SET `name` = 'reldens-forest' WHERE `name` = 'ReldensForest';
+UPDATE `rooms` SET `name` = 'reldens-house-1' WHERE `name` = 'ReldensHouse_1';
+UPDATE `rooms` SET `name` = 'reldens-house-2' WHERE `name` = 'ReldensHouse_2';
+UPDATE `rooms` SET `name` = 'reldens-town' WHERE `name` = 'ReldensTown';
+UPDATE `rooms` SET `name` = 'reldens-house-1-2d-floor' WHERE `name` = 'ReldensHouse_1b';
+UPDATE `rooms` SET `name` = 'reldens-gravity' WHERE `name` = 'TopDownRoom';
+
+#######################################################################################################################
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+#######################################################################################################################
diff --git a/migrations/production/reldens-basic-config-v4.0.0.sql b/migrations/production/reldens-basic-config-v4.0.0.sql
index ee1f1b90d..947a31d0e 100644
--- a/migrations/production/reldens-basic-config-v4.0.0.sql
+++ b/migrations/production/reldens-basic-config-v4.0.0.sql
@@ -386,7 +386,7 @@ REPLACE INTO `features` (`id`, `code`, `title`, `is_enabled`) VALUES
(13, 'rewards', 'Rewards', 1),
(14, 'snippets', 'Snippets', 1),
(16, 'ads', 'Ads', 1),
- (17, 'world', 'World', 1);
+ (17, 'world', 'World', 0);
REPLACE INTO `items_types` (`id`, `key`) VALUES
(10, 'base'),
diff --git a/migrations/production/reldens-sample-data-v4.0.0.sql b/migrations/production/reldens-sample-data-v4.0.0.sql
index 39e0b5950..6299e805e 100644
--- a/migrations/production/reldens-sample-data-v4.0.0.sql
+++ b/migrations/production/reldens-sample-data-v4.0.0.sql
@@ -90,10 +90,6 @@ REPLACE INTO `ads_event_video` (`id`, `ads_id`, `event_key`, `event_data`) VALUE
(1, 5, 'activatedRoom_ReldensTown', '{"rewardItemKey":"coins","rewardItemQty":1}'),
(2, 6, 'activatedRoom_ReldensForest', '{"rewardItemKey":"coins","rewardItemQty":1}');
-REPLACE INTO `ads_played` (`id`, `ads_id`, `player_id`, `started_at`, `ended_at`) VALUES
- (7, 5, 1, '2023-10-17 18:28:17', '2023-10-17 18:28:22'),
- (8, 6, 1, '2023-09-28 21:00:31', '2023-09-28 21:00:41');
-
REPLACE INTO `ads_providers` (`id`, `key`, `enabled`) VALUES
(1, 'crazyGames', 0),
(2, 'gameMonetize', 0);
@@ -518,7 +514,7 @@ REPLACE INTO `features` (`id`, `code`, `title`, `is_enabled`) VALUES
(13, 'rewards', 'Rewards', 1),
(14, 'snippets', 'Snippets', 1),
(16, 'ads', 'Ads', 1),
- (17, 'world', 'World', 1);
+ (17, 'world', 'World', 0);
REPLACE INTO `items_group` (`id`, `key`, `label`, `description`, `files_name`, `sort`, `items_limit`, `limit_per_item`) VALUES
(1, 'weapon', 'Weapon', 'All kinds of weapons.', 'weapon.png', 2, 1, 0),
@@ -531,10 +527,10 @@ REPLACE INTO `items_group` (`id`, `key`, `label`, `description`, `files_name`, `
REPLACE INTO `items_item` (`id`, `key`, `type`, `group_id`, `label`, `description`, `qty_limit`, `uses_limit`, `useTimeOut`, `execTimeOut`, `customData`) VALUES
(1, 'coins', 3, NULL, 'Coins', NULL, 0, 1, NULL, NULL, NULL),
(2, 'branch', 10, NULL, 'Tree branch', 'An useless tree branch (for now)', 0, 1, NULL, NULL, NULL),
- (3, 'heal_potion_20', 5, NULL, 'Heal Potion', 'A heal potion that will restore 20 HP.', 0, 1, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"hide":true,"usePlayerPosition":true,"closeInventoryOnUse":true,"followPlayer":true,"startsOnTarget":true},"removeAfterUse":true}'),
- (4, 'axe', 1, 1, 'Axe', 'A short distance but powerful weapon.', 0, 0, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"hide":true,"destroyOnComplete":true,"usePlayerPosition":true,"closeInventoryOnUse":true,"followPlayer":true,"startsOnTarget":true}}'),
- (5, 'spear', 1, 1, 'Spear', 'A short distance but powerful weapon.', 0, 0, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"hide":true,"destroyOnComplete":true,"usePlayerPosition":true,"closeInventoryOnUse":true,"followPlayer":true,"startsOnTarget":true}}'),
- (6, 'magic_potion_20', 5, NULL, 'Magic Potion', 'A magic potion that will restore 20 MP.', 0, 1, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"hide":true,"usePlayerPosition":true,"closeInventoryOnUse":true,"followPlayer":true,"startsOnTarget":true},"removeAfterUse":true}');
+ (3, 'heal_potion_20', 5, NULL, 'Heal Potion', 'A heal potion that will restore 20 HP.', 0, 1, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"usePlayerPosition":true,"followPlayer":true,"startsOnTarget":true},"removeAfterUse":true}'),
+ (4, 'axe', 1, 1, 'Axe', 'A short distance but powerful weapon.', 0, 0, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"destroyOnComplete":true,"usePlayerPosition":true,"followPlayer":true,"startsOnTarget":true}}'),
+ (5, 'spear', 1, 1, 'Spear', 'A short distance but powerful weapon.', 0, 0, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"destroyOnComplete":true,"usePlayerPosition":true,"followPlayer":true,"startsOnTarget":true}}'),
+ (6, 'magic_potion_20', 5, NULL, 'Magic Potion', 'A magic potion that will restore 20 MP.', 0, 1, NULL, NULL, '{"animationData":{"frameWidth":64,"frameHeight":64,"start":6,"end":11,"repeat":0,"usePlayerPosition":true,"followPlayer":true,"startsOnTarget":true},"removeAfterUse":true}');
REPLACE INTO `items_item_modifiers` (`id`, `item_id`, `key`, `property_key`, `operation`, `value`, `maxProperty`) VALUES
(1, 4, 'atk', 'stats/atk', 5, '5', NULL),
@@ -675,12 +671,12 @@ REPLACE INTO `rewards` (`id`, `object_id`, `item_id`, `modifier_id`, `experience
(2, 6, 2, NULL, 10, 100, 3, 0, 0, 1);
REPLACE INTO `rooms` (`id`, `name`, `title`, `map_filename`, `scene_images`, `room_class_key`, `customData`) VALUES
- (2, 'ReldensHouse_1', 'House - 1', 'reldens-house-1.json', 'reldens-house-1.png', NULL, NULL),
- (3, 'ReldensHouse_2', 'House - 2', 'reldens-house-2.json', 'reldens-house-2.png', NULL, NULL),
- (4, 'ReldensTown', 'Town', 'reldens-town.json', 'reldens-town.png', NULL, NULL),
- (5, 'ReldensForest', 'Forest', 'reldens-forest.json', 'reldens-forest.png', NULL, NULL),
- (6, 'ReldensHouse_1b', 'House - 1 - Floor 2', 'reldens-house-1-2d-floor.json', 'reldens-house-1-2d-floor.png', NULL, NULL),
- (7, 'TopDownRoom', 'Gravity World!', 'reldens-gravity.json', 'reldens-gravity.png', NULL, '{"gravity":[0,625],"applyGravity":true,"allowPassWallsFromBelow":true,"timeStep":0.012,"type":"TOP_DOWN_WITH_GRAVITY","useFixedWorldStep":false,"maxSubSteps":5,"movementSpeed":200,"usePathFinder":false}');
+ (2, 'reldens-house-1', 'House - 1', 'reldens-house-1.json', 'reldens-house-1.png', NULL, NULL),
+ (3, 'reldens-house-2', 'House - 2', 'reldens-house-2.json', 'reldens-house-2.png', NULL, NULL),
+ (4, 'reldens-town', 'Town', 'reldens-town.json', 'reldens-town.png', NULL, NULL),
+ (5, 'reldens-forest', 'Forest', 'reldens-forest.json', 'reldens-forest.png', NULL, NULL),
+ (6, 'reldens-house-1-2d-floor', 'House - 1 - Floor 2', 'reldens-house-1-2d-floor.json', 'reldens-house-1-2d-floor.png', NULL, NULL),
+ (7, 'reldens-gravity', 'Gravity World!', 'reldens-gravity.json', 'reldens-gravity.png', NULL, '{"gravity":[0,625],"applyGravity":true,"allowPassWallsFromBelow":true,"timeStep":0.012,"type":"TOP_DOWN_WITH_GRAVITY","useFixedWorldStep":false,"maxSubSteps":2,"movementSpeed":160,"usePathFinder":false}');
REPLACE INTO `rooms_change_points` (`id`, `room_id`, `tile_index`, `next_room_id`) VALUES
(1, 2, 816, 4),
@@ -699,7 +695,7 @@ REPLACE INTO `rooms_change_points` (`id`, `room_id`, `tile_index`, `next_room_id
(14, 6, 664, 2),
(15, 7, 540, 3),
(16, 3, 500, 7),
- (17, 3, 780, 7);
+ (17, 3, 780, 4);
REPLACE INTO `rooms_return_points` (`id`, `room_id`, `direction`, `x`, `y`, `is_default`, `from_room_id`) VALUES
(1, 2, 'up', 548, 615, 1, 4),
diff --git a/package-lock.json b/package-lock.json
index ab1950e72..93e2b7dc9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "reldens",
- "version": "4.0.0-beta.30",
+ "version": "4.0.0-beta.31",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "reldens",
- "version": "4.0.0-beta.30",
+ "version": "4.0.0-beta.31",
"license": "MIT",
"dependencies": {
"@adminjs/design-system": "2.1.2",
@@ -54,11 +54,11 @@
"@parcel/transformer-svg": "2.10.3",
"@parcel/transformer-webmanifest": "2.10.3",
"@parcel/transformer-worklet": "2.10.3",
- "@reldens/items-system": "^0.23.0",
- "@reldens/modifiers": "^0.20.0",
- "@reldens/skills": "^0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.1",
+ "@reldens/items-system": "^0.25.0",
+ "@reldens/modifiers": "^0.21.0",
+ "@reldens/skills": "^0.22.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.22.0",
"@sendgrid/mail": "7.7.0",
"adminjs": "5.7.3",
"bcrypt": "5.1.1",
@@ -3023,16 +3023,16 @@
}
},
"node_modules/@mikro-orm/core": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.9.3.tgz",
- "integrity": "sha512-SYcRa4Rmi6GSPAvaXIsrBrhHLCieZtnFHYXtcUVMRpJRBxUbqv8RfhUedhYZGty8eTd44nNY9+zn6auv1x8IoA==",
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.9.7.tgz",
+ "integrity": "sha512-VzbpJPQlwuK6Q/4FkppWNGKvzyYL31Gsw/qskr/GCa/010yLO8u3RQio/Q1EKRi+tNsjhqTPGA1b7OOM+DvpiQ==",
"dependencies": {
"acorn-loose": "8.3.0",
"acorn-walk": "8.2.0",
"dotenv": "16.3.1",
"fs-extra": "11.1.1",
"globby": "11.1.0",
- "mikro-orm": "5.9.3",
+ "mikro-orm": "5.9.7",
"reflect-metadata": "0.1.13"
},
"engines": {
@@ -3087,9 +3087,9 @@
}
},
"node_modules/@mikro-orm/mongodb": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/@mikro-orm/mongodb/-/mongodb-5.9.3.tgz",
- "integrity": "sha512-ltuBs6dwJz1p1TCuIunyCmvAhMwa5o3NeTe9KFIbJYXoUQGqMYLUcHFKGe9+KYsIAz0K6j3kMUGbL1xKGax8Sg==",
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/@mikro-orm/mongodb/-/mongodb-5.9.7.tgz",
+ "integrity": "sha512-KKV8IsN7yDXDEDOXhVNw1Labm8Z9Sg0KsGBY45fUUlaPSMKJQcmoV9hFYg1fKh5Hab6EG5DEOcFGj5Q0JINs2w==",
"dependencies": {
"bson": "^5.4.0",
"mongodb": "5.8.1"
@@ -3173,9 +3173,9 @@
}
},
"node_modules/@mongodb-js/saslprep": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz",
- "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.3.tgz",
+ "integrity": "sha512-SyCxhJfmK6MoLNV5SbDpNdUy9SDv5H7y9/9rl3KpnwgTHWuNNMc87zWqbcIZXNWY+aUjxLGLEcvHoLagG4tWCg==",
"optional": true,
"dependencies": {
"sparse-bitfield": "^3.0.3"
@@ -5005,50 +5005,66 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"node_modules/@reldens/items-system": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@reldens/items-system/-/items-system-0.25.0.tgz",
+ "integrity": "sha512-+gNO0Ng49GbzIAC3LhJf0CklwGPDORaIpNPOsNMHLBPXV/FljZmbzBYEyH8odasyJW/VoDDHqcCXvXXowsKSMQ==",
+ "dependencies": {
+ "@reldens/modifiers": "0.21.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.23.0"
+ }
+ },
+ "node_modules/@reldens/items-system/node_modules/@reldens/utils": {
"version": "0.23.0",
- "resolved": "https://registry.npmjs.org/@reldens/items-system/-/items-system-0.23.0.tgz",
- "integrity": "sha512-9UixVYzHk1jZsRWZelIBLyEF2CPMYXPets2R/VYWXRrukFvkNbb8w9nWYY5f6ANAnRr+uH/79SbGMMfGMdLU9w==",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.23.0.tgz",
+ "integrity": "sha512-oZLsZZ4xthEJJThXVlth4fswEQ816u+N2qsjpGs9Q+Gq9GrFAX65tWesyjIIYOJPj4iloDFZTNUGo/j5sHwIkg==",
"dependencies": {
- "@reldens/modifiers": "0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.1"
+ "await-event-emitter": "^2.0.2"
}
},
"node_modules/@reldens/modifiers": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/@reldens/modifiers/-/modifiers-0.20.0.tgz",
- "integrity": "sha512-pHNhvpHxWJeEjB8hvouMSaQDbTAmhX0RM/joe8O0Jc96tKJp3y+LMuOqZVw2UbsCiyakwIpz5iSz6WJBe6ZHkQ==",
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@reldens/modifiers/-/modifiers-0.21.0.tgz",
+ "integrity": "sha512-1btXX0cLE5GB1NJ/cCZRYbVVDaQBDJYsbenSICy0IryjEyvXLd7ej48ccLiBVBwk2A/6PR6+95WoSiV/d8ea6Q==",
"dependencies": {
- "@reldens/utils": "^0.21.0"
+ "@reldens/utils": "^0.22.0"
}
},
"node_modules/@reldens/skills": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/@reldens/skills/-/skills-0.20.0.tgz",
- "integrity": "sha512-fDufgiBsB0yXA4oWHzX+8zZmMBCq0KdcUCEETmbREICd/dWVOF3fUaBUPqwclLHf0k1yt49VF9ayD1+CrdN7LQ==",
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@reldens/skills/-/skills-0.22.0.tgz",
+ "integrity": "sha512-qHsOzJHW0PB+FT93pVLKylpXwAU2LUleb9TINVKrT2SMOUwSYnfP4I7xcVr7nfxQew4lbcxastwhgMrHRJNJ/Q==",
+ "dependencies": {
+ "@reldens/modifiers": "^0.21.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.23.0"
+ }
+ },
+ "node_modules/@reldens/skills/node_modules/@reldens/utils": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.23.0.tgz",
+ "integrity": "sha512-oZLsZZ4xthEJJThXVlth4fswEQ816u+N2qsjpGs9Q+Gq9GrFAX65tWesyjIIYOJPj4iloDFZTNUGo/j5sHwIkg==",
"dependencies": {
- "@reldens/modifiers": "^0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.0"
+ "await-event-emitter": "^2.0.2"
}
},
"node_modules/@reldens/storage": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@reldens/storage/-/storage-0.18.0.tgz",
- "integrity": "sha512-MuUIlzOzv3HifVEL8mGXZZJv+2w5/e4JrmMfaLGIRlujwPAAOY0A/3Gvy0g4PxLA8TUSsh0ETACtZNYwYZzDCw==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@reldens/storage/-/storage-0.19.0.tgz",
+ "integrity": "sha512-PzB8ojymvuzUAlgSmukD/z3iAXSUe2NT4mXe2RvloumAa8yEJfPBoN1N2La0y5Uniu0K+cMXHmLuo53rLI9DsQ==",
"dependencies": {
"@mikro-orm/core": "^5.9.3",
"@mikro-orm/mongodb": "^5.9.3",
- "@reldens/utils": "^0.21.0",
- "knex": "^3.0.1",
+ "@reldens/utils": "^0.22.0",
+ "knex": "^3.1.0",
"mysql": "^2.18.1",
- "objection": "^3.1.2"
+ "objection": "^3.1.3"
}
},
"node_modules/@reldens/utils": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.21.1.tgz",
- "integrity": "sha512-APamwB56m2FgAxdLaa59yXEb9TcCmZ7FubKHElf7QaJ16l1AHEvcFRUbv24O7RdKqsGpTpqHRCfcn+lO+s2Ukg==",
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.22.0.tgz",
+ "integrity": "sha512-khf38VbfMvA6No/OowkCVTMxrObSPi8uVNz330psznMTXJzPn5ZPHEYA9VdMKC5ozKhCi8Ug4SNI+e/jXXKyMA==",
"dependencies": {
"await-event-emitter": "^2.0.2"
}
@@ -5683,9 +5699,9 @@
}
},
"node_modules/acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+ "version": "8.11.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+ "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"bin": {
"acorn": "bin/acorn"
},
@@ -5779,9 +5795,9 @@
}
},
"node_modules/ajv": {
- "version": "8.11.2",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
- "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -6349,9 +6365,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001570",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz",
- "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==",
+ "version": "1.0.30001579",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
+ "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
"funding": [
{
"type": "opencollective",
@@ -7630,9 +7646,9 @@
"optional": true
},
"node_modules/fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
+ "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
"dependencies": {
"reusify": "^1.0.4"
}
@@ -8415,9 +8431,9 @@
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
+ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
"engines": {
"node": ">= 4"
}
@@ -8937,9 +8953,9 @@
}
},
"node_modules/knex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/knex/-/knex-3.0.1.tgz",
- "integrity": "sha512-ruASxC6xPyDklRdrcDy6a9iqK+R9cGK214aiQa+D9gX2ZnHZKv6o6JC9ZfgxILxVAul4bZ13c3tgOAHSuQ7/9g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz",
+ "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==",
"dependencies": {
"colorette": "2.0.19",
"commander": "^10.0.0",
@@ -8950,7 +8966,7 @@
"getopts": "2.3.0",
"interpret": "^2.2.0",
"lodash": "^4.17.21",
- "pg-connection-string": "2.6.1",
+ "pg-connection-string": "2.6.2",
"rechoir": "^0.8.0",
"resolve-from": "^5.0.0",
"tarn": "^3.0.2",
@@ -9405,9 +9421,9 @@
}
},
"node_modules/mikro-orm": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.9.3.tgz",
- "integrity": "sha512-lLBWENtV7yUE5KraqJEMaaKDPotnab6i/uf+wOyjILxYPjaXivH+oq7g9U3WS7K1fLUpQlR+bdQTOExHLy1FtQ==",
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.9.7.tgz",
+ "integrity": "sha512-0AxNDxQWk45n5N5g5q/K2tVj1/Narf4h5+1fhFc0uYAp/tOGAGvjmVK43Xy4TisEm/1VpBNOtS7FYKvh14WVOQ==",
"engines": {
"node": ">= 14.0.0"
}
@@ -9838,11 +9854,11 @@
}
},
"node_modules/objection": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/objection/-/objection-3.1.2.tgz",
- "integrity": "sha512-V8YwRWz+DFbB9JS/m7TBLhRPVAFK/VX7yV3ZDAMkfUG9qYHLRyG/K4ZS0acKtGPWtRdVrCuN4qM1VkH3PuJ5Lg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/objection/-/objection-3.1.3.tgz",
+ "integrity": "sha512-X4DH8/xKBS34bwWOSLAPyceg0JgLhLiUuz+cEEyDA8iDFoT1UM9UbtwBpwHV11hYskAKxOgVlNHeveFQiOPDXA==",
"dependencies": {
- "ajv": "^8.6.2",
+ "ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"db-errors": "^0.2.3"
},
@@ -10080,9 +10096,9 @@
}
},
"node_modules/pg-connection-string": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz",
- "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
+ "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA=="
},
"node_modules/phaser": {
"version": "3.70.0",
@@ -14335,23 +14351,23 @@
}
},
"@mikro-orm/core": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.9.3.tgz",
- "integrity": "sha512-SYcRa4Rmi6GSPAvaXIsrBrhHLCieZtnFHYXtcUVMRpJRBxUbqv8RfhUedhYZGty8eTd44nNY9+zn6auv1x8IoA==",
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-5.9.7.tgz",
+ "integrity": "sha512-VzbpJPQlwuK6Q/4FkppWNGKvzyYL31Gsw/qskr/GCa/010yLO8u3RQio/Q1EKRi+tNsjhqTPGA1b7OOM+DvpiQ==",
"requires": {
"acorn-loose": "8.3.0",
"acorn-walk": "8.2.0",
"dotenv": "16.3.1",
"fs-extra": "11.1.1",
"globby": "11.1.0",
- "mikro-orm": "5.9.3",
+ "mikro-orm": "5.9.7",
"reflect-metadata": "0.1.13"
}
},
"@mikro-orm/mongodb": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/@mikro-orm/mongodb/-/mongodb-5.9.3.tgz",
- "integrity": "sha512-ltuBs6dwJz1p1TCuIunyCmvAhMwa5o3NeTe9KFIbJYXoUQGqMYLUcHFKGe9+KYsIAz0K6j3kMUGbL1xKGax8Sg==",
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/@mikro-orm/mongodb/-/mongodb-5.9.7.tgz",
+ "integrity": "sha512-KKV8IsN7yDXDEDOXhVNw1Labm8Z9Sg0KsGBY45fUUlaPSMKJQcmoV9hFYg1fKh5Hab6EG5DEOcFGj5Q0JINs2w==",
"requires": {
"bson": "^5.4.0",
"mongodb": "5.8.1"
@@ -14381,9 +14397,9 @@
}
},
"@mongodb-js/saslprep": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz",
- "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.3.tgz",
+ "integrity": "sha512-SyCxhJfmK6MoLNV5SbDpNdUy9SDv5H7y9/9rl3KpnwgTHWuNNMc87zWqbcIZXNWY+aUjxLGLEcvHoLagG4tWCg==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
@@ -15487,50 +15503,70 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"@reldens/items-system": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/@reldens/items-system/-/items-system-0.23.0.tgz",
- "integrity": "sha512-9UixVYzHk1jZsRWZelIBLyEF2CPMYXPets2R/VYWXRrukFvkNbb8w9nWYY5f6ANAnRr+uH/79SbGMMfGMdLU9w==",
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@reldens/items-system/-/items-system-0.25.0.tgz",
+ "integrity": "sha512-+gNO0Ng49GbzIAC3LhJf0CklwGPDORaIpNPOsNMHLBPXV/FljZmbzBYEyH8odasyJW/VoDDHqcCXvXXowsKSMQ==",
"requires": {
- "@reldens/modifiers": "0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.1"
+ "@reldens/modifiers": "0.21.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.23.0"
+ },
+ "dependencies": {
+ "@reldens/utils": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.23.0.tgz",
+ "integrity": "sha512-oZLsZZ4xthEJJThXVlth4fswEQ816u+N2qsjpGs9Q+Gq9GrFAX65tWesyjIIYOJPj4iloDFZTNUGo/j5sHwIkg==",
+ "requires": {
+ "await-event-emitter": "^2.0.2"
+ }
+ }
}
},
"@reldens/modifiers": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/@reldens/modifiers/-/modifiers-0.20.0.tgz",
- "integrity": "sha512-pHNhvpHxWJeEjB8hvouMSaQDbTAmhX0RM/joe8O0Jc96tKJp3y+LMuOqZVw2UbsCiyakwIpz5iSz6WJBe6ZHkQ==",
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@reldens/modifiers/-/modifiers-0.21.0.tgz",
+ "integrity": "sha512-1btXX0cLE5GB1NJ/cCZRYbVVDaQBDJYsbenSICy0IryjEyvXLd7ej48ccLiBVBwk2A/6PR6+95WoSiV/d8ea6Q==",
"requires": {
- "@reldens/utils": "^0.21.0"
+ "@reldens/utils": "^0.22.0"
}
},
"@reldens/skills": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/@reldens/skills/-/skills-0.20.0.tgz",
- "integrity": "sha512-fDufgiBsB0yXA4oWHzX+8zZmMBCq0KdcUCEETmbREICd/dWVOF3fUaBUPqwclLHf0k1yt49VF9ayD1+CrdN7LQ==",
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@reldens/skills/-/skills-0.22.0.tgz",
+ "integrity": "sha512-qHsOzJHW0PB+FT93pVLKylpXwAU2LUleb9TINVKrT2SMOUwSYnfP4I7xcVr7nfxQew4lbcxastwhgMrHRJNJ/Q==",
"requires": {
- "@reldens/modifiers": "^0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.0"
+ "@reldens/modifiers": "^0.21.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.23.0"
+ },
+ "dependencies": {
+ "@reldens/utils": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.23.0.tgz",
+ "integrity": "sha512-oZLsZZ4xthEJJThXVlth4fswEQ816u+N2qsjpGs9Q+Gq9GrFAX65tWesyjIIYOJPj4iloDFZTNUGo/j5sHwIkg==",
+ "requires": {
+ "await-event-emitter": "^2.0.2"
+ }
+ }
}
},
"@reldens/storage": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@reldens/storage/-/storage-0.18.0.tgz",
- "integrity": "sha512-MuUIlzOzv3HifVEL8mGXZZJv+2w5/e4JrmMfaLGIRlujwPAAOY0A/3Gvy0g4PxLA8TUSsh0ETACtZNYwYZzDCw==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@reldens/storage/-/storage-0.19.0.tgz",
+ "integrity": "sha512-PzB8ojymvuzUAlgSmukD/z3iAXSUe2NT4mXe2RvloumAa8yEJfPBoN1N2La0y5Uniu0K+cMXHmLuo53rLI9DsQ==",
"requires": {
"@mikro-orm/core": "^5.9.3",
"@mikro-orm/mongodb": "^5.9.3",
- "@reldens/utils": "^0.21.0",
- "knex": "^3.0.1",
+ "@reldens/utils": "^0.22.0",
+ "knex": "^3.1.0",
"mysql": "^2.18.1",
- "objection": "^3.1.2"
+ "objection": "^3.1.3"
}
},
"@reldens/utils": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.21.1.tgz",
- "integrity": "sha512-APamwB56m2FgAxdLaa59yXEb9TcCmZ7FubKHElf7QaJ16l1AHEvcFRUbv24O7RdKqsGpTpqHRCfcn+lO+s2Ukg==",
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/@reldens/utils/-/utils-0.22.0.tgz",
+ "integrity": "sha512-khf38VbfMvA6No/OowkCVTMxrObSPi8uVNz330psznMTXJzPn5ZPHEYA9VdMKC5ozKhCi8Ug4SNI+e/jXXKyMA==",
"requires": {
"await-event-emitter": "^2.0.2"
}
@@ -16003,9 +16039,9 @@
}
},
"acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw=="
+ "version": "8.11.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+ "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg=="
},
"acorn-loose": {
"version": "8.3.0",
@@ -16083,9 +16119,9 @@
}
},
"ajv": {
- "version": "8.11.2",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
- "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@@ -16516,9 +16552,9 @@
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="
},
"caniuse-lite": {
- "version": "1.0.30001570",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz",
- "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw=="
+ "version": "1.0.30001579",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
+ "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA=="
},
"chalk": {
"version": "4.1.2",
@@ -17470,9 +17506,9 @@
"optional": true
},
"fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
+ "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
"requires": {
"reusify": "^1.0.4"
}
@@ -18048,9 +18084,9 @@
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ=="
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
+ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg=="
},
"immutable": {
"version": "4.1.0",
@@ -18412,9 +18448,9 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
},
"knex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/knex/-/knex-3.0.1.tgz",
- "integrity": "sha512-ruASxC6xPyDklRdrcDy6a9iqK+R9cGK214aiQa+D9gX2ZnHZKv6o6JC9ZfgxILxVAul4bZ13c3tgOAHSuQ7/9g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz",
+ "integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==",
"requires": {
"colorette": "2.0.19",
"commander": "^10.0.0",
@@ -18425,7 +18461,7 @@
"getopts": "2.3.0",
"interpret": "^2.2.0",
"lodash": "^4.17.21",
- "pg-connection-string": "2.6.1",
+ "pg-connection-string": "2.6.2",
"rechoir": "^0.8.0",
"resolve-from": "^5.0.0",
"tarn": "^3.0.2",
@@ -18684,9 +18720,9 @@
}
},
"mikro-orm": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.9.3.tgz",
- "integrity": "sha512-lLBWENtV7yUE5KraqJEMaaKDPotnab6i/uf+wOyjILxYPjaXivH+oq7g9U3WS7K1fLUpQlR+bdQTOExHLy1FtQ=="
+ "version": "5.9.7",
+ "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-5.9.7.tgz",
+ "integrity": "sha512-0AxNDxQWk45n5N5g5q/K2tVj1/Narf4h5+1fhFc0uYAp/tOGAGvjmVK43Xy4TisEm/1VpBNOtS7FYKvh14WVOQ=="
},
"mime": {
"version": "3.0.0",
@@ -19008,11 +19044,11 @@
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"objection": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/objection/-/objection-3.1.2.tgz",
- "integrity": "sha512-V8YwRWz+DFbB9JS/m7TBLhRPVAFK/VX7yV3ZDAMkfUG9qYHLRyG/K4ZS0acKtGPWtRdVrCuN4qM1VkH3PuJ5Lg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/objection/-/objection-3.1.3.tgz",
+ "integrity": "sha512-X4DH8/xKBS34bwWOSLAPyceg0JgLhLiUuz+cEEyDA8iDFoT1UM9UbtwBpwHV11hYskAKxOgVlNHeveFQiOPDXA==",
"requires": {
- "ajv": "^8.6.2",
+ "ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"db-errors": "^0.2.3"
}
@@ -19180,9 +19216,9 @@
}
},
"pg-connection-string": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz",
- "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
+ "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA=="
},
"phaser": {
"version": "3.70.0",
diff --git a/package.json b/package.json
index 242bc2e58..68a62882a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "reldens",
- "version": "4.0.0-beta.30",
+ "version": "4.0.0-beta.31",
"description": "Reldens - MMORPG Platform",
"author": "Damian A. Pastorini",
"license": "MIT",
@@ -79,11 +79,11 @@
"@parcel/transformer-svg": "2.10.3",
"@parcel/transformer-webmanifest": "2.10.3",
"@parcel/transformer-worklet": "2.10.3",
- "@reldens/items-system": "^0.23.0",
- "@reldens/modifiers": "^0.20.0",
- "@reldens/skills": "^0.20.0",
- "@reldens/storage": "^0.18.0",
- "@reldens/utils": "^0.21.1",
+ "@reldens/items-system": "^0.25.0",
+ "@reldens/modifiers": "^0.21.0",
+ "@reldens/skills": "^0.22.0",
+ "@reldens/storage": "^0.19.0",
+ "@reldens/utils": "^0.22.0",
"@sendgrid/mail": "7.7.0",
"adminjs": "5.7.3",
"bcrypt": "5.1.1",
diff --git a/theme/default/assets/custom/sprites/heal-potion-20.png b/theme/default/assets/custom/sprites/heal_potion_20.png
similarity index 100%
rename from theme/default/assets/custom/sprites/heal-potion-20.png
rename to theme/default/assets/custom/sprites/heal_potion_20.png
diff --git a/theme/default/assets/custom/sprites/magic-potion-20.png b/theme/default/assets/custom/sprites/magic_potion_20.png
similarity index 100%
rename from theme/default/assets/custom/sprites/magic-potion-20.png
rename to theme/default/assets/custom/sprites/magic_potion_20.png
diff --git a/theme/default/assets/maps/reldens-gravity.json b/theme/default/assets/maps/reldens-gravity.json
index ca0298e81..32987496c 100644
--- a/theme/default/assets/maps/reldens-gravity.json
+++ b/theme/default/assets/maps/reldens-gravity.json
@@ -77,7 +77,7 @@
"firstgid":1,
"image":"reldens-gravity.png",
"imageheight":32,
- "imagewidth":102,
+ "imagewidth":100,
"margin":0,
"name":"reldens-gravity",
"spacing":2,
diff --git a/theme/default/assets/maps/reldens-gravity.png b/theme/default/assets/maps/reldens-gravity.png
index 02a760d3a..337aeb448 100644
Binary files a/theme/default/assets/maps/reldens-gravity.png and b/theme/default/assets/maps/reldens-gravity.png differ
diff --git a/theme/default/es-index.html b/theme/default/es-index.html
index 54f101a4d..f16828ac2 100644
--- a/theme/default/es-index.html
+++ b/theme/default/es-index.html
@@ -1,211 +1,213 @@
-
+
DwDeveloper - Reldens | MMORPG Plataforma
+
+
-
-
-
-
- - reldens - demo -
- - tu logo aqui -
-
-
-
-
-
-
- Descargo: Reldens no es solo un juego, es una plataforma para crear juegos.
- Esta es una demostración para mostrar cuántas funciones están disponibles en la plataforma.
-
+
+
+
+
+ - reldens - demo -
+ - tu logo aqui -
+
+
+
+
+
+
+ Descargo: Reldens no es solo un juego, es una plataforma para crear juegos.
+ Esta es una demostración para mostrar cuántas funciones están disponibles en la plataforma.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
Tárminos y Condiciones
-
-
-
-
-
-
-
-
-
-
-
Instructions
-
-
Muávete con las flechas o usando W-A-S-D.
-
Utiliza el clic izquierdo para seguir un camino, pero por ahora, para cambiar a otra escena, debes atravesar el punto de cambio (como el puente en la parte superior o las puertas de las casas).
-
Utiliza clic derecho o TAB para apuntar a enemigos o jugadores cercanos.
-
Debes tener un objetivo para ejecutar una habilidad/acción.
-
Utiliza los botones de la pantalla para activar las diferentes habilidades/acciones del jugador.
-
-
-
-
-
-
-
- ¡Moriste!
- Sólo espera...
- ¡Seras revivido automaticamente para esta demostracion!
-