LOADING

加载过慢请开启缓存 浏览器默认开启

Lumorian's Blog

永恒的紫罗兰

风花雪月本闲, 而扰攘者自冗

博客更新日志

2026/2/11

展示最近的 5 次更新, 查看全部更新日志请点击阅读全文

26-5-20

新增了Steam 在 niri (xwayland-satellite) 下的崩溃修复指南

26-4-17

更新了修复 libinput 鼠标点击抖动限制
更新了我的 Arch + Niri 全安裝及配置

26-4-14

新增了修复 libinput 鼠标点击抖动限制

26-4-13

更新了我的 Arch + Niri 全安裝及配置

26-4-02

新增了Daysmatter-终端交互式倒计时工具

阅读全文

Steam 在 niri (xwayland-satellite) 下的崩溃修复指南

2026/5/20

前言/废话

记录一下 Steam 在 niri + xwayland-satellite + NVIDIA 环境下从无法启动到恢复正常运行的完整修复过程, 包括 GDK 补丁、NVIDIA 驱动版本对齐、以及 Proton 游戏闪退排查等内容

环境

项目
操作系统 Arch Linux (rolling)
合成器 niri (scrollable-tiling Wayland compositor)
X11 兼容层 xwayland-satellite
glibc 版本 2.43
显示服务 :0 (通过 xwayland-satellite 提供的 X11 DISPLAY)

Steam 启动崩溃修复

Steam 启动后立即崩溃(SIGSEGV),从 GDB 回溯和 Breakpad minidump 分析发现多个崩溃点

# 问题 类型
1 GDK Xinerama 崩溃 SIGSEGV
2 GDK XRANDR 崩溃 SIGSEGV
3 JIT/CEF NULL 字符串崩溃 SIGSEGV
4 nvidia_drm.modeset 未启用 配置错误
5 32 位 NVIDIA 驱动版本不匹配 配置错误

GDK Xinerama 崩溃

症状: Steam 首次启动时立即段错误

根源: xwayland-satellite 不支持 XINERAMA 扩展。GDK 检查 Xinerama 时向 NULL 指针写入标志位

修复: NOP 掉 Steam 捆绑的 GDK 二进制文件中写入 movl $0x1,0x22c(%eax) 的指令

# 备份原始文件
cp /home/lumorian/.local/share/Steam/ubuntu12_32/steam-runtime/usr/lib/i386-linux-gnu/libgdk-x11-2.0.so.0.2400.10 \
   /home/lumorian/.local/share/Steam/ubuntu12_32/steam-runtime/usr/lib/i386-linux-gnu/libgdk-x11-2.0.so.0.backup

# 文件偏移 0x627cc: 将 c7 80 2c 02 00 00 01 00 00 00 替换为 10 个 NOP
python3 -c "
data = bytearray(open('libgdk-x11-2.0.so.0.2400.10', 'rb').read())
data[0x627cc:0x627d6] = b'\x90' * 10
open('libgdk-x11-2.0.so.0.2400.10', 'wb').write(data)
"

GDK XRANDR 崩溃

症状: 修复 Xinerama 崩溃后 Steam 仍然崩溃, 错误信息包含 XRRGetOutputInfo Workaround: initialized with override: 0 real: (nil)

根源: xwayland-satellite 的 XRANDR 支持不完整, XRRGetOutputInfo() 返回 NULL

修复: NOP 掉跳转到 XRANDR 路径的条件跳转指令, 同时预加载系统 libXrandr

# 文件偏移 0x62737: 将 0f 85 0b 01 00 00 (jne) 替换为 6 个 NOP
python3 -c "
data = bytearray(open('libgdk-x11-2.0.so.0.2400.10', 'rb').read())
data[0x62737:0x6273d] = b'\x90' * 6
open('libgdk-x11-2.0.so.0.2400.10', 'wb').write(data)
"

启动时预加载系统 libXrandr

export LD_PRELOAD="/usr/lib32/libXrandr.so.2"

