# 杂项技术

背景

我们有的时候只是涉及到一些小文件,比如一些配置文件,一些小的图片等等,这些文件的内容不是很大,但是我们又不想直接把这些文件放到项目中,这个时候我们可以使用链接来直接存储这些小文件的内容。

而url支持使用 data 协议来使用base64格式直接存储小文件的内容,这样我们就可以直接使用链接来存储小文件的内容。

使用

我们可以使用如下的方式来存储小文件的内容:

1
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/0lEQVQ4jZXTsUoDQRDG8d8Q9" alt="Red dot" />

这里的 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/0lEQVQ4jZXTsUoDQRDG8d8Q9 就是一个base64格式的图片内容,我们可以直接使用这个链接来展示图片。

然后我写了一个简单的脚本来生成base64格式的图片内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <fstream>
#include <vector>
#include <string>
#include <iostream>

const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

#include <chrono>

std::string base64_encode(const std::vector<unsigned char>& buffer) {
std::string encoded;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];

int totalBytes = buffer.size();
int progressInterval = totalBytes / 10; // Update progress every 10% of the total bytes

for (const auto& byte : buffer) {
char_array_3[i++] = byte;
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;

for (i = 0; (i < 4); i++)
encoded += base64_chars[char_array_4[i]];
i = 0;

// Update progress
if (encoded.size() % progressInterval == 0) {
int progress = (encoded.size() * 100) / totalBytes;
std::cout << "Progress: " << progress << "%" << std::endl;
}
}
}

if (i) {
for (j = i; j < 3; j++)
char_array_3[j] = '\0';

char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

for (j = 0; (j < i + 1); j++)
encoded += base64_chars[char_array_4[j]];

while ((i++ < 3))
encoded += '=';
}

return encoded;
}

void fileToBase64(const std::string& path) {
std::ifstream file(path, std::ios::binary);
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(file), {});

std::string base64 = base64_encode(buffer);
std::string dataUrl = "data:application/x-rar-compressed;base64," + base64;
//输出到 “downloadLink_”+文件名.md文件

//1.获取不带路径的文件名
std::string::size_type iPos = path.find_last_of('\\') + 1;
std::string fileName = path.substr(iPos, path.length() - iPos);
std::cout << fileName << std::endl;

//2.获取不带后缀的文件名
std::string fileNameWithoutExtension = fileName.substr(0, fileName.rfind("."));
std::cout << fileNameWithoutExtension << std::endl;

//3.获取后缀名
std::string suffix_str = fileName.substr(fileName.find_last_of('.') + 1);
std::cout << suffix_str << std::endl;

std::string outputFileName = "downloadLink_" + fileNameWithoutExtension + ".md";
std::ofstream output(outputFileName);
//输出到md文件
//为md文件添加属性
//---
// title: downloadLink_下载文件名称
// date: 2024-05-02 17:36
// mathjax: false
// tags:
// - Download
// ---
output << "---" << std::endl;
output << "title: " << fileName << std::endl;
output << "date: 2024-03-01 17:36" << std::endl;
output << "mathjax: false" << std::endl;
output << "tags:" << std::endl;
output << " - Download" << std::endl;
output << "---" << std::endl;
//输出下载链接,文件名为原文件名
//以按钮的形式显示下载链接
output << "<a href=\"" << dataUrl << "\" download=\""<< fileName <<"\">点击下载</a>";
output.close();

//再在文件夹“DownloadLink”里添加一个只有属性但是不包含下载链接的md文件
std::string outputFileName2 = "downloadLink_" + fileNameWithoutExtension + ".md";
std::ofstream output2("DownloadLink\\" + outputFileName2);
//输出到md文件
//为md文件添加属性
//---
// title: downloadLink_下载文件名称
// date: 2024-05-02 17:36
// mathjax: false
// tags:
// - Download
// ---
output2 << "---" << std::endl;
output2 << "title: " << fileName << std::endl;
output2 << "mathjax: false" << std::endl;
output2 << "date: 2024-03-01 17:36" << std::endl;
output2 << "tags:" << std::endl;
output2 << " - Download" << std::endl;
output2 << "---" << std::endl;
output2.close();

