@@ -1,11 +1,13 @@ | |||
define([ | |||
'ui/uiBase', | |||
'js/system/events', | |||
'js/system/client', | |||
'js/system/globals', | |||
'js/misc/tosAcceptanceValid' | |||
], function ( | |||
uiBase, | |||
events, | |||
client, | |||
globals, | |||
tosAcceptanceValid | |||
) { | |||
@@ -29,14 +31,39 @@ define([ | |||
}); | |||
}, | |||
onEnterGame: function () { | |||
onEnterGame: async function () { | |||
events.clearQueue(); | |||
globals.clientConfig.uiList.forEach(u => { | |||
if (u.path) | |||
this.buildModUi(u); | |||
else | |||
this.build(u); | |||
await Promise.all( | |||
globals.clientConfig.uiList.map(u => { | |||
const uiType = u.path ? u.path.split('/').pop() : u; | |||
return new Promise(res => { | |||
const doneCheck = () => { | |||
const isDone = this.uis.some(ui => ui.type === uiType); | |||
if (isDone) { | |||
res(); | |||
return; | |||
} | |||
setTimeout(doneCheck, 100); | |||
}; | |||
this.build(uiType, { path: u.path }); | |||
doneCheck(); | |||
}); | |||
}) | |||
); | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'player', | |||
method: 'notifyServerUiReady' | |||
} | |||
}); | |||
}, | |||
@@ -10,34 +10,51 @@ define([ | |||
], function ( | |||
events | |||
) { | |||
const onHover = (el, item, e) => { | |||
if (item) | |||
this.hoverItem = item; | |||
else | |||
item = this.hoverItem; | |||
let ttPos = null; | |||
if (el) { | |||
ttPos = { | |||
x: ~~(e.clientX + 32), | |||
y: ~~(e.clientY) | |||
}; | |||
const renderItemManager = { | |||
hoverItem: null, | |||
onHover: function (el, item, e) { | |||
if (item) | |||
this.hoverItem = item; | |||
else | |||
item = this.hoverItem; | |||
let ttPos = null; | |||
if (el) { | |||
ttPos = { | |||
x: ~~(e.clientX + 32), | |||
y: ~~(e.clientY) | |||
}; | |||
} | |||
events.emit('onShowItemTooltip', item, ttPos, true); | |||
}, | |||
onKeyDown: function (key) { | |||
if (key === 'shift' && this.hoverItem) | |||
this.onHover(); | |||
}, | |||
onKeyUp: function (key) { | |||
if (key === 'shift' && this.hoverItem) | |||
this.onHover(); | |||
} | |||
events.emit('onShowItemTooltip', item, ttPos, true); | |||
}; | |||
events.on('onKeyDown', renderItemManager.onKeyDown.bind(renderItemManager)); | |||
events.on('onKeyUp', renderItemManager.onKeyUp.bind(renderItemManager)); | |||
const hideTooltip = (el, item, e) => { | |||
events.emit('onHideItemTooltip', item); | |||
}; | |||
const addTooltipEvents = (el, item) => { | |||
let moveHandler = onHover.bind(null, el, item); | |||
let moveHandler = renderItemManager.onHover.bind(renderItemManager, el, item); | |||
let downHandler = () => {}; | |||
if (isMobile) { | |||
moveHandler = () => {}; | |||
downHandler = onHover.bind(null, el, item); | |||
downHandler = renderItemManager.bind(renderItemManager, el, item); | |||
} | |||
el | |||
@@ -290,10 +290,6 @@ define([ | |||
text: 'equip', | |||
callback: this.performItemAction.bind(this, item, 'equip') | |||
}, | |||
mail: { | |||
text: 'mail', | |||
callback: this.openMailUi.bind(this, item) | |||
}, | |||
split: { | |||
text: 'split stack', | |||
callback: this.splitStackStart.bind(this, item) | |||
@@ -345,9 +341,6 @@ define([ | |||
if (item.quantity > 1 && !item.quest) | |||
ctxConfig.push(menuItems.split); | |||
if ((!item.noDrop) && (!item.quest)) | |||
ctxConfig.push(menuItems.mail); | |||
ctxConfig.push(menuItems.link); | |||
if (!item.eq && !item.active && !item.noDestroy) { | |||
@@ -548,12 +541,6 @@ define([ | |||
}); | |||
}, | |||
openMailUi: function (item) { | |||
events.emit('onSetMailItem', { | |||
item: item | |||
}); | |||
}, | |||
onKeyDown: function (key) { | |||
if (key === 'i') | |||
this.toggle(); | |||
@@ -1,150 +0,0 @@ | |||
define([ | |||
'js/system/events', | |||
'js/system/client', | |||
'html!ui/templates/mail/template', | |||
'css!ui/templates/mail/styles', | |||
'ui/shared/renderItem' | |||
], function ( | |||
events, | |||
client, | |||
template, | |||
styles, | |||
renderItem | |||
) { | |||
return { | |||
tpl: template, | |||
centered: true, | |||
modal: true, | |||
hasClose: true, | |||
hoverItem: null, | |||
item: null, | |||
postRender: function () { | |||
this.onEvent('onSetMailItem', this.onSetItem.bind(this)); | |||
this.onEvent('onKeyDown', this.onKeyDown.bind(this)); | |||
this.onEvent('onKeyUp', this.onKeyUp.bind(this)); | |||
this.find('input').on('keydown', this.onInputKeyDown.bind(this)); | |||
this.find('.btnSend').on('click', this.onSendClick.bind(this)); | |||
}, | |||
onSendClick: function () { | |||
if (!this.item) | |||
return; | |||
let recipient = this.find('.txtRecipient').val(); | |||
if (recipient.length === 0) | |||
return; | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'inventory', | |||
method: 'mailItem', | |||
data: { | |||
itemId: this.item.id, | |||
recipient: recipient | |||
} | |||
}, | |||
callback: this.onSend.bind(this) | |||
}); | |||
}, | |||
onSend: function (res) { | |||
if (res.length > 0) { | |||
events.emit('onGetAnnouncement', { | |||
msg: res, | |||
type: 'failure' | |||
}); | |||
return; | |||
} | |||
events.emit('onSendMail'); | |||
this.hide(); | |||
}, | |||
onSetItem: function (msg) { | |||
this.toggle(); | |||
this.item = msg.item; | |||
const itemContainer = this.find('.itemContainer').empty(); | |||
let item = msg.item; | |||
const itemEl = renderItem(itemContainer, item); | |||
this.find('.txtRecipient').val(''); | |||
let moveHandler = this.onHover.bind(this, itemEl, item); | |||
let downHandler = () => {}; | |||
if (isMobile) { | |||
moveHandler = () => {}; | |||
downHandler = this.onHover.bind(this, itemEl, item); | |||
} | |||
itemEl | |||
.data('item', item) | |||
.on('mousedown', downHandler) | |||
.on('mousemove', moveHandler) | |||
.on('mouseleave', this.hideTooltip.bind(this, itemEl, item)); | |||
}, | |||
onAfterShow: function () { | |||
this.find('input').focus(); | |||
}, | |||
hideTooltip: function () { | |||
events.emit('onHideItemTooltip', this.hoverItem); | |||
this.hoverItem = null; | |||
}, | |||
onHover: function (el, item, e) { | |||
if (item) | |||
this.hoverItem = item; | |||
else | |||
item = this.hoverItem; | |||
let ttPos = null; | |||
if (el) { | |||
el.removeClass('new'); | |||
delete item.isNew; | |||
let elOffset = el.offset(); | |||
ttPos = { | |||
x: ~~(elOffset.left + 74), | |||
y: ~~(elOffset.top + 4) | |||
}; | |||
} | |||
events.emit('onShowItemTooltip', item, ttPos, true); | |||
}, | |||
onKeyDown: function (key) { | |||
if (!this.shown) | |||
return; | |||
if (key === 'shift' && this.hoverItem) | |||
this.onHover(); | |||
else if (key === 'esc') | |||
this.toggle(); | |||
}, | |||
onKeyUp: function (key) { | |||
if (!this.shown) | |||
return; | |||
if (key === 'shift' && this.hoverItem) | |||
this.onHover(); | |||
}, | |||
onInputKeyDown: function ({ keyCode }) { | |||
if (keyCode === 27) | |||
this.toggle(); | |||
} | |||
}; | |||
}); |
@@ -1,119 +0,0 @@ | |||
@import "../../../css/colors.less"; | |||
.uiMail { | |||
display: none; | |||
background-color: @blackB; | |||
border: 5px solid @blackB; | |||
text-align: center; | |||
> .heading { | |||
color: @blueA; | |||
width: 100%; | |||
height: 36px; | |||
background-color: @blackB; | |||
.heading-text { | |||
padding-top: 8px; | |||
margin: auto; | |||
} | |||
} | |||
.bottom { | |||
height: 99px; | |||
background-color: @blackC; | |||
padding: 10px; | |||
.col { | |||
float: left; | |||
width: 80px; | |||
height: 80px; | |||
&.itemContainer { | |||
padding: 4px; | |||
.item { | |||
width: 72px; | |||
height: 72px; | |||
float: left; | |||
position: relative; | |||
cursor: pointer; | |||
box-sizing: border-box; | |||
margin: 4px; | |||
background-color: @blackD; | |||
&.hover { | |||
background-color: fade(@blueA, 10%); | |||
} | |||
.quantity { | |||
left: 6px; | |||
bottom: 3px; | |||
position: absolute; | |||
color: @white; | |||
filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
-moz-filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
} | |||
.icon { | |||
width: 64px; | |||
height: 64px; | |||
position: absolute; | |||
left: 4px; | |||
top: 4px; | |||
} | |||
&:hover { | |||
.icon { | |||
filter: brightness(160%); | |||
-moz-filter: brightness(160%); | |||
} | |||
} | |||
} | |||
} | |||
&:nth-child(2) { | |||
width: 200px; | |||
padding-top: 4px; | |||
margin-left: 10px; | |||
> * { | |||
width: 100%; | |||
height: 31px; | |||
} | |||
.btnSend { | |||
height: 35px; | |||
background-color: @blueB; | |||
text-align: center; | |||
padding-top: 12px; | |||
color: @white; | |||
cursor: pointer; | |||
} | |||
input, input:-webkit-autofill { | |||
box-shadow: 0 0 0px 1000px darken(@blackB, 15%) inset; | |||
color: @white; | |||
-webkit-text-fill-color: @white; | |||
margin-bottom: 5px; | |||
text-align: center; | |||
} | |||
/* We duplicate this for firefox which doesn't like the webkit selector */ | |||
input { | |||
box-shadow: 0 0 0px 1000px darken(@blackB, 15%) inset; | |||
color: @white; | |||
-webkit-text-fill-color: @white; | |||
margin-bottom: 5px; | |||
text-align: center; | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,12 +0,0 @@ | |||
<div class="uiMail"> | |||
<div class="heading"> | |||
<div class="heading-text">mail item</div> | |||
</div> | |||
<div class="bottom"> | |||
<div class="col itemContainer"></div> | |||
<div class="col"> | |||
<input class="txtRecipient textbox" type="text" placeholder="recipient"> | |||
<div class="btnSend">send</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -4,7 +4,6 @@ const skins = require('../config/skins'); | |||
const roles = require('../config/roles'); | |||
const profanities = require('../misc/profanities'); | |||
const fixes = require('../fixes/fixes'); | |||
const mail = require('../mail/mail'); | |||
const spirits = require('../config/spirits'); | |||
const ga = require('../security/ga'); | |||
const events = require('../misc/events'); | |||
@@ -44,10 +43,6 @@ module.exports = { | |||
}, | |||
onSendRewards: async function (data, character) { | |||
//Bit of a hack. Rethink doesn't have a busy list | |||
if (mail.busy) | |||
delete mail.busy[character.name]; | |||
await io.setAsync({ | |||
key: this.username, | |||
table: 'accountInfo', | |||
@@ -1,6 +1,5 @@ | |||
const scheduler = require('../../misc/scheduler'); | |||
const rewardGenerator = require('../../misc/rewardGenerator'); | |||
const mail = require('../../mail/mail'); | |||
const calculateDaysSkipped = (oldTime, newTime) => { | |||
let daysSkipped = 1; | |||
@@ -50,6 +49,7 @@ module.exports = async (cpnAuth, data, character, cbDone) => { | |||
) | |||
) { | |||
cbDone(); | |||
return; | |||
} | |||
@@ -66,10 +66,20 @@ module.exports = async (cpnAuth, data, character, cbDone) => { | |||
const rewards = rewardGenerator(itemCount); | |||
if (!rewards) { | |||
cbDone(); | |||
return; | |||
} | |||
rewards[0].msg = `Daily login reward for ${loginStreak} day${(loginStreak > 1) ? 's' : ''}:`; | |||
const msg = `Daily login reward for ${loginStreak} day${(loginStreak > 1) ? 's' : ''}`; | |||
if (global.mailManager) { | |||
await global.mailManager.sendSystemMail({ | |||
to: character.name, | |||
subject: 'Login Rewards', | |||
msg, | |||
items: rewards | |||
}); | |||
} | |||
mail.sendMail(character.name, rewards, cbDone); | |||
cbDone(); | |||
}; |
@@ -37,7 +37,7 @@ let commandRoles = { | |||
getItem: 10, | |||
getGold: 10, | |||
setLevel: 10, | |||
godMode: 10, | |||
godMode: 0, | |||
clearInventory: 10, | |||
completeQuests: 10, | |||
getReputation: 10, | |||
@@ -383,45 +383,6 @@ module.exports = { | |||
}, this); | |||
}, | |||
mailItem: async function (msg) { | |||
let item = this.findItem(msg.itemId); | |||
if (!item || item.noDrop || item.quest) { | |||
this.resolveCallback(msg); | |||
return; | |||
} | |||
let res = await io.getAsync({ | |||
key: msg.recipient, | |||
table: 'character' | |||
}); | |||
if (!res) { | |||
this.resolveCallback(msg, 'Recipient does not exist'); | |||
return; | |||
} else if (!this.findItem(msg.itemId)) | |||
return; | |||
const resolveTrans = transactions.register(); | |||
let blocked = false; | |||
if (res.components) { | |||
let social = res.components.find(f => f.type === 'social'); | |||
if (social.blockedPlayers && social.blockedPlayers.includes(this.obj.name)) | |||
blocked = true; | |||
} | |||
const mappedItem = this.simplifyItem(item); | |||
this.destroyItem(item.id); | |||
if (!blocked) | |||
await this.obj.instance.mail.sendMail(msg.recipient, [mappedItem]); | |||
this.resolveCallback(msg); | |||
resolveTrans(); | |||
}, | |||
hookItemEvents: function (items) { | |||
items = items || this.items; | |||
if (!items.push) | |||
@@ -12,6 +12,7 @@ module.exports = { | |||
init: function (blueprint) { | |||
this.msg = blueprint.msg; | |||
this.msgFunction = blueprint.msgFunction; | |||
this.actions = blueprint.actions || {}; | |||
this.announce = blueprint.announce; | |||
this.maxLevel = blueprint.maxLevel || 0; | |||
@@ -32,6 +33,12 @@ module.exports = { | |||
let cpn = null; | |||
if (typeof(action) === 'function') { | |||
action(obj); | |||
return; | |||
} | |||
if (action.targetId) { | |||
let target = this.obj.instance.objects.find(o => o.id === action.targetId); | |||
if (target) { | |||
@@ -58,13 +65,15 @@ module.exports = { | |||
this.callAction(obj, 'enter'); | |||
if (!this.msg) | |||
if (!this.msg && !this.msgFunction) | |||
return; | |||
const msg = this.msg || this.msgFunction(obj); | |||
if (this.announce) { | |||
this.syncer.queue('onGetAnnouncement', { | |||
src: this.obj.id, | |||
msg: this.msg | |||
msg | |||
}, [obj.serverId]); | |||
return; | |||
@@ -72,7 +81,7 @@ module.exports = { | |||
this.syncer.queue('onGetDialogue', { | |||
src: this.obj.id, | |||
msg: this.msg | |||
msg | |||
}, [obj.serverId]); | |||
}, | |||
@@ -268,5 +268,11 @@ module.exports = { | |||
msg.data.data.callbackId = atlas.registerCallback(msg.callback); | |||
atlas.performAction(this.obj, msg.data); | |||
}, | |||
notifyServerUiReady: function () { | |||
this.obj.instance.eventEmitter.emit('onPlayerUiReady', { | |||
obj: this.obj | |||
}); | |||
} | |||
}; |
@@ -736,8 +736,6 @@ module.exports = { | |||
let stats = this.stats; | |||
let time = scheduler.getTime(); | |||
stats.lastLogin = time; | |||
this.obj.instance.mail.getMail(this.obj.name); | |||
}, | |||
getKillStreakCoefficient: function (mobName) { | |||
@@ -31,7 +31,8 @@ module.exports = { | |||
this.buffer = []; | |||
}, | |||
queue: function (args) { | |||
queue: function (args, a) { | |||
console.log(args, a); | |||
this.buffer.push(args); | |||
}, | |||
@@ -178,7 +178,6 @@ const config = { | |||
'death', | |||
'leaderboard', | |||
'reputation', | |||
'mail', | |||
'wardrobe', | |||
'passives', | |||
'workbench', | |||
@@ -1,6 +1,6 @@ | |||
module.exports = { | |||
//At which interval does each zone tick in ms | |||
tickTime: 350, | |||
tickTime: 100, | |||
//The maximum level a player can reach | |||
maxLevel: 20, | |||
@@ -51,13 +51,13 @@ const descriptionStrings = { | |||
}; | |||
const config = { | |||
cron: '0 */3 * * *', | |||
//cron: '* * * * *', | |||
//cron: '0 */3 * * *', | |||
cron: '* * * * *', | |||
idFirstSpawnPhase: 6, | |||
idFailPhase: 19, | |||
maxEscapees: 5, | |||
repeats: [5, 5, 3], | |||
//repeats: [1, 1, 1], | |||
maxEscapees: 5000, | |||
//repeats: [5, 5, 3], | |||
repeats: [1, 1, 1], | |||
rewardItemsPerKill: 3 | |||
}; | |||
@@ -8,7 +8,7 @@ module.exports = { | |||
// sqlite | |||
// rethink | |||
//eslint-disable-next-line no-process-env | |||
db: process.env.IWD_DB || 'sqlite', | |||
db: process.env.IWD_DB || 'rethink', | |||
//eslint-disable-next-line no-process-env | |||
dbHost: process.env.IWD_DB_HOST || 'localhost', | |||
//eslint-disable-next-line no-process-env | |||
@@ -75,6 +75,21 @@ module.exports = { | |||
return res; | |||
}, | |||
getFilterAsync: async function ({ table, noDefault, filter }) { | |||
const res = await r | |||
.table(table) | |||
.filter(filter) | |||
.run(); | |||
if (res) | |||
return res; | |||
if (!noDefault) | |||
return []; | |||
return null; | |||
}, | |||
getAllAsync: async function ({ | |||
table, | |||
key, | |||
@@ -6,7 +6,6 @@ const tableNames = [ | |||
'login', | |||
'leaderboard', | |||
'customMap', | |||
'mail', | |||
'customChannels', | |||
'error', | |||
'modLog', | |||
@@ -240,15 +240,25 @@ module.exports = { | |||
giveRewards: function (config) { | |||
const { event: { rewards = {} } } = config; | |||
const subject = `${config.name} Rewards`; | |||
const senderName = config.rewardSenderName; | |||
Object.entries(rewards).forEach(e => { | |||
const [ name, rList ] = e; | |||
if (!rList || !rList.length) | |||
return; | |||
rList[0].msg = `${config.name} reward:`; | |||
this.instance.mail.sendMail(name, rList); | |||
if (global.mailManager) { | |||
global.mailManager.sendSystemMail({ | |||
to: name, | |||
from: senderName, | |||
subject, | |||
msg: '', | |||
items: rList, | |||
notify: true | |||
}); | |||
} | |||
}); | |||
if ((config.events) && (config.events.afterGiveRewards)) | |||
@@ -2,15 +2,26 @@ module.exports = { | |||
init: function (event) { | |||
const { config, rewards, eventManager } = event; | |||
const { name: eventName, rewardSenderName } = config; | |||
const subject = `${eventName} Rewards`; | |||
Object.entries(rewards).forEach(e => { | |||
const [ name, rList ] = e; | |||
if (!rList | !rList.length) | |||
return; | |||
rList[0].msg = `${config.name} reward:`; | |||
this.instance.mail.sendMail(name, rList); | |||
if (global.mailManager) { | |||
global.mailManager.sendSystemMail({ | |||
to: name, | |||
from: rewardSenderName, | |||
subject, | |||
msg: '', | |||
items: rList, | |||
notify: true | |||
}); | |||
} | |||
}); | |||
if ((config.events) && (config.events.afterGiveRewards)) | |||
@@ -1,9 +0,0 @@ | |||
let serverConfig = require('../config/serverConfig'); | |||
const moduleMap = { | |||
sqlite: 'Sqlite', | |||
rethink: 'RethinkDb' | |||
}; | |||
const modulePath = `./mail${moduleMap[serverConfig.db]}`; | |||
module.exports = require(modulePath); |
@@ -1,183 +0,0 @@ | |||
//This lock system is so stupid. But until we rewrite mail (no more auto-fetch) | |||
// We need a way to stop race conditions (listener picking up mail when we just want to getMail normally) | |||
const locks = {}; | |||
module.exports = { | |||
init: function (instance) { | |||
this.instance = instance; | |||
this.listen(); | |||
}, | |||
listen: function () { | |||
io | |||
.subscribe('mail') | |||
.then(cursor => { | |||
cursor.each(async (err, data) => { | |||
let doc = data.new_val; | |||
if (!doc) | |||
return; | |||
let player = this.instance.objects.objects.find(o => o.name === doc.id && o.player); | |||
if (!player) | |||
return; | |||
if (locks[player.name]) | |||
return; | |||
locks[player.name] = 1; | |||
let items = doc.value; | |||
let inventory = player.inventory; | |||
let stash = player.stash; | |||
let sentMessages = []; | |||
items.forEach(function (r) { | |||
if (r.removeAll) { | |||
for (let i = 0; i < inventory.items.length; i++) { | |||
let item = inventory.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
inventory.destroyItem(item.id, item.quantity ? item.quantity : null); | |||
i--; | |||
} | |||
} | |||
if (stash) { | |||
for (let i = 0; i < stash.items.length; i++) { | |||
let item = stash.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
stash.destroyItem(item.id); | |||
i--; | |||
} | |||
} | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
delete r.pos; | |||
delete r.quickSlot; | |||
inventory.getItem(r, false, false, false, true); | |||
} | |||
}); | |||
await io.deleteAsync({ | |||
key: doc.id, | |||
table: 'mail' | |||
}); | |||
delete locks[player.name]; | |||
}); | |||
}); | |||
}, | |||
getMail: async function (playerName) { | |||
let items = await io.getAsync({ | |||
key: playerName, | |||
table: 'mail' | |||
}); | |||
if (!items || !(items instanceof Array)) | |||
return; | |||
let player = this.instance.objects.objects.find(o => o.name === playerName && o.player); | |||
if (!player) | |||
return; | |||
if (locks[playerName]) | |||
return; | |||
locks[playerName] = 1; | |||
let inventory = player.inventory; | |||
let stash = player.stash; | |||
let sentMessages = []; | |||
items.forEach(function (r) { | |||
if (r.removeAll) { | |||
for (let i = 0; i < inventory.items.length; i++) { | |||
let item = inventory.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
inventory.destroyItem(item.id, item.quantity ? item.quantity : null); | |||
i--; | |||
} | |||
} | |||
if (stash) { | |||
for (let i = 0; i < stash.items.length; i++) { | |||
let item = stash.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
stash.destroyItem(item.id); | |||
i--; | |||
} | |||
} | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
delete r.pos; | |||
delete r.quickSlot; | |||
inventory.getItem(r, false, false, false, true); | |||
} | |||
}); | |||
await io.deleteAsync({ | |||
key: playerName, | |||
table: 'mail' | |||
}); | |||
delete locks[playerName]; | |||
}, | |||
sendMail: async function (playerName, items, callback) { | |||
if (await io.exists({ | |||
key: playerName, | |||
table: 'mail' | |||
})) { | |||
await io.append({ | |||
key: playerName, | |||
table: 'mail', | |||
value: items, | |||
field: 'value' | |||
}); | |||
} else { | |||
await io.setAsync({ | |||
key: playerName, | |||
table: 'mail', | |||
value: items | |||
}); | |||
} | |||
if (callback) | |||
callback(); | |||
} | |||
}; |
@@ -1,160 +0,0 @@ | |||
module.exports = { | |||
queue: {}, | |||
busy: {}, | |||
init: function (instance) { | |||
this.instance = instance; | |||
}, | |||
getMail: async function (playerName, noBlock) { | |||
if (!noBlock) | |||
this.busy[playerName] = (this.busy[playerName] || 0) + 1; | |||
let player = this.instance.objects.objects.find(o => o.name === playerName && o.player); | |||
if (!player) { | |||
process.send({ | |||
method: 'callDifferentThread', | |||
playerName: playerName, | |||
data: { | |||
module: 'mail', | |||
method: 'getMail', | |||
args: [playerName] | |||
} | |||
}); | |||
this.busy[playerName]--; | |||
this.processQueue(playerName); | |||
return; | |||
} | |||
let result = await io.getAsync({ | |||
key: playerName, | |||
table: 'mail', | |||
noParse: true | |||
}); | |||
this.busy[playerName]--; | |||
await this.onGetMail(player, result); | |||
}, | |||
onGetMail: async function (player, result) { | |||
if (result === 'null') | |||
result = null; | |||
else if (result) { | |||
result = result.split('`').join('\''); | |||
//Hack for weird google datastore error | |||
if (result[0] === '<') | |||
return; | |||
} | |||
result = JSON.parse(result || '[]'); | |||
let sentMessages = []; | |||
let inventory = player.inventory; | |||
let stash = player.stash; | |||
result.forEach(function (r) { | |||
if (r.removeAll) { | |||
for (let i = 0; i < inventory.items.length; i++) { | |||
let item = inventory.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
inventory.destroyItem(item.id, item.quantity ? item.quantity : null); | |||
i--; | |||
} | |||
} | |||
if (stash) { | |||
for (let i = 0; i < stash.items.length; i++) { | |||
let item = stash.items[i]; | |||
if ((r.nameLike) && (item.name.indexOf(r.nameLike) > -1)) { | |||
stash.destroyItem(item.id); | |||
i--; | |||
} | |||
} | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
inventory.getItem(r, false, false, false, true); | |||
} | |||
}); | |||
await io.setAsync({ | |||
key: player.name, | |||
table: 'mail', | |||
value: '' | |||
}); | |||
this.processQueue(player.name); | |||
}, | |||
processQueue: function (playerName) { | |||
if (this.busy[playerName]) | |||
return; | |||
let queue = this.queue[playerName]; | |||
if (!queue) | |||
return; | |||
delete this.queue[playerName]; | |||
this.sendMail(playerName, queue); | |||
}, | |||
sendMail: async function (playerName, items, callback) { | |||
if (this.busy[playerName]) { | |||
let queue = this.queue[playerName]; | |||
if (!queue) | |||
queue = this.queue[playerName] = []; | |||
queue.push(...extend([], items)); | |||
return; | |||
} | |||
//Only maintain the busy queue on child threads | |||
//since the parent thread never actually distributes items | |||
if (process.send) | |||
this.busy[playerName] = (this.busy[playerName] || 0) + 1; | |||
if (!items.push) | |||
items = [items]; | |||
let result = await io.getAsync({ | |||
key: playerName, | |||
table: 'mail', | |||
noParse: true | |||
}); | |||
if (result === 'null') | |||
result = null; | |||
result = JSON.parse(result || '[]'); | |||
result.push(...items); | |||
const itemString = JSON.stringify(result).split('\'').join('`'); | |||
await io.setAsync({ | |||
key: playerName, | |||
table: 'mail', | |||
value: itemString | |||
}); | |||
(callback || this.getMail.bind(this, playerName, true))(); | |||
} | |||
}; |
@@ -10,7 +10,7 @@ const routerConfig = { | |||
dialogue: ['talk'], | |||
gatherer: ['gather'], | |||
quests: ['complete'], | |||
inventory: ['combineStacks', 'splitStack', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'mailItem', 'sortInventory'], | |||
inventory: ['combineStacks', 'splitStack', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'sortInventory'], | |||
equipment: ['equip', 'unequip', 'setQuickSlot', 'useQuickSlot', 'inspect'], | |||
stash: ['withdraw', 'open'], | |||
trade: ['buySell'], | |||
@@ -18,7 +18,8 @@ const routerConfig = { | |||
wardrobe: ['open', 'apply'], | |||
stats: ['respawn'], | |||
passives: ['tickNode', 'untickNode'], | |||
workbench: ['open', 'craft', 'getRecipe'] | |||
workbench: ['open', 'craft', 'getRecipe'], | |||
player: ['notifyServerUiReady'] | |||
}, | |||
globalAllowed: { | |||
clientConfig: ['getClientConfig'], | |||
@@ -8,7 +8,6 @@ let spellCallbacks = require('../config/spells/spellCallbacks'); | |||
let questBuilder = require('../config/quests/questBuilder'); | |||
let events = require('../events/events'); | |||
let scheduler = require('../misc/scheduler'); | |||
let mail = require('../mail/mail'); | |||
let herbs = require('../config/herbs'); | |||
let eventEmitter = require('../misc/events'); | |||
const transactions = require('../security/transactions'); | |||
@@ -39,7 +38,6 @@ module.exports = { | |||
questBuilder, | |||
events, | |||
zone: map.zone, | |||
mail, | |||
map, | |||
scheduler, | |||
eventEmitter, | |||
@@ -63,7 +61,7 @@ module.exports = { | |||
map.clientMap.zoneId = this.zoneId; | |||
[resourceSpawner, syncer, objects, questBuilder, events, mail].forEach(i => i.init(fakeInstance)); | |||
[resourceSpawner, syncer, objects, questBuilder, events].forEach(i => i.init(fakeInstance)); | |||
this.tick(); | |||
}, | |||