<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Keshane的小众宝藏博客</title>
  <icon>https://keshane.moe/image/avatar.jpg</icon>
  
  <link href="https://keshane.moe/feed.xml" rel="self"/>
  
  <link href="https://keshane.moe/"/>
  <updated>2026-07-27T14:35:50.600Z</updated>
  <id>https://keshane.moe/</id>
  
  <author>
    <name>Keshane</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>从抢票到散场_BW_2026_回顾</title>
    <link href="https://keshane.moe/2026/07/27/bw2026-review/"/>
    <id>https://keshane.moe/2026/07/27/bw2026-review/</id>
    <published>2026-07-27T14:30:27.000Z</published>
    <updated>2026-07-27T14:35:50.600Z</updated>
    
    <content type="html"><![CDATA[<h2 id="艰难的抢票和行程安排"><a href="#艰难的抢票和行程安排" class="headerlink" title="艰难的抢票和行程安排"></a>艰难的抢票和行程安排</h2><p>几年前我就想去BW了，不过从来就没抢到过票，今年大概是抢票的第三年，我和我朋友一起抢票。</p><p>朋友在沈阳，而我在杭州。我俩在一开的时候我负责抢星期天的，他负责抢星期六的，不过只抢到了星期天的票。</p><p>二开没抢到票，所以一开始的行程安排是朋友周五晚上下班之后到达杭州，然后周六白天在杭州随便逛逛，顺便去吃之前安利我的杭州临平的甜皮鸭（我很好奇有这么好吃吗）</p><h3 id="意外之喜与意外"><a href="#意外之喜与意外" class="headerlink" title="意外之喜与意外"></a>意外之喜与意外</h3><p>意料之外的惊喜是三开抢到了周六的票，所以我把周六下午去上海的火车改签到周六上午9点半附近，准备大概10点半左右到达国家会展中心。</p><p>没想到由于台风，我们原来定的车票被取消了，从此开始了疯狂的订票&#x2F;取消，真的很离谱，我都考虑过打车去上海了。</p><p>最终订了一躺早上出发的，这趟车是千岛湖始发的，应该是避开了台风波及的地方。</p><p>这个是朋友用豆包问了一下各个列车的路线之后选择的，豆包严选。</p><p>12306上甚至已经买不到了，赶紧找了第三方的app用拼好车的方式买上了，虽然是需要换座+补票，但是好歹是成功出票了可以去上海了。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%81%9C%E8%BF%90%E8%BD%A6%E7%A5%A8.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%81%9C%E8%BF%90%E8%BD%A6%E7%A5%A8.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="停运车票"></p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%A4%8D%E6%9D%82%E7%9A%84%E4%B9%98%E8%BD%A6%E6%96%B9%E5%BC%8F.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%A4%8D%E6%9D%82%E7%9A%84%E4%B9%98%E8%BD%A6%E6%96%B9%E5%BC%8F.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="复杂的乘车方式"></p><h2 id="周六-前往漫展"><a href="#周六-前往漫展" class="headerlink" title="周六 前往漫展"></a>周六 前往漫展</h2><p>由于早上出发太早了，我就在周五晚上在杭州东下面定了个酒店，我稍微先到酒店，朋友大概凌晨一点多的时候到酒店，想的是第二天早上不用起床太早前往火车站。</p><p>不过这个晚上并没有睡好，甚至不知道自己睡着没有那种状态。第二天早上顶着这种状态，居然也不太困。</p><p>上车之后需要换座+补票，挺麻烦的，车上感觉有不少人应该都是去BW的，到了虹桥火车站之后去便利店买了点咖啡红牛啥的，坐地铁前往国家会展中心。</p><p>这段路上人就特别多了，时间大概是8：40左右吧，国家会展中心出站之后一路上都是人，从出地铁到进入场馆走了很长的路，进入场馆之后还要在一个馆中走很长的长蛇阵才能进去。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%8E%92%E9%98%9F%E7%9A%84%E4%BA%BA.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%8E%92%E9%98%9F%E7%9A%84%E4%BA%BA.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="排队的人"></p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%85%A5%E5%9C%BA%E7%9A%84%E9%95%BF%E8%9B%87%E9%98%B5.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%85%A5%E5%9C%BA%E7%9A%84%E9%95%BF%E8%9B%87%E9%98%B5.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="入场的长蛇阵"></p><p>扫身份证进去之后门口有2233指引，好像BW这次请了不少cos成2233的工作人员负责指引，至少我在不少展馆的连接处都遇到了。</p><p>我之前在B站上刷到了有人制作了BW逛展助手，我还是第一次知道原来B站也有这个静态页面托管服务，真是没想到b站还有这种服务 <a href="https://www.bilibili.com/toy/bw2026-guide/index.html">https://www.bilibili.com/toy/bw2026-guide/index.html</a></p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/BiliBili%20Toy%E4%B8%8A%E7%9A%84%E4%BF%A1%E6%81%AF.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/BiliBili%20Toy%E4%B8%8A%E7%9A%84%E4%BF%A1%E6%81%AF.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="BiliBili Toy上的信息"></p><p>场馆还是很大的，应该是我去过的最大的漫展，之前都只去过一些小型的漫展。由于我这段时间在玩鸣潮，在来BW之前我是打算领鸣潮的物料和买周边的，而我的朋友是官人痴，他准备去vtuber区买点周边，并且看一下vtuber舞台。一开始是这么打算的，不过这几个二游排队的人都太多了。所以，我俩决定先逛一圈整个场馆。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E9%B8%A3%E6%BD%AE%E5%B1%95%E5%8F%B0.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E9%B8%A3%E6%BD%AE%E5%B1%95%E5%8F%B0.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="鸣潮展台"></p><p>咋说呢，场馆还是很大的，但是去的比较早，舞台其实还没开始活动，有一些相机和摄影器材的展台前面已经有一些人围着在拍照了。不得不说这几个摄影器材厂商是真挺好的，打光这些弄得很不错，还能用他们的设备，还能免费租相机。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%BA%94%E8%AF%A5%E6%98%AF%E7%B4%A2%E5%B0%BC.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%BA%94%E8%AF%A5%E6%98%AF%E7%B4%A2%E5%B0%BC.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="应该是索尼"></p><p>3-4-5这三个场馆都是游戏相关的，人是真的多，走进去逛了一圈感觉差点出不来，碧蓝航线和棕色尘埃2的展台周围围了好几圈人，根本肘不进去</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%A3%95%E8%89%B2%E5%B0%98%E5%9F%832%E5%B1%95%E5%8F%B0.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%A3%95%E8%89%B2%E5%B0%98%E5%9F%832%E5%B1%95%E5%8F%B0.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="棕色尘埃2展台"></p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E7%A2%A7%E8%93%9D%E8%88%AA%E7%BA%BF%E7%9A%84Coser.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E7%A2%A7%E8%93%9D%E8%88%AA%E7%BA%BF%E7%9A%84Coser.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="碧蓝航线的Coser"></p><p>这些展台中，我只领了个蓝色星原的雷霆大背包，这个发得挺快的，没有排很久队。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%93%9D%E8%89%B2%E6%98%9F%E5%8E%9F%E7%9A%84%E9%9B%B7%E9%9C%86%E5%A4%A7%E8%83%8C%E5%8C%85.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%93%9D%E8%89%B2%E6%98%9F%E5%8E%9F%E7%9A%84%E9%9B%B7%E9%9C%86%E5%A4%A7%E8%83%8C%E5%8C%85.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="蓝色星原的雷霆大背包"></p><p>Dota2展台有一个很好看的卓尔游侠Cos，我看到前面有人在合照，也跟着去合照了一张（一开始还挺犹豫的，因为我看她在对着镜头进行互动，但是朋友在旁边等着，为了不让朋友等着就鼓足了劲问了一下</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%8D%93%E5%B0%94%E6%B8%B8%E4%BE%A0.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E5%8D%93%E5%B0%94%E6%B8%B8%E4%BE%A0.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="卓尔游侠"></p><p>之前看到玩机器会在周六来BW，我也特地去三角洲行动的展台看了一下🐖，这里人数也非常恐怖，全靠长焦端200mm才能勉强拍到舞台。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E7%8E%A9%E6%9C%BA%E5%99%A8.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E7%8E%A9%E6%9C%BA%E5%99%A8.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="玩机器"></p><p>只能说逛这种大型漫展感觉和小型漫展差别很大啊，比如你在这里能看见战锤40k里的星际战士，还能看到一些熟悉的B站Up主在舞台上表演</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%98%9F%E9%99%85%E6%88%98%E5%A3%AB.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%98%9F%E9%99%85%E6%88%98%E5%A3%AB.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="星际战士"></p><p>原神那个展台在 5.1 馆，还有王者荣耀和一堆乙游，真是完全走不动路</p><p>场馆很大，但是人也很多。所以还是挺难找到坐的地方，不过有不少地方都有人扎堆席地而坐，大部分展台都在发编织袋，可以去个人少的展商领一个口袋垫一下（</p><p>其实逛到下午已经有点逛不动了，我的右边大腿髋关节外侧感觉都有点疼痛（对不起我软脚了）</p><p>甚至不看地图的话都没反应过来还有个6.1馆没逛过 😂</p><p>下午快4点的时候，我和朋友离开了国家会展中心，打车去酒店了，这时候外面风已经很大了，怕等会下雨我俩就点了外卖。</p><p>晚上7点多吧，我稍微补了一会觉，我朋友在边上玩游戏，大概一个小时左右我醒了，朋友告诉我之前定的12号回杭州的车票因为台风已经被取消了。</p><p>当时我还在睡觉，他看了一下12号到杭州的火车全部都没了，急忙买了13号的回杭州的车票。还好他发现了，我醒的时候13号的火车票都已经快买不到了（因为他中午的飞机，所以我们只能早上回杭州）</p><p>12号只能住酒店了，这时候才发现我们住的酒店已经订满了，只能订另一家酒店了。顺便赶紧点了个外卖买雨衣和雨伞。</p><h2 id="周日"><a href="#周日" class="headerlink" title="周日"></a>周日</h2><p>12号早上我们决定先把东西放进新的酒店里，然后再去，结果这时候发生一件事，定的那家酒店告诉我他们没有双床房了，是上下床？？？</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%88%91%E5%8F%AA%E6%83%B3%E6%89%A3%E5%87%BA%E4%B8%80%E4%B8%AA%E9%97%AE%E5%8F%B7.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E6%88%91%E5%8F%AA%E6%83%B3%E6%89%A3%E5%87%BA%E4%B8%80%E4%B8%AA%E9%97%AE%E5%8F%B7.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="我只想扣出一个问号"></p><p>我真是服了立马找了另一家酒店，还顺路去找携程客服投诉了一波，耽误了不少时间，真该死啊，我之前打电话确认的时候都没告诉我这事，非等我去了才给我说，并且我要是不问一句能不能入住估计她也不给我讲。</p><p>入场的时候我和朋友说感觉得走快点，怕还没入场就下雨了。结果还真滴了几滴雨，不过后面看了下全程也没下雨。</p><p>周六的时候我相机测光一直用的广域，我后面发现有几张人物有点过曝。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%BF%87%E6%9B%9D%E4%BA%86.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%BF%87%E6%9B%9D%E4%BA%86.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="过曝了"></p><p>周日的时候我把测光模式换成了点测光。真是一个错误的决定，我大概无法原谅那天的我吧，虽然由于相机的宽容度很好，没有完全废掉，但是Imaging Edge传到手机上看着原图黑乎乎的一片还是很抽象。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%BF%87%E6%9A%97%E4%BA%86.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E8%BF%87%E6%9A%97%E4%BA%86.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="过暗了"></p><p>场馆里的优酸乳摊位还挺好的，没有溢价（回去之后发现公司便利店比场馆里卖得还贵，真是离谱）</p><p>中午的时候路过 AMD 的展台，发现没什么人，然后顺手做了个 AMD 的活动，领了点钥匙扣啥的。</p><p>整个第二天依然是在各个区域闲逛，偶尔去主舞台看了一下，我朋友要去排某个Up主的签售，我也在周围闲逛，找一些好看的coser合影</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/%E4%B8%80%E4%BA%9B%E5%90%88%E5%BD%B1.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/%E4%B8%80%E4%BA%9B%E5%90%88%E5%BD%B1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="一些合影"></p><p>感觉 2233 来当引导真是很合适啊，很符合 BiliBili 的设定</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/2233.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/2233.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="2233"></p><p>在散场之前还会有 2233 来给大家道别，但是第二天我实在是右腿髋关节外侧一直到膝盖这一块太痛了，没办法跟着去场馆中间看更多的了。</p><p><img src="https://webp.keshane.moe/2026/07/27/bw2026-review/2233.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/27/bw2026-review/2233.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="2233"></p><h2 id="一些感受"><a href="#一些感受" class="headerlink" title="一些感受"></a>一些感受</h2><p>现在回想起来，好像BW也没有什么能够讲出来的特别有意思的地方，我也没有专注某一个展台。如果说有什么遗憾，那就是我还真没走进过某一个展台具体的看他们的东西（主要我玩的游戏的周边都没领到）。并且有几个馆人太多了，希望下次能够把这些热门的游戏厂商稍微分散一下（其实要是能多办几天就好了，抢票也方便一点）。</p><p>这次我看见过很多好看的路人Coser，一开始我甚至不是很敢上去合影，后面也敢找一些Coser上去合影。不过还是没有找路人coser拍图片哈哈。尝试用A7M4路了几段视频 ，不过没有防抖感觉录出来很难受，还好发现了一个叫 Gyroflow 的软件，可以自动帮你后期软件进行防抖操作。（下次就知道还是手机方便）</p><p>现在会想起BW感觉真是美好的一场梦，可以抛开现实世界的沉浸其中，像我这种生活中的社恐看见喜欢的角色也敢上去合影。不过梦终究是会结束的，我们又是回到了日复一日的工作生活中，继续面对熟悉而枯燥的循环，正因如此，回想起BW的时光显得更加美好，才会更加期待，在某个尚未抵达的明天，还能有下一个美好的梦。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="BiliBili World" scheme="https://keshane.moe/tags/BiliBili-World/"/>
    
    <category term="BW 2026" scheme="https://keshane.moe/tags/BW-2026/"/>
    
    <category term="BW" scheme="https://keshane.moe/tags/BW/"/>
    
    <category term="漫展" scheme="https://keshane.moe/tags/%E6%BC%AB%E5%B1%95/"/>
    
  </entry>
  
  <entry>
    <title>聊聊终末地开服时期我的体验</title>
    <link href="https://keshane.moe/2026/07/08/arknights-endfield-1-0version-review/"/>
    <id>https://keshane.moe/2026/07/08/arknights-endfield-1-0version-review/</id>
    <published>2026-07-08T15:44:47.000Z</published>
    <updated>2026-07-27T14:35:50.651Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>本文写于2026 年 7 月 6 日，距离终末地开服已经过了快半年了，不代表最新的游戏体验</p></blockquote><p>最近在网上刷到了一些《终末地》后续内容的视频，比如危机合约的玩法，还有后面一些剧情演出片段。看上去评价还不错，让我又想体验一下。其实仔细想想感觉终末地的战斗和地图还有点意思，我就又下下来了。</p><p>但是比较有意思的是，游戏下载好了，还在编译着色器阶段，我就又想起了当时我为什么退坑的了。</p><p>所以这里先说清楚，下面这些主要代表我当时游玩的开服版本的体验，不代表我对当前版本的评价。甚至正是因为我刷到了后续内容里一些看起来还不错的东西，才会重新想聊聊它：它明明有一些很吸引我的部分，但当时让我退坑的问题也很明确。</p><h2 id="先说一下我的个人偏好"><a href="#先说一下我的个人偏好" class="headerlink" title="先说一下我的个人偏好"></a>先说一下我的个人偏好</h2><p>在聊终末地之前，感觉还是得先说一下我自己的游戏偏好。</p><p>我个人并不是一个很喜欢钻研战斗系统的玩家。不管是什么游戏，基本上只要战斗系统不影响我正常推进，不让我频繁卡关，我通常就不会特别深入研究。</p><p>角色机制、配队、输出循环这些东西，我不是完全不能理解，但是这些并不是我最愿意花时间的部分。尤其是手游里那种为了打高难然后去研究各种配队、手法、数值收益，我个人其实兴趣不大。</p><p>相比起来，我更愿意把时间花在探索、基建、剧情这些内容上。这是终末地最吸引我的地方，也是我认为他最独特的气质。</p><h2 id="我个人认为开荒体验很不错"><a href="#我个人认为开荒体验很不错" class="headerlink" title="我个人认为开荒体验很不错"></a>我个人认为开荒体验很不错</h2><p>终末地的地图设计是比较巧妙的，箱庭设计很独特，限制了人物的移动性能，然后引出了拉电线，放置滑索的必要性，方便二次探索跑图。这种限制开荒的时候有一定探索感，并不是那种完全平铺直叙的地图，引导玩家一点点打开空间。</p><p>战斗体验更偏向策略类型，在我不长的游玩中感觉这套战斗系统其实是挺有乐趣的，相较于操作，更偏向于配队、指令编排。但是对我来说，虽然战斗体验还不错，但是在当时感觉大地图堆怪太多，频繁的战斗其实打断了我的地图探索体验。</p><p>基建虽然限制很多，收益很小，但是也算比较有乐趣，主要是基建和大世界探索之间有一部分联动。比如拉电线、放滑索、在地图上摆一些装置。说实话，我第一次玩的时候，这部分还挺上头的。因为它确实给了我一种我正在开拓这个世界的感觉。</p><p><img src="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/power-line.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/power-line.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="拉电线"></p><p>这部分初见体验是真的还行，我还是挺喜欢拉电线的.jpg</p><h2 id="基建玩法很容易触及上限"><a href="#基建玩法很容易触及上限" class="headerlink" title="基建玩法很容易触及上限"></a>基建玩法很容易触及上限</h2><p>基建系统我个人在看到预告的时候还是有挺大的期待，至少我认为可能是一个能真正影响游戏体验的系统。</p><p>虽然我不算是一个很硬核的流水线类型的游戏玩家，但是我对这个题材比较感兴趣</p><p>但我当时玩下来最大的感受是：它和角色养成之间的关系并不够强。</p><p>基建主要和装备有关系，其他产出在我印象里基本都是蚊子腿。它当然不是完全没用，但是也没有成为我想象中那种“核心玩法”。它更像是一个被限制在特定框架里的辅助系统。</p><p>而“拉电线”相关的内容，由于每张地图都有一定限制，所以也很难做到那种能够将造物铺满整个地图的类似改变世界的效果，滑索铺好之后虽然能极大的增强探索体验，但是也仅此而已了。</p><p>不过我也能理解对于一个抽卡手游而言，为了照顾不同玩家的体验都会采取偏弱保软的设计，如果基建系统完全不加以限制，不同玩家之间的体验可能差距特别大（别人的MC,我的MC.jpg）</p><p><img src="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/earning-money.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/earning-money.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p>另外角色肯定是重要卖点（不然怎么让你抽卡），正因为游戏里有抽卡角色和角色养成这条主线，所以基建不能做得太重。不能真的让玩家靠建造、规划和生产解决太多问题，因为那样就会削弱角色养成的重要性。</p><h2 id="抽卡和角色养成"><a href="#抽卡和角色养成" class="headerlink" title="抽卡和角色养成"></a>抽卡和角色养成</h2><p>终末地有了优秀的地图设计，有深度的战斗系统，一个轻量化的基建系统。但是他的核心卖点依然是角色和它的养成。这部分我是真的讨厌。</p><p>我不是说其他抽卡手游就比终末地好，大家都做得 emmmm 怎么说呢，一言难尽。</p><p>体力刷本、刷材料、刷装备、刷武器珠子，这些东西我已经在很多二游里见过太多次了。我之前吐槽二游时说过的，抽卡机制的存在很大程度上会限制玩法，一切玩法最后都会为了角色铺路。</p><p>探索是为了资源，战斗是为了验证养成，基建是为了服务装备，日常是为了拉长周期。哪怕一个游戏表面上有大世界、有建造、有策略，它最后还是很容易被“抽卡 + 角色养成”这套核心商业模式拉回去。</p><p>这也是我最反感的一点。（木棍打小龙虾.jpg）</p><p><img src="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/lobster-hit.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/lobster-hit.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="木棒打小龙虾"></p><p>我不讨厌角色养成本身，也不是不能接受 RPG 数值成长。但当一个游戏里几乎所有系统最后都要汇入抽卡角色养成时，感觉就很奇怪</p><p>尤其是《终末地》这种游戏，它明明有一些很有潜力的长板：地图探索、基建、战斗策略。但这些长板没有覆盖它对我来说最大的短板。甚至可以说，正是因为这些长板让我觉得它本来可以更好玩，所以我才会更加遗憾。</p><p>我不敢想象，要是没有抽卡和这种绑定的刷体力式的角色养成，终末地作为一个探索、基建驱动的游戏会有多好玩（</p><h2 id="角色和剧情也没有撑起养成的动力"><a href="#角色和剧情也没有撑起养成的动力" class="headerlink" title="角色和剧情也没有撑起养成的动力"></a>角色和剧情也没有撑起养成的动力</h2><p>还有一个问题是，至少在我当时玩的版本里，《终末地》的角色塑造和剧情演出没有撑起角色养成的成本。</p><p>如果一个抽卡游戏要让我愿意养角色，那角色本身至少要让我喜欢，因为我对战力不太看重，所以抽卡和养成基本上都是靠主观爱好。剧情、演出、角色魅力，这些东西需要给我一个投入的理由。</p><p>我本身是明日方舟玩家，对于再旅者这个设定，感觉比较微妙……我对于42、小羊、杰哥这些角色肯定是有情怀存在的，但再旅者这个设定又相当于和以前的人物切割，我只能当成一个新的角色对待。最大的问题还是角色塑造比较拉跨，剧情演出也显得羸弱，有些地方甚至有点尴尬。我玩其他游戏很少跳过剧情，但是终末地里面的有些剧情真的可以说又臭又长，只好跳过。</p><p>于是体验就变成了：我本来是冲着探索和基建来的，但游戏不断提醒我，你还是得回去养角色，但是剧情演出，角色塑造又没那么吸引我，自然就更难坚持下去。</p><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>所以终末地给我的感觉依然是一款传统的二游，在基建、探索背后依然是角色养成，但是角色塑造这部分却没能让我队角色养成产生足够的兴趣。</p><p>我最感兴趣的部分被做得很轻，最传统、最让我疲惫的抽卡养成部分反而成了主干。</p><p>这也是我对很多二游最无奈的地方。</p><p>它们不是没有创意，而是创意经常只能作为“糖衣”存在。最后真正支撑长期游玩的，还是抽卡、养成、日常、刷体力那套东西。</p><p>当然，我现在还没有重新完整体验当前版本，所以也不能直接判断它后面有没有解决这些问题。也许后续更新中确实更好玩，也许后续角色塑造也有所进步。正是因为我刷到了这些评价不错的视频，才会又把游戏下载回来。</p><p>但对我来说，旧版本里一切为了角色养成服务的印象依然很深，这也是我在打开游戏之前犹豫的原因。</p><p>（虽然卡池好像结束了，但是至少庄方宜很对我胃口）</p><p><img src="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/zhuang-fangyi.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/07/08/arknights-endfield-1-0version-review/zhuang-fangyi.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="庄方宜"></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="手游" scheme="https://keshane.moe/tags/%E6%89%8B%E6%B8%B8/"/>
    
    <category term="游戏体验" scheme="https://keshane.moe/tags/%E6%B8%B8%E6%88%8F%E4%BD%93%E9%AA%8C/"/>
    
    <category term="二游" scheme="https://keshane.moe/tags/%E4%BA%8C%E6%B8%B8/"/>
    
    <category term="明日方舟:终末地" scheme="https://keshane.moe/tags/%E6%98%8E%E6%97%A5%E6%96%B9%E8%88%9F-%E7%BB%88%E6%9C%AB%E5%9C%B0/"/>
    
    <category term="终末地" scheme="https://keshane.moe/tags/%E7%BB%88%E6%9C%AB%E5%9C%B0/"/>
    
    <category term="抽卡" scheme="https://keshane.moe/tags/%E6%8A%BD%E5%8D%A1/"/>
    
    <category term="地图" scheme="https://keshane.moe/tags/%E5%9C%B0%E5%9B%BE/"/>
    
    <category term="基建" scheme="https://keshane.moe/tags/%E5%9F%BA%E5%BB%BA/"/>
    
  </entry>
  
  <entry>
    <title>关于“二游”这种品类，我的一些个人看法</title>
    <link href="https://keshane.moe/2026/03/13/anime-game-view/"/>
    <id>https://keshane.moe/2026/03/13/anime-game-view/</id>
    <published>2026-03-13T14:07:22.000Z</published>
    <updated>2026-07-27T14:35:50.541Z</updated>
    
    <content type="html"><![CDATA[<h2 id="关于-“二游”-这个词"><a href="#关于-“二游”-这个词" class="headerlink" title="关于 “二游” 这个词"></a>关于 “二游” 这个词</h2><p>之前吹了一下《鸣潮》的演出，诚然我玩过的“二游”不少，我玩这种手游的时间感觉比我听到“二游”这个词的时间还长，说到底我觉得“二游”这个词我觉得很奇怪，不知道什么时候二游成了一个固定的名词了，好像二游就特指 —— 带有动漫风格渲染，抽卡，手机游戏的集合体了。</p><p>下面的话都是我的个人见解，如果说得不对还请指正。</p><h2 id="还是得先聊聊《原神》"><a href="#还是得先聊聊《原神》" class="headerlink" title="还是得先聊聊《原神》"></a>还是得先聊聊《原神》</h2><blockquote><p>这种“二游”走进更多的人的眼里估计还得追溯到 《原神》</p></blockquote><p>原神一开始让我记住的恰好就是那个很像塞尔达的pv，后面我也在朋友的安利下玩了不短的时间。不得不说当时的原神能火也并不奇怪，一款随时能用手机游玩，能够自由探索大世界，虽然自由度和地图设计没有那么优秀，但是在手机上肯定算是不错的。并且角色形象设计也挺有特色的。当时入坑应该是2.0版本吧，当时为了抽雷神还是充了一些礼包。后面的神女劈观剧情感觉算是当时我玩的最好的剧情。看了眼时间应该是22年春节。</p><p><img src="https://webp.keshane.moe/2026/03/13/anime-game-view/shennv.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/13/anime-game-view/shennv.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="神女劈观"></p><p>不过原神的后续版本相比起来并没有完全保持住很高的水品。须弥版本的剧情设计感觉高开低走（散兵这段剧情我很不喜欢）后面枫丹的版本水下探索还是挺有意思的，但是别的也没啥特别有印象的。就逐渐退坑了。</p><p>相比起上面这些长处，原神，或者说后续我接触到的二游似乎都会给你搞个深渊一样的东西，由于我玩手游都是休闲目的，抽卡都是抽喜欢的卡，所以深渊这种我是根本不碰。</p><h2 id="关于二游社区氛围"><a href="#关于二游社区氛围" class="headerlink" title="关于二游社区氛围"></a>关于二游社区氛围</h2><p>国内的二游社区氛围很奇怪的，玩不同游戏的人总是互相谩骂，好像杀了对方的父母一样。有人说自己玩的游戏有一点不好，就要去攻击别人，仿佛自己不是玩游戏的那个。还有什么互相比谁流水多，仿佛消费流水多就更牛逼一样。属实是让人大开眼界，好像游戏厂商是什么宗教信仰一样，不能说一点坏话，这一点不管是哪家厂商都一样，感觉这几家二游厂商特别明显。<del>我没经历过宗教论战，但是我经历过二游社区</del></p><p><img src="https://webp.keshane.moe/2026/03/13/anime-game-view/dog.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/13/anime-game-view/dog.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="不要当厂商的狗啊"></p><h2 id="最后聊一下这种游戏类型"><a href="#最后聊一下这种游戏类型" class="headerlink" title="最后聊一下这种游戏类型"></a>最后聊一下这种游戏类型</h2><p>仅个人看法这种大世界二游个人感觉有一个很重大的问题，那就是抽卡要素。抽卡给厂商带来了高额的回报，使得他们可以以一个相对大的投入来保持一个短时间更新的版本。对于玩家来说，这种抽卡+免费游戏的方式哪怕不花钱也能够体验到大部分主线的游戏内容。</p><p>但是我个人体验下来感觉抽卡这一要素可以说是绑架了游戏设计。相比起一些一锤子买卖的付费游戏，不论是原神还是鸣潮，地图的探索体验是相对比较差的，因为探索和抽卡资源绑定，你探索的目的很大程度上是为了抽卡资源。（当然现在有一些大场景做得也挺不错）所以我个人在玩的时候并没有执着于想去探索什么地方，更多的都在做任务和剧情。偶尔也就是只在地图上闲逛。</p><p>和抽卡另一个强关联的地方在于养成&#x2F;日常，由于抽卡的设计，再加上厂商可能要保持一个日活，所以厂商整了一套很长的养成周期，基本上是逼着你每天都要玩游戏。</p><p>一个角色从抽出来到完全养成其实还是比较费劲的，你需要不断地去刷材料，用体力刷副本，刷声骸&#x2F;圣遗物&#x2F;装备，还有技能等级&#x2F;武器素材等等。有的材料需要你去地图上捡，有的材料需要你去大世界里打怪，有的材料需要刷一周只能打3次的副本。</p><p>所以养成周期是很漫长的，玩到后期颇有一种在游戏里上班的感觉，或者使用蓝绿修改器。</p><p><img src="https://webp.keshane.moe/2026/03/13/anime-game-view/hack.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/13/anime-game-view/hack.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="蓝绿修改器"></p><p>这一套抽卡-养成感觉充满了游戏场商小巧思，当然由于手游玩家和扩大受众群体的需求，所以这些厂商并不会设置一个特别高的水温，除了游戏最终的类似深渊的高难度挑战本。</p><p>对于这种设计，我个人是建议随心所欲的玩。完全放弃这种周期刷新的高难本（说实话好像也没给多少）。体验自己想要体验的内容，不喜欢的内容通通跳过就好了，糖衣炮弹把糖衣吃掉把炮弹吐掉。保持自己玩游戏的本心，不要被游戏玩。但是我说是这么说，我也认可情绪价值的重要，我也经常上头🤣，总的来说，开心就好。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="手游" scheme="https://keshane.moe/tags/%E6%89%8B%E6%B8%B8/"/>
    
    <category term="游戏体验" scheme="https://keshane.moe/tags/%E6%B8%B8%E6%88%8F%E4%BD%93%E9%AA%8C/"/>
    
    <category term="二游" scheme="https://keshane.moe/tags/%E4%BA%8C%E6%B8%B8/"/>
    
  </entry>
  
  <entry>
    <title>聊聊《鸣潮》，可能是我玩过的演出最好的手游</title>
    <link href="https://keshane.moe/2026/03/12/wuthering-waves-review/"/>
    <id>https://keshane.moe/2026/03/12/wuthering-waves-review/</id>
    <published>2026-03-12T16:18:53.000Z</published>
    <updated>2026-07-27T14:35:50.542Z</updated>
    
    <content type="html"><![CDATA[<h2 id="关于鸣潮"><a href="#关于鸣潮" class="headerlink" title="关于鸣潮"></a>关于鸣潮</h2><p>我应该是第一次写篇文章来推荐这种所谓的“二游”，虽然鸣潮没有各方面都做得十全十美，称不上什么不玩会后悔的那种游戏。但是在演出方面给我的体验非常不错，个人感觉是这个品类中比较好的那一档（其实我觉得是我玩过的二游中最好的了，但是我也没玩过很多二游，不太好吹）</p><p>这篇文章流水线的记录一下这段时间的体验</p><h2 id="关于付费"><a href="#关于付费" class="headerlink" title="关于付费"></a>关于付费</h2><p>这种抽卡制的手游，相对于一锤子的单机游戏而言，最大的好处是“免费”，最大的缺点也是“免费”。</p><p>免费游玩可以让任何人都能进来体验一下，但是抽卡的方式会让整体游戏的设计为了抽卡而服务，游戏体验也会根据你 “无氪”、“月卡”、“微氪”、“中氪”、“重氪” 等付费程度以及所谓的 “抽卡规划” 发生改变。我个人是只抽我自己喜欢的卡</p><p>还好主线剧情往往不会和抽卡强绑定，一般是来卖卡的（</p><h2 id="游玩的心路历程"><a href="#游玩的心路历程" class="headerlink" title="游玩的心路历程"></a>游玩的心路历程</h2><p>鸣潮我是3.0之前入坑的，入坑原因大概是我刷到了直播鸣潮的切片，看上去还挺像那么回事的。当时正好是TGA期间，搜了一下好像会发抽卡资源，并且隔两天就会开新版本(3.0)，就下了一个玩了一下。</p><p>我过剧情的顺序比较奇怪，玩得也是比较慢的那一档。</p><p>当时先过了一点1.0的剧情，大概刚刚见到今汐打了那个残星会的伤痕就去过3.0的剧情了，一开始其实没想抽卡，过完剧情感觉演出挺不错，琳奈也挺对我xp的，过boss的演出对我个人而言还是比较惊艳的，当时想的就是boss演出都这么好看了，这卡我就抽了呗。</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/after_3,0_boss.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/after_3,0_boss.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="3.0BOSS战之后"></p><p>后面过了1.0剩下的剧情，大概就是跟着忌炎打鸣式这一段，感觉就是有点无聊，相比较3.0上半部分，这里剧情有点平淡，感觉各个出场人物也没什么塑造，演出也比较一般。</p><p>乘霄山的剧情感觉不错，从初遇长离开始就很惊艳（长离很好看），这一段剧情和节奏就比较舒服了。今汐和角的剧情也很不错。这段剧情开始感觉鸣潮对人物的塑造相比起最初确实提升了不少（也有可能是今汐和长离好看）</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/jinxi.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/jinxi.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="今汐"></p><p>黑海岸群岛的剧情说实话我没看太明白，泰提斯系统到提示什么，到底要做什么我也不知道，感觉了解了一堆名词，揭露了主角部分身世。不过守岸人很好看，BGM我很喜欢，塑造也很不错。这段演出感觉致敬了《EVA:破》里面的”把凌波还给我”这一段</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/like_eva.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/like_eva.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="感觉像名场面"></p><p>长离伴星也是长离的个人塑造，还有对于主角身世的一些揭示。长离真好看。<del>每个女角色都好看</del></p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/changli.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/changli.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="长离"></p><p>2.0 感觉是一个开幕，介绍了一下新的地方的各个风俗。不过这个地图感觉拉古那城是不是太小了，感觉像个小镇一样。这个写书的主角出现在哪他也出现在哪，感觉就像有问题（还有独立建模），最后看上去也是背后boss。</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/feibi.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/feibi.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="菲比拉电线"></p><p>3.0 下半，我感觉3.0下半剧情有点太快了，很多情节提了一下就结束了，最重要的换日仪式感觉一直全程在开摩托，莫宁的塑造也比较少，感觉不如一个角色pv。</p><p>2.2 感觉剧情演出都挺棒的，影响最深的还是那个视角转来转去的塔那里，最后打boss的演出也很帅。坎特雷拉真好看啊</p><p>3.1 感觉很牛逼，人物塑造、演出、剧情算是拉满了，情绪层层递进（可以说这篇文章就是为了3.1这点醋包的饺子）<br>爱弥斯和漂泊者的关系塑造成了不止是拯救与被拯救的关系，更是一个理解者。漂泊者在之前的剧情中更多的是承担了一个救世主的职责，但是在渐湖这段剧情中爱弥斯作为漂泊者的养女（养过一段时间也算！），却能更好的走进漂泊者的内心，揭露了过去看似强大的漂泊者，内心也会有细腻的情感，让漂泊者更像人而非神。</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/3.1.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/3.1.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="爱弥斯"></p><p>在之后更是一种关心的感觉，不想让漂泊者背负沉重的过往。</p><p>爱弥斯是唯漂泊者至上的，她的救世来源于对漂泊者的感情。爱弥斯作出了牺牲自己去拯救漂泊者的决定，而漂泊者作为常规的救世者在这段剧情中和爱弥斯身份互换，成为了被拯救的人。有一种拯救了世界却没能救下自己的亲人的感觉。</p><p>爱弥斯这段内心的独白和闪回太顶级了</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/aimisi_1.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/aimisi_1.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="爱弥斯"></p><p>这里还涉及一点时间循环因果关系的感觉。现在的漂泊者托起了小时候的爱弥斯，过去的漂泊者抱起了小时候的爱弥斯。爱弥斯的牺牲成为了因果闭环。</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/3.1_animation.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/3.1_animation.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="3.1版本动画"></p><p>最后漂泊者说要去驾驶隧者救出爱弥斯这里后面直接跳到了学院里面，从驾驶舱里面抱出了爱弥斯。我还以为跳过了一段剧情，怎么直接就救回来了。结果根本就没救回来！这里的爱弥斯只是日灵拼出来的频率，只是一个植物人。</p><p>最终结尾的时候漂泊者和爱弥斯在车站相遇，刮鼻子这个动作，贯穿始终，扔出纸飞机之后的动画真的很催泪。</p><p>这一段拼凑的爱弥斯扔出去纸飞机的画面，和她拯救的世界形成了鲜明的对比。</p><p>这个世界越是美好，就越显得爱弥斯的价值。</p><p>最后这一段的运镜也很神。</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/biananguo.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/biananguo.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="别难过"></p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/aimisi_3.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/aimisi_3.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="拼装爱弥斯（"></p><h2 id="一些吐槽和后续"><a href="#一些吐槽和后续" class="headerlink" title="一些吐槽和后续"></a>一些吐槽和后续</h2><p>不得不吐槽一下鸣潮 QTE 是真的多啊，但是 PC 上 QTE 按键相对于这个图标会慢半拍显示，能不能别搞这么多 QTE</p><p>然后就是剧情，虽然牛逼的剧情演出很牛逼，但是也有3.1下半这种节奏很奇怪的剧情演出出现（感觉像垫了一样），我能理解版本之间叙事有差异，毕竟这种长期更新的游戏不同版本有起伏是很正常的，但是如果有突破下限的内容就不太好了。</p><p>其实鸣潮的剧情本身来讲倒是一个比较普通的故事，我个人是认可讲好一个故事&gt;讲一个好故事的。毕竟这一套讲故事的逻辑情绪价值给足了，我个人还是很吃这一套的。</p><p>后面的夏空剧情，2.4剧情据说也很不错，慢慢再玩了</p><p><img src="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/xiakong.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/03/12/wuthering-waves-review/xiakong.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="夏空可爱捏"></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="手游" scheme="https://keshane.moe/tags/%E6%89%8B%E6%B8%B8/"/>
    
    <category term="游戏体验" scheme="https://keshane.moe/tags/%E6%B8%B8%E6%88%8F%E4%BD%93%E9%AA%8C/"/>
    
    <category term="二游" scheme="https://keshane.moe/tags/%E4%BA%8C%E6%B8%B8/"/>
    
    <category term="鸣潮" scheme="https://keshane.moe/tags/%E9%B8%A3%E6%BD%AE/"/>
    
    <category term="演出" scheme="https://keshane.moe/tags/%E6%BC%94%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>利用大模型辅助减肥</title>
    <link href="https://keshane.moe/2026/02/20/lose-weight-with-llm/"/>
    <id>https://keshane.moe/2026/02/20/lose-weight-with-llm/</id>
    <published>2026-02-20T09:45:53.000Z</published>
    <updated>2026-07-27T14:35:50.536Z</updated>
    
    <content type="html"><![CDATA[<h1 id="利用大模型辅助减肥"><a href="#利用大模型辅助减肥" class="headerlink" title="利用大模型辅助减肥"></a>利用大模型辅助减肥</h1><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E8%84%82%E7%A7%B0%E8%AE%B0%E5%BD%95%E7%9A%84%E4%BD%93%E9%87%8D%E5%8F%98%E5%8C%96.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E8%84%82%E7%A7%B0%E8%AE%B0%E5%BD%95%E7%9A%84%E4%BD%93%E9%87%8D%E5%8F%98%E5%8C%96.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="体脂称记录的体重变化"></p><blockquote><p>写作本文的时候，正是春节期间，我正在家里胡吃海喝。我想复盘并分享一下这几个月的减肥历程。</p></blockquote><h2 id="为什么减肥"><a href="#为什么减肥" class="headerlink" title="为什么减肥"></a>为什么减肥</h2><p>我曾是一名大体重人群，巅峰体重一度达到120kg。几年前我曾尝试通过制造热量差（少吃多运动）来减肥，但最终未能坚持。</p><p>必须要强调的是，减脂没有捷径，唯一的途径就是制造“热量差”。只要每日消耗的热量大于摄入热量，并长期坚持，就一定能瘦。如果瘦不下来，要么是热量计算有误，要么你可能是来入侵地球的外星人👽</p><p>为什么需要减肥，首要原因当然是健康。其实对于我个人来讲，我也不想一直胖下去，不仅仅是颜值问题，更大的风险还是健康问题（体检的时候注意自己的心血管指标）。</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/emoji1.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/emoji1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p>在25年上半年（大约4月份）我尝试去健身房开始运动。不过当时并没有任何控制饮食的行为，零食什么的也在正常吃。</p><p>真正意义上开始使用各种手段开始减肥的时候，其实已经是国庆假期之后了。当时放完假之后家里没有任何零食了，正好我有一个同事每天中午都吃同一家店的轻食，我也跟着一块吃，于是大概10月初到11月，感觉体重掉的飞快。后来在一位健身朋友的带动下，我意识到目标不能只是“瘦”，更要“有线条”。</p><p>随着体重慢慢下降，感觉一个是自己去健身房训练的效果不咋地，一个是自己周末其实也没怎么控制饮食，感觉就卡在这里了，这时候我想到了借助AI的帮助。</p><h2 id="关于模型选择"><a href="#关于模型选择" class="headerlink" title="关于模型选择"></a>关于模型选择</h2><p>回顾2025年，AI大模型发展迅猛。如果说2024年的模型还处于“已读乱回”的探索期，那么到了2025年末，主流大模型已完全具备了生产力工具的潜质。</p><p>随着大模型的能力逐渐变得强大，我们可以让大模型做到部分辅助我们的工作。在模型选择上，我体验过几乎所有主流的大模型。综合来看Gemini的使用体验是最棒的，并且多模态效果非常不错。</p><h2 id="把大模型当作一个健身私教"><a href="#把大模型当作一个健身私教" class="headerlink" title="把大模型当作一个健身私教"></a>把大模型当作一个健身私教</h2><p>我们可以把大模型当作一个虚拟的健身私教，除了不能帮助你做动作之外，饮食和训练上的问题他都能给你很好的解决，有什么问题都可以直接询问。</p><p>我个人比较习惯在新开的对话中，把我目前的身体情况，饮食计划，训练情况，近期体重变化都发给大模型，这样能够得到更加全面的答案。</p><p>下面分享一下我个人的一些用法，这些Prompt是我在使用中摸索出来的，在我这种使用情况下体验比较好。</p><h2 id="饮食计划"><a href="#饮食计划" class="headerlink" title="饮食计划"></a>饮食计划</h2><p>把你的个人信息和日常的作息情况作为一并输入给大模型，这样可以让大模型对你的身体情况和目标做一个基础的计划。</p><p>我的Prompt中将我的个人信息和作息习惯全部附带上了，有助于让大模型更好的理解。</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">## 个人基本信息</span></span><br><span class="line">年龄 ，身高 ， 体重 ，腰围 </span><br><span class="line">// 补充其他情况</span><br><span class="line"><span class="section">## 作息情况</span></span><br><span class="line">工作上班都是坐在电脑前</span><br><span class="line">【工作日-训练日(一周 2-3 次)】</span><br><span class="line">各种时间节点，例如起床、吃饭、训练</span><br><span class="line">【工作日-非训练日】</span><br><span class="line">【周末-休息日】</span><br><span class="line"><span class="section">## 目标：</span></span><br><span class="line">增肌减脂（减脂的同时尽量不掉肌肉）</span><br></pre></td></tr></table></figure><p>在你没有一个初始的计划时，可以把你的个人信息发给大模型让他帮你出一个饮食计划。</p><blockquote><p>根据以上情况，帮我整理一份饮食计划</p></blockquote><p>我这里是将这种计划类的输出全部复制到了外部文档中方便查阅。</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E5%A4%96%E9%83%A8%E6%96%87%E6%A1%A3.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E5%A4%96%E9%83%A8%E6%96%87%E6%A1%A3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="外部文档"></p><h2 id="饮食审计"><a href="#饮食审计" class="headerlink" title="饮食审计"></a>饮食审计</h2><p>在做好基础的饮食规划之后呢，我最重要的一部分工作就是饮食审计。</p><p>为什么需要饮食审计，因为你的一天中不可能全部吃带有营养成分表的食物，所以有些食物我们可能不好判断具体的热量是多少。</p><p>在有了饮食计划后，可以发送一个类似的这种Prompt给大模型，然后后续可以将食物拍照或者口述给大模型，这样我们就可以得到一个分析表格。</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">后续我会把一些饮食发给你，你帮我评估一下，并给出后续建议，然后给我一个记录行，记录行格式为表格，列信息为： 日期(YYYY-MM-DD),餐别,食物,热量 (kcal),碳水 (g),蛋白质 (g),脂肪(g),宏量结构(例如高碳高脂高蛋白),简要评价(红黄绿+评价),审计备注</span><br></pre></td></tr></table></figure><p>举个例子，这是我某次在食堂吃的称重菜</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E9%A3%9F%E5%A0%82%E7%85%A7%E7%89%87.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E9%A3%9F%E5%A0%82%E7%85%A7%E7%89%87.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="食堂照片"></p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/gemini%E5%9B%9E%E7%AD%94.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/gemini%E5%9B%9E%E7%AD%94.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="gemini回答"></p><p>我们能得到一个类似的表格。</p><p>现在我们可以去找一个在线文档的表格功能，例如语雀多维表或者飞书多维表格。</p><p>个人不推荐使用类似excel的工具，我一开始使用的excel，后面发现现在这种多维表格产品有一个很好用的仪表盘功能。当然excel是非常强大的，我excel用的不好。</p><p>然后复制进去，我个人推荐使用飞书多维表格，体验感觉比语雀多维表、腾讯文档更好。比如~380这种数字复制进去他能直接去除波浪号不用处理。</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E9%A5%AE%E9%A3%9F%E8%AE%B0%E5%BD%95.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E9%A5%AE%E9%A3%9F%E8%AE%B0%E5%BD%95.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="多维表格记录的内容"></p><p>我们可以向多维表格中新建一个仪表盘，里面配置一下这种数据，这样就能准确评估每天到现在吃了多少，还缺多少。</p><p>仪表盘感觉是个挺不错的功能，我算是知道为什么领导都喜欢看大屏报表了。</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E5%88%9B%E5%BB%BA%E4%BB%AA%E8%A1%A8%E7%9B%98.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E5%88%9B%E5%BB%BA%E4%BB%AA%E8%A1%A8%E7%9B%98.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="仪表盘"></p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BB%AA%E8%A1%A8%E7%9B%98.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BB%AA%E8%A1%A8%E7%9B%98.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="仪表盘"></p><h2 id="训练分析"><a href="#训练分析" class="headerlink" title="训练分析"></a>训练分析</h2><p>想要改变身体，除了饮食，还有训练。所以也需要参考上面的步骤构造一个训练计划和相对应的分析。</p><p>不过，这取决于你的目标，并且训练有很重要的一部分是让自己不要受伤，所以一定要根据自身情况来。<del>毕竟吃饭吃少了饿不死，但是训练不合理真的会受伤</del></p><p>我个人训练比较划水，也没有完全按照计划来，基本上是按照 胸-背-腿 三分化进行训练（不过我很菜，一直也没有什么重量突破）</p><p>所以我没有按照饮食那样严格的记录，只是记录了一下我的训练内容和反馈，训练完成后一并发给大模型进行分析</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E8%AE%AD%E7%BB%83%E8%AE%B0%E5%BD%95.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E8%AE%AD%E7%BB%83%E8%AE%B0%E5%BD%95.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="训练记录"></p><h2 id="以周维度的体重分析"><a href="#以周维度的体重分析" class="headerlink" title="以周维度的体重分析"></a>以周维度的体重分析</h2><p>体重的变化并不是每天都能看出来的，所以不要给自己找不自在，俗话说的好</p><blockquote><p>体重长了就是在长肌肉，体重掉了就是在减脂肪</p></blockquote><p>保持一个良好的心态有助于我们减肥。</p><p>我个人选择的是每周六起床之后，先大小便排空身体，然后穿着内裤和一件薄T恤站上体脂秤，获得本周的体重数据。</p><p>我还会测量我的腰围，对于大体重人群来讲，腰围其实比体重更重要。</p><p>在最近呢，我又添加了一列图片，我会隔几周对着镜子拍上半身正面和侧面照来做参考对比（裸体）。</p><p>我也建立了一个飞书多维表格来记录体重（仅供参考）</p><p>在完成这一系列步骤之后，就可以把这周的饮食记录，训练记录，近几周的体重记录，如果有照片也可以加上，发给大模型。</p><p>然后得出一周的一个总结情况</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E9%87%8D%E8%AE%B0%E5%BD%95.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E9%87%8D%E8%AE%B0%E5%BD%95.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="体重记录"></p><p>然后我们也可以通过仪表盘功能制作一个曲线</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E9%87%8D%E6%9B%B2%E7%BA%BF.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/%E4%BD%93%E9%87%8D%E6%9B%B2%E7%BA%BF.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="自己用飞书多维表格记录的体重变化"></p><h2 id="循环往复"><a href="#循环往复" class="headerlink" title="循环往复"></a>循环往复</h2><p>计划不是一成不变了，当身体在几周内都没有发生改变的时候，我们可以把上述部分整理为一份统一的Prompt，并附上近几周的体重变化，训练情况等信息发送给新的对话，生成新的计划。并按照这个模式坚持一下。</p><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>大模型的发展对我个人来讲真是极大的方便了我的生活，有些平时不知道该搜索什么关键词的东西，都可以直接向大模型提问，或多或少都能得到一个结果。</p><p>本文虽然不是由大语言模型生成的，但是我个人对人体的理解有限，并且每个人的情况并不相同，仅仅是提供了一种供参考的减肥思路，但是一切外来事物都是辅助，贵在坚持。祝大家春节多多长胖，来年可以一同减肥🤓</p><p><img src="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/emoji2.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/02/20/lose-weight-with-llm/emoji2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="减肥" scheme="https://keshane.moe/tags/%E5%87%8F%E8%82%A5/"/>
    
    <category term="健康" scheme="https://keshane.moe/tags/%E5%81%A5%E5%BA%B7/"/>
    
    <category term="大模型" scheme="https://keshane.moe/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    
    <category term="Gemini" scheme="https://keshane.moe/tags/Gemini/"/>
    
    <category term="健身" scheme="https://keshane.moe/tags/%E5%81%A5%E8%BA%AB/"/>
    
    <category term="身体重塑" scheme="https://keshane.moe/tags/%E8%BA%AB%E4%BD%93%E9%87%8D%E5%A1%91/"/>
    
  </entry>
  
  <entry>
    <title>不管是文章还是实际旅行都鸽了许久的珠海、澳门旅行</title>
    <link href="https://keshane.moe/2026/01/18/travel-zhuhai-and-macau/"/>
    <id>https://keshane.moe/2026/01/18/travel-zhuhai-and-macau/</id>
    <published>2026-01-18T12:08:57.000Z</published>
    <updated>2026-07-27T14:35:50.517Z</updated>
    
    <content type="html"><![CDATA[<p>说起来，港澳这两个地方在我国还挺特殊的，我国对其拥有合法主权，但是通过合法的渠道过去需要通行证（虽然很好办理），其中涉及到了制度、法律相关的问题。不过也确实因为这个通行证导致我原本想去澳门玩的计划搁置了很久。原本去年临时起意准备珠海航展期间去看下航展然后一块去澳门玩一下，但是因为我没提前准备，而我又不是本地户口，无法在7个工作日内获得港澳通行证因此作罢。本次和我一块去的同学由于各地要求不同，还需要办理当地的实体居住证，步骤更加复杂（（</p><h2 id="珠海-海滨城市的休闲旅途"><a href="#珠海-海滨城市的休闲旅途" class="headerlink" title="珠海 - 海滨城市的休闲旅途"></a>珠海 - 海滨城市的休闲旅途</h2><p>首先避坑一个叫珠海阿那亚的地方。我同学从小红书上看到这个地方，你在网上看到的图可能长这样。</p><p>看着挺好看，并且离我们第一天住的酒店还算比较近（机场附近的酒店）。第二天早上我们打车前往这个地方。</p><p>emmm只能说请以实物为准。实际上就这么个小房子，如果你想靠近还要收30门票，当时天气不好，呆了一会就突然下大雨了。我掏出了唯一的一把伞，结果风太大甚至把我的伞骨吹断了😂</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/anaya.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/anaya.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="阿那亚"></p><p>赶紧打车溜了溜了。</p><p>不过下午就天晴了，就决定沿着珠海的海岸线逛一下。</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/map.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/map.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="地图"></p><p>本来我俩骑了共享单车沿着海岸线骑，然后路过一个灯塔，把单车停在路边下去看了一下，回来发现同学的共享单车不见了，赶紧在手机app上一顿狂点锁车。剩下的路只能慢慢腿着了。</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%B5%B7%E5%B2%B8%E7%BA%BF-%E5%BA%94%E8%AF%A5%E6%98%AF%E6%B8%AF%E7%8F%A0%E6%BE%B3%E5%A4%A7%E6%A1%A5.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%B5%B7%E5%B2%B8%E7%BA%BF-%E5%BA%94%E8%AF%A5%E6%98%AF%E6%B8%AF%E7%8F%A0%E6%BE%B3%E5%A4%A7%E6%A1%A5.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="海岸线-港港珠大港"></p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%97%A5%E6%9C%88%E8%B4%9D.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%97%A5%E6%9C%88%E8%B4%9D.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="日月贝"></p><p>当天不知道是不是有什么活动，这个日月贝的小岛晚上人非常多，这个桥上还有一堆兜售用无人机拍照的。</p><p>作为一个内陆长大的孩子，很少有机会能够接触到大海这种望不到对岸的场景。珠海的海岸线还是挺好看的，当然8月末的夏天还是太热了。</p><h2 id="澳门"><a href="#澳门" class="headerlink" title="澳门"></a>澳门</h2><p>说到澳门，可能大部分人想到的都是金币辉煌的赌场，充满资本主义的气息。澳门其实主要分为两个部分，可以大致理解为老城区和新城区（或许还有一块自然风景区，因为我并没有去路环那一块）。新城区的部分可能就和大部分人想象中的一样，充满资本主义世界的纸醉金迷。而老城区则能感受到上个世纪澳门本地文化和西方文化的融合感。</p><p>酒店斟酌了很久，最后定了巴黎人，澳门酒店定了几乎都不能取消，结果当天入住的时候查了一下便宜300多块钱 🤡</p><p>看地图澳门其实不大，所以也没有做很细节的规划，感觉随便走走就能逛完，但是在澳门感觉还是遗漏了很多地方没有去（甚至住的巴黎人酒店都没有去那个铁塔上）。虽然澳门占地面积很小，但是如果进了赌场之类的地方，建筑设计得都比较大里面也挺绕的，对于我来讲就像刘姥姥进大观园一样（并且我也是第一次去赌场，虽然没钱，但是还是围观别人看了很久（（ </p><p>澳门因为占地面积比较小，再加上各个酒店会有自己的接驳车（网上都叫发财车），所以在澳门的两天出行都是靠各个酒店的发财车通勤，一般是坐离要去目的地比较近的一个酒店。当然八月末的天气还是很热的，所以除了大三巴，基本上都是在室内。</p><ul><li>澳门历史城区</li></ul><p>澳门历史城区是世界文化遗产，这片的建筑比较老旧，感觉不少都是上个世纪的建筑。充满了历史人文气息，相对于高大的赌场和酒店显得更加市井气息。</p><p>不过由于没有提前做攻略，再加上8月末的室外实在是太热了，所以只是粗略的逛了一下。</p><p>大三巴牌坊作为非常著名的景点当然是要去一下的，坐酒店的发财车到新八佰伴附近，然后步行一小会就能到达。</p><p>大三巴牌坊本身是一个教堂，被火烧之后留下来的一面墙，形成了这种独特的景观</p><p>大三巴牌坊旁边一点就是博物馆和大炮台，不过去的时候比较晚，博物馆已经关门了。大炮台算是澳门半岛的高处，可以俯瞰澳门半岛</p><ul><li>赌场</li></ul><p>新葡京酒店感觉是澳门半岛上最为醒目的建筑，不管在什么位置，都能够看到这个闪烁着金光的建筑，从大三巴牌坊一路向下走一会就能到。</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E5%92%95%E5%92%95%E5%92%95.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E5%92%95%E5%92%95%E5%92%95.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="咕咕咕"></p><p>走在新葡京酒店旁边的路上，一种割裂的景象就越发明显，大三巴酒店是金碧辉煌，但是旁边的建筑却是很老旧的建筑，仿佛像是枝干榨干了周围土壤的养分。</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%96%B0%E8%91%A1%E4%BA%AC%E6%97%81.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%96%B0%E8%91%A1%E4%BA%AC%E6%97%81.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="新葡京旁.png"><br><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%96%B0%E8%91%A1%E4%BA%AC%E4%B8%8B.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%96%B0%E8%91%A1%E4%BA%AC%E4%B8%8B.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="新葡京.png"></p><p>这附近有好多赌场都是挨着的，不过不知道是不是经营问题，感觉之前在网上看见的各个赌场的新手福利基本上是没有看见的。我有印象的只有澳娱旗下的几个赌场新客有50筹码或者20老虎机可以选择，剩下的就是美高梅有不用开卡就能领的免费奶茶和零食。我住的巴黎人酒店是金沙旗下的，需要办卡之后可以领取免费的零食。永利的去问了下好像没啥福利（</p><p>这几个赌场都逛了一下感觉都差不多，里面似乎都充斥着一种差不多的很浓郁的香味，理论上赌场内部是不允许拍照的，就不放照片了（</p><p>靠着新葡京送的20老虎机在一台机器上赢了300多，那个中奖动画还挺酷炫的，让你不断地往下点击，好像是特别牛逼的奖项一样，让人感觉“奖池还在累计” （可以去搜一下柏青哥中奖画面，感觉柏青哥那个画面更酷炫一点）</p><p>而在桌上玩的那些，门槛有点高（没钱.jpg），只是站在桌边围观了别人玩，看着还挺刺激的，也能理解为什么会有人停不下来。</p><p>逛了在澳门半岛的几座赌场之后，乘坐美高梅酒店的发财车从半岛回酒店所在的路凼。</p><p>路过永利皇宫看了一会喷泉，当时已经很晚了，门口还是有不少人拍照</p><p><img src="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%B0%B8%E5%88%A9%E7%9A%87%E5%AE%AB.png" class="lazy" data-srcset="https://webp.keshane.moe/2026/01/18/travel-zhuhai-and-macau/%E6%B0%B8%E5%88%A9%E7%9A%87%E5%AE%AB.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="永利皇宫.png"></p><p>在走回巴黎人酒店的路中，我们想直接从伦敦人里面走，这样快一点。但是感觉澳门的酒店全程都是为了把你引导向赌场设计的，赌场往往在很中心的地方，很容易找到。但是其他的如果有特定目标反而不太容易找路。最终我们看了好久的地图才找到回巴黎人酒店的路（</p><p>我看携程上的酒店页面，入住巴黎人酒店可以免费上那个仿造的铁塔，不过第一天回来的时候太晚了，已经下班了。第二天上午的时候想上去发现要12点才上班，血亏（🤣</p><h2 id="稍微总结一下"><a href="#稍微总结一下" class="headerlink" title="稍微总结一下"></a>稍微总结一下</h2><p>说实话全程对吃的印象不是太深刻了，就记得生蚝鸡挺好吃的。</p><p>对于在内陆长大的我来讲，感觉海滨城市还是挺舒服的，不过当地的人可能也觉得看腻了吧，不过大部分就是这样从自己呆到腻的地方跑到别人呆到腻的地方。</p><p>感觉澳门不同的地方是两个世界，澳门的历史城区比较复古，而赌场附近则是金碧辉煌  最近在b站又刷到了罗大佑的青春舞曲2000，感觉里面的一句歌词“关帝遥望天父”拿来形容澳门也挺合适的。</p><p>虽然这次出门带了相机，在珠海沿着海岸线骑车、走路的时候也感觉脖子上挂着个相机有点难受，在澳门都没把相机带出酒店，很多都是手机拍的，让我感觉在手机+滤镜的加持下如果不是需要超长焦或者超广角这种手机自身很难做到的场景，都没有把相机掏出来的理由。不过至少对于我自己拿着相机有一点好处是按下快门前，会思考一下构图和光影。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="旅游" scheme="https://keshane.moe/tags/%E6%97%85%E6%B8%B8/"/>
    
    <category term="生活" scheme="https://keshane.moe/tags/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="珠海" scheme="https://keshane.moe/tags/%E7%8F%A0%E6%B5%B7/"/>
    
    <category term="澳门" scheme="https://keshane.moe/tags/%E6%BE%B3%E9%97%A8/"/>
    
  </entry>
  
  <entry>
    <title>一次不那么完美的桂林旅游</title>
    <link href="https://keshane.moe/2024/07/13/202405-guilin-travel/"/>
    <id>https://keshane.moe/2024/07/13/202405-guilin-travel/</id>
    <published>2024-07-13T10:00:44.000Z</published>
    <updated>2026-07-27T14:35:50.461Z</updated>
    
    <content type="html"><![CDATA[<p>其实一直都听闻“桂林山水甲天下”再加上经常能看到一些非常好看的风光图片，所以一直想去玩一下，而最近有小伙伴正好在那边读书，所以准备正好蹭着五一节就过去玩一下。由于有同学在那边，并且还信誓旦旦的告诉我们不需要做攻略，于是我们什么都没准备都过去了。结果从抢火车票开始到游玩途中都和预期的不一样，但是总的来说桂林这个城市给我的感觉还挺不错的，以后有机会甚至还挺想去玩的。</p><h2 id="计划"><a href="#计划" class="headerlink" title="计划"></a>计划</h2><p>原计划呢大概是1号到达桂林，然后2、3号去阳朔玩，4号回桂林玩，5号返程。除去路程接近7小时的高铁时间，基本上也就只有3天半的时间游玩。然而由于抢不到5号的票，变成了4号返程，所以修改了大部分计划</p><h2 id="day1"><a href="#day1" class="headerlink" title="day1"></a>day1</h2><p>第一天到桂林的时候已经是下午快到晚饭的时间了，桂林北距离桂林比较中心的几个地方有大概20分钟的车程。</p><p>其实在桂林市区内就能感受出这边山水的风景（这是在顺风车上拍的一张图）</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%9A%8F%E6%89%8B.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%9A%8F%E6%89%8B.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><h3 id="东西巷"><a href="#东西巷" class="headerlink" title="东西巷"></a>东西巷</h3><p>众所周知，一般的景区美食街价格都是非常昂贵的，但是可能由于我在杭州呆久了，感觉桂林这边美食街的价格和我在杭州吃的正常食物价格都差不多，但是美食街嘛，懂得都懂，全国各地卖的东西都差不多</p><p>（这个十块钱的土豆颇有我小学门口摊位卖的味道）</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%9C%9F%E8%B1%86.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%9C%9F%E8%B1%86.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="土豆"></p><p>在这边逛了一会，等待另一个同学的火车过来。</p><p>可能是节假日的原因，人流量不能说特别多吧，只能说基本走不动路，不知道是不是有什么活动，感觉有不少穿cos服的。这边还有个靖江王城景区，排队的人也挺多的。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E4%B8%9C%E8%A5%BF%E5%B7%B7.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E4%B8%9C%E8%A5%BF%E5%B7%B7.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="东西巷"></p><ul><li>牛八宝</li></ul><p>第一天的晚餐，据说是桂林的特产，还挺好吃的，有一股酸笋的味道，我很喜欢这个味道。牛八宝具体有哪几样我也忘了，可以理解为牛身上的不同部位。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%89%9B%E5%85%AB%E5%AE%9D.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%89%9B%E5%85%AB%E5%AE%9D.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="牛八宝"></p><h3 id="日月双塔、两江四湖（并没有）"><a href="#日月双塔、两江四湖（并没有）" class="headerlink" title="日月双塔、两江四湖（并没有）"></a>日月双塔、两江四湖（并没有）</h3><p>好吧，吃完饭天黑了在下面拍了下日月双塔的照片，这边能看到不少穿民族服饰的人在拍照。然后本来打算后面去坐的游船由于后面买票的原因也没坐成。</p><p>这个日月双塔晚上开灯还挺好看的，不知道是不是守望先锋里漓江塔的原型</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%97%A5%E6%9C%88%E5%8F%8C%E5%A1%94.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%97%A5%E6%9C%88%E5%8F%8C%E5%A1%94.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="日月双塔"></p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%97%A5%E6%9C%88%E5%8F%8C%E5%A1%942.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%97%A5%E6%9C%88%E5%8F%8C%E5%A1%942.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="日月双塔"></p><h2 id="day2、day3"><a href="#day2、day3" class="headerlink" title="day2、day3"></a>day2、day3</h2><h3 id="桂林米粉"><a href="#桂林米粉" class="headerlink" title="桂林米粉"></a>桂林米粉</h3><p>第二天早上在同学的带领下吃了桂林米粉，真好吃啊，我个人也比较喜欢吃这种一咬就碎的米粉，再加上这个米粉的料是真的香，感觉特别符合我的口味，我在这边每天都吃了米粉。太好吃了，并且在桂林市区里价格非常便宜（阳朔得20一碗呢）</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%B1%B3%E7%B2%89.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%B1%B3%E7%B2%89.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="米粉"></p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%B1%B3%E7%B2%892.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E7%B1%B3%E7%B2%892.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="米粉"></p><p>（辣椒和酸笋啥的自己加，我这是按照公司食堂的辣椒来评估辣度的，所以加了挺多的，然后把自己辣到肚子痛了😂后面吃米粉都怂了）</p><p>这边感觉跨城出行通过顺风车比较方便</p><ul><li>啤酒鱼</li></ul><p>到达阳朔之后吃了一顿当地特产啤酒鱼，感觉不太习惯。。。但是不难吃。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%95%A4%E9%85%92%E9%B1%BC.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%95%A4%E9%85%92%E9%B1%BC.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="啤酒鱼"></p><h3 id="十里画廊"><a href="#十里画廊" class="headerlink" title="十里画廊"></a>十里画廊</h3><p>之前看天气预报这几天都有雨，但是到了阳朔之后天气还挺好的，为了防止堵车，所以我们准备租电动车前往景点。本身十里画廊，是一个多个景点之间的组合景点，所以骑车相对来讲是更方便的。我们租电瓶车的价格是50元&#x2F;天，有的店好像要贵一些</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%8D%81%E9%87%8C%E7%94%BB%E5%BB%8A%E5%85%A5%E5%8F%A3.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%8D%81%E9%87%8C%E7%94%BB%E5%BB%8A%E5%85%A5%E5%8F%A3.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="十里画廊"></p><p>当然由于节假日人太多，可以感受到电瓶车堵车、停车难的情况</p><h3 id="遇龙河"><a href="#遇龙河" class="headerlink" title="遇龙河"></a>遇龙河</h3><p>遇龙河在十里画廊内部，从桥上看风景很不错，由于没有做攻略，所以没办法坐这个竹筏（需要预约or早上8点去排队买票😥），但是风景还是挺不错的</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%81%87%E9%BE%99%E6%B2%B3.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%81%87%E9%BE%99%E6%B2%B3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="遇龙河"></p><p>（这图是堵车的时候手机上用jpeg格式修的，所以很糊）</p><h3 id="月亮山"><a href="#月亮山" class="headerlink" title="月亮山"></a>月亮山</h3><p>十里画廊的后段有这个景区，我们骑车到这边的时候已经没什么人了，需要买门票爬山上去。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%9C%88%E4%BA%AE%E5%B1%B1.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%9C%88%E4%BA%AE%E5%B1%B1.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="月亮山"></p><p>月亮山顾名思义，山顶上有一块形似月亮的部分，大自然的鬼斧神工。</p><p>在山顶上可以俯瞰山下的城镇，景色挺不错的，我们上山的时候已经快天黑了，并且有点开始下雨了</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%9C%88%E4%BA%AE%E5%B1%B1%E9%A1%B62.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%9C%88%E4%BA%AE%E5%B1%B1%E9%A1%B62.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="月亮山顶的风光"></p><h3 id="西街"><a href="#西街" class="headerlink" title="西街"></a>西街</h3><p>一条古风步行街，可以参考各位当地的各种类似景区，个人没感觉出有什么特别的地方</p><p>在这边买了一种当地的叫酸嘢的小吃，类似水果捞吧，不过是拌的辣椒和醋？（没太了解过）感觉非常黑暗，建议不要轻易尝试</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%85%B8%E5%98%A2.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%85%B8%E5%98%A2.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="酸嘢.jpeg"></p><p>本来打算在阳朔住2晚的，但是由于行程改变，需要提前返程，所以第二天就准备玩完之后返回桂林。</p><h3 id="兴坪古镇"><a href="#兴坪古镇" class="headerlink" title="兴坪古镇"></a>兴坪古镇</h3><p>这里离阳朔还有一段距离。在小镇里找了家店吃饭，点了可能也是这边特色的竹筒鸡，个人感觉比啤酒鱼好吃</p><p>兴坪古镇是人民币二十元取景地。可惜我们没有准备20元人民币，还好机智如我找了张图片</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/20rmb2.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/20rmb2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="20元人民币取景地"></p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/20rmb.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/20rmb.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="20元人民币取景地"></p><p>岸边有很多竹筏可以让你拍那种古风大片。</p><p>坐了游船，其实和在岸边看到的景色没什么区别，但是来都来了（</p><p>在等游船的地方，有一块镜面，可以拍出那种倒影的效果，可能都在网上见到过类似的，当然都是收费才能站人上去（</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%82%AE%E8%88%B9%E7%AD%89%E5%BE%85.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E9%82%AE%E8%88%B9%E7%AD%89%E5%BE%85.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="邮船等待"></p><p>顺风车走的一条国道，能够沿着漓江一路开到桂林，其实沿途的风景也挺不错的，让我感觉没必要去这些热门景点人挤人。但是呢出门旅游一趟，不去热门景点总感觉会亏点什么。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%B0%8F%E8%B7%AF.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E5%B0%8F%E8%B7%AF.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="国道上的风景"></p><h3 id="油茶"><a href="#油茶" class="headerlink" title="油茶"></a>油茶</h3><p>晚餐吃的是这边的油茶，感觉也是这边的一个特色了，但是我个人不太喜欢，有股怪怪的味道</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%B2%B9%E8%8C%B6.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E6%B2%B9%E8%8C%B6.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="油茶"></p><p>左下角那个黄瓜是用百香果拌的，过于黑暗了，除了油茶和黄瓜都挺好吃的。</p><h2 id="day4"><a href="#day4" class="headerlink" title="day4"></a>day4</h2><h3 id="象鼻山"><a href="#象鼻山" class="headerlink" title="象鼻山"></a>象鼻山</h3><p>这天就是被行程更改牺牲的一天，在去车站前还有一点时间，到这里略略逛了一圈，这个洞还挺有特色的。天气不是太好，试了一下小米的天空替换。</p><p><img src="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E8%B1%A1%E9%BC%BB%E5%B1%B1.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/07/13/202405-guilin-travel/%E8%B1%A1%E9%BC%BB%E5%B1%B1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="象鼻山"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>来桂林一趟，感觉就是风景真的和网上的图片一样好。见过了很多图片和实物不同的景点，有这种体验还挺难得。不过由于天气、买票、节假日人多等原因，很多地方都匆匆忙忙走过去了，但是哪怕就是这种走马观花式的游玩也能感受出桂林山水的秀丽。个人感觉这边是一个很适合工作日自驾来游玩的地方，可以随心所欲的想去哪去哪，不用感受节假日的拥挤，一些小众的景点都有很不错的体验。有机会再去吧。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="旅游" scheme="https://keshane.moe/tags/%E6%97%85%E6%B8%B8/"/>
    
    <category term="生活" scheme="https://keshane.moe/tags/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="桂林" scheme="https://keshane.moe/tags/%E6%A1%82%E6%9E%97/"/>
    
    <category term="吃的" scheme="https://keshane.moe/tags/%E5%90%83%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>用一些歪门邪道自动化构建 intellij idea 插件</title>
    <link href="https://keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/"/>
    <id>https://keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/</id>
    <published>2024-03-24T08:27:00.000Z</published>
    <updated>2026-07-27T14:35:50.457Z</updated>
    
    <content type="html"><![CDATA[<p>前言：请停止使用过时技术构建项目</p><p><img src="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/cry.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/cry.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p>官方文档中的使用devkit创建插件的部分已经不见了，如果要开新项目推荐大家一步到位直接使用gradle，这个文章的内容应该是2022年6月份左右做的，所以已经过时了，主要是记录一下之前偿还的技术债。</p><p><img src="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/intellij-doc.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/intellij-doc.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea文档"></p><p>之前我们的插件都是手动在idea工程里右键deploy打包的，但是这样打包过于不方便，并且有可能会因为各个人的idea版本，java版本不同导致打包出现问题，所以自动化打包让流水线来做这个事是很有必要的。</p><h1 id="相关背景调查"><a href="#相关背景调查" class="headerlink" title="相关背景调查"></a>相关背景调查</h1><p>Idea官方的建议是通过Gradle构建插件工程，并通过官方提供的gradle插件来进行打包发布等操作，如果使用官方文档上推荐的操作，自动化打包应该是一件比较容易的事情，只需要执行gradle命令就好了</p><p>参考 <a href="https://plugins.jetbrains.com/docs/intellij/deployment.html">https://plugins.jetbrains.com/docs/intellij/deployment.html</a></p><p>和官方gradle插件的 buildPlugin 命令 <a href="https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#buildplugin-task">https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#buildplugin-task</a></p><p>但是在国内的网络环境下使用gradle是有一点困难的，相关的依赖也需要添加在公司的制品库中，总结一句就是使用起来相当不便，所以我们的插件工程是使用的devkit的模式<a href="https://plugins.jetbrains.com/docs/intellij/using-dev-kit.html">https://plugins.jetbrains.com/docs/intellij/using-dev-kit.html</a></p><p>打包的话是通过idea的菜单，<strong>Build | Prepare Plugin Module $MODULE_NAME$ for Deployment</strong>. 来进行打包。</p><p>但是这个打包的操作是在界面上完成的，我们不可能说在流水线上安装一个完整的idea客户端，然后通过界面进行打包，所以我们需要知道这个菜单背后的实现逻辑。</p><h1 id="原理分析"><a href="#原理分析" class="headerlink" title="原理分析"></a>原理分析</h1><h3 id="jar包分析"><a href="#jar包分析" class="headerlink" title="jar包分析"></a>jar包分析</h3><p>idea的插件包一般来说都是以一个zip包，这个zip包里面包含了一个代表插件本身工程编译出来的jar包和一些工程内部的依赖包，例如github-colpilot插件，解压之后得到的结构基本上如下图</p><p><img src="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/plugin-zip-structure.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/plugin-zip-structure.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="插件zip包结构"></p><p>图中的github-copilot-intellij-1.5.0.5148.jar就是插件工程编译而出来的jar包。其他的jar包都是引入的依赖。</p><p>github-copilot-intellij-1.5.0.5148.jar就和普通的java工程一样，里面装了class文件，其中有一个特殊的就是META-INF下面有idea插件的描述性文件plugin.xml。</p><p>自此我们知道了idea插件打包出来的结构，我们再来看一下Idea的 Prepare Plugin Module $MODULE_NAME$ for Deployment菜单背后的逻辑</p><h3 id="从idea源码入手"><a href="#从idea源码入手" class="headerlink" title="从idea源码入手"></a>从idea源码入手</h3><p>这部分对应的源码在 <a href="https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java">https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java</a></p><p>入口是 <code>actionPerformed</code>方法</p><p>核心的逻辑为每个模块都会调用的doPrepare方法:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">doPrepare</span><span class="params">(Module <span class="keyword">module</span>, List&lt;String&gt; errorMessages, List&lt;String&gt; successMessages)</span> &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">pluginName</span> <span class="operator">=</span> <span class="keyword">module</span>.getName();</span><br><span class="line">    <span class="type">String</span> <span class="variable">defaultPath</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(<span class="keyword">module</span>.getModuleFilePath()).getParent() + File.separator + pluginName;</span><br><span class="line">    <span class="comment">// 收集所有运行时模块(modules), 依赖(libs)</span></span><br><span class="line">    Set&lt;Module&gt; modules = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line">    PluginBuildUtil.getDependencies(<span class="keyword">module</span>, modules);</span><br><span class="line">    modules.add(<span class="keyword">module</span>);</span><br><span class="line">    Set&lt;Library&gt; libs = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">for</span> (Module dep : modules) &#123;</span><br><span class="line">      PluginBuildUtil.getLibraries(dep, libs);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Map&lt;Module, String&gt; jpsModules = collectJpsPluginModules(<span class="keyword">module</span>);</span><br><span class="line">    modules.removeAll(jpsModules.keySet());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果没有更多的依赖和模块则为 jar 包如果有则为 zip 包</span></span><br><span class="line">    <span class="type">boolean</span> <span class="variable">isZip</span> <span class="operator">=</span> !libs.isEmpty() || !jpsModules.isEmpty();</span><br><span class="line">    <span class="type">String</span> <span class="variable">oldPath</span> <span class="operator">=</span> defaultPath + (isZip ? JAR_EXTENSION : ZIP_EXTENSION);</span><br><span class="line">    <span class="type">File</span> <span class="variable">oldFile</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(oldPath);</span><br><span class="line">    <span class="keyword">if</span> (oldFile.exists()) &#123;</span><br><span class="line">      <span class="type">String</span> <span class="variable">message</span> <span class="operator">=</span> DevKitBundle.message(<span class="string">&quot;suggest.to.delete&quot;</span>, oldPath), title = DevKitBundle.message(<span class="string">&quot;info.message&quot;</span>);</span><br><span class="line">      <span class="keyword">if</span> (Messages.showYesNoDialog(<span class="keyword">module</span>.getProject(), message, title, Messages.getInformationIcon()) == Messages.YES) &#123;</span><br><span class="line">        FileUtil.delete(oldFile);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">String</span> <span class="variable">dstPath</span> <span class="operator">=</span> defaultPath + (isZip ? ZIP_EXTENSION : JAR_EXTENSION);</span><br><span class="line">    <span class="type">File</span> <span class="variable">dstFile</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(dstPath);</span><br><span class="line">    <span class="keyword">return</span> clearReadOnly(<span class="keyword">module</span>.getProject(), dstFile) &amp;&amp; ProgressManager.getInstance().runProcessWithProgressSynchronously(() -&gt; &#123;</span><br><span class="line">      <span class="type">ProgressIndicator</span> <span class="variable">progressIndicator</span> <span class="operator">=</span> ProgressManager.getInstance().getProgressIndicator();</span><br><span class="line">      <span class="keyword">if</span> (progressIndicator != <span class="literal">null</span>) &#123;</span><br><span class="line">        progressIndicator.setText(DevKitBundle.message(<span class="string">&quot;prepare.for.deployment.task.progress&quot;</span>));</span><br><span class="line">        progressIndicator.setIndeterminate(<span class="literal">true</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 编译插件jar包</span></span><br><span class="line">        <span class="type">File</span> <span class="variable">jarFile</span> <span class="operator">=</span> preparePluginsJar(<span class="keyword">module</span>, modules);</span><br><span class="line">        <span class="keyword">if</span> (isZip) &#123;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 合并所有的模块，插件，依赖</span></span><br><span class="line">            processLibrariesAndJpsPlugins(jarFile, dstFile, pluginName, libs, jpsModules);</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">finally</span> &#123;</span><br><span class="line">            FileUtil.delete(jarFile);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">          FileUtil.rename(jarFile, dstFile);</span><br><span class="line">        &#125;</span><br><span class="line">        LocalFileSystem.getInstance().refreshIoFiles(Collections.singleton(dstFile), <span class="literal">true</span>, <span class="literal">false</span>, <span class="literal">null</span>);</span><br><span class="line">        successMessages.add(DevKitBundle.message(<span class="string">&quot;saved.message&quot;</span>, isZip ? <span class="number">1</span> : <span class="number">2</span>, pluginName, dstPath));</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        errorMessages.add(e.getMessage() + <span class="string">&quot;\n(&quot;</span> + dstPath + <span class="string">&quot;)&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;, DevKitBundle.message(<span class="string">&quot;prepare.for.deployment.task&quot;</span>, pluginName), <span class="literal">true</span>, <span class="keyword">module</span>.getProject());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>可以看到在这个方法里面，首先收集了所有的模块和依赖，如果没有只有单个工程，没有模块和依赖，那么最终的输出结果就是一个单独的jar包，如果有模块和依赖，则将编译后的代码输出为一个jar包，并将所有的依赖jar包和这个依赖合并为一个zip包，最终组成插件的安装包。</p><p>而在 preparePluginsJar 方法中，则是创建jar包，并将每个模块编译出来的 class 文件和插件的配置文件 plugin.xml 复制进jar包中</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> File <span class="title function_">preparePluginsJar</span><span class="params">(Module <span class="keyword">module</span>, Set&lt;Module&gt; modules)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="type">PluginBuildConfiguration</span> <span class="variable">configuration</span> <span class="operator">=</span> PluginBuildConfiguration.getInstance(<span class="keyword">module</span>);</span><br><span class="line">    <span class="type">Manifest</span> <span class="variable">manifest</span> <span class="operator">=</span> createOrFindManifest(configuration);</span><br><span class="line">    <span class="keyword">return</span> jarModulesOutput(modules, manifest, configuration != <span class="literal">null</span> ? configuration.getPluginXmlPath() : <span class="literal">null</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> File <span class="title function_">jarModulesOutput</span><span class="params">(Set&lt;Module&gt; modules, <span class="meta">@Nullable</span> Manifest manifest, <span class="meta">@Nullable</span> String pluginXmlPath)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="type">File</span> <span class="variable">tempFile</span> <span class="operator">=</span> FileUtil.createTempFile(TEMP_PREFIX, JAR_EXTENSION);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> (Compressor.<span class="type">Jar</span> <span class="variable">jar</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Compressor</span>.Jar(tempFile)) &#123;</span><br><span class="line">      <span class="type">FileTypeManager</span> <span class="variable">manager</span> <span class="operator">=</span> FileTypeManager.getInstance();</span><br><span class="line">      Set&lt;String&gt; uniqueEntries = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line">      jar.filter((entryName, file) -&gt; !manager.isFileIgnored(PathUtil.getFileName(entryName)) &amp;&amp; uniqueEntries.add(entryName));</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (manifest != <span class="literal">null</span>) &#123;</span><br><span class="line">        jar.addManifest(manifest);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">for</span> (Module <span class="keyword">module</span> : modules) &#123;</span><br><span class="line">        <span class="comment">// 编译每个模块，并将代码 class 文件添加进 jar 包中</span></span><br><span class="line">        <span class="type">CompilerModuleExtension</span> <span class="variable">extension</span> <span class="operator">=</span> CompilerModuleExtension.getInstance(<span class="keyword">module</span>);</span><br><span class="line">        <span class="keyword">if</span> (extension != <span class="literal">null</span>) &#123;</span><br><span class="line">          <span class="type">VirtualFile</span> <span class="variable">outputPath</span> <span class="operator">=</span> extension.getCompilerOutputPath();</span><br><span class="line">          <span class="keyword">if</span> (outputPath != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// pre-condition: output dirs for all modules are up-to-date</span></span><br><span class="line">            jar.addDirectory(<span class="keyword">new</span> <span class="title class_">File</span>(outputPath.getPath()));</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 复制 plugin.xml</span></span><br><span class="line">      <span class="keyword">if</span> (pluginXmlPath != <span class="literal">null</span>) &#123;</span><br><span class="line">        jar.addFile(PluginDescriptorConstants.PLUGIN_XML_PATH, <span class="keyword">new</span> <span class="title class_">File</span>(pluginXmlPath));</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> tempFile;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>如果是需要输出为zip包的化则执行 processLibrariesAndJpsPlugins 方法</p><p>理解了这个逻辑，我们就可以写自己的自动化脚本了。我们的工程结构比较奇葩，由于官方不支持maven的结构创建插件工程，所以我们创建了一个插件工程，然后创建了一堆maven模块来使用需要的依赖包，这一堆的maven模块是通过idea的Project Structure手动进行管理的（所以配置环境很容易爆炸）。我们还在sdk配置中添加了一些idea官方的扩展包，</p><p><img src="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/idea-dependency.png" class="lazy" data-srcset="https://webp.keshane.moe/2024/03/24/auto-build-intellij-plugin-without-gradle/idea-dependency.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p>这些包并不在普通的java运行环境中，所以我们在编译的时候需要把这些包添加classpath中，但是在插件运行时，这些jar包实际上是idea环境自带的，我们只是在打包的时候需要，并不需要添加到最终的class里面。</p><p>根据之前的逻辑，我们需要做的事情有以下几点</p><ol><li>将 maven 中的依赖和 idea sdk 中的 jar 包一起联合编译我们的 java 文件为 class</li><li>将编译好的 class 还有 resources 里面的静态文件打包成插件本身的 Jar 包</li><li>完成以上步骤之后，将插件本身的 Jar 包和 Maven 依赖的 Jar 包一起打包成最终的插件包 (zip)</li></ol><p>我们使用ant作为工具来构建我们的插件</p><p>首先我们需要准备好idea的SDK，maven的依赖，然后将这些依赖添加进 classpath 中，编译我们的 java 文件</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">taskdef</span> <span class="attr">uri</span>=<span class="string">&quot;antlib:org.apache.maven.resolver.ant&quot;</span> <span class="attr">resource</span>=<span class="string">&quot;org/apache/maven/resolver/ant/antlib.xml&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">classpath</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">dir</span>=<span class="string">&quot;.&quot;</span> <span class="attr">includes</span>=<span class="string">&quot;maven-resolver-ant-tasks-*uber.jar&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">classpath</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">taskdef</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">target</span> <span class="attr">name</span>=<span class="string">&quot;compile&quot;</span> <span class="attr">depends</span>=<span class="string">&quot;clean&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">resolver:resolve</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">resolver:dependencies</span> <span class="attr">pomRef</span>=<span class="string">&quot;pom&quot;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">resolver:path</span> <span class="attr">refid</span>=<span class="string">&quot;cp.compile.main&quot;</span> <span class="attr">classpath</span>=<span class="string">&quot;compile&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">resolver:resolve</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">id</span>=<span class="string">&quot;download.jar&quot;</span> <span class="attr">dir</span>=<span class="string">&quot;$&#123;build.temp.dir&#125;/local-repo&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">include</span> <span class="attr">name</span>=<span class="string">&quot;**/*.jar&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">fileset</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">path</span> <span class="attr">id</span>=<span class="string">&quot;runtime-classpath&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">id</span>=<span class="string">&quot;idea.lib1&quot;</span> <span class="attr">dir</span>=<span class="string">&quot;$&#123;idea.dir&#125;/lib&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">include</span> <span class="attr">name</span>=<span class="string">&quot;**/*&quot;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">fileset</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">id</span>=<span class="string">&quot;idea.lib2&quot;</span> <span class="attr">dir</span>=<span class="string">&quot;$&#123;idea.dir&#125;/plugins&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">include</span> <span class="attr">name</span>=<span class="string">&quot;**/*.jar&quot;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">fileset</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">refid</span>=<span class="string">&quot;download.jar&quot;</span>/&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">dir</span>=<span class="string">&quot;lib&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">path</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">manifestclasspath</span> <span class="attr">property</span>=<span class="string">&quot;manifest.classpath&quot;</span> <span class="attr">maxparentlevels</span>=<span class="string">&quot;10&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">jarfile</span>=<span class="string">&quot;$&#123;classpath-compile.jar&#125;&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">classpath</span> <span class="attr">refid</span>=<span class="string">&quot;runtime-classpath&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">manifestclasspath</span>&gt;</span></span><br><span class="line"></span><br><span class="line">      <span class="tag">&lt;<span class="name">jar</span> <span class="attr">destfile</span>=<span class="string">&quot;$&#123;classpath-compile.jar&#125;&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">manifest</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">attribute</span> <span class="attr">name</span>=<span class="string">&quot;Class-Path&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;manifest.classpath&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">jar</span>&gt;</span></span><br><span class="line"></span><br><span class="line">      <span class="tag">&lt;<span class="name">javac</span> <span class="attr">srcdir</span>=<span class="string">&quot;src/main/java&quot;</span> <span class="attr">destdir</span>=<span class="string">&quot;$&#123;build.temp.dir&#125;/classes&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">includeAntRuntime</span>=<span class="string">&quot;false&quot;</span> <span class="attr">source</span>=<span class="string">&quot;8&quot;</span> <span class="attr">target</span>=<span class="string">&quot;8&quot;</span> <span class="attr">encoding</span>=<span class="string">&quot;UTF-8&quot;</span> <span class="attr">fork</span>=<span class="string">&quot;true&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">classpath</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pathelement</span> <span class="attr">location</span>=<span class="string">&quot;$&#123;classpath-compile.jar&#125;&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">classpath</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">javac</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br></pre></td></tr></table></figure><p>然后将所有的静态资源，依赖的 Jar 包复制到对应的目录中</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">copy</span> <span class="attr">todir</span>=<span class="string">&quot;$&#123;build.plugin.dir&#125;&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">dir</span>=<span class="string">&quot;lib&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">refid</span>=<span class="string">&quot;download.jar&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">mapper</span> <span class="attr">type</span>=<span class="string">&quot;flatten&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">copy</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">copy</span> <span class="attr">todir</span>=<span class="string">&quot;$&#123;build.temp.dir&#125;/classes&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">dir</span>=<span class="string">&quot;src/main/resources&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">fileset</span> <span class="attr">dir</span>=<span class="string">&quot;../resources&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">copy</span>&gt;</span></span><br></pre></td></tr></table></figure><p>把编译好的文件和静态资源打包成 Jar 包，并最终和依赖一同打包成插件的 zip 包</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">target</span> <span class="attr">name</span>=<span class="string">&quot;package&quot;</span> <span class="attr">depends</span>=<span class="string">&quot;compile&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">jar</span> <span class="attr">destfile</span>=<span class="string">&quot;$&#123;build.plugin.dir&#125;/plugin.jar&quot;</span> <span class="attr">basedir</span>=<span class="string">&quot;$&#123;build.temp.dir&#125;/classes&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">zip</span> <span class="attr">destfile</span>=<span class="string">&quot;../plugin.zip&quot;</span> <span class="attr">basedir</span>=<span class="string">&quot;$&#123;build.plugin.zip&#125;&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">resolver:artifacts</span> <span class="attr">id</span>=<span class="string">&quot;output&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifact</span> <span class="attr">file</span>=<span class="string">&quot;$&#123;build.plugin.dir&#125;/plugin.jar&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">resolver:artifacts</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br></pre></td></tr></table></figure><h1 id="相关代码参考"><a href="#相关代码参考" class="headerlink" title="相关代码参考"></a>相关代码参考</h1><p><a href="https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareAllToDeployAction.java">https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareAllToDeployAction.java</a></p><p><a href="https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java">https://github.com/JetBrains/intellij-community/blob/master/plugins/devkit/devkit-core/src/build/PrepareToDeployAction.java</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="intellij idea" scheme="https://keshane.moe/tags/intellij-idea/"/>
    
    <category term="plugin" scheme="https://keshane.moe/tags/plugin/"/>
    
    <category term="idea插件" scheme="https://keshane.moe/tags/idea%E6%8F%92%E4%BB%B6/"/>
    
    <category term="ant" scheme="https://keshane.moe/tags/ant/"/>
    
    <category term="gradle" scheme="https://keshane.moe/tags/gradle/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 博客使用 WebP Cloud Service</title>
    <link href="https://keshane.moe/2023/06/14/using-webp-cloud-service-on-hexo/"/>
    <id>https://keshane.moe/2023/06/14/using-webp-cloud-service-on-hexo/</id>
    <published>2023-06-14T12:12:44.000Z</published>
    <updated>2026-07-27T14:35:50.457Z</updated>
    
    <content type="html"><![CDATA[<h2 id="为什么要使用-WebP-格式"><a href="#为什么要使用-WebP-格式" class="headerlink" title="为什么要使用 WebP 格式"></a>为什么要使用 WebP 格式</h2><p>用一张图片来说就是</p><p><img src="https://webp.keshane.moe/2023/06/14/using-webp-cloud-service-on-hexo/webp_server_go.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/06/14/using-webp-cloud-service-on-hexo/webp_server_go.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="webp_server_go"></p><p>WebP 格式的图片更小，可以让你打开 <a href="http://keshane.moe/">keshane.moe</a> 的加载速度变得更快。</p><h2 id="为什么我的博客之前没使用-webp-格式的图片"><a href="#为什么我的博客之前没使用-webp-格式的图片" class="headerlink" title="为什么我的博客之前没使用 webp 格式的图片"></a>为什么我的博客之前没使用 webp 格式的图片</h2><p>虽然目前的主流浏览器都支持了 WebP 格式，但是如果你使用了过于先进的浏览器或者某些小而美的聊天软件，可能不能很好的支持 WebP 格式，所以我们目前暂时不能一股脑的在页面上用上把所有的图片换成 WebP 格式，之前 <a href="nova.moe">Nova</a> 大佬开发了 <a href="https://github.com/webp-sh/webp_server_go">https://github.com/webp-sh/webp_server_go</a> 可以在不改变 url 和原始图片格式的情况下根据不同的设备返回不同的图片。但是由于我是个懒人，所有图片都是丢在 git 仓库下的，静态页面是 cloudflare page ，并不想再单独部署一个 webp_server_go 来提供更好的浏览体验<del>反正也没啥人看（</del></p><h2 id="WebP-Cloud"><a href="#WebP-Cloud" class="headerlink" title="WebP Cloud"></a>WebP Cloud</h2><p>因为上述不便呢，一个在线托管的 webp_server 服务就很有必要了。Webp Cloud Service 出现了，<a href="https://webp.se/">https://webp.se/</a> </p><p>使用方式可以参考<a href="https://docs.webp.se/webp-cloud/basic/">官方文档</a></p><h2 id="快速接入"><a href="#快速接入" class="headerlink" title="快速接入"></a>快速接入</h2><p>使用 hexo 提供的<a href="%5Bhttps://hexo.io/zh-cn/api/filter%5D(https://hexo.io/zh-cn/api/filter)">过滤器</a>和插件机制，我们可以简单的处理内容。</p><p>我做了个简单的插件，将 img 标签中的 src 内容替换为 Webp Cloud Service 提供的代理 url<a href="https://www.npmjs.com/package/hexo-webp-cloud-proxy">hexo-webp-cloud-proxy</a></p><ol><li>首先安装这个插件</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-webp-cloud-proxy --save</span><br></pre></td></tr></table></figure><ol><li>然后将下面的内容复制到你的配置文件中</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">webp_cloud_proxy:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="comment"># the suffix of img type to use webp cloud service</span></span><br><span class="line">  <span class="attr">convert_type_list:</span> [<span class="string">&quot;jpg&quot;</span>, <span class="string">&quot;jpeg&quot;</span>, <span class="string">&quot;png&quot;</span>, <span class="string">&quot;gif&quot;</span>]</span><br><span class="line">  <span class="comment"># your site url</span></span><br><span class="line">  <span class="attr">pre_url:</span> <span class="string">https://keshane.moe</span></span><br><span class="line">  <span class="comment"># webp cloud service proxy url</span></span><br><span class="line">  <span class="attr">proxy_url:</span> <span class="string">https://webp.keshane.moe</span></span><br><span class="line">  <span class="comment"># the filter priority, see https://hexo.io/api/filter.html</span></span><br><span class="line">  <span class="attr">priority:</span> <span class="number">10</span></span><br></pre></td></tr></table></figure><p>后续就和正常使用 hexo 一样了</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://webp.se/">webp cloud service</a></li><li><a href="https://hexo.io/api/filter">hexo过滤器</a></li></ul>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="hexo" scheme="https://keshane.moe/tags/hexo/"/>
    
    <category term="webp" scheme="https://keshane.moe/tags/webp/"/>
    
    <category term="webp cloud service" scheme="https://keshane.moe/tags/webp-cloud-service/"/>
    
  </entry>
  
  <entry>
    <title>Maven插件开发过程中的一些坑</title>
    <link href="https://keshane.moe/2023/03/30/maven-plugin-development-tips/"/>
    <id>https://keshane.moe/2023/03/30/maven-plugin-development-tips/</id>
    <published>2023-03-30T13:02:02.000Z</published>
    <updated>2026-07-27T14:35:50.456Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Maven插件开发过程中的一些坑"><a href="#Maven插件开发过程中的一些坑" class="headerlink" title="Maven插件开发过程中的一些坑"></a>Maven插件开发过程中的一些坑</h1><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>去年底写了一个 <code>maven</code> 插件，类似功能大概是解析 <code>@Controller</code> 以及其他的注解，生成一份类似接口文档的东西，标明出入参啥的，用 <code>maven</code> 插件可以尽量少的侵入代码，一开始是使用的一个文本解析库Qdox，但是经过验证有些功能不满足我们的需求，想了下 Maven 反正是在在构建时执行的，可以直接想办法获取 Classloader 然后用反射来获取需要的属性，在这个过程中踩了一些坑。记录一下这些坑。</p><h2 id="maven插件在root工程执行，不在每个模块工程都执行一次"><a href="#maven插件在root工程执行，不在每个模块工程都执行一次" class="headerlink" title="maven插件在root工程执行，不在每个模块工程都执行一次"></a>maven插件在root工程执行，不在每个模块工程都执行一次</h2><p>一开始发现这个maven插件在所有的模块都会跑一次，我本来在root工程执行的时候就回去收集所有信息了，不需要跑多次</p><p>解决方案，在@Mojo注解中 添加上 <code>aggregator=true</code></p><p><img src="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/aggregator.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/aggregator.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="aggregator"></p><h2 id="maven插件在编译后在执行"><a href="#maven插件在编译后在执行" class="headerlink" title="maven插件在编译后在执行"></a>maven插件在编译后在执行</h2><p>因为要用反射嘛，所以一定要编译完之后才能用</p><p>最靠谱的方案是把你的 Maven 插件配置好对应的声明周期，配置在 compile 或者 prepare_package 之后就行了。当然你的用户可能 xjb 改你的执行周期，所以这个问题也可以等价为</p><h3 id="maven插件在执行前先单独执行生命周期"><a href="#maven插件在执行前先单独执行生命周期" class="headerlink" title="maven插件在执行前先单独执行生命周期"></a>maven插件在执行前先单独执行生命周期</h3><p>在入口Mojo处加上@Execute注解，里面可以填写需要的生命周期</p><p>参考官方文档 </p><p><img src="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/execute.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/execute.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="execute.png"></p><h2 id="获取目标工程所有依赖信息"><a href="#获取目标工程所有依赖信息" class="headerlink" title="获取目标工程所有依赖信息"></a>获取目标工程所有依赖信息</h2><p>首先需要在 @Mojo 注解上加上 <code>requiresDependencyResolution</code> 配置，这个配置表明需要在执行前解析指定类路径中的依赖关系，参考官方文档，</p><p><img src="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/requiresDependencyResolution.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/03/30/maven-plugin-development-tips/requiresDependencyResolution.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="requiresDependencyResolution"></p><p>还有一个类似的配置 <code>requiresDependencyCollection</code> 和 <code>requiresDependencyResolution</code> 类似，支持相同的<requiredClassPath>值。区别在于，该配置不会解析依赖关系的文件，即与Maven项目相关的依赖可以缺少一个文件。因此，该注释适用于那些只想分析依赖关系的 mojo，尤其是在生命周期的早期阶段，由于项目尚未建立，完全的依赖关系解析可能会失败。</p><p>配置了这个之后就能通过 <code>Maven-Core</code> 的 <code>MavenProject</code> 类获取所有的依赖</p><h2 id="获取目标工程的-ClassLoader"><a href="#获取目标工程的-ClassLoader" class="headerlink" title="获取目标工程的 ClassLoader"></a>获取目标工程的 ClassLoader</h2><p>再配置了解析依赖信息之后，参考</p><p><a href="https://stackoverflow.com/questions/49737706/access-project-classes-from-a-maven-plugin">Access project classes from a maven plugin</a></p><p>这样自定义一个classloader</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> ClassLoader <span class="title function_">getClassLoader</span><span class="params">(MavenProject project)</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">try</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="type">List</span> <span class="variable">classpathElements</span> <span class="operator">=</span> project.getCompileClasspathElements();</span><br><span class="line">            classpathElements.add( project.getBuild().getOutputDirectory() );</span><br><span class="line">            classpathElements.add( project.getBuild().getTestOutputDirectory() );</span><br><span class="line">            URL urls[] = <span class="keyword">new</span> <span class="title class_">URL</span>[classpathElements.size()];</span><br><span class="line">            <span class="keyword">for</span> ( <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; classpathElements.size(); ++i )</span><br><span class="line">            &#123;</span><br><span class="line">                urls[i] = <span class="keyword">new</span> <span class="title class_">File</span>( (String) classpathElements.get( i ) ).toURL();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">URLClassLoader</span>( urls, <span class="built_in">this</span>.getClass().getClassLoader() );</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">catch</span> ( Exception e )</span><br><span class="line">        &#123;</span><br><span class="line">            getLog().debug( <span class="string">&quot;Couldn&#x27;t get the classloader.&quot;</span> );</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">this</span>.getClass().getClassLoader();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://maven.apache.org/developers/mojo-api-specification.html">Maven – Mojo API Specification</a></p><p><a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html">Maven – Introduction to the Build Lifecycle</a></p><p><a href="https://stackoverflow.com/questions/49737706/access-project-classes-from-a-maven-plugin">Access project classes from a maven plugin</a></p><p><a href="https://stackoverflow.com/questions/67703238/load-project-class-within-maven-mojo">Load project class within maven mojo</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="maven" scheme="https://keshane.moe/tags/maven/"/>
    
    <category term="java" scheme="https://keshane.moe/tags/java/"/>
    
    <category term="maven plugin development" scheme="https://keshane.moe/tags/maven-plugin-development/"/>
    
    <category term="tips" scheme="https://keshane.moe/tags/tips/"/>
    
    <category term="技巧" scheme="https://keshane.moe/tags/%E6%8A%80%E5%B7%A7/"/>
    
  </entry>
  
  <entry>
    <title>搭建饥荒服务器</title>
    <link href="https://keshane.moe/2023/01/12/host-dst-dedicated-server/"/>
    <id>https://keshane.moe/2023/01/12/host-dst-dedicated-server/</id>
    <published>2023-01-12T13:46:15.000Z</published>
    <updated>2026-07-27T14:35:50.453Z</updated>
    
    <content type="html"><![CDATA[<h1 id="搭建饥荒服务器"><a href="#搭建饥荒服务器" class="headerlink" title="搭建饥荒服务器"></a>搭建饥荒服务器</h1><p>在国内的网络环境下，遍布五湖四海，分布不同运营商的同学想要成功的玩一下低延迟、不会回溯的饥荒，在官方服务器上是个很难的事。更难得的事情是在大伙都在上班的时候，不太可能能找到一个稳定在线的人上线启动游戏。所以自建一个位于国内的服务器还是很有必要的。</p><p>推荐直接使用<a href="#%E7%AE%80%E5%8D%95%E7%9A%84%E6%AD%A5%E9%AA%A4%E4%BD%BF%E7%94%A8docker%E6%90%AD%E5%BB%BA%E9%A5%A5%E8%8D%92%E6%9C%8D%E5%8A%A1%E5%99%A8">简单的步骤，使用docker搭建饥荒服务器</a> </p><h2 id="一个比较传统的步骤"><a href="#一个比较传统的步骤" class="headerlink" title="一个比较传统的步骤"></a>一个比较传统的步骤</h2><p>参考这个帖子，需要安装一堆依赖，安装steamcmd</p><p><a href="https://forums.kleientertainment.com/forums/topic/64441-dedicated-server-quick-setup-guide-linux/">Dedicated Server Quick Setup Guide - Linux</a></p><p>*** 总之就是不适合我这种懒人*** </p><p>到这里我突然意识到，前面的步骤好像可以编写一个 docker 来自动搞定</p><h2 id="简单的步骤，使用docker搭建饥荒服务器"><a href="#简单的步骤，使用docker搭建饥荒服务器" class="headerlink" title="简单的步骤，使用docker搭建饥荒服务器"></a>简单的步骤，使用docker搭建饥荒服务器</h2><p>然后我就去搜了一下，发现果然有人已经做了，我这里用的是这一个</p><p><a href="https://github.com/Jamesits/docker-dst-server">https://github.com/Jamesits/docker-dst-server</a></p><p>附上自己的docker-compose文件</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.5&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">dst-server:</span></span><br><span class="line">     <span class="attr">image:</span> <span class="string">jamesits/dst-server:latest</span></span><br><span class="line">     <span class="attr">container_name:</span> <span class="string">dst_server</span></span><br><span class="line">     <span class="attr">restart:</span> <span class="string">&quot;on-failure:5&quot;</span></span><br><span class="line">     <span class="attr">ports:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&quot;10998-11001:10998-11001/udp&quot;</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&quot;12346-12347:12346-12347/udp&quot;</span></span><br><span class="line">     <span class="attr">volumes:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">./data:/data</span></span><br><span class="line">     <span class="attr">stop_grace_period:</span> <span class="string">6m</span></span><br></pre></td></tr></table></figure><p>这里要注意的是port，等会后面会有坑</p><p>到这里，只需要创建一个docker-compose.yml 然后执行一下 <code>docker-compose up</code> 就可以很轻松的跑起来一个饥荒的服务器。第一次运行会在本地生成一些服务器配置文件，需要手动更改</p><p>目录结构大致如下</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Cluster_1<span class="comment">--------------------------------存档根目录</span></span><br><span class="line">    Caves<span class="comment">--------------------------------洞穴文件夹</span></span><br><span class="line">        backup<span class="comment">---------------------------服务器日志及聊天日志存档</span></span><br><span class="line">        save<span class="comment">-----------------------------存档文件夹</span></span><br><span class="line">        leveldataoverride.lua<span class="comment">------------世界配置文件，可以修改这个文件改变世界的特性</span></span><br><span class="line">        modoverrides.lua<span class="comment">-----------------模组配置文件</span></span><br><span class="line">        server_chat_log.txt<span class="comment">--------------服务端本次启动玩家的聊天日志</span></span><br><span class="line">        server_log.txt<span class="comment">-------------------服务器本次运行日志</span></span><br><span class="line">        server.ini<span class="comment">-----------------------世界的配置信息，例如端口等</span></span><br><span class="line">    Master<span class="comment">-------------------------------主世界文件夹</span></span><br><span class="line">        backup<span class="comment">---------------------------服务器日志及聊天日志存档</span></span><br><span class="line">        save<span class="comment">-----------------------------存档文件夹</span></span><br><span class="line">        leveldataoverride.lua<span class="comment">------------世界配置文件，可以修改这个文件改变世界的特性</span></span><br><span class="line">        modoverrides.lua<span class="comment">-----------------模组配置文件</span></span><br><span class="line">        server_chat_log.txt<span class="comment">--------------服务端本次启动玩家的聊天日志</span></span><br><span class="line">        server_log.txt<span class="comment">-------------------服务器本次运行日志</span></span><br><span class="line">        server.ini<span class="comment">-----------------------世界的配置信息，例如端口等</span></span><br><span class="line">    cluster_token.txt<span class="comment">--------------------服务端Token</span></span><br><span class="line">    cluster.ini<span class="comment">--------------------------服务端名称、密码、模式等配置信息</span></span><br></pre></td></tr></table></figure><h2 id="服务器配置"><a href="#服务器配置" class="headerlink" title="服务器配置"></a>服务器配置</h2><h3 id="基本的配置"><a href="#基本的配置" class="headerlink" title="基本的配置"></a>基本的配置</h3><p>登录klei的官网</p><p><a href="https://accounts.klei.com/login">Klei Account</a></p><p>在 “游戏” Tab页面找到饥荒联机版的服务器</p><p><img src="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/game_tab.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/game_tab.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="游戏tab"></p><p><img src="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/game_list_page.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/game_list_page.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="页面"></p><p>点击添加服务器</p><p>然后可以在上方看见你刚刚添加的服务器，点击配置</p><p>这里设置你的服务器的基础配置，注意这个KEY，别的不重要（</p><p><strong>个人推荐在这里就可以停下了，记录下这个KEY，直接去本地新建一个服务器存档</strong> <a href="#%E4%BD%BF%E7%94%A8%E6%9C%AC%E5%9C%B0%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AD%98%E6%A1%A3">使用本地的服务器存档</a> </p><p><img src="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/server_key_page.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/server_key_page.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="key"></p><p><img src="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/server_config_page.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/server_config_page.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="Untitled"></p><p>把你的Key复制到 <code>cluster_token.txt</code> 里面。</p><p>当然也可以把这个设置下载下来，然后可以覆盖你的服务器数据文件</p><h3 id="使用MOD"><a href="#使用MOD" class="headerlink" title="使用MOD"></a>使用MOD</h3><p>基础配置好之后怎么使用MOD呢</p><p>使用mod我们需要编辑mods目录下的 <code>dedicated_server_mods_setup.lua</code> ，添加这种形式的代码</p><p><code>ServerModSetup(&quot;&lt;创意工坊ID&gt;&quot;)</code> </p><p>这里推荐一下使用VSCode的 remote-ssh 贼好用（也有可能是我之前都是直接ssh xxx没用过ssh客户端） ~</p><p><img src="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/vscode.png" class="lazy" data-srcset="https://webp.keshane.moe/2023/01/12/host-dst-dedicated-server/vscode.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="vscode"></p><p>到这里，重启服务器，就可以进入游戏了。</p><p>更多配置可以参考<br><a href="https://steamcommunity.com/sharedfiles/filedetails/?l=schinese&id=1616647350">Dedicated Server配置项和命令行参数详解</a></p><h2 id="使用本地的服务器存档"><a href="#使用本地的服务器存档" class="headerlink" title="使用本地的服务器存档"></a>使用本地的服务器存档</h2><p>可以发现之前的配置还是比较复杂的，特别是想更改世界生成的设置，添加很多的mod的情况下，一个个去创意工坊找显得很愚蠢，明明在饥荒游戏的创建世界界面就能有一个gui进行设置。所以更推荐在本地创建好一个世界，然后复制到服务器上去。</p><ol><li>在本地创建世界</li><li>进入选择人物界面后即可退出当前服务器，并在 <code>文档\Klei\DoNotStarveTogether</code><br>目录下找到刚刚创建的游戏存档文件夹，默认格式为 <code>Cluster_X</code> </li><li>将之前在Klei官网创建的服务器的Key填写到 <code>cluster_token.txt</code> 里面</li><li>把你的存档复制到服务器上面</li></ol><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><p>很重要的一点 <strong>注意 Caves 和 Masters 里面的 <code>server.ini</code></strong></p><p>里面的network部分，这个 server_port 必须要在 docker-compose.yml 里暴露出去</p><p>还有 <strong><code>cluster.ini</code></strong> 中的 [SHARD] 里面的 master_port 也得暴露出去 shard_enabled 得改为 true</p><p>（反正这里和 docker-compose 文件总得改一个地方，推荐改 docker-compose.yml ）</p><h2 id="接下来"><a href="#接下来" class="headerlink" title="接下来"></a>接下来</h2><p>没啥毛病的话，重启一下 <code>docker-compose</code> 就能在服务器大厅里面找到你的服务器了，接下来就可以愉快的玩耍了（</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://dontstarve.fandom.com/wiki/Guides/Don%E2%80%99t_Starve_Together_Dedicated_Servers">Guides&#x2F;Don’t Starve Together Dedicated Servers</a></p><p><a href="https://forums.kleientertainment.com/forums/topic/64441-dedicated-server-quick-setup-guide-linux/">Dedicated Server Quick Setup Guide - Linux</a></p><p><a href="https://developer.valvesoftware.com/wiki/SteamCMD#Linux">SteamCMD</a></p><p><a href="https://github.com/Jamesits/docker-dst-server">https://github.com/Jamesits/docker-dst-server</a></p><p><a href="https://github.com/mathielo/dst-dedicated-server#the-world">https://github.com/mathielo/dst-dedicated-server#the-world</a></p><p><a href="https://www.hxuanyu.com/dst_server.html">Linux 搭建饥荒联机版服务器</a></p><p><a href="https://steamcommunity.com/sharedfiles/filedetails/?l=schinese&id=1616647350">Steam 社区 Dedicated Server配置项和命令行参数详解</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="游戏" scheme="https://keshane.moe/tags/%E6%B8%B8%E6%88%8F/"/>
    
    <category term="饥荒联机版" scheme="https://keshane.moe/tags/%E9%A5%A5%E8%8D%92%E8%81%94%E6%9C%BA%E7%89%88/"/>
    
    <category term="服务器" scheme="https://keshane.moe/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    <category term="docker" scheme="https://keshane.moe/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>乌镇游记</title>
    <link href="https://keshane.moe/2022/10/26/travel-wuzhen/"/>
    <id>https://keshane.moe/2022/10/26/travel-wuzhen/</id>
    <published>2022-10-26T08:43:48.000Z</published>
    <updated>2026-07-27T14:35:50.422Z</updated>
    
    <content type="html"><![CDATA[<h1 id="乌镇游记"><a href="#乌镇游记" class="headerlink" title="乌镇游记"></a>乌镇游记</h1><p>六月的某个周末，我和好友L相约去乌镇玩了一天（顺便去拍拍照）。</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/cameras.png" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/cameras.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="(相机.jpg)"></p><p>我自认为商业化古镇都一个鸟样，里面充斥着各种商业气息的小摊小贩，所以其实兴趣并不是太浓厚，但是实际游玩下来，乌镇的规划确实是比国内很多的古镇要好很多，本次游玩的体验虽然略有遗憾，但是也是非常不错的古镇体验。（毕竟门票150元）</p><h2 id="计划"><a href="#计划" class="headerlink" title="计划"></a>计划</h2><p>根据网上的资料，乌镇主要是分为东栅和西栅，东栅相对来讲没太多的东西，我们本来打算周六下午到达乌镇镇，然后先去东栅玩一会，然后再去西栅，因为对于我们来讲，古镇其实就是走马观花的逛一逛，所以我们预计的时间并不是很长。等到我们决定买票的时候发现了一个问题</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E4%B9%B0%E7%A5%A8.png" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E4%B9%B0%E7%A5%A8.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="购票页面"></p><p>这东栅的门票月售0，这也太诡异了（其实是疫情原因东栅没有开放），于是我们临时取消了东栅游玩的计划，决定直接前往西栅，后来的事实证明这个决定是正确的，因为确实想要玩完乌镇，一天的时间不太够啊。</p><p>由于我对于古镇的个人看法，我们并没有做太多的资料准备，我们在notion上略微的规划了一下</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E8%A7%84%E5%88%92.png" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E8%A7%84%E5%88%92.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="简易的规划...."></p><p>真的是很略微啊（（（</p><p>甚至没去乌镇官网上看，只在各个平台上搜了一下酒店然后发现好像没有西栅内的酒店，这真是规划上的重大失误。</p><p>实际上乌镇西栅内的酒店和民宿是乌镇统一管理的，只在乌镇官网和小程序上提供，价格并没有想象中的那么贵，并且是唯一能够住在西栅里面（或者说可以自由进出）的方案。</p><h2 id="前往"><a href="#前往" class="headerlink" title="前往"></a>前往</h2><p>乌镇并没有高铁直达，所以要吗在周边城市直接坐旅游大巴，要吗做高铁到桐乡然后再做大巴到乌镇客运站（自己有车肯定是坠吼的）。顺带一提，我从杭州出发，发现各个平台的销售的客车票好像都不太相同，反正我是随便买了一个直接到景区的，但是那个客车的师傅好像很不熟练，找不到上高速的路口，结果就是我比预计中晚了快一个小时。</p><p>当天上午其实还在下雨，没想到下午就出大太阳了，墨镜也没带，防晒霜也没带，一路上都只能钻阴影走（</p><h2 id="体验"><a href="#体验" class="headerlink" title="体验"></a>体验</h2><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E5%9C%B0%E5%9B%BE.png" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E5%9C%B0%E5%9B%BE.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="地图"></p><p>整个西栅景区呢，就是图片上这么一块，只需要全部走完一遍就可以了（</p><p>其实可以做游船或者观光车，但是我们都是下午到的，想要进去吃饭，所以就先避开了观光车和游船的起始点，找了个餐馆吃饭。直到离开都没能坐到游船，非常后悔（</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E8%B7%AF%E7%BA%BF.png" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E8%B7%AF%E7%BA%BF.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="路线"></p><p>其实只需要绕着中间这个比较核心的河流走一圈就可以欣赏到大部分的景色，当然也可以去网上看看别人的路线。这里面的木心美术馆是比较独特的，需要单独购买门票。</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E6%9C%A8%E5%BF%83%E7%BE%8E%E6%9C%AF%E9%A6%86.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E6%9C%A8%E5%BF%83%E7%BE%8E%E6%9C%AF%E9%A6%86.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="木心美术馆"></p><p>虽然看着不大，但其实还是要走不少路的，我们在景区内部吃完午饭，基本上是很匆忙的在景区里面逛了一圈时间就很晚了，比较匆忙。</p><p>想要获得更好的体验，最好是在乌镇西栅的酒店（不一定是在西栅里面，指的是乌镇官方运营的酒店，只能在乌镇官网上预定）里面住一晚，这样你购买的西栅门票可以多次进出，不必在里面一次性逛完。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>总的来说乌镇相对于其他的一些江浙一代的古镇而言并没有十分鲜明的特点，只能说规划得比较好，也没有那种缠着你推销或者说在路中把你拦下来吃饭的店主（为什么古镇给我的映像都是这种）。走下来大概需要消耗完整的一天时间，并且会比较匆忙，个人比较推荐的建议是去乌镇官网购买酒店&#x2F;民宿和景区的通票，这样的话中途走累了还能出去一下，不用像我们一样硬着走到底，并且可以不用很匆忙的逛古镇害怕错过什么景点。</p><p>下面是一些照片，在这之前都没怎么用过相机，大部分图片都丢到<a href="https://500px.com.cn/kn1fe">500px_cn</a>上了</p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E7%A5%88%E7%BC%98.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E7%A5%88%E7%BC%98.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="祈缘"></p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E4%B9%8C%E9%95%87%E5%A4%A7%E5%89%A7%E9%99%A2.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E4%B9%8C%E9%95%87%E5%A4%A7%E5%89%A7%E9%99%A2.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="乌镇大剧院"></p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E6%9C%A8%E5%BF%83%E7%BE%8E%E6%9C%AF%E9%A6%86%E5%86%85.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E6%9C%A8%E5%BF%83%E7%BE%8E%E6%9C%AF%E9%A6%86%E5%86%85.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="木心美术馆内"></p><p><img src="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E5%B1%82%E5%B3%A6%E5%8F%A0%E5%B6%82.jpeg" class="lazy" data-srcset="https://webp.keshane.moe/2022/10/26/travel-wuzhen/%E5%B1%82%E5%B3%A6%E5%8F%A0%E5%B6%82.jpeg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="层峦叠嶂的酱缸"></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="旅游" scheme="https://keshane.moe/tags/%E6%97%85%E6%B8%B8/"/>
    
    <category term="生活" scheme="https://keshane.moe/tags/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="乌镇" scheme="https://keshane.moe/tags/%E4%B9%8C%E9%95%87/"/>
    
  </entry>
  
  <entry>
    <title>简单体验一下JetBrains的远程开发方案——Projector</title>
    <link href="https://keshane.moe/2021/11/28/try-jetbrains-projector/"/>
    <id>https://keshane.moe/2021/11/28/try-jetbrains-projector/</id>
    <published>2021-11-28T05:30:50.000Z</published>
    <updated>2026-07-27T14:35:50.408Z</updated>
    
    <content type="html"><![CDATA[<p>作为 Java 开发人员，IDEA 应该是接触得最多的开发工具，如果能够将 IDEA 跑在云端，不限制特定的客户端的话，就能随时随地的加班了（逃Projector 是 JetBrains 开发的远程开发解决方案，根据官方文档的介绍， Projector 最直接的作用就是通过网络远程运行 JetBrains IDE 和 Swing 应用程序。Projector 是一款 C-S 架构的软件，可以使用 Projector 达到 IDE 在服务器上运行，然后本地连接到服务器上部署的 IDE 进行开发的效果，官方提供了一个客户端应用，当然也可以使用网页进行 IDE 的操作。作为一个远程 IDE 的解决方案，他和微软的 VSCode Remote 有很大的不同。</p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/code.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/code.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="远程办公"></p><p>JetBrains 三月发布的 Projector 可能就能满足这种需求。</p><h2 id="Projector-是啥"><a href="#Projector-是啥" class="headerlink" title="Projector 是啥"></a>Projector 是啥</h2><p>Projector 是 JetBrains 开发的远程开发解决方案，根据官方文档的介绍， Projector 最直接的作用就是通过网络远程运行 JetBrains IDE 和 Swing 应用程序。Projector 是一款 C-S 架构的软件，可以使用 Projector 达到 IDE 在服务器上运行，然后本地连接到 IDE 进行开发官方提供了一个客户端应用，当然也可以使用网页进行 IDE 的操作。作为一个远程 IDE 的解决方案，他和微软的 VSCode Remote 有很大的不同</p><ul><li>VSCode Remote 是通过 SSH 连接到远程服务器，对远程文件进行修改，只传输代码等数据，将计算匀给服务器，而渲染显示等还是依赖本地的 VSCode 客户端。</li><li>Projector 是修改了 Swing 的渲染机制，让 Swing 程序通过网络进行渲染，更接近于一个远程桌面的形式，但是仅仅只显示 IDE 窗口。</li></ul><h2 id="体验Projector"><a href="#体验Projector" class="headerlink" title="体验Projector"></a>体验Projector</h2><p>Projector 是 C-S 架构的软件，我们需要分别准备服务端和客户端：</p><p>Projector 的服务端有三种安装方式</p><ul><li>通过官方的 <a href="%5B%5D()">projector-installer</a> 安装脚本进行安装，目前仅支持 linux 安装。</li><li>通过官方提供的 Docker 镜像 <a href="%5B%5D()">projector-docker</a>  安装。</li><li>直接在 JetBrains 的 IDE 上安装 <a href="%5B%5D()">Projector</a>这个插件，这种安装方式会把这个 ide 作为服务器，需要有图形界面的支持。</li></ul><p>官方提供了两种客户端：</p><ul><li>直接通过浏览器访问，这样的好处是不用下载客户端，不用受平台限制，但是会有部分快捷键不能使用。</li><li><a href="%5B%5D()">官方的project-client</a> 这个客户端本质上也是对web进行的一层封装，好处是可以使用一些被浏览器默认占用的快捷键，比如 Ctrl + W 。</li></ul><p>使用 Docker 来运行当然是最简单的方法在 <a href="%5B%5D()">projector-docker</a>  这个项目下，能看到 Intellij 官方提供的 Intellij 平台的 IDE 的 docker 镜像。在这里我们跑一个 Intellij IDEA 社区版试一下</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull registry.<span class="property">jetbrains</span>.<span class="property">team</span>/p/prj/containers/projector-idea-c</span><br><span class="line">docker run --rm -p <span class="number">8887</span>:<span class="number">8887</span> -it registry.<span class="property">jetbrains</span>.<span class="property">team</span>/p/prj/containers/projector-idea-<span class="attr">c</span>:latest</span><br></pre></td></tr></table></figure><p>通过 Docker 跑起来之后访问 8887 端口就能看到熟悉的 IDEA 授权界面</p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_grant.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_grant.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea授权"></p><p>一路点击下去就能看到熟悉的 IDEA 界面啦，默认有一个java文件和一个kotlin文件，这个界面和正常使用的IDEA并没有区别，能够正常的编辑。</p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea界面"></p><p>点击一下运行，就像在本地运行一样能够成功编译、运行，可以在下方的控制台看到结果。</p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_terminal.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_terminal.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea输出"></p><p>一切操作都和本地使用 IDEA 一样，也可以创建 Maven 项目来开发更复杂的需求。</p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_new.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_new.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea新建项目"></p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_maven.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_maven.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="idea maven项目"></p><p>实际使用过程中整体的体验还算完整，看上去一切都很不错，感觉在浏览器上复刻本地 IDE 的体验就快要实现了。不过在体验中我发现还是需要踩一些坑。</p><h2 id="使用中的一些问题"><a href="#使用中的一些问题" class="headerlink" title="使用中的一些问题"></a>使用中的一些问题</h2><p>使用中影响最大的问题是如下两个，目前都有解决方案</p><ul><li>最主要的问题就是 IDE 快捷键和浏览器冲突，比如用于选中代码的 Ctrl-W，在浏览器中就变成关闭网页窗口了，实在是有些难受。解决方法就是使用 Jetbrains 提供的 Projector 客户端，但是都要另外再下一个客户端了，我为什么不直接用本地的 IDE 呢。</li><li>默认无法使用输入法，最初使用的时候我是在外面把字打好复制进去。经过一番搜索，根据 YouTrack 上的这个 Issue <a href="%5B%5D()">Support for IME</a>  通过加上页面参数 inputMethod&#x3D;ime 可以启用输入法。不过这个功能默认关闭。</li></ul><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/ime_param.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/ime_param.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p><img src="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_input_method.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/11/28/try-jetbrains-projector/idea_input_method.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="使用输入法"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Projector 目前依然是一个非常新的技术，在使用当中如果是低延迟的环境下能够获得和本地 IDE 类似的环境，但是有一些问题依然出现。在各家都在发力远程办公的今天，Projector 目前的体验很难称得上是远程 IDE 的最佳解决方案。这种更改 Swing 渲染机制然后通过 Canvas 绘制的方式相较于直接使用 Web 技术的在线 IDE 总感觉有些怪怪的。总的来说使用 Projector IDEA 目前的水平只能称得上能用，它尽力的把本地 IDE 的体验搬上了云端，但是目前的一些小问题还需要更多的完善。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="Projector" scheme="https://keshane.moe/tags/Projector/"/>
    
    <category term="云ide" scheme="https://keshane.moe/tags/%E4%BA%91ide/"/>
    
    <category term="Jetbrains - Intellij IDEA" scheme="https://keshane.moe/tags/Jetbrains-Intellij-IDEA/"/>
    
  </entry>
  
  <entry>
    <title>使用树莓派进行室温监测</title>
    <link href="https://keshane.moe/2021/07/11/house-temperature-monitor/"/>
    <id>https://keshane.moe/2021/07/11/house-temperature-monitor/</id>
    <published>2021-07-11T13:21:58.000Z</published>
    <updated>2026-07-27T14:35:50.417Z</updated>
    
    <content type="html"><![CDATA[<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>自从购买了树莓派之后，树莓派就呆在家里的角落里当一个无情的转发机器，恰好最近天气越来越热，所以想要一个东西统计一下家庭室温，就盯上了原本闲置在角落里的树莓派。（原本是想体验一把hassio做智能家居的）</p><h2 id="树莓派温度传感器选择"><a href="#树莓派温度传感器选择" class="headerlink" title="树莓派温度传感器选择"></a>树莓派温度传感器选择</h2><p>一般我们在网上能够搜索到的教程中树莓派的温度传感器选择基本上有2种，一种是DS18B20这样的传感器，只能采集温度，使用起来感觉比较方便，只需要读取文件。还有一种是是DHT11&#x2F;DHT22这种的，可以采集温度和湿度，DHT22精度更高，但是使用起来略微要复杂一点点。在神奇的淘宝上面可以买到上述芯片的封装模块，DS18B20模块大概5块钱1个DHT11&#x2F;DHT22分别要10、20块钱一个。</p><p>具体不同的温度传感器对比可以参考<a href="https://randomnerdtutorials.com/dht11-vs-dht22-vs-lm35-vs-ds18b20-vs-bme280-vs-bmp180/">https://randomnerdtutorials.com/dht11-vs-dht22-vs-lm35-vs-ds18b20-vs-bme280-vs-bmp180/</a></p><p>本篇文章使用的传感器为DS18B20。</p><h2 id="传感器的连接"><a href="#传感器的连接" class="headerlink" title="传感器的连接"></a>传感器的连接</h2><p>在某宝上买了一个传感器模块之后，我们需要把模块和树莓派进行连接，模块长这个样子</p><p><img src="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/ds18b20.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/ds18b20.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="DS18B20模块"></p><p>3个引脚从左到右分别是电源，数据，接地</p><p><img src="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/raspberry-gpio.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/raspberry-gpio.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="树莓派4B GPIO示意图"></p><p>然后再找一个对应型号的树莓派的GPIO图例进行连接就好，电源接入5V的那个</p><p>我这里接入的是2,7,6这三个接口</p><p>注意要用母对母的杜邦线进行连接（</p><h2 id="在树莓派上读取数据"><a href="#在树莓派上读取数据" class="headerlink" title="在树莓派上读取数据"></a>在树莓派上读取数据</h2><p>按照某些教程所讲的，应该要打开配置文件 sudo nano &#x2F;boot&#x2F;config.txt 在最后一行手动添加</p><p>dtoverlay&#x3D;w1-gpio-pullup,gpiopin&#x3D;&lt;你连接的gpio&gt;，保存并重启树莓派。</p><p>然后我发现我的&#x2F;boot下面并没有config.txt，在查了一波资料之后发现是我没有挂载boot分区，通过fdisk -l找到boot分区 mount &#x2F;dev&#x2F;xxxxxxx &#x2F;boot 之后就在&#x2F;boot下发现了config.txt</p><p>在config.txt的最后加上一行</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dtoverlay=w1-gpio</span><br></pre></td></tr></table></figure><p>重启之后就能在&#x2F;sys&#x2F;bus&#x2F;w1&#x2F;devices&#x2F;下面看到自己的设备，我这里叫28-01204409fc7c<strong>，进入目录后</strong>温度数据在temperature这个文本文件下面，直接读取这个文件就好了。</p><p>需要注意的是这个温度需要除以1000才是我们平时所熟知的温度单位。</p><h2 id="数据的存储和可视化"><a href="#数据的存储和可视化" class="headerlink" title="数据的存储和可视化"></a>数据的存储和可视化</h2><h3 id="数据的存储"><a href="#数据的存储" class="headerlink" title="数据的存储"></a>数据的存储</h3><p>这一块有很多的解决方案，我用的influxdb进行数据存储和可视化，参考<a href="https://docs.influxdata.com/influxdb/v2.0/install/">官方文档</a>安装influxdb之后，访问8086端口进行一些配置，然后创建一个bucket。为了方便，我这里采用了一个最简单的方案，用python写了一个简单的脚本，然后通过crontab没隔5分钟执行一次脚本。脚本的内容是读取传感器数据并写入influxdb里面，这样只需要调整cron表达式就能调整采集频率。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> influxdb_client <span class="keyword">import</span> InfluxDBClient, Point, WritePrecision</span><br><span class="line"><span class="keyword">from</span> influxdb_client.client.write_api <span class="keyword">import</span> SYNCHRONOUS</span><br><span class="line"></span><br><span class="line">token = <span class="string">&quot;&lt;your_token&gt;&quot;</span></span><br><span class="line">org = <span class="string">&quot;&lt;your_organization&gt;&quot;</span></span><br><span class="line">bucket = <span class="string">&quot;home-temperature&quot;</span></span><br><span class="line">url = <span class="string">&quot;&lt;your_url&gt;&quot;</span></span><br><span class="line"></span><br><span class="line">read_temp = <span class="number">0.0</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/sys/bus/w1/devices/28-01204409fc7c/temperature&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    read_temp = (<span class="built_in">float</span>)(f.read())</span><br><span class="line"></span><br><span class="line">real_temp = read_temp/<span class="number">1000.0</span></span><br><span class="line"><span class="built_in">print</span>(real_temp)</span><br><span class="line"></span><br><span class="line">client = InfluxDBClient(url=url, token=token)</span><br><span class="line">write_api = client.write_api(write_options=SYNCHRONOUS)</span><br><span class="line">point = Point(<span class="string">&quot;home_temperature&quot;</span>).tag(<span class="string">&quot;host&quot;</span>, <span class="string">&quot;&lt;your_host&gt;&quot;</span>).field(<span class="string">&quot;temperature&quot;</span>,real_temp).time(datetime.utcnow(), WritePrecision.NS)</span><br><span class="line">write_api.write(bucket, org, point)</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 每五分钟执行一次</span><br><span class="line">*/5 * * * * python3 /path/to/your/temperature.py</span><br></pre></td></tr></table></figure><h3 id="数据可视化"><a href="#数据可视化" class="headerlink" title="数据可视化"></a>数据可视化</h3><p><img src="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo2.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="influxdb实例"></p><p>通过influxdb2.0自带的界面就可以进行很好的可视化，点击Boards新建一个DashBoard，然后Add Cell，这里面通过点点点就能快速的生成查询语句和图像。</p><p><img src="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo3.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="influxdb配置"></p><p>当然如果会一些基本的查询语句，就可以用grafana等其他的展示界面了。</p><p><img src="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo4.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/07/11/house-temperature-monitor/demo4.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="grafana配置"></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://shumeipai.nxez.com/2018/05/16/dht11-temperature-and-humidity-sensor-raspberry-pi.html">https://shumeipai.nxez.com/2018/05/16/dht11-temperature-and-humidity-sensor-raspberry-pi.html</a></p><p><a href="https://zhuanlan.zhihu.com/p/57087906">https://zhuanlan.zhihu.com/p/57087906</a></p><p><a href="https://www.raspberrypi.org/forums/viewtopic.php?t=148529">https://www.raspberrypi.org/forums/viewtopic.php?t=148529</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="树莓派" scheme="https://keshane.moe/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
    <category term="室温" scheme="https://keshane.moe/tags/%E5%AE%A4%E6%B8%A9/"/>
    
    <category term="influxdb" scheme="https://keshane.moe/tags/influxdb/"/>
    
  </entry>
  
  <entry>
    <title>如何在 IntelliJ IDEA 插件中动态的生成psi代码</title>
    <link href="https://keshane.moe/2021/05/06/intellij-idea-gen-psi-element/"/>
    <id>https://keshane.moe/2021/05/06/intellij-idea-gen-psi-element/</id>
    <published>2021-05-06T11:37:21.000Z</published>
    <updated>2026-07-27T14:35:50.416Z</updated>
    
    <content type="html"><![CDATA[<p>在公司的主要工作内容是维护公司内部框架的开发工具，就是 Eclipse 和 IDEA 平台的插件，这两个平台的在国内互联网几乎找不到文章，真是非常小众，今天聊一下我在工作中遇到的一个问题。</p><h2 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求</h2><p>我们内部其实有一个类似lombok的包，用于给公司内部的框架对应的一些数据生成相应的代码，比如在类上注解@Field({“ddd_ddd”})就会生成对应的字段和getter&#x2F;setter。和lombok类似，这个也是在编译时的Annotation Processing生成代码。</p><p>关于lombok的原理可以查看</p><p><a href="https://www.cnblogs.com/vipstone/p/12597756.html">https://www.cnblogs.com/vipstone/p/12597756.html</a></p><p><a href="https://blog.mythsman.com/post/5d2c11c767f841464434a3bf/">https://blog.mythsman.com/post/5d2c11c767f841464434a3bf/</a></p><h2 id="一些问题"><a href="#一些问题" class="headerlink" title="一些问题"></a>一些问题</h2><p>如果使用记事本进行开发，这种使用方式呢是不会有问题的。但是由于现代的ide都非常智能，能够在开发编码时进行错误校验，那么这种在编译时才生成的代码在ide里面就会显示报错，并且不会有代码提示，使用起来非常不便，所以一般情况下要使用lombok就还需要使用对应ide的插件来解决这个问题。</p><h2 id="lombok源码阅读"><a href="#lombok源码阅读" class="headerlink" title="lombok源码阅读"></a>lombok源码阅读</h2><p>在Jetbrain官方的开发文档中并没有讲这一部分的内容，而网上这一块的资料也比较少，所以只能去看一下lombok插件的源码。</p><p>Intellij平台插件都需要一个声明文件plugin.xml，声明插件的内容。<a href="https://plugins.jetbrains.com/docs/intellij/welcome.html?from=jetbrains.org">https://plugins.jetbrains.com/docs/intellij/welcome.html?from=jetbrains.org</a></p><p>当然现在版本的lombok-idea插件已经非常复杂了，我们可以把版本回退到早期的commit，这时候plugin.xml里还没有多少东西</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">idea-plugin</span> <span class="attr">version</span>=<span class="string">&quot;2&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>Lombook Plugin<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>A plugin that adds first-class support for Project Lombok<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">vendor</span>&gt;</span>Michail Plushnikov<span class="tag">&lt;/<span class="name">vendor</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">idea-version</span> <span class="attr">since-build</span>=<span class="string">&quot;8000&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">application-components</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- Add your application components here --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">component</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">implementation-class</span>&gt;</span>de.plushnikov.intellij.plugin.LombokLoader<span class="tag">&lt;/<span class="name">implementation-class</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">component</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">application-components</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">project-components</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- Add your project components here --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">project-components</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">actions</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- Add your actions here --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">actions</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">extensions</span> <span class="attr">defaultExtensionNs</span>=<span class="string">&quot;com.intellij&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- Add your extensions here --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">lang.psiAugmentProvider</span> <span class="attr">implementation</span>=<span class="string">&quot;de.plushnikov.intellij.plugin.provider.LombokAugmentProvider&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">implicitUsageProvider</span> <span class="attr">implementation</span>=<span class="string">&quot;de.plushnikov.intellij.plugin.provider.LombokImplicitUsageProvider&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">renameHandler</span> <span class="attr">implementation</span>=<span class="string">&quot;de.plushnikov.intellij.plugin.handler.LombokElementRenameHandler&quot;</span> <span class="attr">order</span>=<span class="string">&quot;first&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">treeGenerator</span> <span class="attr">implementation</span>=<span class="string">&quot;de.plushnikov.intellij.lombok.psi.MyLightMethodTreeGenerator&quot;</span>/&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;refactoring.changeSignatureUsageProcessor implementation=&quot;&quot;/&gt;--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;refactoring.safeDeleteProcessor      --&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;refactoring.moveHandler implementation=&quot;de.plushnikov.intellij.plugin.handler.LombokElementMoveHandler&quot; order=&quot;first&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">extensions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">idea-plugin</span>&gt;</span></span><br></pre></td></tr></table></figure><p>里面重要的参数就是这个 lang.psiAugmentProvider ，但是离谱的是官方文档里面对这个完全没有任何介绍。经过谷歌之后找到了一点介绍 <a href="https://intellij-support.jetbrains.com/hc/en-us/community/posts/206127669-Documentation-or-explanation-of-PsiAugmentProvider-">Idea社区</a><br><a href="https://blog.csdn.net/ExcellentYuXiao/article/details/80273347">CSDN</a> 那么查过资料之后就能很容易的知道这是干什么的了，这个东西是 IDEA 动态获取每个文件的 psi，添加相应的方法和字段， psi 是 IDEA 内部解析文件和语义转换的一层抽象模型</p><blockquote><p>The Program Structure Interface, commonly referred to as just PSI, is the layer in the IntelliJ Platform responsible for parsing files and creating the syntactic and semantic code model that powers so many of the platform’s features.</p></blockquote><p>对应到Java程序就是PsiJavaFile,PsiClass,PsiMethod,PsiField对应java文件，java类，方法，字段。</p><h2 id="生成一个Getter试试"><a href="#生成一个Getter试试" class="headerlink" title="生成一个Getter试试"></a>生成一个Getter试试</h2><p>PsiAugmentProvider 继承之后需要重写 getAugments 方法，需要传入3个参数（旧版本2个）PsiElement element， Class<Psi> type, nameHint。其中element是当前需要扩展psi的 psi 模型。type 是当前所需要的 psi 类型可以通过 type.isAssignableFrom(Class cls) 来判断当前需要的到底是什么 psi 模型。返回值是一个Psi类型的List，这个 list 只是新增的 psi，而 IDEA 自带的该有还是有。</p><p>我们需要给标记为 Getter 的字段生成 psi 的 getter 方法，那么我们需要判断一下当前需要的是否是方法</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">boolean</span> <span class="variable">isMethod</span> <span class="operator">=</span> type.isAssignableFrom(PsiMethod.class); </span><br></pre></td></tr></table></figure><p>如果是方法, 然后可以通过 psiclass 可以获取里面的字段</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psiClass.getOwnFields();</span><br></pre></td></tr></table></figure><p>或者复杂点</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Arrays.stream(psiClass.getChildren()).filter(PsiField::isInstance).map(PsiField.class::cast).collect(Collectors.toList());</span><br></pre></td></tr></table></figure><p>遍历每一个字段，通过PsiField的getAnnotations方法获取他的注解，通过getQualifiedName()可以获得注解的完整包名，这样就能判断每个字段上是否有对应的注解。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">PsiAnnotation[] annotations = psiField.getAnnotations();</span><br><span class="line"><span class="keyword">for</span> (PsiAnnotation annotation : annotations) &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">annoName</span> <span class="operator">=</span> annotation.getQualifiedName();</span><br><span class="line">    <span class="comment">// 必须填完整包名</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="string">&quot;pkg1.MyAnnotation&quot;</span>.equals(annoName)) &#123;</span><br><span class="line">        result.add((Psi) createGetterMethod(psiField));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>生成对应的Psi代码的话可以使用 Idea 提供的类 LightMethodBuilder 。不过可以自己继承一下便于后面生成Structure时使用</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> psiField.getName();</span><br><span class="line"><span class="type">String</span> <span class="variable">methodName</span> <span class="operator">=</span> fieldName.substring(<span class="number">0</span>, <span class="number">1</span>).toUpperCase() + fieldName.substring(<span class="number">1</span>);</span><br><span class="line"><span class="type">String</span> <span class="variable">getterName</span> <span class="operator">=</span> <span class="string">&quot;get&quot;</span> + methodName;</span><br><span class="line"><span class="type">LightMethodBuilder</span> <span class="variable">methodBuilder</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LightMethodBuilder</span>(psiField.getManager(), JavaLanguage.INSTANCE, getterName);</span><br><span class="line">methodBuilder.addModifier(PsiModifier.PUBLIC);</span><br><span class="line">methodBuilder.setMethodReturnType(psiField.getType());</span><br><span class="line">methodBuilder.setNavigationElement(psiField);</span><br><span class="line">methodBuilder.setContainingClass(psiField.getContainingClass());</span><br><span class="line"><span class="type">boolean</span> <span class="variable">isStatic</span> <span class="operator">=</span> psiField.hasModifierProperty(PsiModifier.STATIC);</span><br><span class="line"><span class="keyword">if</span> (isStatic) &#123;</span><br><span class="line">    methodBuilder.addModifier(PsiModifier.STATIC);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后对应的getter方法就有了</p><p><img src="https://webp.keshane.moe/2021/05/06/intellij-idea-gen-psi-element/getter.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/05/06/intellij-idea-gen-psi-element/getter.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="getter"></p><p>但是只是做到这一步我们并不能在Structure的界面中看到生成的方法</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">depends</span>&gt;</span>com.intellij.modules.platform<span class="tag">&lt;/<span class="name">depends</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">depends</span>&gt;</span>com.intellij.modules.lang<span class="tag">&lt;/<span class="name">depends</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">depends</span>&gt;</span>com.intellij.modules.java<span class="tag">&lt;/<span class="name">depends</span>&gt;</span></span><br></pre></td></tr></table></figure><p>我们需要再实现一个lang.structureViewExtension扩展点。</p><p>实现getChildren，需要将传入的类中自己生成的psi模型转化成PsiTreeElement</p><p>这里直接复制的lombok的源码</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">  <span class="keyword">public</span> StructureViewTreeElement[] getChildren(PsiElement parent) &#123;</span><br><span class="line">      <span class="keyword">final</span> <span class="type">PsiClass</span> <span class="variable">parentClass</span> <span class="operator">=</span> (PsiClass) parent;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">final</span> Stream&lt;PsiFieldTreeElement&gt; lombokFields = Arrays.stream(parentClass.getFields())</span><br><span class="line">              .filter(LombokLightFieldBuilder.class::isInstance)</span><br><span class="line">              .map(psiField -&gt; <span class="keyword">new</span> <span class="title class_">PsiFieldTreeElement</span>(psiField, <span class="literal">false</span>));</span><br><span class="line"></span><br><span class="line">      <span class="keyword">final</span> Stream&lt;PsiMethodTreeElement&gt; lombokMethods = Arrays.stream(parentClass.getMethods())</span><br><span class="line">              .filter(LombokLightMethodBuilder.class::isInstance)</span><br><span class="line">              .map(psiMethod -&gt; <span class="keyword">new</span> <span class="title class_">PsiMethodTreeElement</span>(psiMethod, <span class="literal">false</span>));</span><br><span class="line"></span><br><span class="line">      <span class="keyword">final</span> Stream&lt;JavaClassTreeElement&gt; lombokInnerClasses = Arrays.stream(parentClass.getInnerClasses())</span><br><span class="line">              .filter(LombokLightClassBuilder.class::isInstance)</span><br><span class="line">              .map(psiClass -&gt; <span class="keyword">new</span> <span class="title class_">JavaClassTreeElement</span>(psiClass, <span class="literal">false</span>));</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> Stream.concat(Stream.concat(lombokFields, lombokMethods), lombokInnerClasses)</span><br><span class="line">              .toArray(StructureViewTreeElement[]::<span class="keyword">new</span>);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>这样在Structure界面中就能看见自己生成的方法了</p><p><img src="https://webp.keshane.moe/2021/05/06/intellij-idea-gen-psi-element/structureview.png" class="lazy" data-srcset="https://webp.keshane.moe/2021/05/06/intellij-idea-gen-psi-element/structureview.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="structureview.png"></p><h2 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h2><p>由于没有加上缓存，所以这里只要在编辑框中随便按键，左侧的Strucure中就会刷新一下，其他地方虽然没有刷新但是感觉对性能也产生了影响。</p><p>那么，加个缓存吧</p><p>Psi中有个方法，putUserData。传入Key和Value，这里的Key是通过Key.create创建的，然后在Value放入生成的PsiMethod就行了。最后在生成代码之前检查一下是否已经创建过。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//存放一个静态变量，不然每次Key.create创建出来的都是新的变量</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> Key&lt;PsiMethod&gt; GETTER_KEY = Key.create(<span class="string">&quot;MyGetter&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加缓存</span></span><br><span class="line">psiClass.putUserData(GETTER_KEY),psiMethod);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 判断</span></span><br><span class="line"><span class="keyword">if</span> (psiField.getUserData(GETTER_KEY) != <span class="literal">null</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> psiField.getUserData(GETTER_KEY);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="小小的总结"><a href="#小小的总结" class="headerlink" title="小小的总结"></a>小小的总结</h2><p>ide的插件开发是真的小众，国内互联网上的资料真是非常少，很多东西都要去找有类似功能的已有插件看<del>抄</del>源码，希望这篇文章能给不幸和我一样踏上写插件这条路的人一些帮助。<br><a href="https://github.com/KnifeC/Intellij-PsiAugmentProvider-Demo">这里有一个Demo</a>可以参考一下，也可以看下 Lombok 的 Idea 插件</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="IntelliJ IDEA" scheme="https://keshane.moe/tags/IntelliJ-IDEA/"/>
    
    <category term="Jetbrain" scheme="https://keshane.moe/tags/Jetbrain/"/>
    
    <category term="插件" scheme="https://keshane.moe/tags/%E6%8F%92%E4%BB%B6/"/>
    
    <category term="ide" scheme="https://keshane.moe/tags/ide/"/>
    
  </entry>
  
  <entry>
    <title>关于前后端分离的项目对接cas单点登录的一些问题</title>
    <link href="https://keshane.moe/2021/02/13/using-cas-in-front-back-separation-project/"/>
    <id>https://keshane.moe/2021/02/13/using-cas-in-front-back-separation-project/</id>
    <published>2021-02-13T11:26:49.000Z</published>
    <updated>2026-07-27T14:35:50.416Z</updated>
    
    <content type="html"><![CDATA[<h1 id="关于前后端分离的项目对接cas单点登录的一些问题"><a href="#关于前后端分离的项目对接cas单点登录的一些问题" class="headerlink" title="关于前后端分离的项目对接cas单点登录的一些问题"></a>关于前后端分离的项目对接cas单点登录的一些问题</h1><h2 id="简单介绍一下情况"><a href="#简单介绍一下情况" class="headerlink" title="简单介绍一下情况"></a>简单介绍一下情况</h2><p>最近在公司内的一个不正经项目上遇到了一些问题，我们的项目是前后端分离的，在对接公司的cas单点登录时遇到了一些问，简单记录一下解决的方案，也不清楚这么做是不是对的。</p><p>本文会涉及 cas，单点登录，cookie，session</p><h2 id="什么是cas"><a href="#什么是cas" class="headerlink" title="什么是cas"></a>什么是cas</h2><p>CAS，CAS全称为Central Authentication Service即中央认证服务，是一个单点登录的解决方案，具体的可以去github仓库看看</p><p><a href="https://github.com/apereo/cas">https://github.com/apereo/cas</a></p><p>具体的特征什么的可以参考这个</p><p>The following features are supported by the CAS project:</p><ul><li>CAS v1, v2 and v3 Protocol</li><li>SAML v1 and v2 Protocol</li><li>OAuth v2 Protocol</li><li>OpenID &amp; OpenID Connect Protocol</li><li>WS-Federation Passive Requestor Protocol</li><li>Authentication via JAAS, LDAP, RDBMS, X.509, Radius, SPNEGO, JWT, Remote, Apache Cassandra, Trusted, BASIC, Apache Shiro, MongoDb, Pac4J and more.</li><li>Delegated authentication to WS-FED, Facebook, Twitter, SAML IdP, OpenID, OpenID Connect, CAS and more.</li><li>Authorization via ABAC, Time&#x2F;Date, REST, Internet2’s Grouper and more.</li><li>HA clustered deployments via Hazelcast, Ehcache, JPA, Apache Cassandra, Memcached, Apache Ignite, MongoDb, Redis, DynamoDb, Couchbase and more.</li><li>Application registration backed by JSON, LDAP, YAML, Apache Cassandra, JPA, Couchbase, MongoDb, DynamoDb, Redis and more.</li><li>Multifactor authentication via Duo Security, YubiKey, RSA, Google Authenticator, U2F, WebAuthn and more.</li><li>Administrative UIs to manage logging, monitoring, statistics, configuration, client registration and more.</li><li>Global and per-application user interface theme and branding.</li><li>Password management and password policy enforcement.</li><li>Deployment options using Apache Tomcat, Jetty, Undertow, packaged and running as Docker containers.</li></ul><h3 id="cas登录步骤"><a href="#cas登录步骤" class="headerlink" title="cas登录步骤"></a>cas登录步骤</h3><p>如果你去网上搜索cas的登录步骤大概会看到一张非常复杂的图片</p><p>然后下面列出123456789…..</p><p>看上去就很头疼，但是实际上不需要这么复杂的去理解</p><p><del>把大象放进冰箱只需要3步</del></p><ol><li>用户访问我们的网站，此时发现用户没有登陆，跳转到cas服务器对应的地址&#x2F;cas&#x2F;login?service&#x3D;{backend_url}</li><li>用户在cas上进行登录</li><li>由cas跳转回我们的系统，此时由cas的客户端完成登录。</li></ol><h2 id="传统的对接方法"><a href="#传统的对接方法" class="headerlink" title="传统的对接方法"></a>传统的对接方法</h2><p>按照传统功夫的对接方法，我们需要在项目中配置cas客户端的拦截器，然后由cas的拦截器来验证我们的请求，进行验证和跳转。</p><p>在我个人的实践中发现其实cas拦截器的跳转功能可以由我们自己手动进行跳转，cas客户端的拦截器是基于session中是否存在const_cas_assertion参数进行拦截，而我们的系统需要进行一些手动的更改。所以在这里没有使用cas客户端的拦截器，使用自己编写的拦截器进行校验，然后发现session里取不到值，在查了一些资料之后发现从cas跳转回我们的系统之后必须使用cas客户端的拦截器进行拦截。</p><p>为什么必须用cas客户端的拦截器进行拦截，而不能自己在跳转后进行拦截呢，这就要深入一下cas跳转回我们的系统之后进行的验证过程了，cas跳转回自己的系统中的url上会带上一个参数ticket并写入一个名为CASTGC的cookie值，而cas的客户端会根据这些信息去验证是否登录。那么传统的cas对接只需要简单的配置一下cas的拦截器就好</p><p>如果后端使用springboot的话</p><p>参考 ： <a href="https://github.com/apereo/java-cas-client#spring-boot-autoconfiguration">https://github.com/apereo/java-cas-client#spring-boot-autoconfiguration</a></p><p>只需要在配置文件中加上</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cas.<span class="property">server</span>-url-prefix=<span class="attr">https</span>:<span class="comment">//cashost.com/cas</span></span><br><span class="line">cas.<span class="property">server</span>-login-url=<span class="attr">https</span>:<span class="comment">//cashost.com/cas/login</span></span><br><span class="line">cas.<span class="property">client</span>-host-url=<span class="attr">https</span>:<span class="comment">//casclient.com</span></span><br></pre></td></tr></table></figure><p>然后在启动类上加上注解</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">@SpringBootApplication</span><br><span class="line">@Controller</span><br><span class="line">@EnableCasClient</span><br><span class="line">public class MyApplication &#123; .. &#125;</span><br></pre></td></tr></table></figure><p>就基本算是上可以使用了</p><h2 id="前后端分离下的问题和我的解决方案"><a href="#前后端分离下的问题和我的解决方案" class="headerlink" title="前后端分离下的问题和我的解决方案"></a>前后端分离下的问题和我的解决方案</h2><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>首先一个问题就是哪怕cas登录了前后端涉及跨域问题，而标准的cas客户端验证是基于cookie和session的，如果不做任何处理的话会导致所有的请求都爆炸掉，后端也无法争取的拿到值。</p><p>第二个问题就是虽然拦截器能够拦截请求，但是会自动进行跳转，并且这个过程在前端通过跨域请求的情况下会出现问题，所以要想办法绕过这个过程由我们手动进行跳转。</p><h3 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h3><p>为了解决这两个问题呢机智的我想出了这么一个比较笨拙的方法。</p><p>cas客户端的拦截器只负责拦截一个接口，然后其他的接口交给我自己的拦截器进行控制，然后跳转的情况下只需要传递给cas服务器的service参数跳转回这个被cas客户端拦截的接口就好。在这个接口中获取对应的数据，然后后面的就简单了，可以将数据和一个sessionid存入缓存中，也可以生成jwt进行验证，然后想办法把这个sessionid或者jwt传给前端，然后前端后续的请求都在header中带上这个值。自己的拦截器只需要进行这些简单的判断并且在没有登陆的情况下返回401错误，然后前端进行跳转。</p><p>首先配置一下cas客户端的配置，只拦截我们手写的login接口</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cas.<span class="property">validation</span>-url-patterns=<span class="regexp">/api/</span>login</span><br></pre></td></tr></table></figure><p>然后前端直接跳转到这个接口，就会被重定向到cas登陆的界面</p><p>在cas系统中完成登录之后就会跳转回这个接口，cas客户端的拦截器回验证是否登陆，我们在这个接口中跳转到前端的页面，并将sessionid发送给前端，这里发送sessionid是通过url参数发送的，暂时没有想出什么其他的好方法。</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">@<span class="title class_">GetMapping</span>(<span class="string">&quot;/login&quot;</span>)</span><br><span class="line">    public <span class="keyword">void</span> <span class="title function_">redirectView</span>(<span class="params">HttpServletResponse response, HttpServletRequest request</span>) &#123;</span><br><span class="line">        <span class="title class_">HttpSession</span> session = request.<span class="title function_">getSession</span>();</span><br><span class="line">        <span class="title class_">Object</span> casAssertion = session.<span class="title function_">getAttribute</span>(<span class="title class_">CasConstants</span>.<span class="property">CAS_SESSION_KEY</span>);</span><br><span class="line">        <span class="title class_">Assertion</span> assertion = (<span class="title class_">Assertion</span>) casAssertion;</span><br><span class="line">        <span class="title class_">String</span> sessionId = session.<span class="title function_">getId</span>();</span><br><span class="line">        <span class="title class_">String</span> userAccount = assertion.<span class="title function_">getPrincipal</span>().<span class="title function_">getName</span>();</span><br><span class="line">        <span class="title class_">UserDetailModel</span> detail = userDetailService.<span class="title function_">getUserDetailByAccount</span>(userAccount);</span><br><span class="line">        <span class="title class_">UserLoginModel</span> cacheModel = <span class="keyword">new</span> <span class="title class_">UserLoginModel</span>(sessionId, userAccount, detail);</span><br><span class="line">        <span class="title class_">CasCacheUtil</span>.<span class="title function_">put</span>(sessionId, cacheModel);</span><br><span class="line">        log.<span class="title function_">info</span>(<span class="string">&quot;用户登录: &quot;</span> + userAccount + <span class="string">&quot; ,JSESSIONID: &quot;</span> + sessionId);</span><br><span class="line">        <span class="title class_">String</span> url = casConfig.<span class="property">CLIENT_FRONT_URL</span> + <span class="string">&quot;?JSESSIONID=&quot;</span> + sessionId;</span><br><span class="line">        response.<span class="title function_">addHeader</span>(<span class="title class_">CasConstants</span>.<span class="property">AUTHORAZATION</span>, session.<span class="title function_">getId</span>());</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            response.<span class="title function_">sendRedirect</span>(url);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (<span class="title class_">IOException</span> e) &#123;</span><br><span class="line">            e.<span class="title function_">printStackTrace</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>然后前端之后的每次请求都会带上Authorization头部，我们自己的拦截器中进行验证。如果没有登陆则抛出401错误，前端拿到这个错误之后就跳转到登陆接口。</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">public <span class="keyword">class</span> <span class="title class_">LoginInterceptor</span> <span class="keyword">extends</span> <span class="title class_ inherited__">HandlerInterceptorAdapter</span> &#123;</span><br><span class="line"></span><br><span class="line">    @<span class="title class_">Override</span></span><br><span class="line">    public boolean <span class="title function_">preHandle</span>(<span class="title class_">HttpServletRequest</span> request, <span class="title class_">HttpServletResponse</span> response, <span class="title class_">Object</span> handler) throws <span class="title class_">Exception</span> &#123;</span><br><span class="line">        <span class="title class_">String</span> uri = request.<span class="title function_">getRequestURI</span>();</span><br><span class="line">        <span class="comment">// 放行登录</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="title class_">StringUtils</span>.<span class="title function_">equalsIgnoreCase</span>(<span class="string">&quot;/api/login&quot;</span>,uri) ) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title class_">String</span> auth = request.<span class="title function_">getHeader</span>(<span class="title class_">CasConstants</span>.<span class="property">AUTHORAZATION</span>);</span><br><span class="line">        <span class="keyword">if</span> (auth == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">returnError</span>(response);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="title class_">UserLoginModel</span> userLoginModel = <span class="title class_">AuthUtil</span>.<span class="title function_">getUserLoginModel</span>(request);</span><br><span class="line">        <span class="keyword">if</span> (userLoginModel == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">returnError</span>(response);</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="keyword">void</span> <span class="title function_">returnError</span>(<span class="title class_">HttpServletResponse</span> response) throws <span class="title class_">IOException</span> &#123;</span><br><span class="line">        <span class="title class_">Map</span>&lt;<span class="title class_">String</span>, <span class="title class_">Object</span>&gt; errorDetails = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        errorDetails.<span class="title function_">put</span>(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;需要登陆&quot;</span>);</span><br><span class="line">        response.<span class="title function_">setStatus</span>(<span class="title class_">HttpStatus</span>.<span class="property">UNAUTHORIZED</span>.<span class="title function_">value</span>());</span><br><span class="line">        response.<span class="title function_">setContentType</span>(<span class="title class_">MediaType</span>.<span class="property">APPLICATION_JSON_UTF8_VALUE</span>);</span><br><span class="line">        response.<span class="title function_">getWriter</span>().<span class="title function_">print</span>(errorDetails.<span class="title function_">toString</span>());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这样通过一个比较复杂的逻辑完成了前后端分离下对接cas单点登录，虽然不太优雅，但能用（</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="cas" scheme="https://keshane.moe/tags/cas/"/>
    
    <category term="前后端分离" scheme="https://keshane.moe/tags/%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB/"/>
    
    <category term="单点登录" scheme="https://keshane.moe/tags/%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95/"/>
    
  </entry>
  
  <entry>
    <title>我为什么喜欢玩游戏</title>
    <link href="https://keshane.moe/2020/09/13/why-i-love-play-games/"/>
    <id>https://keshane.moe/2020/09/13/why-i-love-play-games/</id>
    <published>2020-09-13T16:44:59.000Z</published>
    <updated>2026-07-27T14:35:50.408Z</updated>
    
    <content type="html"><![CDATA[<p>好久没有水博客了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">咕咕咕 咕咕咕咕 咕咕~ 咕~咕咕咕 咕咕 咕咕~咕咕 咕咕咕~ 咕~咕~咕~ 咕~咕咕 咕 咕~咕 咕~咕~咕 咕~咕咕~咕~ 咕咕咕~ 咕咕~ 咕~咕 </span><br></pre></td></tr></table></figure><p>毕业之后这几个月发生了许多事情。租房，工作等一堆破事真的是让人怀念读书的时光。</p><p>在公司结识了一个朋友（在这里骂一句SB公司，他作为一个完全没有接触过前端的人被拉去写前端，我一个从来没有接触过eclipse插件开发的人被拉去做eclipse插件，应届生真就工具人呗。）。他比较热衷于生活，而我则是一个比较标准的二次元宅男，我们都喜欢玩游戏，但我们的游戏观念都不相同。</p><p>曾经我无法理解为什么有人会在手游里面投入大量的金钱，但和他交流过之后也是终于知道了部分人的想法。不同的人有不同的游戏观念主要取决与另一个问题。</p><h2 id="我们为什么玩游戏"><a href="#我们为什么玩游戏" class="headerlink" title="我们为什么玩游戏"></a>我们为什么玩游戏</h2><p>游戏并不是生活的必须品，没有游戏，我们依然可以过得很快乐。游戏至今在世界上依然不被所有人所认可，游戏甚至还要为枪击案背锅。</p><p>大多数人接触游戏的契机或多或少都缘于周围好友的推荐，或者说是一些来自于网上的推荐，而部分人只是把游戏当作社交的工具（周围的人都在玩我不玩就会显得奇怪），并不是真正觉得游戏好玩，这就是玩游戏的原因——跟风，跟随着潮流玩游戏，只是为了和周围的人有共同的话语，并不是真正想玩游戏。</p><p>而部分人接触游戏之后将游戏当作了自己消解时间的工具，这个可能是大部分人的感受。为什么玩游戏？单纯的就是因为游戏好玩，或者说是找不到其他的比游戏更加好玩的东西。</p><p>还有部分人会去”体验“由设计者所设计的关卡，营造的虚拟世界，并探索其中的角落，尝试”鉴赏“游戏。</p><p>在电子竞技盛行的今天，也有很多人通过电子竞技了解游戏，这些人更多的玩着竞技类的游戏，希望超越对手。</p><p>而在网络游戏和现在大部分抽卡类手游中，部分玩家享受着一种”你无我有“的快感以及抽卡&#x2F;掉装备时获取的快感，通过差异化的物品来满足自己。</p><p>我列举了部分玩家玩游戏的原因，不同的人玩游戏的理由都不相同（当然也有觉得游戏就是电子鸦片的人）。</p><h2 id="不同的游戏理念"><a href="#不同的游戏理念" class="headerlink" title="不同的游戏理念"></a>不同的游戏理念</h2><p>开头说到的那个同学，他玩游戏应该是有两个理由，一个是在网络游戏&#x2F;手机游戏中获取差异化的快感，还有一个就是在各种单机游戏中体验游戏设计者所设计的道具。一次和他一起吃过晚饭后闲聊时他表示，他玩单机游戏基本都是破解版，并且还要开修改器来快速通关&#x2F;解锁道具，除非是那种联机比较困难的游戏才会在steam上买，但他却能在dnf和一些手游中充值大把大把的钱，仅仅是为了一些装备&#x2F;角色（我任然不太理解这种行为）。并在我提出我的疑问之后向我解释</p><blockquote><p>他：”你现在上班之后有那么多时间玩游戏吗？“</p></blockquote><blockquote><p>我：”上班之后时间是挺少的，但是开修改器不是破坏了游戏的乐趣吗？“</p></blockquote><blockquote><p>他：”你想想你没什么时间玩游戏，想要体验游戏的所有内容不是很难吗？你看我开个修改器，几乎所有的道具，关卡都能很快的玩一次，而要自己慢慢解锁的话就很慢。“（其实我在玩黄游的时候也会用修改器快速解锁cg）</p></blockquote><blockquote><p>我：”如果只是为了快速的体会游戏的道具玩游戏就没什么意思了啊。“</p></blockquote><blockquote><p>他：“那你慢慢玩游戏的意思又是什么呢，我这样能玩到所有的物品，体验整个游戏。”</p></blockquote><blockquote><p>我：“那你在网游，手游里充钱的乐趣在哪呢？”</p></blockquote><blockquote><p>他：“当然有乐趣啊，我充了钱，别人没有那些东西，而我有，显得我很牛逼啊。”</p></blockquote><blockquote><p>我：“那你用这个钱买正版游戏不是可以获得更多的乐趣吗。”</p></blockquote><blockquote><p>他：“我靠，那些游戏都好贵啊，我本来不花钱就能玩到，为什么还要花这么多钱买正版。”</p></blockquote><p>（这里吐槽一下，这个人已经离职了，我每次都跟他说我想离职了，但是没想到他比我离职还快。。。）</p><p>。。。。</p><p>由于我是一个非常内向的人，从小的交际圈都比较固定，都是一起玩游戏的人，所以大部分人对于游戏和我的观点都差不多，所以这是我第一次意识到，虽然大家都玩着游戏，虽然玩的种类不同，但是不同的人对于玩游戏的观念出入真的非常大。</p><h2 id="我的一些看法"><a href="#我的一些看法" class="headerlink" title="我的一些看法"></a>我的一些看法</h2><p>首先我并不认可他对游戏消费的相关观念，自从大概初中的时候解除了steam，我基本上所有的pc游戏都是在类似的平台进行购买。而在手游兴起之后也接触过一些手游，不过当今手游大多都是换皮抽卡游戏，虽然抽卡的快感很满足，但是我很少在手游里面投入时间和金钱。手机游戏除了便携性（当然便携度也很重要）各方面都比不上pc和主机游戏，也正是由于手机游戏的便携性才造就了它的火热，但是现在的手机游戏都失去了核心，都是相似的玩法加上几乎只能靠肝和氪的角色获取与养成。手机平台上已经很久没有出现过类似《愤怒的小鸟》《水果忍者》这类让人眼前一亮的作品了。</p><p>我个人认为玩游戏就是去体会开发者所创造的那一个世界，去体验人物的故事，去欣赏每一处风景，爬上每一座高塔，挑战boss。而游戏最重要的是它所的玩法，这在我看来是游戏的核心，某种角度上来说，画面、剧情、音乐、演出虽然也是游戏中很重要的组成部分，这些东西都拥有其他的替代品，例如电影、小说、歌曲，仅仅只有这些元素无法支撑一个游戏，这些元素加上游戏的玩法，最终组成了现在我所热爱的游戏。</p><h2 id="我为什么玩游戏"><a href="#我为什么玩游戏" class="headerlink" title="我为什么玩游戏"></a>我为什么玩游戏</h2><p>其实在最初，我玩游戏也是因为现实生活中没有(<del>女朋友</del>)更加吸引我的东西，所以沉浸在了虚拟的世界中。不过如果只是为了打发时间，按照正常的工作时间那么手游确实就能很好的满足消遣这个需求，哪怕到了pc上面也有lol，csgo，ow这种无止尽的竞技游戏可以消耗大把的时间。但是当游戏的阅历足够多之后，就会去尝试更多的游戏，因为这个时候能够去分辨好与坏，游戏媒体普遍满分的游戏也会存在缺点，大部分人不够看好的游戏也有其充满创意的设计，所以才会去尝试各类游戏，才会去尝试“鉴赏”游戏，才会期待未来的《2077》《荒野之息2》能够我带来新的体验。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="游戏" scheme="https://keshane.moe/tags/%E6%B8%B8%E6%88%8F/"/>
    
    <category term="手机游戏" scheme="https://keshane.moe/tags/%E6%89%8B%E6%9C%BA%E6%B8%B8%E6%88%8F/"/>
    
    <category term="单机游戏" scheme="https://keshane.moe/tags/%E5%8D%95%E6%9C%BA%E6%B8%B8%E6%88%8F/"/>
    
  </entry>
  
  <entry>
    <title>译：Linux 中的 TTY 是什么</title>
    <link href="https://keshane.moe/2020/05/30/what-is-tty-on-linux/"/>
    <id>https://keshane.moe/2020/05/30/what-is-tty-on-linux/</id>
    <published>2020-05-30T07:53:27.000Z</published>
    <updated>2026-07-27T14:35:50.407Z</updated>
    
    <content type="html"><![CDATA[<p>原文链接:<a href="https://www.howtogeek.com/428174/what-is-a-tty-on-linux-and-how-to-use-the-tty-command/">What is a TTY on Linux? (and How to Use the tty Command)</a></p><p>tty命令是干什么的？它打印出你正在使用的终端名。TTY 代表 “电传打字机(teletypewriter)”。 这个命令名字背后的故事是什么？这需要更多解释。</p><h2 id="19世纪的电传打字机"><a href="#19世纪的电传打字机" class="headerlink" title="19世纪的电传打字机"></a>19世纪的电传打字机</h2><p>在19世纪30年代至40年代，称为电传打字机的机器被开发出来。这些机器可以将输入的消息通过“线下（down the wire）”传输到遥远的地方。消息是由发送者在各种键盘上输入的。它们在接收端被打印在纸上。它们是电报中的一个进化步骤，在以前是通过摩斯电码和类似的编码进行传输。</p><p>消息被编码和传输然后被接收、解码和打印。有数种技术被用于编码和解码消息。其中最著名、最多产的一项专利是1874年由埃米尔·博多(Émile Baudot)获得的，波特率（baud rate）就是以他的名字命名的。他的字符编码方案比ASCII早了89年。</p><p>最终，波特的编码成为了在电传打字机编码中最接近标准的编码，他被大多数厂商采纳。波特原始的硬件设计只有5个按键，就像钢琴键一样。操作者被要求为每一个字母学习特殊的按键组合。最终，波特编码系统被结合进了传统的键盘布局。</p><p>为了纪念这个进步，这个机器被命名为电传打字机（teletypewriters）。这被缩短为teletypes并且最后称为TTYS。这就是TTY这个首字母缩写的由来，但是电报和计算机有什么关系？</p><h2 id="ASCII-和-电报"><a href="#ASCII-和-电报" class="headerlink" title="ASCII 和 电报"></a>ASCII 和 电报</h2><p>当 ASCII 于1963年问世时，它被电传打字机制造商采用。尽管电话被发明和得到了广泛的使用，电传打字机依然在发展。</p><p>电报是一个世界范围的电传打字机网络，可以将书面消息发往全球。在第二次世界大战之后到1980年代传真机火热期间，它们是传输书面消息的主要手段。</p><p>计算机也不断发展。他们变得能够与用户实时交互并且能够支持多个用户。老旧的批处理方法变得无法满足需求。人们步希望等待24小时或更久来得到结果。制作一堆打孔卡带然后等上个几夜来获得结果已经无法接收。</p><p>人们需要一个设备能够让他们输入指令并且直接返回结果给他们。人们想要效率。</p><h2 id="电传打字机的新用途"><a href="#电传打字机的新用途" class="headerlink" title="电传打字机的新用途"></a>电传打字机的新用途</h2><p>电传打字机是一个完美的输入&#x2F;输出设备选择。毕竟他是一种能够打字，编码，发送，接收，解码和打印的设备。</p><p>电传打字机关注如果连接在另一端的设备不是另一个电传打字机吗？只要它使用相同的编码语言并且能够接收并发送消息回来电传打字机就很开心。</p><p>当然，它也多少使用了标准键盘。</p><h2 id="硬件模拟的电传打字机"><a href="#硬件模拟的电传打字机" class="headerlink" title="硬件模拟的电传打字机"></a>硬件模拟的电传打字机</h2><p>电传打字机成了那个年代与微型计算机和大型计算机的默认方式。</p><p>他们最终被使用电子模拟这些机电器械的设备所取代。这些设备使用阴极射线管（Cathode Ray Tubes (CRTs)）而不是卷纸。当计算机传输响应时，他们不会抖动。他们允许使用至今无法实现的功能，例如在屏幕周围移动光标，清空屏幕，加粗字体，以及更多。 [ They were eventually replaced by devices that emulated those electro-mechanical machines using electronics. These had Cathode Ray Tubes (CRTs) instead of paper rolls. They didn’t shake when delivering responses from the computer. They permitted hitherto impossible functionality, such as moving the cursor around the screen, clearing the screen, bolding text, and so on. ]</p><p>DEC VT05 是虚拟电传打字机的早期示例，并且是著名的 DEC VT100 的祖先。DEC VT100 被售出了数百万台。</p><h2 id="软件模拟的电传打字机"><a href="#软件模拟的电传打字机" class="headerlink" title="软件模拟的电传打字机"></a>软件模拟的电传打字机</h2><p>在 Linux 和其他类 Unix 操作系统例如macOS的桌面环境中，终端窗口和例如 x-term 和 Konsole 的应用程序是虚拟电传打字机的样例。但是这些是完全从软件层面实现的他们被称为伪电传打字机（pseudo-teletypes），缩写为 PTS。</p><p>这就是 TTY 的由来。</p><h2 id="TTY-能告诉我们什么"><a href="#TTY-能告诉我们什么" class="headerlink" title="TTY 能告诉我们什么"></a>TTY 能告诉我们什么</h2><p>在 Linux 中有一个伪电传打字机多路复用器（pseudo-teletype multiplexor）来处理来自终端窗口伪电传打字机（PTS）的连接。这个多路复用器是 master，PTS是 slave， 多路复用器由内核通过位于 <code>/dev/ptmx</code> 下的设备文件进行寻址。</p><p><code>tty</code> 命令将打印你的使用了 master 接口的 slave 伪电传打字机的设备文件名称。[The tty command will print the name of the device file that your pseudo-teletype slave is using to interface to the master.] 实际上这就是终端窗口的编号。</p><p>让我们看看 <code>tty</code> 为我们的终端窗口报告了什么:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">tty</span></span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tty"></p><p>这个响应显示我们连接到了位于 <code>/dev/pts/0</code> 的设备文件。</p><p>我们的终端窗口，是电传打字机（TTY）的软件模拟，以伪电传打字机（PTS）的方式连接到伪电传打字机多路复用器。并且编号正好是0。</p><h2 id="静默选项"><a href="#静默选项" class="headerlink" title="静默选项"></a>静默选项</h2><p><code>-s</code>（silent） 选项可以让 <code>tty</code> 不产生输入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tty -s</span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttys.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttys.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tty -s in a terminal window"></p><p>它会产生一个退出码，如下：</p><ul><li>0: 如果标准输入来自模拟的或物理的 TTY 设备。</li><li>1: 如果标准输入不是来自 TTY 设备。</li><li>2: 语法错误，使用了错误的命令行参数。</li><li>3: 发生了写入错误。</li></ul><p>这看上去似乎在 Bash 脚本中最有用。但是即使在命令行，我们可以也演示如何只使用终端窗口（TTY或PTS会话）时执行命令.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tty -s &amp;&amp; echo &quot;In a tty&quot;</span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttyandecho.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttyandecho.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tty -s &amp;&amp; echo &quot;In a tty&quot; in a terminal window"></p><p>因为我们运行在 TTY 会话中，我们的退出码为0，并且第二条指令已经执行。</p><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttyandechoresponse.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/ttyandechoresponse.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="&quot;In a tty&quot; in a terminal window"></p><h2 id="who-指令"><a href="#who-指令" class="headerlink" title="who 指令"></a><code>who</code> 指令</h2><p>有其他命令可以显示你的 TTY 编号。 <code>who</code> 命令将会列出包含你自己的所有登陆 的用户信息。</p><p>Alec 和 Mary 正在远程连接这台 Linux 电脑。 他们连接到了 PTS 1 和 2。</p><p>用户 dave 显示正连接到 “:0” 。</p><p>这代表了屏幕和键盘物理的连接到了这台电脑。尽管屏幕和键盘是硬件设备，他们依然通过设备文件连接到了多路复用器。 <code>tty</code> 显示这是 <code>/dev/pts/2</code> 。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">who</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">tty</span></span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/whoandtty.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/whoandtty.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="who command"></p><h2 id="访问-TTY"><a href="#访问-TTY" class="headerlink" title="访问 TTY"></a>访问 TTY</h2><p>你可以通过按住 <code>Ctrl+Alt</code> 加上一个功能键来访问全屏的 TTY 会话</p><p><code>Ctrl+Alt+F3</code> 将会显示 tty3 的登陆提示。</p><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty3.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tty3"></p><p>如果登录并执行 <code>tty</code> 命令，您将看到已连接到 <code>/dev/tty3</code>。</p><p>这不是伪电传打字机（软件层面模拟）；他是一个虚拟电传打字机（硬件层面模拟）。它通过屏幕和键盘连接到你的电脑，并且模拟了一个虚拟电传打字机就像 DEC VT100 所做的一样。</p><p>你可以使用功能键 <code>Ctrl+Alt</code> 配合上功能键 F3 至 F6 可以选择4个 TTY 会话。例如你可以登陆进 tty3 并且按下 <code> Ctrl+Alt+F6</code> 来切换到 tty6 。</p><p><img src="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty6.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/05/30/what-is-tty-on-linux/tty6.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tty6"></p><p>想要回到图形的桌面环境需要按 <code>Ctrl+Alt+F2</code> 。</p><p>按 <code>Ctrl+Alt+F1</code> 将返回图形桌面会话的登录界面。</p><p>从 <code>Ctrl+Alt+F1</code> 到 <code>Ctrl+Alt+F6</code> 将打开全屏TTY控制台，而 <code>Ctrl+Alt+F7</code> 将使您返回图形桌面环境。如果你使用旧一点的 Linux 发行版，则取决于你系统的行为。<br>This was tested on current releases of Manjaro, Ubuntu, and Fedora and they all behaved like this:<br>这已在 Manjaro ， Ubuntu 和 Fedora 的当前版本上进行了测试，他们所有的行为如下：</p><ol><li>Ctrl+Alt+F1: 返回图形桌面环境的登陆界面。</li><li>Ctrl+Alt+F2: 返回图形桌面环境。</li><li>Ctrl+Alt+F3: 打开 TTY 3。</li><li>Ctrl+Alt+F4: 打开 TTY 4。</li><li>Ctrl+Alt+F5: 打开 TTY 5。</li><li>Ctrl+Alt+F6: 打开 TTY 6。</li></ol><p>通过访问这些全屏控制台，允许仅通过命令行安装的 Linux 的人 <del>并且许多 Linux 服务器通过这种方式配置</del> 能够使用多个控制台。</p><p>你曾使用带图形桌面环境的 Linux 机器工作并被一些问题让你的会话冻结吗？现在你可以跳到 TTY 控制台其中一个会话来尝试纠正这些问题。</p><p>你可以使用 <code>top</code> 和 <code>ps</code> 来尝试定位出错的应用，然后使用 <code>kill</code> 来终结它，或者使用 <code>shutdown</code> 直接以计算机允许的方式尽可能优雅的关掉计算机。</p><h2 id="历史悠久的三封信"><a href="#历史悠久的三封信" class="headerlink" title="历史悠久的三封信"></a>历史悠久的三封信</h2><p><code>tty</code> 命令因为19世纪晚期的设备得名，并在1971年出现于 Unix 上， 并且至今作为 Linux 和类 Unix 操作系统的一部分。</p><p>这个小东西的背后有一个传奇。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="linux" scheme="https://keshane.moe/tags/linux/"/>
    
    <category term="tty" scheme="https://keshane.moe/tags/tty/"/>
    
    <category term="terminal" scheme="https://keshane.moe/tags/terminal/"/>
    
    <category term="teletypewriter" scheme="https://keshane.moe/tags/teletypewriter/"/>
    
    <category term="teletype" scheme="https://keshane.moe/tags/teletype/"/>
    
  </entry>
  
  <entry>
    <title>gnome在休眠后有线连接中断的问题</title>
    <link href="https://keshane.moe/2020/05/03/gnome-ethernet-disconnected-after-suspend/"/>
    <id>https://keshane.moe/2020/05/03/gnome-ethernet-disconnected-after-suspend/</id>
    <published>2020-05-03T07:53:27.000Z</published>
    <updated>2026-07-27T14:35:50.407Z</updated>
    
    <content type="html"><![CDATA[<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>就是某一次在启动之后很久没操作然后自动休眠了，我也不知道是不是gnome的问题，但是我在用i3的时候就没出现过这个问题。（别问我为什么换回gnome</p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>参考了<a href="https://forum.manjaro.org/t/no-ethernet-network-connection-after-resume-very-recent-problem/53197"></a>和<a href="https://askubuntu.com/questions/1029250/ubuntu-18-04-ethernet-disconnected-after-suspend"></a>，首先通过</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo lshw -C network</span><br></pre></td></tr></table></figure><p>在<code>description: Ethernet interface</code>下的<code>configuration:</code>找到驱动（driver&#x3D;?）</p><p>因为Systemd会在休眠之前和之后执行放在<code>/lib/systemd/system-sleep/</code> 下的所有脚本, 会传递2个参数, <code>$1</code>状态(<code>pre</code>——在休眠之前, 或者 <code>post</code>——唤醒之后), <code>$2</code>是执行的动作 (<code>suspend</code>, <code>hibernate</code>, <code>hybrid-state</code> <code>suspend-then-hibernate</code>)</p><p>然后需要写一段shell放进<code>/lib/systemd/system-sleep/</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line">PROGNAME=$(<span class="built_in">basename</span> <span class="string">&quot;<span class="variable">$0</span>&quot;</span>)</span><br><span class="line">state=<span class="variable">$1</span></span><br><span class="line">action=<span class="variable">$2</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="built_in">log</span> &#123;</span><br><span class="line">    logger -i -t <span class="string">&quot;<span class="variable">$PROGNAME</span>&quot;</span> <span class="string">&quot;$*&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">log</span> <span class="string">&quot;Running <span class="variable">$action</span> <span class="variable">$state</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [[ <span class="variable">$state</span> == post ]]; <span class="keyword">then</span></span><br><span class="line">    modprobe -r r8169 \</span><br><span class="line">    &amp;&amp; <span class="built_in">log</span> <span class="string">&quot;Removed r8169&quot;</span> \</span><br><span class="line">    &amp;&amp; modprobe -i r8169 \</span><br><span class="line">    &amp;&amp; <span class="built_in">log</span> <span class="string">&quot;Inserted r8169&quot;</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><p>然后给他运行权限</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x /lib/systemd/system-sleep/r8169-refresh</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本来想稍微总结一下的，但是确实没什么好总结的，只是来做个记录。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="linux" scheme="https://keshane.moe/tags/linux/"/>
    
    <category term="gnome" scheme="https://keshane.moe/tags/gnome/"/>
    
    <category term="NetworkManager" scheme="https://keshane.moe/tags/NetworkManager/"/>
    
  </entry>
  
  <entry>
    <title>数据的恢复</title>
    <link href="https://keshane.moe/2020/03/20/find-the-lost-data/"/>
    <id>https://keshane.moe/2020/03/20/find-the-lost-data/</id>
    <published>2020-03-20T14:50:00.000Z</published>
    <updated>2026-07-27T14:35:50.405Z</updated>
    
    <content type="html"><![CDATA[<h2 id="数据的恢复"><a href="#数据的恢复" class="headerlink" title="数据的恢复"></a>数据的恢复</h2><p>聊一下我是如何在垃圾堆里找回我要的数据的。</p><h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>那是一个阳光明媚的中午，我正在电脑面前无所事事。突然发现在我的home目录下有一些扎眼的东西，为了看上去不那么难受我决定把他们删掉。</p><p>熟练的在终端敲出<code>rm -rf </code>然后敲出首字母按下<code>tab</code>，zsh就会补全那个文件名。就在这个时候，右下角某境外聊天软件的提示突然出现，我打开了软件，一边和别人聊天一边继续我的操作。</p><p>作为一个单进程生物，在尝试异步操作的时候总是会犯一些糊涂。</p><p>比如,</p><p>把自己的工作目录删了。</p><h2 id="数据灾难"><a href="#数据灾难" class="headerlink" title="数据灾难"></a>数据灾难</h2><p>继王A老师在 Java 课程上使用 eclipse 清空自己D盘，王B老师在数据库课程上将数据从C盘备份到E盘后，我也手滑删除了工作目录。这三次在数据上的操作失误史称信息学院数据灾难。（（（</p><p>经过检查，我发现部分文件其实在移动硬盘上是有备份的，另外部分文件都丢在 Github 上，真不愧是世界上第二好用的网盘（第一好用的是某境外聊天软件</p><p>目前无法手动恢复的只有一个小玩具和我的 Beancount 账本那个小玩具没了可以再写，唯独这个 Beancount 账本要想再次手动记录还是有点难度。所以想要找回这些文件。</p><blockquote><p>所以，为什么不备份呢？</p></blockquote><p>就像小学老师问你：“为什么会做错呢？”，我要是知道我也不会这样了啊。</p><h2 id="准备找回文件"><a href="#准备找回文件" class="headerlink" title="准备找回文件"></a>准备找回文件</h2><p>参考 <a href="https://www.ibm.com/developerworks/cn/linux/1312_caoyq_linuxrestore/index.html">使用 Linux 文件恢复工具</a> 这篇文章，我安装了 <code>Testdisk</code> 这个工具,使用 <code>Photorec</code> 进行恢复</p><p>这个软件整体使用起来还是比较简单</p><p><img src="https://webp.keshane.moe/2020/03/20/find-the-lost-data/photorec1.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/03/20/find-the-lost-data/photorec1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="photorec"></p><p><code>Photorec</code> 可以选择恢复的类型，但是对于文本类都是一样的格式</p><p>虽然早有预感无法很顺利的找回文件，但是我没想到居然这么成功的找回了文件，甚至，成功过头了.</p><h2 id="从垃圾堆里找回需要的文件"><a href="#从垃圾堆里找回需要的文件" class="headerlink" title="从垃圾堆里找回需要的文件"></a>从垃圾堆里找回需要的文件</h2><p><img src="https://webp.keshane.moe/2020/03/20/find-the-lost-data/photorec2.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/03/20/find-the-lost-data/photorec2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="photorec"></p><p>成功的通过 <code>Photorec</code> 找回了文件，找回了……个十百千万……大概500万个文件</p><p><img src="https://webp.keshane.moe/2020/03/20/find-the-lost-data/find.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/03/20/find-the-lost-data/find.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="找回的文件"><br>并且文件名还是重命名过的。</p><p><img src="https://webp.keshane.moe/2020/03/20/find-the-lost-data/woc.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/03/20/find-the-lost-data/woc.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="woc"></p><p>那么要从这500万个文件中找回需要的那几个文件，一个一个找肯定是不太现实的，但是有一点，每个 Beancount 账本里都有一条 “Assets:*” 类似的记录，可以通过这一点来找回文件。</p><p>使用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp $(grep -rnl &quot;Assets:&quot; *) /home/xxx/beancount</span><br></pre></td></tr></table></figure><p>将包含 “Assets:*” 的文件复制到一个新的目录里</p><p>然后发现还有一些 <code>.java</code> <code>.c</code> 等文件，删掉删掉。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rm $(find . ! -name &quot;*.txt&quot;)</span><br></pre></td></tr></table></figure><p>在经过这一系列处理之后，只剩下了<br><img src="https://webp.keshane.moe/2020/03/20/find-the-lost-data/wc.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/03/20/find-the-lost-data/wc.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="><br>5000+个文件……</p><p>所以，还需要</p><h2 id="从找回的垃圾堆里找回需要的文件"><a href="#从找回的垃圾堆里找回需要的文件" class="headerlink" title="从找回的垃圾堆里找回需要的文件"></a>从找回的垃圾堆里找回需要的文件</h2><p>查看了一下这些文件，很多文件都是那种早期保存版本，因为 Beancount 每条记录都有日期，所以只需要找到每个月最后一条记录的日期在哪些文件上就行了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp $(grep -rnl &quot;2020-02-28&quot; *) /home/xxx/beancount-02</span><br></pre></td></tr></table></figure><p>但就这样还是找出几百个文件，还好数据基本都是全的，随机跳出来几个重组了一下文件结构终于又恢复了往日的形状。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><blockquote><p>只要我筛子网做得足够细，留下的永远是想要的形状</p></blockquote><p>(并不</p><p>数据备份还是很重要的，一时手滑一时爽，数据找回火葬场。不知道王A老师是否成功找回了需要的数据，不过我找回数据的过程非常艰辛，终于知道了为什么大佬执迷于研究优雅的数据备份方式，在你手滑的时候，你的备份可能是拯救你的最后一根稻草.</p><blockquote><p>别看你今天闹得欢,小心今后拉清单,这都得应验的.</p></blockquote>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="life" scheme="https://keshane.moe/tags/life/"/>
    
    <category term="data" scheme="https://keshane.moe/tags/data/"/>
    
    <category term="lost" scheme="https://keshane.moe/tags/lost/"/>
    
    <category term="backup" scheme="https://keshane.moe/tags/backup/"/>
    
  </entry>
  
  <entry>
    <title>OWL2020赛季第一周观赛吐槽</title>
    <link href="https://keshane.moe/2020/02/10/owl2020-first-week/"/>
    <id>https://keshane.moe/2020/02/10/owl2020-first-week/</id>
    <published>2020-02-10T16:27:52.000Z</published>
    <updated>2026-07-27T14:35:50.399Z</updated>
    
    <content type="html"><![CDATA[<h2 id="OWL2020赛季第一天观赛吐槽"><a href="#OWL2020赛季第一天观赛吐槽" class="headerlink" title="OWL2020赛季第一天观赛吐槽"></a>OWL2020赛季第一天观赛吐槽</h2><p>在经历了漫长的休赛期与大量的人员变动之后，OWL2020赛季终于开赛。2020赛季，联赛的场地从暴雪竞技场转移到了各个队伍的主场，由于国内疫情的原因可能在一段时间内国内的主场比赛和国内队伍都无法和我们见面。但也是在这个特殊时期，OWL新赛季的开赛也让我们有更多呆在家里的理由。虽然无法身临其境感受到主场比赛的氛围，但是我们依然能够通过转播画面感受到主场观众的热情。但是首周第一天的观赛体验非常不好，让人不得不吐槽一下。</p><p>相较于上个赛季，本赛季大家观看直播的平台发生了变化国内少了战旗，国外从twitch转到了youtube（不能嫖代币了</p><p>首周末是达拉斯和纽约的主场周，不知道是什么原因，第一天的比赛转播状况频出，观看体验非常糟糕。</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem-1.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem-1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="problem-1.png"></p><h3 id="多伦多捍卫者VS巴黎永生"><a href="#多伦多捍卫者VS巴黎永生" class="headerlink" title="多伦多捍卫者VS巴黎永生"></a>多伦多捍卫者VS巴黎永生</h3><p>本场比赛是2020赛季的第一场比赛，巴黎永生队这边在第一张地图拿出了在上个赛季都没得到过太多上场机会的秩序之光。这场比赛可以说是一场中规中矩的OWL级别的比赛，我们可以看见优秀的团队配合以及个人发挥。</p><p>不过不知道是不是转播的信号有问题，在比赛最后两张图的时候出现了画面撕裂的问题，解说也是偶尔会出现电流杂音。</p><p>第一次登上OWL舞台的xzi发挥还算不错，在长枪位置上的发挥还是有得秀，不过logix还是在最后一张图给这个新人上了一课。说起新人，这个休赛期出现了大量的人员变动，而伦敦喷火战斗机队则是引入了大量的新人第一次登上OWL的舞台。</p><h3 id="伦敦喷火战斗机-vs-纽约九霄天擎"><a href="#伦敦喷火战斗机-vs-纽约九霄天擎" class="headerlink" title="伦敦喷火战斗机 vs 纽约九霄天擎"></a>伦敦喷火战斗机 vs 纽约九霄天擎</h3><p>不知道是纽约玩梗还是联盟玩梗，在介绍伦敦队员变动的时候居然玩了一波伦敦喷火无人机的梗</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-1.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-1.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="london-spitfire-drone-1.png"></p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-2.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="london-spitfire-drone-2.png"></p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-3.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/london-spitfire-drone-3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="london-spitfire-drone-3.png"></p><p>伦敦喷火战斗机这个休赛期换了11个人</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/newyork-cbob.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/newyork-cbob.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="newyork-cbob.png"></p><p>坐镇主场的纽约队入场是真的帅</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem2.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem2.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="problem2.png"></p><p>这场比赛的播放情况出现了非常多的失误，不知道是不是纽约主场的导播过于激动，开场有一段时间让我们感受了一下现场观赛的体验。</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem3.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/problem3.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="problem3.png"></p><p>更是在第二张地图中途打得正激烈的时候切出了品客叔叔的广告。。。。。</p><p>整场比赛比较令人惊奇的是虽然面对的是一支几乎全新的队伍，但是纽约队并没有说碾压伦敦队。whoru的表现没有想象中那么出色。纽约作为一支上赛季前三的队伍感觉并没有磨合好。伦敦作为一只全新的队伍面对纽约并不是完全没有还手之力。</p><h3 id="洛杉矶角斗士-vs-温哥华泰坦"><a href="#洛杉矶角斗士-vs-温哥华泰坦" class="headerlink" title="洛杉矶角斗士 vs 温哥华泰坦"></a>洛杉矶角斗士 vs 温哥华泰坦</h3><p>这场比赛是在达拉斯的主场进行，导播化身绯红之王切掉了国王大道的第一波团战。。。。同时解说丹尼的麦克风炸了。。。。。看比赛的真是辛苦</p><p>双方打得有来有回，非常精彩.Haksal还是强，源氏拔刀比光头崽种好看多了2333</p><p><img src="https://webp.keshane.moe/2020/02/10/owl2020-first-week/haksal-genji.png" class="lazy" data-srcset="https://webp.keshane.moe/2020/02/10/owl2020-first-week/haksal-genji.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="haksal-genji.png"> </p><h3 id="洛杉矶英勇-vs-达拉斯燃料"><a href="#洛杉矶英勇-vs-达拉斯燃料" class="headerlink" title="洛杉矶英勇 vs 达拉斯燃料"></a>洛杉矶英勇 vs 达拉斯燃料</h3><p>洛杉矶英勇队的gig绝对是专精大锤冲锋技能的选手，一整场的比赛只要一有机会就会冲锋，并且达拉斯一帮明星选手硬是没有一点配合，全靠个人实力打比赛（苦 gamsu 苦）。两支队伍互相整活，在OWL上能看见国服天梯的状态也是很不错的。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="owerwatch league" scheme="https://keshane.moe/tags/owerwatch-league/"/>
    
    <category term="owl" scheme="https://keshane.moe/tags/owl/"/>
    
    <category term="守望先锋联赛" scheme="https://keshane.moe/tags/%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B%E8%81%94%E8%B5%9B/"/>
    
    <category term="暴雪" scheme="https://keshane.moe/tags/%E6%9A%B4%E9%9B%AA/"/>
    
  </entry>
  
  <entry>
    <title>使用 GitHub Actions 完成 Hexo 博客的自动生成与部署</title>
    <link href="https://keshane.moe/2019/12/25/use-github-action-to-deploy-hexo/"/>
    <id>https://keshane.moe/2019/12/25/use-github-action-to-deploy-hexo/</id>
    <published>2019-12-25T05:37:45.000Z</published>
    <updated>2026-07-27T14:35:50.370Z</updated>
    
    <content type="html"><![CDATA[<h1 id="使用-GitHub-Actions-完成-Hexo-博客的自动生成与部署"><a href="#使用-GitHub-Actions-完成-Hexo-博客的自动生成与部署" class="headerlink" title="使用 GitHub Actions 完成 Hexo 博客的自动生成与部署"></a>使用 GitHub Actions 完成 Hexo 博客的自动生成与部署</h1><p>虽然现在博客已经迁移到 Wordpress 上，但是每次还是会在本地通过 hexo new xxx 来生成一份本地文件。</p><p>而我的 Hexo 原始文件是按照</p><blockquote><p> 使用hexo，如果换了电脑怎么更新博客？ - CrazyMilk的回答 - 知乎 <a href="https://www.zhihu.com/question/21193762/answer/79109280">https://www.zhihu.com/question/21193762/answer/79109280</a></p></blockquote><p>这种方式来进行备份的。因为更换了新的电脑，把仓库 clone 下来的时候因为网络的问题 npm install 总是失败，并且在本地写文章然后 push 然后再执行Hexo 相关的指令相对来说比较复杂。所以就想到把 Hexo 的生成和部署让某些东西自动完成，在本地只需要负责写作就好。</p><h2 id="使用-GitHub-Actions-在-push-的时候自动生成和部署hexo静态页面"><a href="#使用-GitHub-Actions-在-push-的时候自动生成和部署hexo静态页面" class="headerlink" title="使用 GitHub Actions 在 push 的时候自动生成和部署hexo静态页面"></a>使用 GitHub Actions 在 push 的时候自动生成和部署hexo静态页面</h2><h3 id="首先要为仓库生成一个-Deploy-Key"><a href="#首先要为仓库生成一个-Deploy-Key" class="headerlink" title="首先要为仓库生成一个 Deploy Key"></a>首先要为仓库生成一个 Deploy Key</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -b 4096 -C <span class="string">&quot;your_email@example.com&quot;</span></span><br></pre></td></tr></table></figure><p>然后在这一步输入这对 Key 的文件名，如果直接回车会覆盖掉自己的 Key</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Generating public/private rsa key pair.</span><br><span class="line">Enter file in which to save the key (/home/yourname/.ssh/id_rsa): </span><br></pre></td></tr></table></figure><p>接下来去仓库的setting里面</p><p>![](Screenshot from 2019-12-25 11-55-11.png)</p><p>在 Deploy keys 这里把刚刚生成的密钥对中的公钥添加进去</p><p>然后在 Secrets 里把刚刚生成的密钥对中的私钥添加进去，名字可以随意取，在 GitHub Actions 中以 $引用</p><p>![Screenshot from 2019-12-25 11-55-21.png](Screenshot from 2019-12-25 11-55-21.png)</p><h3 id="创建一个-GitHub-Actions-WorkFlow"><a href="#创建一个-GitHub-Actions-WorkFlow" class="headerlink" title="创建一个 GitHub Actions WorkFlow"></a>创建一个 GitHub Actions WorkFlow</h3><p>在目录下创建 .github&#x2F;workflow&#x2F;your-action-name.yml</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">name: deploy hexo</span><br><span class="line"></span><br><span class="line">on:</span><br><span class="line">  push:</span><br><span class="line">    branches:</span><br><span class="line">      - hexo</span><br><span class="line"></span><br><span class="line">jobs:</span><br><span class="line">  generate-and-deploy:</span><br><span class="line">    runs-on: [ubuntu-latest]</span><br><span class="line">    steps:</span><br><span class="line">      - name: checkout</span><br><span class="line">        uses: actions/checkout@v2</span><br><span class="line">        with:</span><br><span class="line">          ref: hexo</span><br><span class="line">          </span><br><span class="line">      - name: setup node env</span><br><span class="line">        uses: actions/setup-node@v1</span><br><span class="line">        with:</span><br><span class="line">          node-version: &quot;10.x&quot;</span><br><span class="line"></span><br><span class="line">      - name: setup ssh ang git env</span><br><span class="line">        env:</span><br><span class="line">          PRIVATE_KEY: $&#123;&#123;secrets.HEXO_DEPLOY_KEY&#125;&#125;</span><br><span class="line">        run: |</span><br><span class="line">          mkdir -p ~/.ssh/ </span><br><span class="line">          echo &quot;$PRIVATE_KEY&quot; &gt; ~/.ssh/id_rsa </span><br><span class="line">          chmod 600 ~/.ssh/id_rsa</span><br><span class="line">          ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span><br><span class="line">          # set git infomation</span><br><span class="line">          git config --global user.name &#x27;your name&#x27;</span><br><span class="line">          git config --global user.email &#x27;your email&#x27;</span><br><span class="line">          npm install &amp; npm install -g hexo-cli</span><br><span class="line">          npm install hexo-renderer-scss --save</span><br><span class="line">          </span><br><span class="line">      - name: gengration and deploy</span><br><span class="line">        run: hexo g -d</span><br><span class="line">       </span><br></pre></td></tr></table></figure><p>具体的用法可以查看<a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions">官方文档</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">on:</span><br><span class="line">  push:</span><br><span class="line">    branches:</span><br><span class="line">      - hexo</span><br></pre></td></tr></table></figure><p>表示在 hexo 分支 push 触发。jobs 表示执行任务，一个 jobs 可以包含多个 steps</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">- name: checkout</span><br><span class="line">     uses: actions/checkout@v2</span><br><span class="line">     with:</span><br><span class="line">       ref: hexo</span><br><span class="line">   - name: setup node env</span><br><span class="line">     uses: actions/setup-node@v1</span><br><span class="line">     with:</span><br><span class="line">       node-version: &quot;10.x&quot;</span><br></pre></td></tr></table></figure><p>使用 <a href="https://github.com/actions/checkout">checkout</a> 获取 hexo 分支的源码 ，并设置 node 环境</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">- name: setup ssh ang git env</span><br><span class="line">      env:</span><br><span class="line">        PRIVATE_KEY: $&#123;&#123;secrets.HEXO_DEPLOY_KEY&#125;&#125;</span><br><span class="line">      run: |</span><br><span class="line">        mkdir -p ~/.ssh/ </span><br><span class="line">        echo &quot;$PRIVATE_KEY&quot; &gt; ~/.ssh/id_rsa </span><br><span class="line">        chmod 600 ~/.ssh/id_rsa</span><br><span class="line">        ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts</span><br><span class="line">        # set git infomation</span><br><span class="line">        git config --global user.name &#x27;your name&#x27;</span><br><span class="line">        git config --global user.email &#x27;your email&#x27;</span><br><span class="line">        npm install &amp; npm install -g hexo-cli</span><br><span class="line">        npm install hexo-renderer-scss --save</span><br><span class="line">        </span><br><span class="line">    - name: gengration and deploy</span><br><span class="line">      run: hexo g -d</span><br></pre></td></tr></table></figure><p>然后就很常规的写入 ssh key 然后安装相应的东西，最后调用 hexo 的命令进行生成和部署</p><h3 id="查看执行情况"><a href="#查看执行情况" class="headerlink" title="查看执行情况"></a>查看执行情况</h3><p>可以去项目仓库的 actions 查看每个 workflow 的执行情况</p><p>![](Screenshot from 2019-12-25 13-43-55.png)</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="github" scheme="https://keshane.moe/tags/github/"/>
    
    <category term="actions" scheme="https://keshane.moe/tags/actions/"/>
    
    <category term="workflow" scheme="https://keshane.moe/tags/workflow/"/>
    
    <category term="hexo" scheme="https://keshane.moe/tags/hexo/"/>
    
  </entry>
  
  <entry>
    <title>简单的快乐——《马里奥：奥德赛》</title>
    <link href="https://keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/"/>
    <id>https://keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/</id>
    <published>2019-12-09T06:40:54.000Z</published>
    <updated>2026-07-27T14:35:50.371Z</updated>
    
    <content type="html"><![CDATA[<h2 id="《马里奥：奥德赛》"><a href="#《马里奥：奥德赛》" class="headerlink" title="《马里奥：奥德赛》"></a>《马里奥：奥德赛》</h2><h3 id="国行相关"><a href="#国行相关" class="headerlink" title="国行相关"></a>国行相关</h3><p>根据国行switch官网，国行switch将会在12月10日正式上市，目前已经在国内商城开启了预购。国行switch的发售，也是第一次三大主机能够同时以一个合法的身份在国内同台竞技。</p><p><img src="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/tencent-nintendo-switch-price.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/tencent-nintendo-switch-price.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="tencent-nintendo-switch-price.png"></p><p>我是在两年前购买的switch。当时我对任天堂并没有太多的认知，认为switch上的游戏大部分都是属于“给小孩子玩的游戏”。当时我购买switch仅仅是想要玩一下《塞尔达传说：荒野之息》这款被多数人称赞的年度游戏，同时还购买了《马里奥：奥德赛》同时感受一下被吹上天的”红帽子“和”绿帽子“。</p><h3 id="箱庭世界"><a href="#箱庭世界" class="headerlink" title="箱庭世界"></a>箱庭世界</h3><p>马里奥系列我相信大部分人在童年都有所接触，那时候是横版的通关游戏。而《马里奥：奥德赛》是我个人接触到的第一款3D的马里奥作品，根据相关的资料，本作已经是马里奥系列的第7部游戏作品。进入游戏之后给我的第一映像就是自由，在一个自由的世界中，没有目标，你需要的只是不停地探索，搜集足够多的月亮来启动飞船。这种没有具体目标的探索给了玩家自由探索的空间。《马里奥：奥德赛》并不是传统意义上的开放世界游戏，而是箱庭冒险游戏，游戏通过十几个不同的国度组成，每个国度都有着自己独特的特性，能够给人不断的带来新的乐趣。</p><h3 id="充满创意的帽子"><a href="#充满创意的帽子" class="headerlink" title="充满创意的帽子"></a>充满创意的帽子</h3><p>从第一次变成青蛙向上跳跃，游戏中你能见到的物品都能通过帽子交互。这顶帽子可以让你变身，可以攻击方块，通过挥动Joycon还能朝不同的方向扔出去，双人模式中，帽子还能独立于马里奥之外行动。这顶神奇的帽子使得奥德赛的游戏体验更加丰富。</p><p><img src="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2018060123353600-8AEDFF741E2D23FBED39474178692DAF.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2018060123353600-8AEDFF741E2D23FBED39474178692DAF.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="2018060123353600-8AEDFF741E2D23FBED39474178692DAF.jpg"></p><p>而这顶帽子的存在给了不同玩家不同的玩法。</p><h3 id="探索的喜悦"><a href="#探索的喜悦" class="headerlink" title="探索的喜悦"></a>探索的喜悦</h3><p>不同于其他的游戏，奥德赛主要的玩法是通过收集要素来推动的，但是一味的收集要素会让游戏后期变得非常枯燥，而任天堂优秀的关卡设计让玩家探险的过程变得非常有趣。游戏每个国度的地图大小都不算大，任天堂在这样不算大的空间中填充了大量内容等着玩家去探索，任何你能想象到的地方都会有着不同的惊喜，通过精心设计的引导让你不自觉的爱上这种探索——月亮出现在每个可能的拐角，跳上向你奔来的一堆栗子小子后会发现顶上还有一个平台，而玩家，将会像马里奥一样思考，柱子的上方是否会有金币，如何通过帽子爬上高楼。。。。。</p><p><img src="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2019120919244400-8AEDFF741E2D23FBED39474178692DAF.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2019120919244400-8AEDFF741E2D23FBED39474178692DAF.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="2019120919244400-8AEDFF741E2D23FBED39474178692DAF.jpg"></p><p>引用在NGA论坛看到的<a href="https://bbs.nga.cn/read.php?pid=328922130&opt=128">一句话</a> :</p><blockquote><p>当你一系列骚操作上了看似上不去的平台，发现老任在那放了一堆金币</p></blockquote><h3 id="溢出屏幕的游戏性"><a href="#溢出屏幕的游戏性" class="headerlink" title="溢出屏幕的游戏性"></a>溢出屏幕的游戏性</h3><p>以前的我一直认为这句话是来黑任天堂的游戏机性能低下，只能靠所谓“游戏性”来吸引玩家。而当我真正玩过任天堂的游戏时，我觉得用溢出屏幕的游戏性来形容任天堂的游戏非常合理。随着技术的发展，玩家们也在不断的追逐更好的游戏画面，更加开放的游戏世界，更加具有带入性的叙事手法。而奥德赛似乎有着神奇的魔力，没有丰富的剧情，没有顶级的画面，没有庞大的世界，却能让你获得无穷的快乐。</p><p><img src="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2018062700173900-8AEDFF741E2D23FBED39474178692DAF.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/12/09/lets-play-Super-Mario-Odyssey/2018062700173900-8AEDFF741E2D23FBED39474178692DAF.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="2018062700173900-8AEDFF741E2D23FBED39474178692DAF.jpg"></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="nintendo" scheme="https://keshane.moe/tags/nintendo/"/>
    
    <category term="switch" scheme="https://keshane.moe/tags/switch/"/>
    
    <category term="主机游戏" scheme="https://keshane.moe/tags/%E4%B8%BB%E6%9C%BA%E6%B8%B8%E6%88%8F/"/>
    
    <category term="任天堂" scheme="https://keshane.moe/tags/%E4%BB%BB%E5%A4%A9%E5%A0%82/"/>
    
    <category term="马里奥:奥德赛" scheme="https://keshane.moe/tags/%E9%A9%AC%E9%87%8C%E5%A5%A5-%E5%A5%A5%E5%BE%B7%E8%B5%9B/"/>
    
  </entry>
  
  <entry>
    <title>Linux下混合分辨率屏幕的解决方案</title>
    <link href="https://keshane.moe/2019/12/02/screen-scale-linux/"/>
    <id>https://keshane.moe/2019/12/02/screen-scale-linux/</id>
    <published>2019-12-02T17:14:01.000Z</published>
    <updated>2026-07-27T14:35:50.371Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Linux下混合分辨率屏幕的解决方案"><a href="#Linux下混合分辨率屏幕的解决方案" class="headerlink" title="Linux下混合分辨率屏幕的解决方案"></a>Linux下混合分辨率屏幕的解决方案</h1><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>我的新笔记本的屏幕是一块2560×1600的13.3英寸的屏幕，而我的显示器则是1920×1080分辨率的24寸屏幕。在使用i3wm后，想要方便的使用这两块屏幕遇见了一些问题</p><ol><li>在默认情况下，笔记本的屏幕显示内容太小了</li><li>在想要进行双瓶拓展的时候由于分辨率不同，显示器只能显示部分内容</li><li>不能灵活的切换显示器</li></ol><p>其实现在linux下很多桌面环境如gnome都能很好的解决上面的问题，但是i3wm要复杂很多。</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>在经过自己的不断尝试和一些参考后给出我的解决方案，总体的思路就是将全局的dpi调整到一个dpi最大的屏幕看上去合适的大小，然后将其他屏幕进行缩放。</p><p>首先，在家目录下创建 .Xresource 文件，并添加 Xft.dpi:192 （数字根据自己dpi最大的屏幕来调整 <a href="https://www.sven.de/dpi/">DPI计算器</a> 然后重启。这样会使得另一块屏幕显示比较诡异。</p><p>然后通过xrandr进行调整</p><h4 id="双屏幕同时显示"><a href="#双屏幕同时显示" class="headerlink" title="双屏幕同时显示"></a>双屏幕同时显示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">xrandr  --dpi 192 \</span><br><span class="line">        --output eDP --mode 2560x1600 --pos 0x0 \</span><br><span class="line">        --output DisplayPort-1 --mode 1920x1080 --scale 2x2 --pos 2560x0 --panning 3840x2160+2560+0</span><br></pre></td></tr></table></figure><p>–dpi 其实这个参数没有什么用，一开始是想通过这个指令来切换dpi而不用去.Xresources里面调整，但是通过这个指令调整之后终端和浏览器等其他地方该看不清的还是看不清。。。<br>–output XXX 显示输出的名称<br>–mode 指定输出的分辨率<br>–scale 指定缩放倍率<br>–pos 指定这个输出的位置<br>–panning 这个参数可以使得鼠标能够正常的在区域内使用</p><h4 id="仅使用显示器"><a href="#仅使用显示器" class="headerlink" title="仅使用显示器"></a>仅使用显示器</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">xrandr  --dpi 192 \</span><br><span class="line">        --output eDP --off \</span><br><span class="line">        --output DisplayPort-1 --scale 2x2 --panning 3840x2160+0+0 </span><br></pre></td></tr></table></figure><h4 id="仅使用电脑屏幕"><a href="#仅使用电脑屏幕" class="headerlink" title="仅使用电脑屏幕"></a>仅使用电脑屏幕</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">xrandr  --dpi 192 \</span><br><span class="line">        --output eDP --mode 2560x1600 --panning 2560x1600+0+0 \</span><br><span class="line">        --output DisplayPort-1 --off</span><br></pre></td></tr></table></figure><h3 id="依然存在的问题"><a href="#依然存在的问题" class="headerlink" title="依然存在的问题"></a>依然存在的问题</h3><ol><li>通过低dpi屏幕适配高dpi然后缩放，虽然一定程度的解决了问题，但是字体会模糊</li><li>突然想要切换显示器的时候，还是只有通过指令，无法自动切换</li></ol><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="https://ntzyz.io/post/linux-dual-monitor-with-different-dpi">https://ntzyz.io/post/linux-dual-monitor-with-different-dpi</a></p><p><a href="https://blog.jamiek.it/2015/04/manually-fixing-multiple-screens-with.html?m=1">https://blog.jamiek.it/2015/04/manually-fixing-multiple-screens-with.html?m=1</a></p><p><a href="https://blog.summercat.com/configuring-mixed-dpi-monitors-with-xrandr.html">https://blog.summercat.com/configuring-mixed-dpi-monitors-with-xrandr.html</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="i3wm" scheme="https://keshane.moe/tags/i3wm/"/>
    
    <category term="linux" scheme="https://keshane.moe/tags/linux/"/>
    
    <category term="多分辨率" scheme="https://keshane.moe/tags/%E5%A4%9A%E5%88%86%E8%BE%A8%E7%8E%87/"/>
    
  </entry>
  
  <entry>
    <title>尝试使用i3 window manager</title>
    <link href="https://keshane.moe/2019/11/01/using-i3-window-manager/"/>
    <id>https://keshane.moe/2019/11/01/using-i3-window-manager/</id>
    <published>2019-11-01T17:13:38.000Z</published>
    <updated>2026-07-27T14:35:50.370Z</updated>
    
    <content type="html"><![CDATA[<h1 id="尝试使用i3-window-manager"><a href="#尝试使用i3-window-manager" class="headerlink" title="尝试使用i3 window manager"></a>尝试使用i3 window manager</h1><p>九月下旬，我把博客从hexo迁移到了wordpress。某一天，我正在修改博客主题的时候，陪我度过了无数游戏时光的笔记本——神船Z7D3 突然熄火，开始我并没有太在意这点，因为这台笔记本过热自动关机在以前是常有的事。然而我在后续的检查中发现出现了一个很严重的问题，只要接了电源，我的笔记本就会在启动之后很快自动熄火，这时候我才意识到问题的棘手。之后找了一个修电脑的朋友咨询了一下，问题依然无法解决，并被告知可以通过淘宝更换主板。在淘宝上找了几家店，选中了其中一家，将主板拆了寄过去（然后被坑了又把主板拿回来了，损失了40块钱的邮费）</p><p>新的电脑还没拿到，之前一直嫖的Nova大佬的电脑在用，现在终于换了个人嫖了台笔记本用。在nova大佬的推荐下安装了fedora和i3 window manager ， 这是我第一次把linux作为日常操作系统使用，感觉还是有些许不习惯，一开始对于这种只有黑框框的桌面我是拒绝的，但在用过一段时间之后还是真香。</p><h3 id="安装i3"><a href="#安装i3" class="headerlink" title="安装i3"></a>安装i3</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf install i3 i3status dmenu i3lock xbacklight feh </span><br></pre></td></tr></table></figure><p>从网上抄的简介</p><ul><li><strong>i3</strong> is the main window manager package.</li><li><strong>i3status</strong> is a utility to generate a string with information to be displayed in the i3bar.</li><li><strong>dmenu</strong> is a utility to launch our apps in the i3 desktop.</li><li><strong>xbacklight</strong> is a utility to set our laptop’s screen brightness.</li><li><strong>feh</strong> is a utility to set a wallpaper.</li></ul><p>这样就安装好了i3和一些配套工具，之后登出Gnome，在登录的时候选择i3就好了，第一次进入需要选择默认的$mod键位置，之后也可以在配置文件（~&#x2F;.config&#x2F;i3&#x2F;config）中改</p><h3 id="i3多显示器配置"><a href="#i3多显示器配置" class="headerlink" title="i3多显示器配置"></a>i3多显示器配置</h3><p>安装lxrandr进行配置，一看就会。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf install lxrandr</span><br></pre></td></tr></table></figure><h3 id="Terminal"><a href="#Terminal" class="headerlink" title="Terminal"></a>Terminal</h3><p>按$mod+Enter可以开启terminal，但是i3默认的terminal实在是太丑了，还是切换回Gnome-terminal比较好。编辑配置文件，找到start a terminal，将i3-sensible-terminal改为gnome-terminal</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># start a terminal</span><br><span class="line">#bindsym $mod+Return exec i3-sensible-terminal</span><br><span class="line">bindsym $mod+Return exec gnome-terminal</span><br></pre></td></tr></table></figure><h3 id="i3锁屏"><a href="#i3锁屏" class="headerlink" title="i3锁屏"></a>i3锁屏</h3><p>配置i3快捷键锁屏，编辑配置文件，添加下列内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># lock the screen</span><br><span class="line">bindsym $mod+l exec i3lock -i xxx.png</span><br><span class="line"># 后面的[-i xxx.png]是锁屏壁纸，如果锁屏就想大白屏的话可以省略</span><br></pre></td></tr></table></figure><h3 id="i3截图"><a href="#i3截图" class="headerlink" title="i3截图"></a>i3截图</h3><p>还是Gnome那一套，不过绑定了i3的快捷键</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># Screen Shot </span><br><span class="line"> bindsym --release $mod+Shift+s exec gnome-screenshot -a</span><br><span class="line"># 注意 --release 表示释放时执行，不能省略</span><br></pre></td></tr></table></figure><h3 id="i3通过键盘fn键进行音量控制"><a href="#i3通过键盘fn键进行音量控制" class="headerlink" title="i3通过键盘fn键进行音量控制"></a>i3通过键盘fn键进行音量控制</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Media volume controls</span><br><span class="line"> bindsym XF86AudioMute exec amixer sset &#x27;Master&#x27; toggle</span><br><span class="line"> bindsym XF86AudioLowerVolume exec amixer sset &#x27;Master&#x27; 5%-</span><br><span class="line"> bindsym XF86AudioRaiseVolume exec amixer sset &#x27;Master&#x27; 5%+</span><br></pre></td></tr></table></figure><h3 id="中文输入法"><a href="#中文输入法" class="headerlink" title="中文输入法"></a>中文输入法</h3><p>命令行执行ibus-setup进行设置，然后将输入法设置为开启i3时自动启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># Start with ibus deamon</span><br><span class="line">exec --no-startup-id ibus-daemon</span><br></pre></td></tr></table></figure><h3 id="配置i3-status-bar"><a href="#配置i3-status-bar" class="headerlink" title="配置i3 status bar"></a>配置i3 status bar</h3><p>根据官网的指示，创建了~&#x2F;.config&#x2F;i3status&#x2F;config</p><p>然后编辑如下，直接抄了大佬的配置然后稍微改了改</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"> i3status configuration file.</span><br><span class="line"># see &quot;man i3status&quot; for documentation.</span><br><span class="line"></span><br><span class="line"># It is important that this file is edited as UTF-8.</span><br><span class="line"># The following line should contain a sharp s:</span><br><span class="line"># ß</span><br><span class="line"># If the above line is not correctly displayed, fix your editor first!</span><br><span class="line"></span><br><span class="line">general &#123;</span><br><span class="line">        colors = true</span><br><span class="line">        interval = 1</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">order += &quot;volume headphones&quot;</span><br><span class="line">order += &quot;cpu_temperature 0&quot;</span><br><span class="line">#order += &quot;cpu_temperature 1&quot;</span><br><span class="line">order += &quot;disk /&quot;</span><br><span class="line">order += &quot;disk /home&quot;</span><br><span class="line">order += &quot;ipv6&quot;</span><br><span class="line">order += &quot;wireless _first_&quot;</span><br><span class="line">order += &quot;ethernet _first_&quot;</span><br><span class="line">order += &quot;battery all&quot;</span><br><span class="line">order += &quot;load&quot;</span><br><span class="line">order += &quot;tztime local&quot;</span><br><span class="line"></span><br><span class="line">wireless _first_ &#123;</span><br><span class="line">        format_up = &quot;W: (%quality at %essid) %ip&quot;</span><br><span class="line">        format_down = &quot;W: down&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">ethernet _first_ &#123;</span><br><span class="line">        # if you use %speed, i3status requires root privileges</span><br><span class="line">        format_up = &quot;E: %ip (%speed)&quot;</span><br><span class="line">        format_down = &quot;E: down&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">cpu_temperature 0 &#123;</span><br><span class="line">        format = &quot;CPU 0: %degrees°&quot;</span><br><span class="line">        path = &quot;/sys/devices/platform/coretemp.0/hwmon/hwmon4/temp1_input&quot;</span><br><span class="line">        max_threshold = 75</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">#cpu_temperature 1 &#123;</span><br><span class="line">#       format = &quot;CPU 1: %degrees°&quot;</span><br><span class="line">#       path = &quot;/sys/devices/platform/coretemp.0/hwmon/hwmon4/temp2_input&quot;</span><br><span class="line">#       max_threshold = 75</span><br><span class="line">#&#125;</span><br><span class="line"></span><br><span class="line">battery all &#123;</span><br><span class="line">        format = &quot;%status %percentage %remaining&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">tztime local &#123;</span><br><span class="line">        format = &quot;%Y-%m-%d %H:%M:%S&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">load &#123;</span><br><span class="line">        format = &quot;%1min&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">disk &quot;/&quot; &#123;</span><br><span class="line">        format = &quot;[/] %avail&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">disk &quot;/home&quot; &#123;</span><br><span class="line">        format = &quot;[~] %avail&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">volume headphones &#123;</span><br><span class="line">   format = &quot;Volume : %volume&quot;</span><br><span class="line">   format_muted = &quot;Volume:muted&quot;</span><br><span class="line">   mixer = &quot;Headphone&quot;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="i3" scheme="https://keshane.moe/tags/i3/"/>
    
    <category term="i3 status bar" scheme="https://keshane.moe/tags/i3-status-bar/"/>
    
    <category term="i3 window manager" scheme="https://keshane.moe/tags/i3-window-manager/"/>
    
    <category term="i3wm" scheme="https://keshane.moe/tags/i3wm/"/>
    
    <category term="linux" scheme="https://keshane.moe/tags/linux/"/>
    
  </entry>
  
  <entry>
    <title>我是如何处理“人行道不停车让行的”到一瞬爆炸的(三)</title>
    <link href="https://keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/"/>
    <id>https://keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/</id>
    <published>2019-06-20T14:51:54.000Z</published>
    <updated>2026-07-27T14:35:50.398Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0">我是如何处理“人行道不停车让行的”到一瞬爆炸的(一)</a></p><p><a href="https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1">我是如何处理“人行道不停车让行的”到一瞬爆炸的(二)</a></p><h3 id="今天终于处理好了"><a href="#今天终于处理好了" class="headerlink" title="今天终于处理好了"></a>今天终于处理好了</h3><p>昨天晚上，我们对今天的行程进行了规划，经过仔细的思考，我们决定溜掉早上的第一节课，然后通过滴滴前往目标点c，并没有前往司机推荐的目标点d</p><p><img src="https://webp.keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/amap.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/amap.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="离我们比较近的几个交警队"></p><p>我们出门的比较早，8:40就到了，然后等到工作人员上班大概在9:30的时候终于处理好了。</p><p><img src="https://webp.keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/end.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/20/deal-with-changan-traveltraffic-violation2/end.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="处罚单"></p><p>其实连着读感觉违章原因就没那么奇怪了</p><h3 id="时隔半年后来写个总结"><a href="#时隔半年后来写个总结" class="headerlink" title="时隔半年后来写个总结"></a>时隔半年后来写个总结</h3><p>使用共享汽车平台在享受了便携的同时也存在许多的风险，一个简单的违章处理都让人身心疲惫，如果发生了更加重大的交通事故，协议，赔偿，垫付等一系列事情都会让人难以处理。</p><p>具体的问题可以查看好友Nova的文章<a href="https://nova.moe/talk-about-car-renting-in-china/">谈谈我对大陆分时租车的理解</a>了解更多。</p><p>出行注意安全。</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="长安出行" scheme="https://keshane.moe/tags/%E9%95%BF%E5%AE%89%E5%87%BA%E8%A1%8C/"/>
    
    <category term="共享汽车" scheme="https://keshane.moe/tags/%E5%85%B1%E4%BA%AB%E6%B1%BD%E8%BD%A6/"/>
    
    <category term="违章" scheme="https://keshane.moe/tags/%E8%BF%9D%E7%AB%A0/"/>
    
    <category term="停车让行" scheme="https://keshane.moe/tags/%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C/"/>
    
    <category term="人行道不停车让行的" scheme="https://keshane.moe/tags/%E4%BA%BA%E8%A1%8C%E9%81%93%E4%B8%8D%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>我是如何处理“人行道不停车让行的”到一瞬爆炸的(二)</title>
    <link href="https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/"/>
    <id>https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/</id>
    <published>2019-06-19T09:24:05.000Z</published>
    <updated>2026-07-27T14:35:50.396Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0">我是如何处理“人行道不停车让行的”到一瞬爆炸的(一)</a></p><h2 id="今天是爆炸的一天"><a href="#今天是爆炸的一天" class="headerlink" title="今天是爆炸的一天"></a>今天是爆炸的一天</h2><p>昨天回寝室之后，我查了一下可以在那些地方办理违章，然后准备找个时间去办理，但是遇到了很多的问题。整理一下今天爆炸的时间线。</p><h2 id="早些时间"><a href="#早些时间" class="headerlink" title="早些时间"></a>早些时间</h2><p>由于今天的课程分布，其实没有太多的时间去办理违章。</p><p>在上课期间，长安出行更新了我的违章状态<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E7%8A%B6%E6%80%81.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E7%8A%B6%E6%80%81.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="状态信息"><br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E7%8A%B6%E6%80%81%E8%AF%A6%E6%83%85.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E7%8A%B6%E6%80%81%E8%AF%A6%E6%83%85.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="状态详情"></p><p>我根本就没处理这个违章，但是怎么突然就处理结束了呢？然后长安出行发短信解释了一下</p><p><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/sms.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/sms.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p><p>长安出行工作人员的操作真骚。</p><h2 id="11-05"><a href="#11-05" class="headerlink" title="11:05"></a>11:05</h2><p>我们的课程是最后一周，在上午第大二节课时老师复习了一节小课之后就不再讲课，所以我和室友在课间的时候溜了出来。通过高德地图查到了几个比较近的交警支队。以下称为A、B、C 3点。<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/amap.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/amap.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="离我们比较近的几个交警队"></p><p>A点的名字叫“重庆市公安局交通巡逻警察总队”，听名字就特别牛逼。我们决定先去这个地方，然后发现我们真是 too young ，这里根本就不办理违章处理。。。。</p><p>在门口保安的指示下，我们前往地点B</p><h2 id="11-30"><a href="#11-30" class="headerlink" title="11:30"></a>11:30</h2><p>我们到达地铁站准备前往地点B</p><h2 id="11-50"><a href="#11-50" class="headerlink" title="11:50"></a>11:50</h2><p>到达地点B，在门口的自助机器上查看了违章详情，发现确实是人行道不停车让行的。可能由于我们是属于租赁车辆，所以不能直接在机器上进行操作，工作人员让我们到后面去跟A、B照的人一起排号进行人工处理。我们到达等候大厅的时候，一个态度非常恶劣的工作人员直接告诉我们下午两点再去，现在已经下班了。</p><h2 id="15-40"><a href="#15-40" class="headerlink" title="15:40"></a>15:40</h2><p>下午第一节课下课之后，我们就又前往地点B。</p><h2 id="16-20"><a href="#16-20" class="headerlink" title="16:20"></a>16:20</h2><p>到达地点B，却发现等候大厅里取号处没有人，等了大概5分钟之后，上午那个态度很差的工作人员又进来跟我们说让我们明天早上9:00再去，现在已经排满号了。<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E9%AA%82%E4%BA%BA.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation1/%E9%AA%82%E4%BA%BA.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="我想骂人"></p><h2 id="16-30"><a href="#16-30" class="headerlink" title="16:30"></a>16:30</h2><p>在B点和工作人员交涉无果后，我们决定去C点碰下运气。在滴滴上，司机推荐了一个比较远的处理点，说是人比较少，但是现在去可能已经来不及了。</p><p>到达C之后依然被告知明天再去。</p><p>!@#$%^&amp;*</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="长安出行" scheme="https://keshane.moe/tags/%E9%95%BF%E5%AE%89%E5%87%BA%E8%A1%8C/"/>
    
    <category term="共享汽车" scheme="https://keshane.moe/tags/%E5%85%B1%E4%BA%AB%E6%B1%BD%E8%BD%A6/"/>
    
    <category term="违章" scheme="https://keshane.moe/tags/%E8%BF%9D%E7%AB%A0/"/>
    
    <category term="停车让行" scheme="https://keshane.moe/tags/%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C/"/>
    
    <category term="人行道不停车让行的" scheme="https://keshane.moe/tags/%E4%BA%BA%E8%A1%8C%E9%81%93%E4%B8%8D%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>我是如何处理“人行道不停车让行的”到一瞬爆炸的(一)</title>
    <link href="https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/"/>
    <id>https://keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/</id>
    <published>2019-06-19T09:18:49.000Z</published>
    <updated>2026-07-27T14:35:50.393Z</updated>
    
    <content type="html"><![CDATA[<p>在6月18号下午，我收到了来自长安出行的一堆短信，告诉我某一次订单中产生了违章。<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/sms.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/sms.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="一堆短信"><br>我的第一想法是我某次还车的时候因为定位除了偏差产生了违章行为，而当我打开长安出行app之后，我傻了，真的。<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E8%BF%9D%E7%AB%A0%E8%AF%A6%E6%83%85.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E8%BF%9D%E7%AB%A0%E8%AF%A6%E6%83%85.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="违章详情"><br>一个1月份的违章，隔了5个月之后给我发短信让我去处理，而这5个月期间，我依然正常的使用了多次长安出行。而违章的原因是</p><blockquote><p>人行道不停车让行的</p></blockquote><p><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E5%BF%83%E6%83%85%E5%A4%8D%E6%9D%82.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E5%BF%83%E6%83%85%E5%A4%8D%E6%9D%82.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="心情复杂"></p><p><del>我今天写博客的时候发现长安出行app上关于违章会在一个月内推送的消息没了，昨天忘记截图了</del></p><p>虽然我是一脸懵逼的，但是问题还是要处理，总之应该在交警那里可以看到违章的照片。</p><p>由于之前没有过处理违章的经验，于是我翻阅了长安出行app的帮助并在网上找了一些相关事故处理的教程。得到了大致的处理流程<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E5%B8%AE%E5%8A%A9%E4%BF%A1%E6%81%AF.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E5%B8%AE%E5%8A%A9%E4%BF%A1%E6%81%AF.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="长安出行的帮助信息"><br>首先预约时间去长安出行公司领取车辆的行驶证，然后再3个工作日内去交通违章处理点进行违章处理并返还行驶证就可以了。</p><p>首先这个预约时间根本不是两个输入框，而是两个选择框，让你二选一，但是这个真的好容易误会<br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E9%80%89%E6%8B%A9%E6%97%B6%E9%97%B41.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E9%80%89%E6%8B%A9%E6%97%B6%E9%97%B41.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="选择时间之前"><br><img src="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E9%80%89%E6%8B%A9%E6%97%B6%E9%97%B42.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/06/19/deal-with-changan-traveltraffic-violation0/%E9%80%89%E6%8B%A9%E6%97%B6%E9%97%B42.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="选择时间之后"></p><p>在误操作直接预约了当天之后，室友使用长安出行一同前往保利中心的长安车联公司。</p><p>而到达了长安车联公司之后，我了解到就是这天下午，交警突然给长安出行发了1000多条信息。而我到达的半个小时之前，来领取行驶证的人已经挤爆了长安车联公司。</p><p>此时已经过了17:00，所以我和室友决定第二天再去违章处理</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="长安出行" scheme="https://keshane.moe/tags/%E9%95%BF%E5%AE%89%E5%87%BA%E8%A1%8C/"/>
    
    <category term="共享汽车" scheme="https://keshane.moe/tags/%E5%85%B1%E4%BA%AB%E6%B1%BD%E8%BD%A6/"/>
    
    <category term="违章" scheme="https://keshane.moe/tags/%E8%BF%9D%E7%AB%A0/"/>
    
    <category term="停车让行" scheme="https://keshane.moe/tags/%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C/"/>
    
    <category term="人行道不停车让行的" scheme="https://keshane.moe/tags/%E4%BA%BA%E8%A1%8C%E9%81%93%E4%B8%8D%E5%81%9C%E8%BD%A6%E8%AE%A9%E8%A1%8C%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>在游戏里创造家园</title>
    <link href="https://keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/"/>
    <id>https://keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/</id>
    <published>2019-05-23T06:21:12.000Z</published>
    <updated>2026-07-27T14:35:50.392Z</updated>
    
    <content type="html"><![CDATA[<h1 id="在游戏里创造家园"><a href="#在游戏里创造家园" class="headerlink" title="在游戏里创造家园"></a>在游戏里创造家园</h1><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=100% height=86 src="//music.163.com/outchain/player?type=2&id=540042&auto=1&height=66"></iframe><p>我不知道在写什么，尝试分析一下我对这类玩法的喜爱，但却什么也想不到。。。</p><h1 id="把生存类游戏玩成模拟游戏"><a href="#把生存类游戏玩成模拟游戏" class="headerlink" title="把生存类游戏玩成模拟游戏"></a>把生存类游戏玩成模拟游戏</h1><p>不知道有没有人和我有差不多同样的玩法，在一些比较开放、自由的生存类游戏中，总是喜欢自己给自己找定一个安全的区域，在这块区域里面建造、种地，一切都自给自足。</p><p>玩 Minecraft 时，和我一同游戏的好友总是比较喜欢去探索，而我则更多的呆在我们的小区域里，开始自己的“农耕”生活，相对于去探索无限开阔的世界，我总是更喜欢守护这一方小小的安宁，创造一个自给自足的世外桃源。在玩 Rust 这种对抗性比较高的游戏时，我和同学们甚至把自己的房子围起来，然后建造碉堡来对抗试图抄家的人，而在 Forest 这种偏向 PVE 的游戏中，每到晚上就是围着院墙打野人的时间<del>然后野人通过胁迫堆进院子里了</del></p><p>建造、守护、外加不怎么进行的探索成了我在生存类游戏的主要玩法，或许是由于在这类生存类游戏中并不是所有的玩家都可以信任，所以我总是想要把自己尽量减少与其他玩家接触的机会，也总是想要保护好自己的家园，就像维护自己现实世界中的家园一样</p><h1 id="模拟建设类的游戏"><a href="#模拟建设类的游戏" class="headerlink" title="模拟建设类的游戏"></a>模拟建设类的游戏</h1><p>在这类游戏中，总是能给我一些中麻烦不断，需要不断解决的问题</p><p>我接触的第一款模拟类游戏大概就是发售于2013年的模拟城市5，这是我第一次购买海外正版游戏，然后玩了一段时间就连不上服务器了。。。</p><p><img src="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/simcity.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/simcity.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="模拟城市上次打开时间"></p><p>然后后来接触了特大城市，都市天际线。这时候我才发现模拟城市5的游戏地图大小真是个弟弟，感觉应该叫做模拟乡村。不过可以多人联机在同一个区域建造几个不同的城市在我看来其实是挺棒的想法。</p><p>而相对来说我游戏时间最长的都市：天际线在游戏性上更加完善</p><p><img src="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/stardew-valley.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/stardew-valley.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="星露谷物语"></p><p><img src="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/stardew-valley2.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/05/23/why-do-i-like-creating-home-in-games/stardew-valley2.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="星露谷物语"></p><p>每个人的心中或许都还保留着儿时的理想，但在现代的生活中却无法实现自己的理想，正是这些模拟类游戏的存在，让我感受到生活不是那么的乏味</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="home" scheme="https://keshane.moe/tags/home/"/>
    
    <category term="随便写写" scheme="https://keshane.moe/tags/%E9%9A%8F%E4%BE%BF%E5%86%99%E5%86%99/"/>
    
  </entry>
  
  <entry>
    <title>和NovaKwok进行的一些测试</title>
    <link href="https://keshane.moe/2019/04/26/test-with-NovaKwok/"/>
    <id>https://keshane.moe/2019/04/26/test-with-NovaKwok/</id>
    <published>2019-04-26T17:16:45.000Z</published>
    <updated>2026-07-27T14:35:50.391Z</updated>
    
    <content type="html"><![CDATA[<h1 id="和NovaKwok进行的一些测试"><a href="#和NovaKwok进行的一些测试" class="headerlink" title="和NovaKwok进行的一些测试"></a>和NovaKwok进行的一些测试</h1><h2 id="发生了什么"><a href="#发生了什么" class="headerlink" title="发生了什么"></a>发生了什么</h2><p>最近 github 上 bilibili 被开源一事闹沸沸扬扬，然后 Nova Kwok 发现了一些有趣的事</p><blockquote><p>账号被盗了，大家散了吧！</p></blockquote><blockquote><p>我自己也不清楚怎么回事，我更没有能力做出这种事，大家散了吧！</p></blockquote><blockquote><p>相关讨论贴: <a href="https://www.v2ex.com/amp/t/557641/3">https://www.v2ex.com/amp/t/557641/3</a> </p></blockquote><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/fake.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/fake.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="有趣的事"></p><p><a href="https://www.v2ex.com/t/557641">v2ex上的讨论</a></p><blockquote><p>你不是号被盗了,是躺枪了…. 话说昨天我已经在那个仓库发了,还让你开个仓库解释一下原理,不明真相的路人来看一眼这个图就明白了.你把仓库删了又没有人知道怎么回事儿了. 改一下readme吧,改成测试的截图就行了</p></blockquote><p>我们对这些描述进行了一系列验证性测试</p><h2 id="按照图上的描述进行了第一次的测试"><a href="#按照图上的描述进行了第一次的测试" class="headerlink" title="按照图上的描述进行了第一次的测试"></a>按照图上的描述进行了第一次的测试</h2><p>在 github 上创建了一个仓库<br><a href="https://github.com/KnifeC/githubtest">github仓库</a></p><p>然后将本地的邮箱及用户配置成 “<a href="mailto:&#x72;&#111;&#111;&#116;&#64;&#x76;&#117;&#108;&#x74;&#x72;&#x2e;&#103;&#117;&#x65;&#115;&#116;">&#x72;&#111;&#111;&#116;&#64;&#x76;&#117;&#108;&#x74;&#x72;&#x2e;&#103;&#117;&#x65;&#115;&#116;</a>“ 和 “root”</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config user.email <span class="string">&quot;root@vultr.guest&quot;</span></span><br><span class="line">git config user.name <span class="string">&quot;root&quot;</span></span><br></pre></td></tr></table></figure><p>然后创建一个readme.md，修改一下内容并commit</p><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_first.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_first.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="本地记录"></p><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/github_first.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/github_first.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="github记录"></p><p>好像和图上说的并不一样</p><h2 id="将邮箱和用户名设置成Nova的邮箱和用户名"><a href="#将邮箱和用户名设置成Nova的邮箱和用户名" class="headerlink" title="将邮箱和用户名设置成Nova的邮箱和用户名"></a>将邮箱和用户名设置成Nova的邮箱和用户名</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config user.email <span class="string">&quot;n0vad3v@xxxxxx.net&quot;</span></span><br><span class="line">git config user.name <span class="string">&quot;n0vad3v&quot;</span></span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_second.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_second.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="本地记录"></p><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/GitHub_second.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/GitHub_second.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="github记录"></p><h2 id="修改用户名"><a href="#修改用户名" class="headerlink" title="修改用户名"></a>修改用户名</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config user.name <span class="string">&quot;keshane&quot;</span></span><br></pre></td></tr></table></figure><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_third.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/local_third.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="本地记录"></p><p><img src="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/github_third.png" class="lazy" data-srcset="https://webp.keshane.moe/2019/04/26/test-with-NovaKwok/github_third.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="github记录"></p><p>还没写完，看情况可能不鸽吧</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="github" scheme="https://keshane.moe/tags/github/"/>
    
    <category term="git" scheme="https://keshane.moe/tags/git/"/>
    
    <category term="commit" scheme="https://keshane.moe/tags/commit/"/>
    
  </entry>
  
  <entry>
    <title>聊聊我玩过的游戏 —— 古剑奇谭三</title>
    <link href="https://keshane.moe/2019/03/28/talk-about-gujian3-0/"/>
    <id>https://keshane.moe/2019/03/28/talk-about-gujian3-0/</id>
    <published>2019-03-28T12:28:12.000Z</published>
    <updated>2026-07-27T14:35:50.383Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/yyw_official.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/yyw_official.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="摇曳湾"></p><blockquote><p>难道羸弱便不求强大,微小便永坠尘泥?</p></blockquote><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=100% height=86 src="//music.163.com/outchain/player?type=3&id=2059343898&auto=1&height=66"></iframe><h1 id="聊聊我玩过的游戏-——-古剑奇谭三"><a href="#聊聊我玩过的游戏-——-古剑奇谭三" class="headerlink" title="聊聊我玩过的游戏 —— 古剑奇谭三"></a>聊聊我玩过的游戏 —— 古剑奇谭三</h1><!-- 对于国产单机游戏市场，大部分人都觉得国内的游戏市场无法支撑一部3a级大作，而近几年的几部国产单机大作使得国产单机的口碑在整个游戏圈不断下滑，导致国产单机游戏近几年都陷入了一种怪圈——技术不足以支撑一部符合玩家心里预期的大作——玩家不愿意玩——没有收入，无法去提升作品质量。对比一下部分手游的投入和收入，在这种条件下大投入的单机游戏无疑是一种冒险的行为，古剑三作为  --><!-- ## 初见 --><p>古剑三的第一眼就足够吸引人，玩家操控满级的玄戈在光明野讨伐魔兽，整个场景非常美。而玄戈流畅的战斗动作着实让被回合制折磨疯的国产单机玩家爽了一把。不得不说，古剑三给人的感觉十分亮眼，对于国产游戏来讲，整体的画面、音乐、人物动作都属于顶尖。而在世界游戏市场上对比，古剑三虽然比不过同时期的一些3A大作，但也可以算作一部不错的作品。<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_1.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_1.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="西陵_姬轩辕"></p><!-- ## 敢于突破的即时制战斗 --><p>战斗系统的进化是我们上手就能感受到的，国产单机游戏终于不再是即时制战斗，在战斗系统上的突破无疑会使古剑三的耐玩度有一定程度的上升。这并不是古剑系列在战斗系统方面尝试的第一次突破，早在古剑二时战斗系统就由回合制转变成了一个需要切换场景的“即时制”战斗。但是古剑二战斗系统的突破非常失败，因为要切换场景的原因，古剑二的战斗在开始之前双方要一字排开然后倒数321开打，显得非常睿智。二代的战斗系统除了需要切入之外，打击感也是非常糟糕，人物操作的硬直非常大，动作根本无法做到流畅。古剑三取消了场景切入，并且整体战斗的流畅性和打击感相比较与二代有了质的飞跃，虽然说比不上一些动作类游戏，但是作为一个ARPG已经是一个合格的战斗系统了。更重要的是，它给了国产单机游戏的热爱者另一种战斗方式的选择。但是随着即时制战斗的引入，初代作品的粉丝肯定稍微有些不适应，于是有人以神农剑法（疯狂嗑药）来进行游戏。</p><!-- ## 不再拘泥于儿女情长的剧情 --><p><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_3.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_3.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="星火世传，奋飞不辍"></p><!-- 很多人对于古剑三的突破更多认为是游戏模式上的突破。对我而言 --><p>古剑三在剧情上的突破则更大，古剑三不再局限于国产单机游戏一贯的儿女情长，而是选择了传承作为故事的主题。扩大了格局，并且将传统文化的方方面面融入进去。游戏剧情从北洛修复天鹿城大阵去人界找寻黄帝后人作为引入，并至始至终贯穿整个游戏流程。整个游戏剧情非常充实，并且没有二代遗留下来的“跑路5分钟，对话一小时”的繁琐对话。古剑三将许多不必要的剧情放在了支线中，比如北洛的身世，我一周目的时候都不知道有这么一个剧情。。。整个故事的前中期铺垫很多，给整个故事留了很多的伏笔，而游戏后期剧情感觉突然加快，很多伏笔没有回收，甚至在最终Boss前还留有其他伏笔。有许多坑游戏里挖了还没填故事就结束了，导致结尾比较草率。希望烛龙能尽快出DLC补足剧情，完善一下整个世界观。</p><!-- ## 不断进步的故事演绎 --><p><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/longgong_1.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/longgong_1.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="非常惊艳的龙宫剧情"><br>古剑系列一直都在故事演绎上走得比其他国产游戏更加靠前。古剑一取消了2D表情，并通过人物面部表情来进行演绎，在那个年代实属难得，并且我没记错应该是国产第一款全程配音的游戏。而古剑二则更加激进，取消了对话框，尝试通过运镜、人物动作和台词来推动剧情,但是动作过于单一，并且镜头比较奇怪，还有冗长的对话使得过场画看得非常难受，成功从游戏变成了有各种穿帮镜头的尴尬舞台剧。<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/beiluo_talk.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/beiluo_talk.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="优秀的分镜"><br>而古剑三人物动作有了进步，虽然不是十分流畅，但是通过合理的分镜成功避开了一些容易出现僵硬动作的镜头，使得过长动画的观感有了大幅提高。但是人物的面部表情依然不足，虽然北洛和云无月都是见得多了，各种情况都是见怪不怪，面无表情都很正常，但是岑缨面部表情缺乏就实在是有些违和了。</p><!-- ## 能够被注意到的细节 --><p>除了肉眼可见的改变，古剑3在许多细节方面也做到了国产游戏未曾做到的深度，北洛撞上行人时的不再是像撞上一堵墙一样没有任何反馈，而是会做出对应的动作<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/zhuang_ren.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/zhuang_ren.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="没有截到图的北洛撞人"></p><p>而NPC们也不是站在那里当摆设，当主角走过的时候也会有一些自言自语，比如下面这个NPC在唱歌<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/NPC_talk.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/NPC_talk.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="唱歌的NPC"></p><p>古剑三在剧情之外还加入了许多丰富的小游戏，你甚至可以在家园里面种田（神农剑法的基础）。不过为什么这一代温泉只能给老鼠泡啊（妖不如鼠），明明二代主角都还可以泡温泉。<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/nmd,wsm.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/nmd,wsm.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="nmd,wsm"><br>虽然很多人沉迷打牌，忘记主线，但是我个人对并不是太感兴趣，也没有仔细玩过。<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/qianqiuxi.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/qianqiuxi.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="千秋戏"></p><!-- ## 然而依然存在的缺点 --><p>古剑三并不是一个完美的作品，有许多地方可以完善，但是却是我们现在能玩到的完成度最高的国产单机游戏。对比一下近几年部分手游的投入和营收，在这种环境下开发单机游戏无疑是一种冒险的行为，更何况我们的制作水平并没有达到3A的水准。在这样的环境下古剑三就像游戏里北洛和云无月的对话一样</p><blockquote><p>便如面对惊涛巨浪，搏命而泳只为一线生机<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/world_2.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/world_2.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="></p></blockquote><p>古剑三是一款成功的作品，也是烛龙在国产游戏市场下的一种坚持，我们没有顶尖的研发实力，我们没有良好的游戏环境，但是</p><blockquote><p>难道羸弱便不求强大,微小便永坠尘泥?<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/world_1.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/world_1.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="难道羸弱便不求强大,微小便永坠尘泥? "></p></blockquote><blockquote><p>人生百年，吾道不孤，总会有人和我们一起的<br><img src="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_4.jpg" class="lazy" data-srcset="https://webp.keshane.moe/2019/03/28/talk-about-gujian3-0/human_4.jpg" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="人生百年，吾道不孤"></p></blockquote>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="game" scheme="https://keshane.moe/categories/game/"/>
    
    
    <category term="国产" scheme="https://keshane.moe/tags/%E5%9B%BD%E4%BA%A7/"/>
    
    <category term="古剑奇谭" scheme="https://keshane.moe/tags/%E5%8F%A4%E5%89%91%E5%A5%87%E8%B0%AD/"/>
    
    <category term="单机" scheme="https://keshane.moe/tags/%E5%8D%95%E6%9C%BA/"/>
    
    <category term="仙侠" scheme="https://keshane.moe/tags/%E4%BB%99%E4%BE%A0/"/>
    
  </entry>
  
  <entry>
    <title>安卓自定义布局</title>
    <link href="https://keshane.moe/2018/11/14/android-modify-layout/"/>
    <id>https://keshane.moe/2018/11/14/android-modify-layout/</id>
    <published>2018-11-14T13:01:01.000Z</published>
    <updated>2026-07-27T14:35:50.370Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Android自定义布局相关的一些笔记"><a href="#Android自定义布局相关的一些笔记" class="headerlink" title="Android自定义布局相关的一些笔记"></a>Android自定义布局相关的一些笔记</h1><p>这个笔记主要记录自己关于Android中自定义布局的相关操作的理解</p><h2 id="仅布局"><a href="#仅布局" class="headerlink" title="仅布局"></a>仅布局</h2><p>这个其实比较简单且好理解,只需要写好一个xml并且在另一个xml中引入就好了</p><ul><li>示例:自定义的xml “title.xml”<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;utf-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">&quot;http://schemas.android.com/tools&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:background</span>=<span class="string">&quot;@color/colorAccent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:orientation</span>=<span class="string">&quot;horizontal&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">&quot;@+id/titleback&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">&quot;0dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_weight</span>=<span class="string">&quot;1&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:text</span>=<span class="string">&quot;返回&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_gravity</span>=<span class="string">&quot;left&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">&quot;0dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_weight</span>=<span class="string">&quot;3&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:gravity</span>=<span class="string">&quot;center&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:text</span>=<span class="string">&quot;自定义布局&quot;</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">&quot;@+id/titleedit&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">&quot;0dp&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_weight</span>=<span class="string">&quot;1&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_gravity</span>=<span class="string">&quot;right&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:text</span>=<span class="string">&quot;自定义&quot;</span></span></span><br><span class="line"><span class="tag">        /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li>在其他布局中引入<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">include</span> <span class="attr">layout</span>=<span class="string">&quot;@layout/title&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>非常简单</li></ul><p>但是这样会存在一个问题,每次在引入自定义布局之后,如果想要有动态实现,都必须要重写里面的监听器方法,而许多按钮的方法是相同的,会浪费大量的时间在重复的事情上<br>所以需要<strong>通过代码新建自定义布局</strong></p><h2 id="通过代码新建自定义布局"><a href="#通过代码新建自定义布局" class="headerlink" title="通过代码新建自定义布局"></a>通过代码新建自定义布局</h2><ol><li>通过代码新建自定义布局依然需要我们自己实现一个xml布局</li><li>然后编写一个普通的类(不是Acticity)继承各个基础Layout布局(取决于你xml中使用的布局)</li><li>重写其中的一个构造方法,在该方法中使用LayoutInflater进行动态渲染</li><li>看下代码中的注释吧</li></ol><ul><li>xml就是上面的title.xml</li><li>通过代码新建,可以直接实现里面的方法<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.example.ckxgo.listview;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.app.Activity;</span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.support.annotation.Nullable;</span><br><span class="line"><span class="keyword">import</span> android.util.AttributeSet;</span><br><span class="line"><span class="keyword">import</span> android.view.LayoutInflater;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"><span class="keyword">import</span> android.widget.Button;</span><br><span class="line"><span class="keyword">import</span> android.widget.LinearLayout;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by ckxgo on 2018/10/15.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TitleactLayout</span> <span class="keyword">extends</span> <span class="title class_">LinearLayout</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TitleactLayout</span><span class="params">(Context context)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(context);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TitleactLayout</span><span class="params">(Context context, <span class="meta">@Nullable</span> AttributeSet attrs)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(context, attrs);</span><br><span class="line">        <span class="comment">//使用LayoutInflater的from方法获取一个上下文</span></span><br><span class="line">        <span class="comment">//通过Context类的inflate()方法渲染一个layout</span></span><br><span class="line">        <span class="comment">//合起来就写成这个样子</span></span><br><span class="line">        <span class="comment">//还可以添加一些方法</span></span><br><span class="line">        LayoutInflater.from(context).inflate(R.layout.title,<span class="built_in">this</span>);</span><br><span class="line">        <span class="type">Button</span> <span class="variable">goBack</span> <span class="operator">=</span> (Button) findViewById(R.id.titleback);</span><br><span class="line">        <span class="type">Button</span> <span class="variable">goEdit</span> <span class="operator">=</span> (Button) findViewById(R.id.titleedit);</span><br><span class="line">        goBack.setOnClickListener(<span class="keyword">new</span> <span class="title class_">View</span>.OnClickListener()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onClick</span><span class="params">(View v)</span> &#123;</span><br><span class="line">                ((Activity)getContext()).finish();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>在layout中引入<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">com.example.ckxgo.listview.TitleactLayout</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;wrap_content&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">com.example.ckxgo.listview.TitleactLayout</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="android" scheme="https://keshane.moe/tags/android/"/>
    
    <category term="modify" scheme="https://keshane.moe/tags/modify/"/>
    
    <category term="layout" scheme="https://keshane.moe/tags/layout/"/>
    
  </entry>
  
  <entry>
    <title>使用python提升生活——随机电影(文件)选择器</title>
    <link href="https://keshane.moe/2018/11/04/using-python-to-get-better-life/"/>
    <id>https://keshane.moe/2018/11/04/using-python-to-get-better-life/</id>
    <published>2018-11-04T16:10:10.000Z</published>
    <updated>2026-07-27T14:35:50.370Z</updated>
    
    <content type="html"><![CDATA[<h1 id="随机电影-文件-选择器"><a href="#随机电影-文件-选择器" class="headerlink" title="随机电影(文件)选择器"></a>随机电影(文件)选择器</h1><p>不知道是不是只有我一个人存在这样的情况,在某个地方存放着珍藏多年<del>不可告人</del>的一堆电影资源,有时候想要挑几部出来看却又犯了选择困难症,所以我个人有了这么一个奇怪的需求</p><p><del>写一行先鸽了</del></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="code" scheme="https://keshane.moe/categories/code/"/>
    
    
    <category term="python" scheme="https://keshane.moe/tags/python/"/>
    
    <category term="life" scheme="https://keshane.moe/tags/life/"/>
    
    <category term="help" scheme="https://keshane.moe/tags/help/"/>
    
  </entry>
  
  <entry>
    <title>hello,blog</title>
    <link href="https://keshane.moe/2018/11/01/hello-blog/"/>
    <id>https://keshane.moe/2018/11/01/hello-blog/</id>
    <published>2018-11-01T13:51:31.000Z</published>
    <updated>2026-07-27T14:35:50.370Z</updated>
    
    <content type="html"><![CDATA[<h1 id="wow-好像成功了"><a href="#wow-好像成功了" class="headerlink" title="wow!好像成功了"></a>wow!好像成功了</h1><p>自己在几周前创建的仓库’knifec.github.io’好像终于有用了。</p><p>插入一张图片庆祝一下</p><p><img src="https://webp.keshane.moe/image/violet_4_10.png" class="lazy" data-srcset="https://webp.keshane.moe/image/violet_4_10.png" srcset="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXMzMyWlpYU2uzLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="pic"></p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    <category term="life" scheme="https://keshane.moe/categories/life/"/>
    
    
    <category term="first" scheme="https://keshane.moe/tags/first/"/>
    
    <category term="diary" scheme="https://keshane.moe/tags/diary/"/>
    
  </entry>
  
</feed>