std::cout << "Output file: " << outputFileName << std::endl;
}

//接收文件位置参数
int main(int argc, char* argv[]) {
//检查参数
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " file1 [file2] [file3] ..." << std::endl;
return 1;
}
//支持多个文件
for (int i = 1; i < argc; i++){
//显示进度条
std::cout << "Processing " << argv[i] << "..." << std::endl;
fileToBase64(argv[i]);
}

//结束后暂停
std::cout << "Press any key to exit..." << std::endl;
std::cin.get();
return 0;
}

这个脚本可以将指定的文件转换为base64格式的内容,并且生成一个md文件,这个md文件包含了下载链接,我们可以直接使用这个md文件来展示下载链接。

下面就是一个使用这个脚本生成的md文件的例子:

1
2
3
4
5
6
7
8
---
title: test.rar
date: 2024-03-01 17:36
mathjax: false
tags:
- Download
---
<a href="data:application/x-rar-compressed;base64,UEsDBAoAAAAAAKx4pVgvcG0lQAAAAEAAAAAMAAAAtePO0rXjztIudHh05ZOI5ZOI5ZOI77yM5piv5LiN5piv5oy65aW9546p55qEDQoNCuS9v+eUqOmTvuaOpeS8oOi+k+WOi+e8qeWMhVBLAQI/AAoAAAAAAKx4pVgvcG0lQAAAAEAAAAAMACQAAAAAAAAAIAAAAAAAAAC1487StePO0i50eHQKACAAAAAAAAEAGACtFN2Yup7aAVB935i6ntoBiknN7yme2gFQSwUGAAAAAAEAAQBeAAAAagAAAAAA" download="test.zip">点击下载</a>

点击下载

这样我们就可以直接使用这个md文件来展示下载链接了。

# 杂项技术

背景

新版 QQnt 使用了基于 Node.js 的插件架构技术,这种技术可以让开发者通过编写插件来扩展 QQnt 的功能。Node.js 是一种 JavaScript 运行时环境,它可以让开发者使用 JavaScript 编写服务器端应用程序。

其使用了node.js来进行处理的话,就意味着我们可以使用插件,来对最终渲染的内容进行修改。实际上就和 【html网页可以使用js插件进行自定义】或者说【hexo可以使用node.js插件进行自定义一样】。

QQnt 的插件架构技术利用了 Node.js 的模块化特性,将不同的功能模块封装成独立的插件,并通过插件管理器来加载和管理这些插件。LiteLoaderQQnt就为我们提供了这样的一个插件管理器,下面将其简称为LLnt。

使用方式&注意事项

使用方式可以查看他们的github页面,有十分详细的教程,在这里就不过多赘述。 LiteLoaderQQNT

tips:设置里面所做出的更改既无法保存也无法生效

需要注意的是,软件必须获取qqnt安装位置的所有文件访问权限,不然的话,llnt设置里面所做出的更改既无法保存也无法生效。解决这个问题有两种办法:

方法一:调整安装位置

只需要将qq安装位置不要放在默认的program file下即可,因为访问里面的文件需要管理员权限。可以将qq安装到其他目录,比如C盘的根目录或者自定义的文件夹中。这样就可以获得访问权限,llnt设置里面的更改才能保存和生效。

方法二:将qqnt文件夹取消只读,以管理员身份启动qqnt

另一种解决方法是取消qqnt文件夹的只读属性,并以管理员身份启动qqnt。这样可以确保llnt设置里面的更改能够保存和生效。

要取消qqnt文件夹的只读属性,可以按照以下步骤操作:

  1. 在资源管理器中,找到qqnt文件夹的位置。
  2. 右键单击qqnt文件夹,并选择“属性”选项。
  3. 在属性对话框中,取消选中“只读”复选框。
  4. 单击“确定”按钮保存更改。

然后,以管理员身份启动qqnt,可以通过以下步骤完成:

  1. 找到qqnt的快捷方式或可执行文件。
  2. 右键单击快捷方式或可执行文件,并选择“以管理员身份运行”选项。