JIT/CEF NULL 字符串崩溃

症状: 修复 GDK 崩溃后 Steam 进程存活时间更长但仍然崩溃, 回溯指向 JIT 编译的代码中 strlen(NULL) 调用

根源: glibc 2.43 的 strlen(), strcmp(), strstr(), strchr() 使用 IFUNC 机制选择 SSE2/AVX2 优化版本, 不处理 NULL 输入

修复: 创建 LD_PRELOAD 库拦截不安全的字符串函数

// nullsafe.c — NULL 安全字符串拦截器
#define _GNU_SOURCE
#include <stddef.h>
#include <dlfcn.h>

extern void *dlsym(void *, const char *);
#define RTLD_NEXT ((void *)-1)

__attribute__((used))
size_t strlen(const char *s) {
    static size_t (*real_fn)(const char*) = NULL;
    if (!real_fn) real_fn = (size_t (*)(const char*))dlsym(RTLD_NEXT, "strlen");
    if (!s) return 0;
    return real_fn(s);
}

__attribute__((used))
int strcmp(const char *s1, const char *s2) {
    static int (*real_fn)(const char*, const char*) = NULL;
    if (!real_fn) real_fn = (int (*)(const char*, const char*))dlsym(RTLD_NEXT, "strcmp");
    if (!s1 && !s2) return 0;
    if (!s1) return -1;
    if (!s2) return 1;
    return real_fn(s1, s2);
}

__attribute__((used))
char *strstr(const char *haystack, const char *needle) {
    static char *(*real_fn)(const char*, const char*) = NULL;
    if (!real_fn) real_fn = (char *(*)(const char*, const char*))dlsym(RTLD_NEXT, "strstr");
    if (!haystack) return NULL;
    if (!needle) return (char*)haystack;
    return real_fn(haystack, needle);
}

__attribute__((used))
char *strchr(const char *s, int c) {
    static char *(*real_fn)(const char*, int) = NULL;
    if (!real_fn) real_fn = (char *(*)(const char*, int))dlsym(RTLD_NEXT, "strchr");
    if (!s) return NULL;
    return real_fn(s, c);
}

编译 (需要注意: 不能包含 <string.h>, 因为 glibc 2.43 使用 _Generic 宏与函数定义冲突)

gcc -m32 -shared -fPIC -o /tmp/nullsafe.so /tmp/nullsafe.c -ldl -O2 -fno-builtin

# 安装到永久路径
cp /tmp/nullsafe.so /home/lumorian/.local/lib/nullsafe.so

nvidia_drm.modeset 未启用

症状: glxinfo 显示 direct rendering: Yes,但 32 位程序无法创建 GLX 直接上下文

根源: GRUB 内核参数 nvidia-drm-modeset=1 格式错误。正确格式应为 nvidia-drm.modeset=1

# 检查当前状态
cat /sys/module/nvidia_drm/parameters/modeset
# 应为 Y, 若为空则未启用

# 修复 GRUB 参数
sudo sed -i 's/nvidia-drm-modeset=1/nvidia-drm.modeset=1/' /etc/default/grub
sudo grub-mkconfig -o /boot/grub/grub.cfg
# 重启生效

32 位 NVIDIA 驱动版本不匹配

症状: nvidia_drm.modeset=Y 后 32 位 GLX 仍然返回 NULL

根源: 32 位 NVIDIA 用户态库被 paru 升级到 580.159.03, 而内核模块和 64 位库为 580.142, 版本不一致

# 检查版本
pacman -Q nvidia-580xx-utils
pacman -Q lib32-nvidia-580xx-utils

# 降级 32 位库
sudo pacman -U /home/lumorian/.cache/paru/clone/lib32-nvidia-580xx-utils/lib32-nvidia-580xx-utils-580.142-1-x86_64.pkg.tar.zst

# 验证
ls -la /usr/lib32/libGLX_nvidia.so.0

Proton 游戏闪退修复

