redis+lua现实游戏中的一些常用功能

游戏中一些常用的功能,仅仅使用redis提供的命令来实现,恐怕难度比较大。好在redis支持lua,能让一系列的操作变为原子操作,让这些常用却又麻烦的功能变的简单了,当然这需要小量的性能损失,别的不多说,懂的自然懂,不懂的看了就懂了,上代码:


class MyStorage extends Redis
{
    public function safeDecr($key, $num)
    {
        $script = "local old=redis.call('get', KEYS[1]);\n";
        $script.= "if not old or old+0 < ARGV[1]+0 then return false;end;";
        $script.= "return redis.call('decrBy', KEYS[1], ARGV[1]);\n";
        return $this->eval($script, array($key, $num), 1);
    }
     
    public function safeHDecr($key, $member, $num)
    {
        $script = "local old=redis.call('hGet', KEYS[1], ARGV[1]);\n";
        $script.= "if not old or old+0 < ARGV[2]+0 then return false;end;";
        $script.= "redis.call('hIncrBy', KEYS[1], ARGV[1], -ARGV[2]);\n";
        $script.= "return true;";
        return $this->eval($script, array($key, "", $member, $num), 2);
    }
     
    public function lock($key, $now, $expire)
    {
        $script = "local old=redis.call('get', KEYS[1]);\n";
        $script.= "if old and ARGV[1]+0 < old+0 then return false;end;\n";
        $script.= "redis.call('set', KEYS[1], ARGV[2]);\n";
        $script.= "return true;";
        return $this->eval($script, array($key, "", $now, $expire), 2);
    }
     
    public function hlock($key, $member, $now, $expire)
    {
        $script = "local old=redis.call('hGet', KEYS[1], ARGV[1]);\n";
        $script.= "if old and ARGV[2]+0 < old+0 then return false;end;\n";
        $script.= "redis.call('hSet', KEYS[1], ARGV[1], ARGV[3]);\n";
        $script.= "return true;";
        return $this->eval($script, array($key, "", "", $member, $now, $expire), 3);
    }
     
    public function rankSwap($key, $r1, $r2)
    {
        $script = "local r1score=redis.call('zScore', KEYS[1], ARGV[1]);\n";
        $script.= "local r2score=redis.call('zScore', KEYS[1], ARGV[2]);\n";
        $script.= "redis.call('zAdd', KEYS[1], r2score, ARGV[1]);\n";
        $script.= "return redis.call('zAdd', KEYS[1], r1score, ARGV[2]);\n";
        return $this->eval($script, array($key, "", $r1, $r2), 2);
    }
}
 
$redis = new MyStorage();
 
//场景1:需要对某个key进行decr操作,但是又不能让他为负数(比如某个物品限量销售)
$redis->safeDecr('mygold', 10);//如果mygold的值小于10,那么会返回false
 
//场景2:需要对hashtable下某个Key做decr操作,但又不能让他为负数(比如用户的金币、游戏币等)
$redis->safeHDecr('mygold2', 'gold', 10);
 
//场景3:锁定某个key,并且让他带有过期时间
$now = time();
$redis->lock('mylock', $now, $now + 5);//5秒后过期,再此期间再进行加锁,会返回false
 
//场影4:锁定hashtable中某个key,并且带过期时间(当然你可以直接用lock,但是这样你要清理所有相关的锁,就必须来一次keys了)
$now = time();
$redis->hlock('mylock', 'lock', $now, $now + 5);
 
//场景5:对排名进行原子的交换(比如游戏中的排行榜,如果你要取出来再zadd回去,估计bug一大堆,当然这个可以用策划来弥补,比如胜利了+N积分)
$redis->rankSwap('myrank', 'r1', 'r2');


你可能感兴趣的:(redis+lua现实游戏中的一些常用功能)