dbToConfig(); } /** * 获取成就列表 * @param int $uid * @return array */ public function getList($uid) { $data = array('code' => -1, 'list' => []); if (!$uid || !$this->achievementConfig) { return $data; } $ret = $this->achievementConfig; $rewardedStr = $this->getRewarded($uid); $rewarded = str_split($rewardedStr); $conKeys = array(); foreach ($ret as $id => &$v) { if (!isset($v['subtask']) || !is_array($v['subtask'])) { unset($v); continue; } $status = isset($rewarded[$id - 1]) ? (int) $rewarded[$id - 1] : 0; foreach ($v['subtask'] as $subid => &$task) { $task['num'] = (int) $task[0]; $task['reward'] = (int) $task[1]; // 匹配用户已完成的子任务 if ($status & (1 << $subid - 1)) { $task['rewarded'] = 1; } else { $task['rewarded'] = 0; } unset($task[0], $task[1]); } $conKeys[] = $v['contype']; unset($v['zh_name']); } $condition = $this->getCondition($uid, $conKeys); // 数据重组 foreach ($ret as $id => &$v) { $v['cur'] = (int) $condition[$v['contype']]; } $data['code'] = 1; $data['list'] = $ret; return $data; } /** * 获取用户领取情况 * @param int $uid * @return array */ public function getRewarded($uid) { if (!$uid) return array(); $cacheKey = okeys::achi($uid); $cache = oo::commonOprRedis('userinfo')->get($cacheKey); if (!is_null($cache) && $cache !== false) { return $cache; } $tb = otable::achi($uid); $query = "select rewarded from {$tb} where uid='{$uid}' limit 1"; $row = oo::commonOprDb('common')->getOne($query, MYSQLI_ASSOC); if ($row) { $rewarded = !empty($row['rewarded']) ? $row['rewarded'] : $this->getDefault(); } else { $rewarded = $this->getDefault(); $query = "insert into {$tb} (uid,rewarded) values ('{$uid}','{$rewarded}')"; $flg = oo::commonOprDb('common')->query($query); if (!$flg) return array(); } oo::commonOprRedis('userinfo')->setex($cacheKey, $rewarded, oo::redisRandomExpire(7 * 86400)); return $rewarded; } /** * 获取用户当前缓存状态 * @param int $uid * @param array $types * @return array */ public function getCondition($uid, $types = array()) { if (!$uid || !$types || !is_array($types)) { return array(); } $cacheKey = okeys::achi($uid.'-'); if (!oo::commonOprRedis('usercache')->exists($cacheKey)) { // 没有缓存 $ret = $this->getConditionFromDB($uid, true); } else { $ret = oo::commonOprRedis('usercache')->hMget($cacheKey, $types); } $property = array(); // if (isset($ret['paid'])) { // $ret['paid'] = $ret['paid']; // 泰铢 // } if (in_array('maxchips', $types)) { $property or $property = oo::commonOprModel('member')->getUserAssetsInfo($uid); $ret['maxchips'] = $property['money']; } return $ret; } /** * 默认串 * @return string */ public function getDefault() { $maxId = max(array_keys($this->achievementConfig)); return str_pad('', $maxId, '0'); } /** * 获取条件值的数据库记录,或更新至缓存 * @param int $uid * @param bool $toCache * @return array */ public function getConditionFromDB($uid, $toCache = false) { if (!$uid) return array(); $tb = otable::achi($uid.'-'); $query = "select * from {$tb} where uid='{$uid}' limit 1"; $data = oo::commonOprDb('common')->getOne($query, MYSQLI_ASSOC); if ($toCache) { oo::commonOprRedis('usercache')->delete(okeys::achi($uid)); unset($data['rewarded']); oo::commonOprRedis('usercache')->hMget(okeys::achi($uid), $data); } return $data; } /** * 设置已领奖励缓存 * @param int $uid * @param int $id * @param int $subid * @return bool */ public function setRewarded($uid, $id, $subid) { if (!$uid || !$id || !$subid) { $this->errCode = -201; return false; } $rewardedStr = $this->getRewarded($uid); // 如果有新成就则可以补全 $maxId = max(array_keys($this->achievementConfig)); $rewardedStr = str_pad($rewardedStr, $maxId, '0'); $rewarded = str_split($rewardedStr); $idx = $id - 1; // ** 重要,存储的字符串是要ID-1 if (!isset($rewarded[$idx])) { $this->errCode = -201; return false; } if ($rewarded[$idx] & (1 << $subid - 1)) { // 已经设置过 $this->errCode = -202; return false; } $rewarded[$idx] |= 1 << $subid - 1; return $this->updateRewarded($uid, implode('', $rewarded)); } /** * 更新领取情况 * @param int $uid * @param string $rewarded * @return bool */ public function updateRewarded($uid, $rewarded) { if (!$uid || empty($rewarded)) { return false; } $rewarded = oo::functions()->escape($rewarded); oo::commonOprRedis('userinfo')->delete(okeys::achi($uid)); $tb = otable::achi($uid); $query = "update {$tb} set rewarded='{$rewarded}' where uid='{$uid}' limit 1"; return oo::commonOprDb('common')->query($query); } /** * 累加条件缓存 * @param int $uid * @param string $type * @param int $num * @return bool */ public function incCondition($uid, $type, $num = 1) { if (!$uid || !in_array($type, $this->contypes)) { return false; } $cacheKey = okeys::achi($uid.'-'); $curCondition = $this->getCondition($uid, [$type]); if ($type == 'winchips' && $curCondition['winchips'] > 100000000) { // 已经超过最大值了 return false; } $diffCacheKey = okeys::achiDiff($uid); if ($type == 'swinchips') { if ($num <= $curCondition['swinchips']) { return false; } else { oo::commonOprRedis('usercache')->hSet($diffCacheKey, $type, $num); return oo::commonOprRedis('usercache')->hSet($cacheKey, $type, $num); } } oo::commonOprRedis('usercache')->hIncrBy($diffCacheKey, $type, $num); $ret = oo::commonOprRedis('usercache')->hIncrBy($cacheKey, $type, $num); return $ret; } /** * 成就用户数据值入库落地(放在用户登录的时候,落地一次) * loginHandler.php * @param array $arr * @return bool */ public function recordCondition($arr) { $uid = (int) $arr['uid']; if (!$uid) return false; $cacheKey = okeys::achiDiff($uid); $cache = oo::commonOprRedis('usercache')->hGetAll($cacheKey); if ($cache === false) { // 没有缓存 return false; } oo::commonOprRedis('usercache')->delete($cacheKey); // 删除差值,重新累加 $tb = otable::achi($uid); if (!is_array($cache) || !$cache) return false; $insert = ""; $update = ""; foreach ($cache as $k => $v) { $v = (int) $v; if (!in_array($k, $this->contypes) || ($v <= 0)) { continue; } $insert .= "`{$k}`='{$v}',"; if ($k == 'swinchips') { // 更新不累加 $update .= "`{$k}`='{$v}',"; } else { $update .= "`{$k}`=`{$k}`+'{$v}',"; } } if (empty($insert)) return false; $insert = rtrim($insert, ','); $update = rtrim($update, ','); $query = "insert into {$tb} set uid='{$uid}',{$insert} on duplicate key update {$update}"; return oo::commonOprDb('achi')->query($query); } /** * 数据库内容读入配置文件 */ public function dbToConfig() { $key = okeys::achievementConfig(); $cacheData = oo::commonOprRedis('config')->get($key); if ($cacheData) { $tempArr = json_decode($cacheData, 1); foreach ($tempArr as $id => &$info) { $info['name'] = oo::getLang('achievement_'.$info['contype']); $info['desc'] = oo::getLang('achievement_desc_'.$info['contype']); } $this->achievementConfig = $tempArr; return; } $table = otable::achievementConfig(); $sql = "SELECT * FROM {$table} ORDER BY aid ASC "; $list = oo::commonOprDb('common')->getAll($sql, 1); $i = 1; $taskList = array(); foreach ($list as $ke => $value) { $value['id'] = $taskid = intval($value['id']); $value['sort'] = intval($value['sort']); $value['name'] = oo::getLang('achievement_'.$value['contype']); $value['desc'] = oo::getLang('achievement_desc_'.$value['contype']); $subtask = json_decode($value['subtask'], 1); $value['subtask'] = $subtask; $taskList[$taskid] = $value; $i++; } $taskListJson = json_encode($taskList); oo::commonOprRedis('config')->set($key, $taskListJson, 3600); $this->achievementConfig = $taskList; return $taskList; } /** * 配置文件写入数据库 */ public function configToDb() { $table = otable::achievementConfig(); foreach ($this->achievementConfig as $key => $info) { $name = $info['name']; $zh_name = $info['zh_name']; $contype = $info['contype']; $image = $info['image']; $sort = $info['sort']; $desc = $info['desc']; $subtask = json_encode( $info['subtask'] ); $sql = "INSERT INTO {$table} VALUES({$key}, '{$name}', '{$zh_name}', '{$contype}', '{$image}', {$sort}, '{$desc}', '{$subtask}')"; oo::commonOprDb('common')->query($sql); echo $key."\r\n"; } } // ----------------------------------------------------------------------------------------------------------------- /** * 成就配置 * @param string $aid * @return mixed * Created by: Owen * Created on: 2019/6/13 17:50 * Description: */ public function getAchieveConfig($aid = ''){ $cacheKey = okeys::AchieveConfig(); $arrJson = oo::commonOprRedis('config')->hGetAll($cacheKey); $arr = funs::getArrFromJsonArr($arrJson); if(empty($arr)||($aid!==''&&empty($arr[$aid]))){ $tb = otable::achievementConfig(); $sql = "SELECT * FROM {$tb}"; $ret = oo::commonOprDb('config')->getAll($sql,1); if(!empty($ret)){ foreach ($ret as $k=>$v){ $arr[$v['aid']] = $v; $cache[$v['aid']] = json_encode($v); } oo::commonOprRedis('config')->hMset($cacheKey,$cache); oo::commonOprRedis('config')->expire($cacheKey,oo::redisRandomExpire(7*86400)); } } $data = $aid===''?$arr:$arr[$aid]; return $data; } /** * 成就列表 * @param $uid * @return array * Created by: Owen * Created on: 2020/4/7 18:27 */ public function getAchieveList($uid){ $achieveConfig = self::getAchieveConfig(); $achieveUser = self::getUserAchieve($uid); $achieve = []; $lang = oo::getDefinedLang($uid); foreach ($achieveConfig as $row){ $reward = json_decode($row['reward']); $stage = explode(',',$row['stage']); $i = 0; $process = ($achieveUser[$row['aid']]['process'])??0; foreach ($stage as $k){ if($process>=$k){ $i++; } } $userStage = ($achieveUser[$row['aid']]['stage'])??0; if($userStage >= count($stage)){ $userStage = $userStage - 1; } if($lang == 'zh'){ $designation = $row['designation']; $content = $row['content']; }else{ $designation = $row['designation_'.$lang]; $content = $row['content_'.$lang]; } $temp = [ 'id' =>$row['aid'], 'rewardTimes' =>$i, 'name' =>$designation, 'desc' =>$content, 'spinsNum' =>$reward[$userStage]->spin, 'coinsNum' =>$reward[$userStage]->coin, 'progress' =>$process, 'target' =>$stage[$userStage], 'curRewardTimes'=>($achieveUser[$row['aid']]['stage'])??0 ]; $achieve[] = $temp; } return $achieve; } /** * 获取用户成就 * @param $uid * @param $aid * @return mixed * Created by: Owen * Created on: 2019/6/13 17:50 * Description: */ public function getUserAchieve($uid,$aid = ''){ $cacheKey = okeys::UserAchieve($uid); $data = oo::commonOprRedis('Usercache')->hGetAll($cacheKey); if(empty($data)){ $tb = otable::achievement($uid); $data = oo::commonOprDb('achievement')->getAll("SELECT * FROM {$tb} WHERE uid={$uid}",MYSQLI_ASSOC); if(empty($data)){ if($aid !== ''){ return self::InsertUserAchieve($uid,$aid); }else if($aid == ''){ return []; } } foreach ($data as $row){ oo::commonOprRedis('Usercache')->hSetNx($cacheKey,$row['aid'],json_encode($row)); } oo::commonOprRedis('Usercache')->expire($cacheKey,oo::redisRandomExpire(3*2*60*60)); }else{ $data = funs::getArrFromJsonArr($data); } $out = []; foreach ($data as $key=>$row){ if($key == $aid && $aid !== ''){ return $row; } $out[$key] = $row; } if($aid === ''){ return $out; }else{ return self::InsertUserAchieve($uid,$aid); } } /** * 插入成就 * @param $uid * @param $aid * @return array * Created by: Owen * Created on: 2020/7/3 14:52 */ public function InsertUserAchieve($uid,$aid){ $cacheKey = okeys::UserAchieve($uid); $ret = [ 'uid' => $uid, 'aid' => $aid, 'process' => 0, 'stage' => 0 ]; $res = oo::commonOprRedis('Usercache')->hSetNx($cacheKey,$aid,json_encode($ret)); if($res){//并发锁 $tb = otable::achievement($uid); oo::commonOprDb('achievement')->query("INSERT INTO {$tb} (uid,aid,process) VALUES ({$uid},{$aid},0)",false); } return $ret; } /** * 更新成就缓存 * @param $uid * @param $aid * @param $ret * @return bool * Created by: Owen * Created on: 2020/4/7 18:19 */ public function updateUserAchieve($uid,$aid,$ret){ $cacheKey = okeys::UserAchieve($uid); $ret['isLanding'] = 1; $bool = oo::commonOprRedis('Usercache')->hSet($cacheKey,$aid,json_encode($ret)); oo::commonOprRedis('Usercache')->expire($cacheKey,oo::redisRandomExpire(3*2*60*60)); /** 数据落地标识 */ oo::commonOprRedis('Usercache')->zAdd(okeys::Landing("ACHIEVE", $uid),time(),$uid); return $bool; } /** * 更新成就数值 * @param $uid * @param $aid * @param int $num * @param string $opt * @return bool * Created by: Owen * Created on: 2020/4/7 10:42 */ public function updateAchi($uid,$aid,$num = 1,$opt = '+'){ $ret = self::getUserAchieve($uid,$aid); if($opt == '+'){ $ret['process'] = $ret['process'] + $num; }else if($opt == '='){ $ret['process'] = $num; } self::updateUserAchieve($uid,$aid,$ret); $ret = self::getAchieveConfig($aid); $stage = explode(',',$ret['stage']); if($ret['process'] <= $stage[count($stage)-1]){ if(count($stage) > $ret['stage'] && $ret['process'] >= $stage[$ret['stage']]){ $is_push = oo::commonOprRedis('Usercache')->hGet(okeys::redPointLock($uid,'Achi-'.$aid),$ret['stage']+1); if(!$is_push){ oo::commonOprModel('Workerman')->push($uid,ocmd::$redPoint,['type'=>10]); oo::commonOprRedis('Usercache')->hSet(okeys::redPointLock($uid,'Achi-'.$aid),$ret['stage']+1,1); oo::commonOprRedis('usercache')->expire(okeys::redPointLock($uid,'Achi-'.$aid),oo::redisRandomExpire(7*86400)); } } } return ($ret)?true:false; } /** * 领取成就奖品 * @param $uid * @param $aid * @return array * Created by: Owen * Created on: 2019/6/13 18:33 * Description: */ public function getAchieveReward($uid,$aid){ $achieve = self::getUserAchieve($uid,$aid); if(empty($achieve)){ return ['code'=>-1,'msg'=>'未达标,无法领取奖品']; } $rewardStage = $achieve['stage']; $config = self::getAchieveConfig($aid); $configStage = explode(',',$config['stage']); if(count($configStage) == $rewardStage){ return ['code'=>-1,'msg'=>'已领取最高等级奖励']; } $lang = oo::getDefinedLang($uid); if($configStage[$rewardStage]<=$achieve['process']){ $achieve['stage'] = $rewardStage + 1; $ret = self::updateUserAchieve($uid,$aid,$achieve); if($ret){ $reward = json_decode($config['reward'],true); $nextReward = $reward[$rewardStage+1]; $rewardTemp = $reward[$rewardStage]; $reward = [ 'spins' => $rewardTemp['spin'], 'money' => $rewardTemp['coin'], ]; oo::commonOprModel('member')->optProperty($uid,$reward,'+',102,'领取成就奖励:'.$aid.'-'.$rewardStage); $i = 0; $process = $achieve['process']; $stage = explode(',',$config['stage']); foreach ($stage as $k){ if($process>$k){ $i++; } } $data = [ 'coin' =>$reward['money'], 'coins'=>$reward['money'], 'spins'=>$reward['spins'], ]; if($lang == 'zh'){ $designation = $config['designation']; $content = $config['content']; }else{ $designation = $config['designation_'.$lang]; $content = $config['content_'.$lang]; } $data['achieve'] = [ 'id' =>$aid, 'rewardTimes' =>$i, 'name' =>$designation, 'desc' =>$content, 'spinsNum' =>$nextReward['spin']??0, 'coinsNum' =>$nextReward['coin']??0, 'progress' =>$process, 'target' =>$stage[$rewardStage+1]??0, 'curRewardTimes'=>($rewardStage+1) ]; oo::commonOprRedis('Usercache')->hDel(okeys::redPointLock($uid,'Achi-'.$aid),$rewardStage+1); return ['code'=>1,'msg'=>'领取奖品成功','data'=>$data]; } }else{ return ['code'=>-1,'msg'=>'未达标,无法领取奖品']; } } /** * 1.5.0 新版配置 -------------------------------------------------------------------------------------------------- */ /** * 成就列表 * @param $uid * @return array * Created by: Owen * Created on: 2020/4/7 18:27 */ public function getAchieveList2($uid){ $achieveConfig = self::getAchieveConfig(); $achieveUser = self::getUserAchieve($uid); $achieve = []; foreach ($achieveConfig as $row){ $process = ($achieveUser[$row['aid']]['process'])??0; $temp = [ 'id' =>$row['aid'], 'progress' =>$process, 'curRewardTimes'=>($achieveUser[$row['aid']]['stage'])??0 ]; $achieve[] = $temp; } return $achieve; } }