背景

在修复完 Steam 本身的崩溃和 GLX 渲染问题后, Steam 商店和库功能正常, 但运行特定 Windows 游戏时仍然闪退

症状

游戏”星空列车与白的旅行”(Steam AppID 1567800)启动后窗口一闪而过, 约 3-5 秒后进程全部退出

排查过程

检查游戏类型

游戏文件包含 UnityPlayer.dll, GameAssembly.dll, 确定是 32 位 Unity IL2CPP 游戏, 需通过 Proton 运行

查看游戏日志

从 Proton 兼容层目录找到 Unity Player 日志:

cat "/mnt/data/SteamLibrary/steamapps/compatdata/1567800/pfx/drive_c/users/steamuser/AppData/LocalLow/Syawase Works/星空列车与白的旅行/Player.log"

日志显示游戏启动正常, D3D11 设备创建成功, Steam API 初始化完成, 然后:

AspectRatioController:wndProc(IntPtr, UInt32, IntPtr, IntPtr)
ApplicationWantsToQuit: False
StartCoroutine -> DelayedQuit
ApplicationWantsToQuit: True

游戏使用了 DenchiSoft 的 UnityAspectRatioController 组件, 它通过 WinAPI (SetWindowLong + WindowProc) 挂钩窗口消息来锁定宽高比。该组件在说明中明确写了仅支持 Windows。在 Proton/Wine 下, WinAPI 窗口钩子的行为与 Windows 不同, 导致组件在初始化时收到意外窗口消息后触发退出

交叉测试

试了以下方案均无效:

  • DISABLE_GAMESCOPE=1 (排除 gamescope 干扰)
  • -screen-width 1920 -screen-height 1080 -screen-fullscreen 1 (Unity 强制分辨率)
  • -popupwindow (强制窗口模式)

导入 Proton 日志

PROTON_LOG=1 %command%  # 生成 ~/steam-1567800.log

日志发现 nullsafe.solibXrandr.so.2 的 LD_PRELOAD 泄漏到了 Proton 进程环境中:

ERROR: ld.so: object '/home/lumorian/.local/lib/nullsafe.so' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored.

nullsafe.so 是 32 位库, 被 Proton 的 32 位 Wine 内部进程加载后干扰了窗口消息的正常处理, 间接导致 AspectRatioController 异常触发退出

解决方案

在 Steam 启动选项中使用以下命令清除继承的 LD_PRELOAD

LD_PRELOAD= %command%

这个命令仅对该游戏生效, 不会影响 Steam 主进程的稳定性

移植到其他游戏的注意点

如果你的 steam-fixed.sh 中设置了全局 LD_PRELOAD, 任何通过 Proton 运行的 Windows 游戏都可能受到干扰。建议每个游戏单独在启动选项添加:

LD_PRELOAD= %command%

完整启动命令

killall -9 steam 2>/dev/null; sleep 1
export LANG=C STEAM_RUNTIME=1 DISPLAY=:0
export LD_PRELOAD="/home/lumorian/.local/lib/nullsafe.so /usr/lib32/libXrandr.so.2"
/home/lumorian/.local/share/Steam/steam.sh -no-cef-sandbox

或使用包装脚本 (完整内容如下)

#!/bin/bash
# Steam 启动包装脚本 — 修复 niri/xwayland-satellite 下的崩溃问题
# 用法: ./steam-fixed.sh [额外参数]

# 永久安装 nullsafe.so:
#   sudo cp /home/lumorian/.local/lib/nullsafe.so /usr/local/lib/nullsafe.so
# 然后改脚本中的 NULLSAFE_PATH

NULLSAFE_PATH="/home/lumorian/.local/lib/nullsafe.so"
# NULLSAFE_PATH="/usr/local/lib/nullsafe.so"  # 如果用 sudo 安装后取消注释

# 杀掉残留进程
killall -9 steam 2>/dev/null

