猫史档案馆


【神奇代码岛】【教程】【签到】

用户:幻想一笑而过幻想一笑而过查看:4 回复:20 评论:4 创建时间:2021-07-31T22:05:17


话不多说,直接上代码

//签到-----------------------------------------------------------------------------
(async function () {
    createTable5()
})();
async function loadPlayer_(entity) { // 导入玩家SQL得分到地图玩家变量
    //用poll确保在数据库短暂掉线后还能继续执行这个sql语句. 
    //userKey包含大写字母, 需要用""包住
    //右边记得加上 ) 匹配左边的 poll(
    const data = (await poll(() => db.sql`SELECT * FROM "playersign" WHERE name=${entity.player.name}`))[0]
    if (data) {
        entity.player.signtime = data.signtime
    }
};
world.onPlayerJoin(({ entity }) => {
    entity.player.signtime = 0
    loadPlayer_(entity)
})

async function createTable5() {
    //一直轮询等待"SELECT 1"执行成功, 这是最简单的测试数据库是否在线的语句
    await poll(() => db.sql`SELECT 1`, '等待玩家签到pg数据库启动中...')
    world.say('玩家签到pg数据库启动完毕')

    await db.sql`CREATE TABLE IF NOT EXISTS "playersign" (
        name VARCHAR(50) NOT NULL,
        "signtime" VARCHAR(50) NOT NULL
    )`
}

// 第一次进入游戏时,新建玩家数据
async function insertPlayer__(name, sign) {
    try {
        await poll(() => db.sql`INSERT INTO "playersign" VALUES (${name}, ${sign})`);
    } catch (e) {
        console.log(`insert sql error: ${e}`, name, sign);
    }
}

// 更新玩家进入游戏时间
async function updatePlayerJoin_(name, value) {
    try {
        await poll(() => db.sql`UPDATE "playersign" SET "signtime" = ${value} WHERE name = ${name}`);
    } catch (e) {
        console.log(`[jointime] update sql error: ${e}`);
    }
}

// 查询数据。如果数据不存在,返回空。
async function getPlayerData_(name) {
    const rows = (await poll(() => db.sql`SELECT * FROM "playersign" WHERE name=${name}`));
    if (rows && !rows.length) {
        return null;
    }
    return rows[0];
}

// 清空所有数据
async function clearsign_() {
    await db.sql`DELETE FROM "playersign"`
    world.say(`清空所有签到数据!`);
}

//今天的时间


//拼接时间
function show() {
    var str = "今天的时间是:" + today;
    return str;
}

async function poll(fn, msg) {//无限轮询执行sql语句直到成功
    while (true) {
        try {
            return await fn()//一旦成功执行, 停止无限轮询, 并返回查询结果
        } catch (e) {
            const m = e.message//需要简略显示的异常消息
            //sql偶尔会执行超时, 但如果反复显示timeout 15秒以上一直不停, 请通知官方人员
            //第一次运行时, 由于玩家在数据表创建前尝试读档会报出 relation does not exist, 属于正常现象
            if (m.includes('timeout') || m.includes('relation')) {
                world.say(m)
            }
            else {
                world.say(msg || e.stack)//如果sql执行出错, 广播错误消息, 用来排查错误原因
                console.log(fn)
            }
        }
        await sleep(1000)
    }
}

world.onPlayerJoin(({ entity }) => { //玩家进⼊游戏时
    entity.player.onPress(async ({ button }) => { //每当有按钮被按下
        if (button == Box3ButtonType.ACTION1) { //如果按钮是右键
            const selection = await entity.player.dialog({
                type: Box3DialogType.SELECT, //对话框类型为选择框
                content: `${entity.player.name}\n欢迎回来`,
                title: `控制⾯板`,
                options: ['签到', '关闭'],

            })
            if (selection) { //确保对话框不是点击x关闭
                if (selection.value === '签到') { //被点击的是保存按钮
                    var day2 = new Date();
                    day2.setTime(day2.getTime());
                    var today = day2.getFullYear() + "-" + (day2.getMonth() + 1) + "-" + day2.getDate();
                    const now = Date.now();    // 获取真实世界的时间戳 timestamp
                    const playerData = await getPlayerData_(entity.player.name);    // 获取上次登陆记录
                    // 如果数据不存在,说明时第一次进入游戏
                    if (playerData == null) {
                        entity.player.score += 10
                        insertPlayer__(entity.player.name, today); // 插入玩家数据
                        entity.player.signtime = today
                        pollLV()
                        savePlayer(entity)
                        entity.player.dialog({
                            type: Box3DialogType.TEXT,
                            title: `系统`,
                            content: `签到成功\n获得10得分`,
                            options: ['确定'],   // 将提供玩家选择的选项放入数组里。
                        });
                    } else if (entity.player.signtime != today) {
                        entity.player.score += 10
                        updatePlayerJoin_(entity.player.name, today); // 更新玩家进入游戏时间
                        entity.player.signtime = today
                        pollLV()
                        savePlayer(entity)
                        entity.player.dialog({
                            type: Box3DialogType.TEXT,
                            title: `系统`,
                            content: `签到成功\n获得10得分`,
                            options: ['确定'],   // 将提供玩家选择的选项放入数组里。
                        });
                    } else {
                        entity.player.dialog({
                            type: Box3DialogType.TEXT,
                            title: `系统`,
                            content: `你今天签到了哦`,
                            options: ['确定'],   // 将提供玩家选择的选项放入数组里。
                        });
                    }
                }
            }
        }
    })
})