这样,llnt设置里面的更改就能够保存和生效了。

下面我保存了一些下载链接,虽然说按理来说可以直接上github链接的,但是总是感觉那个不太稳定(作者删库跑路),所以说这里相当于存一份~

阅读全文 »

# 泰坦陨落2
# 游戏体验日记

铁驭的平台跳跃

贴墙跑,二段跳。游戏将这两个操作性极大的元素加以组合,实现了铁驭独一无二的机动性……

泰坦和铁驭的相结合

游戏中最有魅力的不是开机甲,也不是铁驭的机动性,而是泰坦和铁驭的相结合。

泰坦会和铁驭一起协作,给予铁驭建议,接住铁驭,等等。尤其是从各个角度接住铁驭然后将其塞回驾驶舱,真的是太酷了……

优秀的故事叙事和世界观的展开

游戏的世界观很饱满,让玩家能够真正的感受到处于战场之上的感觉……

阅读全文 »

# 游戏体验日记
# 山海旅人

山海旅人:修改故事的因果……

简而言之吧,游戏的特色解密机制在于回溯事情的过去,然后收获“想法”来影响人。

比如,对于一个本来是要晚归的丈夫,收集家里“米饭很香”的想法,然后用这个想法来影响丈夫“晚点回去的决定”,就能够让其早点回去。

说实话,这和我的那个fairy tale 的 游戏设计机制的第一部分的想法相似,而最后的一小段则又是和我的想法中的最后一个,自己回去修改自己的想法一致……

但是游戏中,对于这些事件的因果逻辑设计的并没有那么深入,其实也有一部分的原因是因为,这个真的要究其本质其实不过是“galgame”的那种分支选择属性罢了……

阅读全文 »

# 游戏设计
# 会议记录

游戏介绍

概述

跳出盒子工作室制作

是一款卡牌战棋杀戮尖塔like类游戏,打算融合: - 战棋 - 卡牌管理元素 - 杀戮尖塔like的肉鸽

四个方向的创新

1. 多角色设计&卡牌循环机制创新

创意思考

多角色设计指的是玩家通过操作复数的角色来完成游戏给定的目标,其本质是在有限角色限制下的角色行为规划。

在很多游戏中,设计多角色设计往往是为了让玩家合理规划不同角色的合作,从而保护目标建筑,或者攻破目标单位。

但是常规的这种设计较为无聊,让我们进一步创新,假设需要保护的对象就是英雄本身……甚至更进一步,需要保护的对象和抽牌堆弃牌堆相关联……


具体而言:

两个主单位,两个从单位,主单位控制两个能力”抽牌堆“”弃牌堆“,弃牌堆炸了之后,置入弃牌堆的牌会被散落。而此时,获取卡牌需要使用移动过去,但是同时,为了调节 卡牌 和 移动 的 矛盾我们可以增加一个拾取范围。

我的看法:
1
2
3
4
5
6
7
8
9
title:我的思考:无用的设计

将主单位作为需要保护的对象,承担了抽牌堆弃牌堆的职权,听起来很酷,但是实际上,对于这两个主对象的操作是有害而无利的。

角色每次移动需要使用一张移动卡,而移动只能移动一格,假设玩家的拾取范围是伽利略距离5格,那么玩家实际上消耗一张卡进行移动,在总卡数20/总地块64的情况之下,玩家实际上即使是对于全部散落的抽卡堆,也只能够拿到2张牌,而且这两张牌在若不是自己所需要的牌,则又会重新散落在场地上……

最终会导致的问题就是,卡牌散落在草地上,玩家每次移动只能拿到少数牌,而如果所需要的核心牌被随机到了最远端,则你这一局基本上就不要再想拿到了。

综上所述,玩家面临的实际情况就是,这两个主单位一旦被击败,给玩家带来的也不过是苟延残喘的机会,而这一延展方式,就导致其根本就不会成为游戏中和还不如主单位死了之后直接任务失败……
阅读全文 »
0%