# 导出环境变量
export LANG=C
export STEAM_RUNTIME=1
export DISPLAY=:0
export LD_PRELOAD="${NULLSAFE_PATH} /usr/lib32/libXrandr.so.2"

# 启动 Steam
exec /home/lumorian/.local/share/Steam/steam.sh "$@"

使用方式:

~/temp/steam-fixed.sh -no-cef-sandbox

Proton 游戏需要在 Steam 启动选项中添加:

LD_PRELOAD= %command%

验证

检查项 结果
Steam 主进程存活
无新的崩溃转储
CEF Web 辅助进程运行
32-bit GLX direct context
nvidia_drm.modeset Y
星空列车与白的旅行 Proton 运行

预防措施

防止 NVIDIA 版本再次不匹配, 锁定 32 位 NVIDIA 包版本

# 编辑 /etc/pacman.conf, 在 [options] 下添加
IgnorePkg = lib32-nvidia-580xx-utils lib32-opencl-nvidia-580xx

关键文件路径

文件 用途
/home/lumorian/.local/lib/nullsafe.so NULL 安全字符串拦截器
/home/lumorian/temp/steam-fixed.sh Steam 启动包装脚本
/home/lumorian/.local/share/Steam/ubuntu12_32/steam-runtime/usr/lib/i386-linux-gnu/libgdk-x11-2.0.so.0.2400.10 补丁后的 GDK 库
/home/lumorian/.local/share/Steam/ubuntu12_32/steam-runtime/usr/lib/i386-linux-gnu/libgdk-x11-2.0.so.0.backup 原始 GDK 库备份
/etc/default/grub GRUB 配置 (含 nvidia-drm.modeset=1)
/mnt/data/SteamLibrary/steamapps/compatdata/1567800/pfx/drive_c/users/steamuser/AppData/LocalLow/Syawase Works/星空列车与白的旅行/Player.log 游戏 Unity Player 日志

参考

阅读全文

修复 libinput 鼠标点击抖动限制

2026/4/14

前言/废话

在 GNU/Linux 中, 无论是 wayland 还是 x11, 都会出现快速点击鼠标时 (例如 DBC), 最高只能识别到约 12 CPS, 而实际 CPS 为 20 CPS 的情况

症状

evtest 能检测到所有点击

libinput debug-eventswev 只能检测到部分点击

根源

libinput 1.23+ 版本引入了按键去抖动功能 (button debouncing) 用于防止硬件接触抖动导致的误触, 但这个功能默认会过滤掉间隔小于 25ms 的点击事件, 从而导致 CPS 被限制在 12 左右

虽然可以通过在 ‘/etc/libinput/local-overrides.quirks’ 中配置 ‘ModelDebounceTime=0’ ‘ModuelBouncingKeys=0’, 但几乎不生效

解决方案

直接通过修改 libinput 源码来禁用按键去抖动

安装编译依赖

sudo pacman -S --noconfirm base-devel git meson ninja libevdev mtdev systemd

克隆 libinput 源码

git clone https://gitlab.freedesktop.org/libinput/libinput.git && cd libinput

签出对应版本

git tag -l | grep 1.31.1 && git checkout 1.31.1

修改 src/libinput-plugin-button-debounce.c, 这里先备份

cp src/libinput-plugin-button-debounce.c src/libinput-plugin-button-debounce.c.bak

修改插件初始化函数

sed -i '855,864c\void\nlibinput_debounce_plugin(struct libinput *libinput)\n{\n\t/* Button debounce disabled permanently - no CPS limit! */\n\treturn;\n}' src/libinput-plugin-button-debounce.c

编译

meson setup builddir -Ddocumentation=false -Dtests=false && cd builddir && meson compile

安装

sudo meson install

编译默认安装到 /usr/local/lib, 由于我是 Archlinux, 默认从 /usr/lib/ 加载, 所以我们把安装好的复制过去

备份原库

sudo cp /usr/lib/libinput.so.10.13.0 /usr/lib/libinput.so.10.13.0.backup