最后告诉各位一个让大家绝望的消息:以上SQL代码仅pg数据库可使用

/**
简介
为什么要用PostgreSQL
使用SQLite数据库时, 有时因为人太多, 同一个游戏自动开了2服3服,多个服务器对同一个db文件写入引发了disk image malformed的问题, 造成了玩家群
体存储时的3种情形:

 · 能够正常读档存档
 · 只能读档无法存档
 · 无法读档无法存档
虽然目前来说, 只有非常受欢迎的地图才会引发这个问题, 但越来越多玩家抱怨自己的游戏存档数据莫名丢失, 技术人员意识到SQLite的这个缺陷后, 决定
使用设计上更可靠的PostgreSQL数据库 (简称pg) 替代它.

PostgreSQL与SQLite在我们使用时的差别
pg和SQLite的语法大致相近, 但还是有些差别:

1. pg的字段名默认会强制转化成小写, 比如userKey会被当成userkey, 用到大写字母的名称要用"“包住才行, 例如"userKey”. 建议所有字段名/表名, 
  无论大小写都用""包住
2. 有时地图启动后, pg还未启动, 需要轮询等待pg到位
3. pg有时因为各种原因短暂下线, sql会执行不成功(比如query timeout), 需要轮询执行sql语句确保语句在数据库到位后继续执行
4. pg的INT整数字段有严格的位数限制, 超过上限将报错, 像1e+53这样的数值是存不进去的, 存进去之前先要把数值限制到有效数值范围(2147483喵7以下)
5. pg的INT整数字段还有另一个限制, 就是不能输入带有小数点的数字, 比如3.14这样的数字存进去会报错, 需要用Math.floor()把数值转成整数3再存入
6. pg里的字符串只能用’'包住, 不能用""包住, ""在pg只用于支持大写名称
7. 如果用到BIGINT类型, 它返回的是字符串而非数字, 在读取时需要用parseInt()转换回js里的整数
更多关于pg的细节教程:

就不告诉你链接
*/


回复

上一页1 页 / 共 1下一页
月下樱花雨_中考退月下樱花雨_中考退

emotion_编程猫_点赞

点赞0


评论


成熟的强袭编程猫548成熟的强袭编程猫548

azaz()()

点赞0


评论


小鱼yuzifu小鱼yuzifu

好耶!顶顶

点赞0


评论


幻想一笑而过幻想一笑而过

代码具体功能自己钻研

点赞0


评论


一个STUB用户_6923702一个STUB用户_6923702

我看到内测群消息时已经是6天后了 我就很后悔awa

点赞0


评论


IaeaIaea

d'd

点赞0


评论


沉浮于世的微尘沉浮于世的微尘

点赞0


评论


1232RvE1232RvE

把pg代码(poll)搬了?

点赞0


评论


1232RvE1232RvE

pollLV()???????

点赞1


评论


DL1DL1

在pg数据库未发布前,请勿透露代码!

点赞0


评论


幻想一笑而过幻想一笑而过

dd

 

点赞0


评论


DebugDynamoDebugDynamo

可以直接用吗

(为了防止某些人喷我)

点赞1


评论


全能代码师全能代码师

喵d

点赞1


评论


用户_869149用户_869149

挖坟(话说这坟能挖吗(算了全能也挖了(挖吧()

点赞0


评论


用户_869149用户_869149

顶顶顶()

点赞0


评论


用户_869149用户_869149

喵d)

点赞0


评论


灵清帝王吃爆一切厕所灵清帝王吃爆一切厕所

喵喵喵

点赞0


评论


AucunAucun

a喵喵

点赞0


评论


幕川北幕川北

eee路过的银发现pollLV没有定义,请大家热热使用()把pollLV改回定义的函数poll食用()

点赞2


评论


yee剑走天下yee剑走天下

以前觉得特銱()在经过一年半的练习后总算能轻松理解了(雾

点赞1


评论