猫史档案馆


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

用户:幻想一笑而过幻想一笑而过查看:796 回复: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


评论

对于PG数据库的补充:PG数据库REAL最大值为8192.0

额鹅鹅鹅


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

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

点赞0


评论


IaeaIaea

d'd

点赞0


评论


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

喵

点赞0


评论


1232RvE1232RvE

把pg代码(poll)搬了?

点赞0


评论


1232RvE1232RvE

pollLV()???????

点赞1


评论


DL1DL1

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

点赞0


评论

PG发布了。。。(至少我们图变PG了


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

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


评论