复制新库

sudo cp /usr/local/lib/libinput.so.10.13.0 /usr/lib/

执行完上一步后系统应该会直接重新加载不需要手动重启, 现在直接打开浏览器 CPS 测试网站或者在游戏中开启 CPS 显示验证即可

预防措施

防止系统更新覆盖修改好的 libinput, 这边手动将其添加到 pacman 的 IgnorePkg

sudo nano /etc/pacman.conf
IgnorePkg = libinput

参考

阅读全文

Daysmatter-终端交互式倒计时工具

2026/4/2

项目简介

本项目所有代码均为 AI 生成

daysmatter 是一款纯Python编写、基于curses的交互式终端倒计时工具,无需图形界面,即可在终端中优雅管理生日、纪念日、节日等重要日期。
工具自动计算倒计时/已过天数,支持年度重复事件、彩色高亮、可视化进度条、全屏展示模式,完美适配中文宽字符,数据本地存储无联网,轻量开箱即用。

核心特性

  • 交互式终端UI:基于curses实现图形化操作,上下键选择,操作极简
  • 全屏展示模式:支持常驻终端/桌面展示
  • 中文完美适配:自动计算宽字符宽度,无排版错乱
  • 本地安全存储:数据保存在本地JSON文件,无隐私泄露
  • 零第三方依赖:仅使用Python标准库,全平台兼容

界面预览

main
full

环境要求

  • Python 3.6 及以上版本
  • 系统自带 curses 库(Linux/macOS 原生支持)

快速使用

1. 获取代码

wget https://git.lumorian.org/Lumorian/daysmatter/raw/branch/main/daysmatter.py

2. 基础运行

python3 daysmatter.py

3. 全屏展示模式

适合终端常驻、桌面展示:

python3 daysmatter.py -F

快捷键说明

主界面

  • ↑ / ↓:选择事件
  • A:添加新事件
  • E:编辑选中事件
  • D:删除选中事件
  • F:切换到全屏展示模式
  • Q:退出程序

全屏展示模式

  • Q:返回主界面/退出

数据存储

所有事件数据本地存储,无任何网络请求:

  • 存储路径~/.config/daysmatter/events.json

支持平台

  • GNU/Linux(所有发行版)
  • macOS
阅读全文

您听说过 '天才少年' 吗? 这是一种迷惑的幻境

2026/2/21

有这样一种时兴的 “产物” – 天才少年, 再加上各种短视频平台的宣传, 贴上 “百万年薪” 标签. 这种混淆普通人对成功概念的理解的产物变得普遍流行并非偶然. 从这种混淆中得利的大公司推动了这种混淆, 最明了的方式就是完全拒绝这一 “产物”

这一 “产物” 本身具有一种不难察觉的偏见: 它暗示人们应认为低的薪资是可耻、失败的, 只有拥有百万年薪才能让人生过上幸福的生活, 才是成功. 由于这种转变正是那些大公司所求之不得的, 于是这种由 “天才少年” 这一产物所带来的偏见迎合了它们.

根据现在供职于XX市第二中学南校区的李教授的观点, 对 “天才少年” 这一产物的广泛使用变得流行是应当的. 从李教授多次演讲中我们可以提炼出以下论点: (1) 未达到百万年薪或以上的人, 未来的出路只有卖菜、搬砖等粗活累活; (2) 收税人大于纳税人, 纳税人低人一等; (3) 不愿成为 “天才少年” “百万年薪” 就是害怕、懒惰、不上进; (4) 认为想过普通生活是可笑的.

它是一种幻境. 人们之所以会误认为 “天才少年” 是一种合乎逻辑的分类, 原因仅仅在于这一产物的广泛使用对于人们理解何为美好生活时产生了误导.

