已知问题7
如果安装了Steam但是没有登录,Wine游戏助手可能会报错:
2022-05-17 23:00:11,865: Starting Lutris 0.5.10.4 2022-05-17 23:00:11,899: No folder at /home/hu60/.local/share/net.winegame.client/runners/retroarch/ 2022-05-17 23:00:11,976: Using NVIDIA drivers 510.68.02 for x86_64 2022-05-17 23:00:11,977: GPU: NVIDIA GeForce RTX 3080 Ti 2022-05-17 23:00:11,977: GPU: 10DE:2208 7377:140A (nvidia drivers) 2022-05-17 23:00:12,200: Error while completing task <bound method LutrisInitDialog.initialize of <dialogs.LutrisInitDialog object at 0x7f1bb253ea68 (lutris+gui+dialogs+LutrisInitDialog at 0x1f442b0)>>: <class 'FileNotFoundError'> [Errno 2] 没有那个文件或目录: '/home/hu60/.local/share/Steam/userdata/352964089/config/shortcuts.vdf' File "/opt/apps/net.winegame.client/files/lib/lutris/lutris/util/jobs.py", line 34, in target result = self.function(*args, **kwargs) File "/opt/apps/net.winegame.client/files/lib/lutris/lutris/gui/dialogs/__init__.py", line 197, in initialize init_lutris() File "/opt/apps/net.winegame.client/files/lib/lutris/lutris/startup.py", line 213, in update_runtime update_all_artwork() File "/opt/apps/net.winegame.client/files/lib/lutris/lutris/util/steam/shortcut.py", line 152, in update_all_artwork with open(shortcut_path, "rb") as shortcut_file: 2022-05-17 23:00:17,790: Shutting down Lutris
@MFVPNHAHA,我没有苹果设备
但是,如果只是“这些地方的分割希望能优化一下”,恕我不知道该优化成什么样子,是增大间距,还是减小间距?是增粗分割线,减弱分割线,还是改变分割线样式?多粗,多弱,什么颜色?
不要把设计自由留给我。我不会设计,只会实施。
或者,如果不会代码也不会作图,又还是想改,那可以给我发精确的修改指令,比如:
把12楼和13楼的间隔增大10像素,其中,分割线以上5像素,分割线以下5像素。
这种我可以做到,我会先给你做个网页插件,让你看到效果。如果你满意,我可以向全站推广。
除了 Stylish 插件,还可以直接把代码粘贴到这里来修改主题:https://hu60.cn/q.php/addin.webplug.html
我需要的就是这样的代码,如果想让我改进主题,最好先自己实现出来,然后把代码提交给我。
如果真的不会HTML/CSS,那就把设计图提交给我,我尝试为你实现。
如果没有代码也没有设计图,只有文字描述,凭我的美术水平,肯定不会有让你满意的实现,在这一点上你一定要相信我,希望有多大失望就有多大。
已知问题5(已在0.5.10.4中修复)
如果安装脚本的
files
区域为空(不下载任何文件),那么installer
区域也会被置为空,导致安装未进行。该错误由lutris开发者在0.5.10引入。
已知问题4(已在0.5.10.4中修复)
wine版本管理页面的排版很混乱
@花祭,jhin主题不是我设计的,如果要我动手改,在没有像素级设计图的情况下,肯定会改得比现在还差。我只能改出经典主题的水平,是什么水平我想你也看到了。
@Albedo,👌
@花祭,那不是可以直接给虎绿林用的效果图,我需要的效果图是真正的虎绿林帖子页面,不需要做任何添加删除修改就能用的。比如,我肯定要把楼层序号放上去,但是网易没有,所以需要我设计。我选的位置和字体肯定不会好看。
@花祭,我对界面设计没有任何想法,我只能等待有人提供效果图或者CSS代码(最好是CSS代码,因为效果图不一定能完美实现),这样我就能直接应用了。只提供文字版的建议没有什么用,我只会改得更难看。
@花祭,都是什么样的?我只看过微博的。
@姜辰,把配置文件里的变量和所需的类复制过来就行了。注意
$CC_DATA
必须指定到tmpfs
内,否则性能会很差,不能防CC。如果没有条件使用tmpfs
,可以改用memcached
。部署cc.php的方法很简单,把这个代码粘贴到程序的主配置文件(
config.php
,就是那个包含数据库配置的文件)开头即可。<?php /////////////////// 防止CC攻击 /////////////////// /** * 是否启用防CC模块 */ $ENABLE_CC_BLOCKING = true; /** * 使用memcache */ $CC_USE_MEMCACHE = false; /** * CC行为记录文件 * * 请指定到tmpfs文件系统内,否则性能会很差。 * 如系统为Windows,请使用memcache,这样就不需要指定该文件。 */ $CC_DATA = '/dev/shm/hu60-cc.dat'; /** * CC行为日志 * * 设为null禁用 */ $CC_BLOCK_LOG = '/tmp/hu60-cc.log'; /** * 正常访问日志 * * 设为null禁用 */ $CC_ACCESS_LOG = null; /** * CC判定范围 */ $CC_LIMIT = [ 10, // n秒内 50, // 最多访问n次 ]; /** * 特定IP判定范围 */ $CC_IP_LIMIT = [ // 设置特定IP n秒最多能访问的次数 '127.0.0.1' => 100, ]; /** * 真实IP * * 开头加#禁用,删除#启用 */ // 无代理时使用 $CC_REAL_IP = $_SERVER['REMOTE_ADDR']; // 采用CloudFlare或百度云加速代理时使用 #$CC_REAL_IP = $_SERVER['HTTP_CF_CONNECTING_IP']; /* 缓存设置 */ /** * 缓存类型 */ define('CACHE_TYPE', 'memcached'); /* memcached设置($CC_USE_MEMCACHE = true 时需要设置) */ /** 服务器名称 */ define('MEMCACHED_NAME', 'hu60'); /** 服务器主机名 */ define('MEMCACHED_HOST', 'localhost'); /** 服务器端口 */ define('MEMCACHED_PORT', 11211); # 防止CC攻击 hu60_cc_prevent(); function hu60_cc_prevent() { global $ENABLE_CC_BLOCKING, $CC_DATA, $CC_LIMIT, // 数组, $CC_LIMIT[0] 秒内最多访问 $CC_LIMIT[1] 次 $CC_USE_MEMCACHE, $CC_BLOCK_LOG, $CC_ACCESS_LOG, $CC_IP_LIMIT, $CC_REAL_IP; // 记录数,决定记录文件的大小 $CC_RECORD_NUM = 256 * 256; // 单个记录字节数 $CC_RECORD_SIZE = 6; if (!$ENABLE_CC_BLOCKING) { return; } if (empty($CC_REAL_IP)) { $CC_REAL_IP = $_SERVER['REMOTE_ADDR']; } if (isset($CC_IP_LIMIT[$CC_REAL_IP])) { $CC_LIMIT[1] = $CC_IP_LIMIT[$CC_REAL_IP]; } // 当前时间,uint16 $currTime = unpack('v', pack('v', $_SERVER['REQUEST_TIME'])); $currTime = $currTime[1]; // IP hash,代表记录在文件中的位置 $ipHash = (hexdec(substr(md5($CC_REAL_IP), 0, 8)) % $CC_RECORD_NUM) * $CC_RECORD_SIZE; if ($CC_USE_MEMCACHE) { $key = "cc/$ipHash"; $record = cache::get($key); } else { if (!is_file($CC_DATA) || filesize($CC_DATA) < $CC_RECORD_NUM * $CC_RECORD_SIZE) { file_put_contents($CC_DATA, str_repeat("\0", $CC_RECORD_NUM * $CC_RECORD_SIZE)); } $CC_DATA = fopen($CC_DATA, 'r+'); fseek($CC_DATA, $ipHash); $record = fread($CC_DATA, $CC_RECORD_SIZE); } $record = unpack('v3', $record); // 首次访问时间 $firstAccTime = $record[1]; // 最后访问时间 $lastAccTime = $record[2]; // 访问次数 $accCount = ++$record[3]; if ($firstAccTime <= 0) { $firstAccTime = $currTime; } if ($lastAccTime <= 0) { $lastAccTime = $currTime; } $timeDiff = $currTime - $firstAccTime; if ($timeDiff < 0) { // uint16溢出时会发生 $firstAccTime = $currTime; $lastAccTime = $currTime; $accCount = 1; $timeDiff = $CC_LIMIT[0]; } elseif ($timeDiff < $CC_LIMIT[0]) { // 不够n秒,补充到n秒 $timeDiff = $CC_LIMIT[0]; } $accRate = $accCount / $timeDiff; $allowRate = $CC_LIMIT[1] / $CC_LIMIT[0]; $block = false; if ($accRate > $allowRate) { $block = true; // 10 秒内访问 434 次 // 设访问速度下降到每秒 5 次的最短等待时间是 t // (434 + 1) / (10 + t) = 5 // 10 + t = (434 + 1) / 5 // t = (434 + 1) / 5 - 10 $needWaitSeconds = ceil(($accCount + 1) / $allowRate - $timeDiff); hu60_cc_output($needWaitSeconds, $timeDiff, $accCount, $accRate, $allowRate); // 超速访问日志 if ($CC_BLOCK_LOG) { hu60_cc_log($CC_BLOCK_LOG, '超速', $timeDiff, $accCount); } } else { // 正常用户访问日志 if ($CC_ACCESS_LOG) { hu60_cc_log($CC_ACCESS_LOG, '正常', $timeDiff, $accCount); } } $lastTimeDiff = $currTime - $lastAccTime; // 上次访问距离这次访问经过了很久,且未超速,重置统计 if (!$block && ($lastTimeDiff > $CC_LIMIT[0] || $lastTimeDiff < 0)) { $firstAccTime = $currTime; $lastAccTime = $currTime; $accCount = 1; $timeDiff = $CC_LIMIT[0]; } $record = pack('v3', $firstAccTime, $currTime, $accCount); if ($CC_USE_MEMCACHE) { cache::set($key, $record); } else { fseek($CC_DATA, $ipHash); fwrite($CC_DATA, $record); fclose($CC_DATA); } if ($block) { exit; } } function hu60_cc_log($file, $stat, $timeDiff, $accCount) { global $CC_REAL_IP; $fp = fopen($file, 'a+'); fwrite($fp, "[" . date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . "] <$stat,{$timeDiff}秒{$accCount}次> $CC_REAL_IP\t[PATH] $_SERVER[REQUEST_URI]\t[REF] $_SERVER[HTTP_REFERER]\n"); fclose($fp); } function hu60_cc_output($needWaitSeconds, $timeDiff, $accCount, $accRate, $allowRate) { global $CC_LIMIT, $CC_REAL_IP; header('HTTP/1.1 503 Service Unavailable'); header('Retry-After: '.$needWaitSeconds); header('Content-Type: text/html; charset=UTF-8'); ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>刷新不规范,虎友两行泪</title> </head> <body> <h4> 虎绿林第三区交通委提醒您:<br/> 网址千万条,耐心第一条。<br/> 刷新不规范,虎友两行泪。 </h4> 虎绿林低速网络限速<?=$CC_LIMIT[0]?>秒内最多访问<?=$CC_LIMIT[1]?>次(每秒<?=round($allowRate, 2)?>次)。<br/> 您在<?=$timeDiff?>秒内访问了<?=$accCount?>次(每秒<?=round($accRate, 2)?>次),您已超速。<br/> 作为惩罚,吊销您的虎绿林通行证<?=$needWaitSeconds?>秒钟,在这段时间内您将不能访问虎绿林。<br/> 您的IP地址为<?php echo $CC_REAL_IP; ?>,违章记录已存档。 请勿反复刷新,否则违章记录将延续。<br/> </body> </html> <?php } interface cacheInterface { public function get($key); public function set($key, $value, $timeout = 0); public function del($key); } class cacheMemcached implements cacheInterface { /* Memcached 设置 */ protected static $memcachedName = MEMCACHED_NAME; protected static $memcachedServers = [ [MEMCACHED_HOST, MEMCACHED_PORT] ]; protected $memcached = null; public function __construct() { $this->memcached = new Memcached(self::$memcachedName); $this->memcached->addServers(self::$memcachedServers); } public function get($key) { return $this->memcached->get($key); } public function set($key, $value, $timeout = 0) { return $this->memcached->set($key, $value, $timeout); } public function del($key) { return $this->memcached->delete($key); } } class cache { protected static $cacheClassName = CACHE_TYPE; protected static $instance = null; static protected function getInstance() { if (self::$instance == null) { $cacheClass = 'cache' . self::$cacheClassName; self::$instance = new $cacheClass(); } return self::$instance; } static public function get($key) { return self::getInstance()->get($key); } static public function set($key, $value, $timeout = 0) { return self::getInstance()->set($key, $value, $timeout); } static public function del($key) { return self::getInstance()->del($key); } } ?>
@胡图图,可以看看4楼的代码2和代码1相比多了什么,它在恰当的地方添加了
success = false;
和
success = true;
这种无中生有的新增,需要真正的人类智能。转换器要先学会像人类一样思考,学会类比、等价和推理,才能完整这种程度的重构。
@胡图图,编译器所做的事情,是把其他一切分支跳转代码转换成goto。所以在别人直接使用goto的情况下,你怎么可能简单的用其他代码进行模拟?它们不是等价的,不是一一对应的,只有goto的某些特定使用方式能转换成if/switch/while,但是开发人员之所以想使用goto,一定是因为if/switch/while的表达能力不满足他们的要求。所以可以这么说,除非程序员真的想滥用goto,否则代码中出现的每个goto都难以自动转换成其他表现形式。
@胡图图,
为什么没有人自己设计一个"goto killer" 把所有带goto的代码,都转换成不带goto的代码?
如果可以优雅地转换,我们就不会提出这种批评了:
“删除 goto 是一种宗教选择,而不是技术选择。”
“如果你发现自己为了避免使用goto而不得不采取真正愚蠢的方案,那就应该停下来。”
转换后的代码一定会比原始代码更蠢,因为一切用于“模拟”goto的代码本质上都是goto。if是goto,while是goto,switch是goto,foreach是goto,甚至函数调用实际上也是goto,只是它们用更精美的包装呈现给你了而已。
所以在那些真正需要非结构化跳转的地方,想用更高层次的“结构化跳转”(if/while/函数调用)模拟goto,只能得到愚蠢的代码,甚至根本难以实现,远比不上直接大大方方的使用goto。
因此,就连中毒最深最讨厌goto的人,也没有办法实现这个自动转换器。
@胡图图,请仔细阅读4楼的代码及其评论。
实际上,编译器生成的代码几乎完全一致。
解释一下这句话:就是说,编译后两者生成的程序里,目标代码(机器语言代码)完全相同。
但是两个代码哪个更清晰,一目了然。
https://stackoverflow.com/a/741517
GOTO 仍被认为有害吗
- tylerl 2009年4月12日 9:32
在某些情况下,
goto
可以为“真正的”异常处理提供一种替代。考虑以下代码:
ptr = malloc(size); if (!ptr) goto label_fail; bytes_in = read(f_in,ptr,size); if (bytes_in =< 0) goto label_fail; bytes_out = write(f_out,ptr,bytes_in); if (bytes_out != bytes_in) goto label_fail;
显然,这段代码被简化以减少空间占用,所以不要太过在意细节。
但是考虑一下我在生产代码中看到过多次的替代方法,看看编码人员为了避免使用
goto
而荒谬的程度:success = false; do { ptr = malloc(size); if (!ptr) break; bytes_in = read(f_in,ptr,size); if (count =< 0) break; bytes_out = write(f_out,ptr,bytes_in); if (bytes_out != bytes_in) break; success = true; } while (false);
从功能上讲,这两段代码完全相同。实际上,编译器生成的代码几乎完全一致。然而,在热切地安抚 Nogoto(可怕的学术谴责之神)的同时,这位程序员完全打破了循环所代表的基本习惯,并对代码的可读性做了真正糟糕的事情。这并不比直接使用
goto
更好。所以,故事的寓意是,如果你发现自己为了避免使用
goto
而不得不采取真正愚蠢的方案,那就应该停下来。