例如, 您可能会看见这样的宣传: “华为百万年薪招聘天才少年”, “天才少年发明打破国外技术封锁”, 这些宣传不断暗示我们都应如此. 您也会见到这样的论断, “天才少年” 是为鼓励人们仍需努力, 为人们提供榜样向他们看齐. 但事实上只适用那些天生就是天才的人, 普通人听多了只会感到厌烦. 让我们回到小时候, 你的父母是否时常将一种叫 “邻家小孩” 的生物挂在嘴边, 将它与你进行对比, 当时你的内心是如何看待这些 “邻家小孩” 的呢?

不难发现, “天才少年” 与 “邻家小孩” 的本质其实是一致的. 唯一的区别在于 “邻家小孩” 可能是你 “独享” 的, 而 “天才少年” 则是大家 “共有” 的. 当长辈们在晚辈面前讨论 “天才少年”, “邻家小孩” 时, 他们通常想要真正表达的是他们在生活或工作中的不如意无处释放, 只能通过像 “天才少年” 这种能切中他们要害的产物丢向晚辈来为自己带来一丝微不足道的高潮快感和莫名奇妙的自豪感.

阅读全文

hexo-butterfly 实现全局本地音乐播放

2026/2/21

前言/废话

接了个给 hexo-butterfly 增加播放本地音乐的小单, 记录一下实现过程, 网上大多为添加第三方源或只是在单页面添加播放器

开始

  1. hexo 目录下安装 hexo-tag-aplayer
npm install --save hexo-tag-aplayer
  1. 准备本地音乐, 封面, 歌词, 放入 source 路径, 例如
path-to-your-blog/
└─ source/
   └─ music/
      ├─ song1.mp3
      ├─ song2.mp3
      ├─ song3.mp3
   └─ cover/
      ├─ song1.jpg
      ├─ song2.jpg
      ├─ song3.jpg
   └─ lrs/
      ├─ song1.lrs
      ├─ song2.lrs
      ├─ song3.lrs
  1. 添加全局播放器

配置主题的 additional-js.pug 文件 (不选择配置 _config.yml 里的 inject 是因为各种神秘版本神秘兼容已经把我搞晕)

nano themes/butterfly/layout/includes/additional-js.pug

最后一行添加

div(id="global-aplayer")
link(rel="stylesheet", href="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.css")
script(src="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.js")
script.
  window.onload = function() {
    if (typeof APlayer !== 'undefined') {
      const ap = new APlayer({ 
        container: document.getElementById('global-aplayer'), 
        fixed: true, 
        autoplay: false, 
        theme: '#F57C00', 
        loop: 'all', 
        volume: 0.7, 
        mutex: true, 
        listFolded: true, 
        listMaxHeight: 300, 
        lrcType: 1,  // 这里填 1 没用的可以试一下填 3
        preload: auto, 
        audio: [
          {
            name: "song1", 
            artist: "artist1", 
            url: "/music/song1.mp3", 
            cover: "/cover/song1.jpg", 
            lrc: "/lrs/song1.lrc"
          }, 
          {
            name: "song2", 
            artist: "artist2", 
            url: "/music/song2.mp3", 
            cover: "/cover/song2.jpg", 
            lrc: "/lrs/song2.lrc"
          }
          {
            name: "song3", 
            artist: "artist3", 
            url: "/music/song3.mp3", 
            cover: "/cover/song3.jpg", 
            lrc: "/lrs/song3.lrc"
          }
        ]
      });
      const apFixed = document.querySelector('.aplayer-fixed');
      if (apFixed) {
        apFixed.style.zIndex = '99999';
        apFixed.style.bottom = '20px';
        apFixed.style.right = '20px';
        apFixed.style.width = '360px';
      }
    }
  };
  1. 清理 inject 配置 (如果你先前参照了其他的一些教程, 则执行这一步)
nano ./_config.yml
# or
nano ./_config_butterfly.yml

找到 inject 部分, 清空先前的配置避免冲突

inject:
  head: 
  bottom: 
  1. 重新启动博客
hexo clean && npm run server

大功告成~~~~

阅读全文

通用餐饮代购协议

2026/2/19

第一版, 2022 年 9 月 16 日
版权所有 © 2022 Peaksol, Lumorian
任何人皆可复制和分发本协议的完整副本, 但不允许修改之.

引言

通用餐饮代购协议是一份适用于餐饮代购环节中代理商为最终消费者提供的服务的协议.
就多数代购行为而言, 最终消费者多对代理商进行利益上的剥削; 相反, 通用餐饮代购协议力图保障代理商与最终消费者的共同利益.
通过使用代理商所提供的餐饮代购服务, 最终消费者接受并同意受到通用餐饮代购协议第一版的约束. 从合同解释的角度来看, 最终消费者获得来自代理商的餐饮代购服务的使用权的对价是接受本协议的条款, 代理商授予最终消费者此权利的对价是可以通过提供其根据本协议提供的服务而获得利益.
以下是对代理商所供服务的使用的条款和条件细则.

条款与条件

0. 定义

a) “本协议” 指通用餐饮代购协议第一版.
b) “食品经营商” 指支持使用电话或短信订购其外卖餐饮的个人或团体.
c) “代理商” 指提供餐饮代购服务的个人.
d) “最终消费者” 指使用代理商所提供的服务的个人.
e) “订单” 指通过代理商在特定食品经验商处订购的单份餐饮. 订单创建者可以是最终消费者或代理商本人.
f) “取件” 过程指订单在从食品经营运输至订单创建者的全过程中, 除食品经营商运输过程以外的所有运输过程.

1. 服务综述

a) 只有最终消费者接受本协议,且代理商同意为最终消费者提供服务,最终消费者才可使用代理商提供的服务。
b) 代理商为最终消费者提供的服务包括本协议第 2 条和第 3 条所述的服务。
c) 最终消费者有权随时停止接受本协议,代理商亦有权随时停止在本协议下提供其服务。但此类停止不影响截至该类停止发生之时仍未结束的服务,除非最终消费者明确表明结束该服务。

2. 订单

a) 最终消费者可免费在代理商处创建订单,订单应指明食品经营商名称,联系方式和预订餐饮。同一服务时段内,最终消费者不得创建多份订单。
b) 同一服务时段内,在代理商将订单提交至食品经营商前,最终消费者有权修改订单内容或取消订单;代理商将订单提交至食品经营商后,最终消费者不得再修改订单内容或取消订单。
c) 代理商仅负责签订单提交至食品经营商,且不承担食品经营商提出的任何费用,包括但不限于餐饮费,运输费。食品经营商对订单提出的任何费用由最终消费者承担。

3. 取件

a) 同一服务时段内,在代理商向某一食品经营商提交指向该食品经营商的所有订单时,若:

  1. 只有 1 份订单指向该食品经营商,且该订单创建者为最终消费者,则最终消费者可选择自行完成该订单的取件过程,或选择使用代理商提供的有偿代取件服务 (如果可用) 以完成该订单的取件过程;
  2. 有多于 1 份订单指向该食品经营商,且该批订单的创建者中不包含代理商,则此类情况下的每位最终消费者可自行完成其订单的取件过程,或相互协商以共同完成其订单的取件过程,或选择使用代理商提供的有偿代取件服务 (如果可用) 以完成其订单的取件过程;
  3. 有多于 1 份订单指向该食品经营商,且该批订单的创建者中包含代理商,则代理商以及此类情况下的每位最终消费者可自行完成订单的取件过程,或相互协商以选定除代理商以外的指定个人或集体以完成其订单的取件过程,或选择使用代理商提供的免费代取件服务 (如果可用) 以完成其订单的取件过程,或选择使用代理商提供的有偿代取件服务 (如果可用) 以完成其订单的取件过程.

b) 代理商对 3a3 情况下的订单提供的免费代取件服务是可用的,如果:

  1. 该批订单中每一份订单的最终消费者都没有出现此情况: 该最终消费者为代理商在食品经营商处的订单进行代取件的次数明显小于代理商为该最终消费者在食品经营商处的订单进行代取件的次数; 且
  2. 同意免费协助代理商对该批订单进行代取件的人数不少于该批订单的总份数除以 5 所得的商在向上取整后减去 1 所得的值。

c) 代理商对 3a2 和 3a3 情况下的订单提供的有偿代取件服务是可用的,如果:

  1. 需求使服务的订单创建者提前与代理商进行协商,并在服务报酬上达成一致意见; 且
  2. 该批订单的总份数不大于 7 份。

d) 订单在代取件过程中出现的损失,须由为订单进行代取件的个人或集体进行承担。订单创建者可与为订单进行代取件的个人或集体就损失赔偿的具体事宜进行协商。

4. 免责声明与责任限制

a) 代理商不对食品经营商嗯餐饮提供任何种类的品质担保。若食品经营商提供的餐饮未达到最终消费者的预期品质,代理商不对此承担任何责任。
b) 代理商不对最终消费者因食用食品经营商的餐饮而遭受的任何直接或间接的伤害和损失承担任何责任,即使代理商受到明示或暗示应对此负责。
条款和条件至此结束

阅读全文

Arch+Niri 下游戏窗口无法正常渲染解决方案

2026/2/18

前言/废话

这天我在我的 Arch 上玩 Galgame 的时候发现游戏能正常启动 (有声音) 但窗口不显示的情况, 简单查询发现是 Niri 对 XWayland 存在兼容性问题, 导致窗口无法正常显示 / 渲染, 下面简单说一下如何修复

安装 gamescope 强制渲染

gamescope 是独立的 Wayland 合成器, 可以绕过 Niri 的 XWayland 兼容性问题

sudo pacman -Syyu
sudo pacman -S gamescope

给游戏启动命令添加启动选项

# 全屏, 自适应分辨率
gamescope -f -- <command>
# 指定分辨率 + 全屏
gamescope -w 1920 -h 1080 -f -- <command>

如果是 Steam 上的 Galgame 的话同样也是给游戏添加启动参数, 将上面的命令 <command> 替换成 %command% 填入即可

阅读全文

tailscale 在 GNU/Linux 中如何收发文件

2026/2/15

前言/废话 (可以不看, 与教学无关)

我第一次在 GNU/Linux 中使用 tailscale 的 taildrop 时发现怎么都找不到发送过来的文件, 一直以为只是藏在了某个隐蔽的路径下, 直到翻看了官方文档才知道原来 GNU/Linux 端不会自动保存, 需要用户手动设置保存路径 (气笑了)

收发文件

收文件

# 把接收文的目录设置为当前目录(. 表示当前)
sudo tailscale file get .

# 或保存到指定的某个目录
sudo tailscale file get ~/Downloads

发文件

tailscale file cp <files> <name-or-ip>:

补充一下 tailscale 的官方文档, 点击这里查看

阅读全文

自编译 chatlog

2026/2/11

环境 Golang,gcc

下载 MinGW-w64, 将压缩包解压, 注意路径不要含有中文或空格, 随后添加到系统环境变量 (重启终端)

#验证
gcc --version

下载 Golang

# 验证
go version

克隆 chatlog 源码 (此为二次开发版)

git clone https://github.com/teest114514/chatlog_alpha

开始编译

cd chatlog_alpha
# 为 Go 配置镜像加速 (临时生效)
$env:GOPROXY = "https://goproxy.cn,direct"
# 验证, 输出 https://goproxy.cn,direct 则说明成功
go env GOPROXY
# 开启 CGO
$env:CGO_ENABLED = 1
if (-not (Test-Path "bin")) { mkdir bin }; go build -o bin/chatlog.exe main.go

注意查看当前支持的微信版本, 截至到本文结束时, wx_key 支持全部 4.x 版本, 最高稳定支持 4.1.5.11 版本. 最新版能用但有点开盲盒的感觉所以个人还是推荐优先使用目前稳定支持的版本

阅读全文