迁移后更改
This commit is contained in:
@@ -1,54 +1,54 @@
|
|||||||
<a href=#en>English</a> <a href=#zh>中文</a>
|
<a href=#en>English</a> <a href=#zh>中文</a>
|
||||||
|
|
||||||
<div id="en"></div>
|
<div id="en"></div>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
A pixel-based UTF-8 printing program
|
A pixel-based UTF-8 printing program
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
> $\color{red} \bf Note:$
|
> $\color{red} \bf Note:$
|
||||||
> The CC compiler reads UTF-8 characters as '?',
|
> The CC compiler reads UTF-8 characters as '?',
|
||||||
> `print("Hello World")` has the same effect as `print("????")`.
|
> `print("Hello World")` has the same effect as `print("????")`.
|
||||||
> To fix this, read files in `"rb"` mode for proper input handling.
|
> To fix this, read files in `"rb"` mode for proper input handling.
|
||||||
|
|
||||||
## How to Create Fonts
|
## How to Create Fonts
|
||||||
- Font files should return a table where keys are UTF-8 code points, and values are corresponding character bitmaps.
|
- Font files should return a table where keys are UTF-8 code points, and values are corresponding character bitmaps.
|
||||||
- Each bitmap is a table of equal-length strings representing a 2x3 pixel grid defined by Computer Craft. To use the bottom-right pixel, subtract 128 from the char code to invert `backgroundColor` and `textColor`.
|
- Each bitmap is a table of equal-length strings representing a 2x3 pixel grid defined by Computer Craft. To use the bottom-right pixel, subtract 128 from the char code to invert `backgroundColor` and `textColor`.
|
||||||
- A single font file may contain bitmaps of different sizes, but it **must** include a bitmap for 'H' (ASCII:72) to indicate the maximum height of the font.
|
- A single font file may contain bitmaps of different sizes, but it **must** include a bitmap for 'H' (ASCII:72) to indicate the maximum height of the font.
|
||||||
- The final output uses the maximum bitmap height in the FontFamily as the baseline for bottom-aligned text.
|
- The final output uses the maximum bitmap height in the FontFamily as the baseline for bottom-aligned text.
|
||||||
- The FontFamily **must** include a '-' (ASCII:45) bitmap for potential word splitting during auto-wrapping.
|
- The FontFamily **must** include a '-' (ASCII:45) bitmap for potential word splitting during auto-wrapping.
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
- `require` a fusion-pixel-12px font consumes approximately **10.5MB** of memory.
|
- `require` a fusion-pixel-12px font consumes approximately **10.5MB** of memory.
|
||||||
- `require` a fusion-pixel-8px font consumes approximately **6MB** of memory.
|
- `require` a fusion-pixel-8px font consumes approximately **6MB** of memory.
|
||||||
- 8px characters occupy 3 rows vertically, while 12px characters occupy 4 rows.
|
- 8px characters occupy 3 rows vertically, while 12px characters occupy 4 rows.
|
||||||
- Fonts are sourced from <a href="https://github.com/TakWolf/fusion-pixel-font/releases">fusion-pixel-font</a>.
|
- Fonts are sourced from <a href="https://github.com/TakWolf/fusion-pixel-font/releases">fusion-pixel-font</a>.
|
||||||
|
|
||||||
<div id="zh"></div>
|
<div id="zh"></div>
|
||||||
|
|
||||||
## 介绍
|
## 介绍
|
||||||
|
|
||||||
一个基于像素打印的utf8打印程序
|
一个基于像素打印的utf8打印程序
|
||||||

|

|
||||||
|
|
||||||
> $\color{red} \bf 注意:$
|
> $\color{red} \bf 注意:$
|
||||||
> CC 编译器会把utf8字符读作 '?',
|
> CC 编译器会把utf8字符读作 '?',
|
||||||
> `print("你好世界")` 与 `print("????")` 的效果相同, 可以`"rb"`模式读取文件以设置输入
|
> `print("你好世界")` 与 `print("????")` 的效果相同, 可以`"rb"`模式读取文件以设置输入
|
||||||
|
|
||||||
|
|
||||||
## 如何制作Font
|
## 如何制作Font
|
||||||
- 字体文件返回一个table,键值为utf8编码,值为和对应字体的bitmap。
|
- 字体文件返回一个table,键值为utf8编码,值为和对应字体的bitmap。
|
||||||
- bitmap为一个包含等长string的table,string中的char属于computer craft定义的2*3像素点阵(如需使用右下角像素,将char的码值减128表示反转backgroundColor 和 textColor)
|
- bitmap为一个包含等长string的table,string中的char属于computer craft定义的2*3像素点阵(如需使用右下角像素,将char的码值减128表示反转backgroundColor 和 textColor)
|
||||||
- 单个字体文件中可以有不同尺寸的bitmap,且**需要**有'H'(ascII:72)的bitmap表示该文件中最大bitmap高度
|
- 单个字体文件中可以有不同尺寸的bitmap,且**需要**有'H'(ascII:72)的bitmap表示该文件中最大bitmap高度
|
||||||
- 会以FontFamily出现的最大bitmap高度为基准,最终输出下对齐的文本
|
- 会以FontFamily出现的最大bitmap高度为基准,最终输出下对齐的文本
|
||||||
- FontFamily中**需要**'-'(ascII:45)的bitmap以供自动换行时可能的切断单词使用
|
- FontFamily中**需要**'-'(ascII:45)的bitmap以供自动换行时可能的切断单词使用
|
||||||
|
|
||||||
## 技术细节
|
## 技术细节
|
||||||
|
|
||||||
- `require`一个fusion-pixel-12px字体,大约消耗**10.5MB**内存
|
- `require`一个fusion-pixel-12px字体,大约消耗**10.5MB**内存
|
||||||
- `require`一个fusion-pixel-8px字体,大约消耗**6MB**内存
|
- `require`一个fusion-pixel-8px字体,大约消耗**6MB**内存
|
||||||
- 8px字符实际占用3格高的字符数, 12px字符实际占用4格高
|
- 8px字符实际占用3格高的字符数, 12px字符实际占用4格高
|
||||||
- 字体来自 <a href="https://github.com/TakWolf/fusion-pixel-font/releases"> fusion-pixel-font </a>
|
- 字体来自 <a href="https://github.com/TakWolf/fusion-pixel-font/releases"> fusion-pixel-font </a>
|
||||||
30
.history/README_20251112115747.md
Normal file
30
.history/README_20251112115747.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
## 介绍
|
||||||
|
|
||||||
|
此仓库克隆自https://github.com/AAAB60/computer-craft-programs/tree/main
|
||||||
|
|
||||||
|
对其进行修改,以共liulikeji程序使用
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 以下为原本介绍
|
||||||
|
一个基于像素打印的utf8打印程序
|
||||||
|
|
||||||
|
> $\color{red} \bf 注意:$
|
||||||
|
> CC 编译器会把utf8字符读作 '?',
|
||||||
|
> `print("你好世界")` 与 `print("????")` 的效果相同, 可以`"rb"`模式读取文件以设置输入
|
||||||
|
|
||||||
|
|
||||||
|
## 如何制作Font
|
||||||
|
- 字体文件返回一个table,键值为utf8编码,值为和对应字体的bitmap。
|
||||||
|
- bitmap为一个包含等长string的table,string中的char属于computer craft定义的2*3像素点阵(如需使用右下角像素,将char的码值减128表示反转backgroundColor 和 textColor)
|
||||||
|
- 单个字体文件中可以有不同尺寸的bitmap,且**需要**有'H'(ascII:72)的bitmap表示该文件中最大bitmap高度
|
||||||
|
- 会以FontFamily出现的最大bitmap高度为基准,最终输出下对齐的文本
|
||||||
|
- FontFamily中**需要**'-'(ascII:45)的bitmap以供自动换行时可能的切断单词使用
|
||||||
|
|
||||||
|
## 技术细节
|
||||||
|
|
||||||
|
- `require`一个fusion-pixel-12px字体,大约消耗**10.5MB**内存
|
||||||
|
- `require`一个fusion-pixel-8px字体,大约消耗**6MB**内存
|
||||||
|
- 8px字符实际占用3格高的字符数, 12px字符实际占用4格高
|
||||||
|
- 字体来自 <a href="https://github.com/TakWolf/fusion-pixel-font/releases"> fusion-pixel-font </a>
|
||||||
@@ -1,74 +1,74 @@
|
|||||||
---@module "cctAPI"
|
---@module "cctAPI"
|
||||||
local monitor = peripheral.find("monitor")
|
local monitor = peripheral.find("monitor")
|
||||||
local computer = term.redirect(monitor)
|
local computer = term.redirect(monitor)
|
||||||
|
|
||||||
-- suggested
|
-- suggested
|
||||||
monitor.setTextScale(0.5)
|
monitor.setTextScale(0.5)
|
||||||
|
|
||||||
term.setBackgroundColor(colors.black)
|
term.setBackgroundColor(colors.black)
|
||||||
term.setTextColor(colors.white)
|
term.setTextColor(colors.white)
|
||||||
term.clear()
|
term.clear()
|
||||||
term.setCursorPos(1, 1)
|
term.setCursorPos(1, 1)
|
||||||
|
|
||||||
local function pirntBorderNum()
|
local function pirntBorderNum()
|
||||||
local termWidth, termHeight = term.getSize()
|
local termWidth, termHeight = term.getSize()
|
||||||
local n = math.floor((termWidth - 1) / 10) + 1
|
local n = math.floor((termWidth - 1) / 10) + 1
|
||||||
local str = "0123456789"
|
local str = "0123456789"
|
||||||
local tc = string.rep("48", 5)
|
local tc = string.rep("48", 5)
|
||||||
local bc = string.rep("84", 5)
|
local bc = string.rep("84", 5)
|
||||||
term.setCursorPos(1, 1)
|
term.setCursorPos(1, 1)
|
||||||
|
|
||||||
for i = 1, n do
|
for i = 1, n do
|
||||||
term.blit(str, tc, bc)
|
term.blit(str, tc, bc)
|
||||||
end
|
end
|
||||||
local num = 1
|
local num = 1
|
||||||
local colorToggle = false
|
local colorToggle = false
|
||||||
term.setCursorPos(1, 2)
|
term.setCursorPos(1, 2)
|
||||||
for y = 2, termHeight do
|
for y = 2, termHeight do
|
||||||
term.setCursorPos(1, y)
|
term.setCursorPos(1, y)
|
||||||
if colorToggle then
|
if colorToggle then
|
||||||
term.setBackgroundColor(colors.lightGray)
|
term.setBackgroundColor(colors.lightGray)
|
||||||
term.setTextColor(colors.yellow)
|
term.setTextColor(colors.yellow)
|
||||||
colorToggle = false
|
colorToggle = false
|
||||||
else
|
else
|
||||||
term.setBackgroundColor(colors.yellow)
|
term.setBackgroundColor(colors.yellow)
|
||||||
term.setTextColor(colors.lightGray)
|
term.setTextColor(colors.lightGray)
|
||||||
colorToggle = true
|
colorToggle = true
|
||||||
end
|
end
|
||||||
term.write(tostring(num))
|
term.write(tostring(num))
|
||||||
|
|
||||||
num = num + 1
|
num = num + 1
|
||||||
if num == 10 then
|
if num == 10 then
|
||||||
num = 0
|
num = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
term.setCursorPos(2, 2)
|
term.setCursorPos(2, 2)
|
||||||
term.setBackgroundColor(colors.black)
|
term.setBackgroundColor(colors.black)
|
||||||
term.setTextColor(colors.white)
|
term.setTextColor(colors.white)
|
||||||
end
|
end
|
||||||
pirntBorderNum()
|
pirntBorderNum()
|
||||||
local M = require("utf8textutils")
|
local M = require("utf8textutils")
|
||||||
|
|
||||||
-- NOTION:
|
-- NOTION:
|
||||||
-- CC compiler reads utf8 code as '?'
|
-- CC compiler reads utf8 code as '?'
|
||||||
-- "print("你好世界")" will act the same as "print("????")"
|
-- "print("你好世界")" will act the same as "print("????")"
|
||||||
-- read file in "rb" mode instead
|
-- read file in "rb" mode instead
|
||||||
local file = fs.open("text", "rb")
|
local file = fs.open("text", "rb")
|
||||||
M.printUtf8(file.readLine())
|
M.printUtf8(file.readLine())
|
||||||
|
|
||||||
local cfg1 = M.getCfg()
|
local cfg1 = M.getCfg()
|
||||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-8px-proportional-zh_hans")
|
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-8px-proportional-zh_hans")
|
||||||
cfg1.textColor = colors.blue
|
cfg1.textColor = colors.blue
|
||||||
cfg1.backgroundColor = colors.green
|
cfg1.backgroundColor = colors.green
|
||||||
cfg1.autoWrapMode = "b"
|
cfg1.autoWrapMode = "b"
|
||||||
|
|
||||||
M.printUtf8(M.sub(file.readLine(), 3, -1), cfg1)
|
M.printUtf8(M.sub(file.readLine(), 3, -1), cfg1)
|
||||||
|
|
||||||
local samplestr = "abcdefghijklmnopqrstuvwxyz"
|
local samplestr = "abcdefghijklmnopqrstuvwxyz"
|
||||||
local samplestr2 = samplestr:upper()
|
local samplestr2 = samplestr:upper()
|
||||||
local samplestr1 = "0123456789"
|
local samplestr1 = "0123456789"
|
||||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-12px-proportional-zh_hans")
|
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||||
--only if no utf8 character in str
|
--only if no utf8 character in str
|
||||||
M.printUtf8(samplestr, cfg1)
|
M.printUtf8(samplestr, cfg1)
|
||||||
M.printUtf8(samplestr2, cfg1)
|
M.printUtf8(samplestr2, cfg1)
|
||||||
M.printUtf8(samplestr1, cfg1)
|
M.printUtf8(samplestr1, cfg1)
|
||||||
@@ -1,49 +1,49 @@
|
|||||||
---@module "cctAPI"
|
---@module "cctAPI"
|
||||||
local monitor = peripheral.find("monitor")
|
local monitor = peripheral.find("monitor")
|
||||||
local computer = term.redirect(monitor)
|
local computer = term.redirect(monitor)
|
||||||
|
|
||||||
-- suggested
|
-- suggested
|
||||||
monitor.setTextScale(0.5)
|
monitor.setTextScale(0.5)
|
||||||
|
|
||||||
term.clear()
|
term.clear()
|
||||||
term.setCursorPos(1, 1)
|
term.setCursorPos(1, 1)
|
||||||
|
|
||||||
local M = require("utf8textutils")
|
local M = require("utf8textutils")
|
||||||
|
|
||||||
---@param str string
|
---@param str string
|
||||||
---@param fps number films per second
|
---@param fps number films per second
|
||||||
local function pirntScrolling(str, fps)
|
local function pirntScrolling(str, fps)
|
||||||
str = str .. " "
|
str = str .. " "
|
||||||
local termWidth = term.getSize()
|
local termWidth = term.getSize()
|
||||||
local cfg1 = M.getCfg("noauto")
|
local cfg1 = M.getCfg("noauto")
|
||||||
cfg1.masking = { 2, 2, termWidth - 1, cfg1.fontFamily.maxHeight + 1 }
|
cfg1.masking = { 2, 2, termWidth - 1, cfg1.fontFamily.maxHeight + 1 }
|
||||||
|
|
||||||
local spf = 1 / fps
|
local spf = 1 / fps
|
||||||
---@type FontFamily
|
---@type FontFamily
|
||||||
local fontFamily = cfg1.fontFamily
|
local fontFamily = cfg1.fontFamily
|
||||||
local wid = 0
|
local wid = 0
|
||||||
for _, code in M.codes(str) do
|
for _, code in M.codes(str) do
|
||||||
local bm = M.getCharMap(code, fontFamily)
|
local bm = M.getCharMap(code, fontFamily)
|
||||||
wid = wid + #bm[1]
|
wid = wid + #bm[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
local cursorX = 2
|
local cursorX = 2
|
||||||
local cursorY = 2
|
local cursorY = 2
|
||||||
local maskingWidth = cfg1.masking[3] - cfg1.masking[1]
|
local maskingWidth = cfg1.masking[3] - cfg1.masking[1]
|
||||||
local repeatNum = math.max(maskingWidth, wid)
|
local repeatNum = math.max(maskingWidth, wid)
|
||||||
while true do
|
while true do
|
||||||
cursorX = 2
|
cursorX = 2
|
||||||
for i = 1, repeatNum do
|
for i = 1, repeatNum do
|
||||||
term.setCursorPos(cursorX, cursorY)
|
term.setCursorPos(cursorX, cursorY)
|
||||||
M.printUtf8(str, cfg1)
|
M.printUtf8(str, cfg1)
|
||||||
|
|
||||||
term.setCursorPos(cursorX + repeatNum, cursorY)
|
term.setCursorPos(cursorX + repeatNum, cursorY)
|
||||||
M.printUtf8(str, cfg1)
|
M.printUtf8(str, cfg1)
|
||||||
cursorX = cursorX - 1
|
cursorX = cursorX - 1
|
||||||
|
|
||||||
os.sleep(spf)
|
os.sleep(spf)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
pirntScrolling("hello -- by AAAB60", 5)
|
pirntScrolling("hello -- by AAAB60", 5)
|
||||||
@@ -1,494 +1,494 @@
|
|||||||
---@module "cctAPI"
|
---@module "cctAPI"
|
||||||
|
|
||||||
---example:
|
---example:
|
||||||
---```
|
---```
|
||||||
---for pos, code in codes("你好world") do
|
---for pos, code in codes("你好world") do
|
||||||
--- print(pos, code)
|
--- print(pos, code)
|
||||||
---end
|
---end
|
||||||
------>
|
------>
|
||||||
---1 20320
|
---1 20320
|
||||||
---4 22909
|
---4 22909
|
||||||
---7 119
|
---7 119
|
||||||
---8 111
|
---8 111
|
||||||
---9 114
|
---9 114
|
||||||
---10 108
|
---10 108
|
||||||
---11 100
|
---11 100
|
||||||
---```
|
---```
|
||||||
---@param str string
|
---@param str string
|
||||||
---@return fun():pos:integer, code:integer
|
---@return fun():pos:integer, code:integer
|
||||||
local function codes(str)
|
local function codes(str)
|
||||||
local len = #str
|
local len = #str
|
||||||
local i = 0
|
local i = 0
|
||||||
|
|
||||||
local function illegalChar()
|
local function illegalChar()
|
||||||
error("Illegal UTF-8 character at position " .. tostring(i))
|
error("Illegal UTF-8 character at position " .. tostring(i))
|
||||||
end
|
end
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
i = i + 1
|
i = i + 1
|
||||||
---@diagnostic disable-next-line
|
---@diagnostic disable-next-line
|
||||||
if i > len then return end
|
if i > len then return end
|
||||||
|
|
||||||
local pos = i
|
local pos = i
|
||||||
local byte = string.byte(str, i)
|
local byte = string.byte(str, i)
|
||||||
|
|
||||||
-- Single-byte character
|
-- Single-byte character
|
||||||
if byte < 0x80 then
|
if byte < 0x80 then
|
||||||
return pos, byte
|
return pos, byte
|
||||||
|
|
||||||
-- Multi-byte sequences
|
-- Multi-byte sequences
|
||||||
elseif byte >= 0xC0 then
|
elseif byte >= 0xC0 then
|
||||||
local bytes_remaining, code = 0, 0
|
local bytes_remaining, code = 0, 0
|
||||||
|
|
||||||
if byte < 0xE0 then -- 2-byte sequence
|
if byte < 0xE0 then -- 2-byte sequence
|
||||||
bytes_remaining = 1
|
bytes_remaining = 1
|
||||||
code = byte - 0xC0
|
code = byte - 0xC0
|
||||||
elseif byte < 0xF0 then -- 3-byte sequence
|
elseif byte < 0xF0 then -- 3-byte sequence
|
||||||
bytes_remaining = 2
|
bytes_remaining = 2
|
||||||
code = byte - 0xE0
|
code = byte - 0xE0
|
||||||
elseif byte < 0xF8 then -- 4-byte sequence
|
elseif byte < 0xF8 then -- 4-byte sequence
|
||||||
bytes_remaining = 3
|
bytes_remaining = 3
|
||||||
code = byte - 0xF0
|
code = byte - 0xF0
|
||||||
else
|
else
|
||||||
illegalChar()
|
illegalChar()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Validate remaining bytes
|
-- Validate remaining bytes
|
||||||
if i + bytes_remaining > len then
|
if i + bytes_remaining > len then
|
||||||
illegalChar()
|
illegalChar()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Calculate code point
|
-- Calculate code point
|
||||||
for j = 1, bytes_remaining do
|
for j = 1, bytes_remaining do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
local next_byte = string.byte(str, i)
|
local next_byte = string.byte(str, i)
|
||||||
if next_byte < 0x80 or next_byte >= 0xC0 then
|
if next_byte < 0x80 or next_byte >= 0xC0 then
|
||||||
illegalChar()
|
illegalChar()
|
||||||
end
|
end
|
||||||
code = code * 0x40 + (next_byte - 0x80)
|
code = code * 0x40 + (next_byte - 0x80)
|
||||||
end
|
end
|
||||||
|
|
||||||
return pos, code
|
return pos, code
|
||||||
else
|
else
|
||||||
illegalChar()
|
illegalChar()
|
||||||
---@diagnostic disable-next-line
|
---@diagnostic disable-next-line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type FontFamily
|
---@type FontFamily
|
||||||
local defaultFontFamily = {
|
local defaultFontFamily = {
|
||||||
maxHeight = 4,
|
maxHeight = 4,
|
||||||
[1] = require("fonts/fusion-pixel-12px-proportional-zh_hans")
|
[1] = require("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||||
}
|
}
|
||||||
|
|
||||||
---@param str string read in `"rb"` mode from file
|
---@param str string read in `"rb"` mode from file
|
||||||
---@param nStartPos integer? 1~n, -n~-1 to represent pos reverse
|
---@param nStartPos integer? 1~n, -n~-1 to represent pos reverse
|
||||||
---@param nEndPos integer? 1~n, -n~-1 to represent pos reverse
|
---@param nEndPos integer? 1~n, -n~-1 to represent pos reverse
|
||||||
---@return string substring sub string of utf8 character from `nStartPos` to `nEndPos`
|
---@return string substring sub string of utf8 character from `nStartPos` to `nEndPos`
|
||||||
local function sub(str, nStartPos, nEndPos)
|
local function sub(str, nStartPos, nEndPos)
|
||||||
local charPos = 0
|
local charPos = 0
|
||||||
local utf8charPosToStr = {}
|
local utf8charPosToStr = {}
|
||||||
|
|
||||||
for pos, _ in codes(str) do
|
for pos, _ in codes(str) do
|
||||||
charPos = charPos + 1
|
charPos = charPos + 1
|
||||||
utf8charPosToStr[charPos] = pos
|
utf8charPosToStr[charPos] = pos
|
||||||
end
|
end
|
||||||
|
|
||||||
nStartPos = nStartPos or 1
|
nStartPos = nStartPos or 1
|
||||||
nEndPos = nEndPos or charPos
|
nEndPos = nEndPos or charPos
|
||||||
nStartPos = nStartPos < 0 and math.max(1, charPos + nStartPos + 1) or math.min(charPos, nStartPos)
|
nStartPos = nStartPos < 0 and math.max(1, charPos + nStartPos + 1) or math.min(charPos, nStartPos)
|
||||||
nEndPos = nEndPos < 0 and math.max(1, charPos + nEndPos + 1) or math.min(charPos, nEndPos)
|
nEndPos = nEndPos < 0 and math.max(1, charPos + nEndPos + 1) or math.min(charPos, nEndPos)
|
||||||
|
|
||||||
local startByte = utf8charPosToStr[nStartPos]
|
local startByte = utf8charPosToStr[nStartPos]
|
||||||
local endByte = utf8charPosToStr[nEndPos + 1] and utf8charPosToStr[nEndPos + 1] - 1 or #str
|
local endByte = utf8charPosToStr[nEndPos + 1] and utf8charPosToStr[nEndPos + 1] - 1 or #str
|
||||||
return string.sub(str, startByte, endByte)
|
return string.sub(str, startByte, endByte)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class FontFamily
|
---@class FontFamily
|
||||||
---@field maxHeight integer
|
---@field maxHeight integer
|
||||||
---@diagnostic disable-next-line
|
---@diagnostic disable-next-line
|
||||||
---@field [integer] Font get from `require(font_name)`
|
---@field [integer] Font get from `require(font_name)`
|
||||||
|
|
||||||
---@param ... string module names of font, font should be
|
---@param ... string module names of font, font should be
|
||||||
---@return FontFamily
|
---@return FontFamily
|
||||||
local function getFontFamily(...)
|
local function getFontFamily(...)
|
||||||
local fonts = { maxHeight = 0 }
|
local fonts = { maxHeight = 0 }
|
||||||
|
|
||||||
for i, path in ipairs({ ... }) do
|
for i, path in ipairs({ ... }) do
|
||||||
if not fs.exists(path .. ".lua") then
|
if not fs.exists(path .. ".lua") then
|
||||||
error("Font module not found: " .. path)
|
error("Font module not found: " .. path)
|
||||||
end
|
end
|
||||||
|
|
||||||
local font = require(path)
|
local font = require(path)
|
||||||
if not font[72] then
|
if not font[72] then
|
||||||
error("'H'(ascII:72) not found in font " .. path)
|
error("'H'(ascII:72) not found in font " .. path)
|
||||||
end
|
end
|
||||||
|
|
||||||
fonts[i] = font
|
fonts[i] = font
|
||||||
fonts.maxHeight = math.max(fonts.maxHeight, #font[72])
|
fonts.maxHeight = math.max(fonts.maxHeight, #font[72])
|
||||||
end
|
end
|
||||||
|
|
||||||
return fonts
|
return fonts
|
||||||
end
|
end
|
||||||
---@alias bitmap string[] the bitmap of a character
|
---@alias bitmap string[] the bitmap of a character
|
||||||
|
|
||||||
---@param code integer
|
---@param code integer
|
||||||
---@param fontFamily FontFamily
|
---@param fontFamily FontFamily
|
||||||
---@return bitmap
|
---@return bitmap
|
||||||
local function getCharMap(code, fontFamily)
|
local function getCharMap(code, fontFamily)
|
||||||
local cm
|
local cm
|
||||||
for _, font in ipairs(fontFamily) do
|
for _, font in ipairs(fontFamily) do
|
||||||
cm = font[code]
|
cm = font[code]
|
||||||
if cm then
|
if cm then
|
||||||
return cm
|
return cm
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
error(("char of utf8 %d is not supported"):format(code))
|
error(("char of utf8 %d is not supported"):format(code))
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class Config
|
---@class Config
|
||||||
---@field fontFamily FontFamily?
|
---@field fontFamily FontFamily?
|
||||||
---@field textColor number?
|
---@field textColor number?
|
||||||
---@field backgroundColor number?
|
---@field backgroundColor number?
|
||||||
---@field masking [integer, integer, integer, integer]?
|
---@field masking [integer, integer, integer, integer]?
|
||||||
---@field autoScroll boolean
|
---@field autoScroll boolean
|
||||||
---@field autoNewLine boolean
|
---@field autoNewLine boolean
|
||||||
---@field autoWrapMode "n"|"b"|"-"?
|
---@field autoWrapMode "n"|"b"|"-"?
|
||||||
---@field autoWrapLen integer?
|
---@field autoWrapLen integer?
|
||||||
---@field avoidBorder boolean
|
---@field avoidBorder boolean
|
||||||
---@field tabLen integer?
|
---@field tabLen integer?
|
||||||
|
|
||||||
---@see Config
|
---@see Config
|
||||||
---@param preset "noauto"?
|
---@param preset "noauto"?
|
||||||
---@return Config
|
---@return Config
|
||||||
local function getCfg(preset)
|
local function getCfg(preset)
|
||||||
---@type Config
|
---@type Config
|
||||||
local base = {
|
local base = {
|
||||||
fontFamily = defaultFontFamily,
|
fontFamily = defaultFontFamily,
|
||||||
textColor = nil,
|
textColor = nil,
|
||||||
backgroundColor = nil,
|
backgroundColor = nil,
|
||||||
masking = nil,
|
masking = nil,
|
||||||
autoScroll = true,
|
autoScroll = true,
|
||||||
autoNewLine = true,
|
autoNewLine = true,
|
||||||
autoWrapMode = "b",
|
autoWrapMode = "b",
|
||||||
autoWrapLen = nil,
|
autoWrapLen = nil,
|
||||||
avoidBorder = true,
|
avoidBorder = true,
|
||||||
tabLen = 2
|
tabLen = 2
|
||||||
}
|
}
|
||||||
if preset == "noauto" then
|
if preset == "noauto" then
|
||||||
base.autoScroll = false
|
base.autoScroll = false
|
||||||
base.autoNewLine = false
|
base.autoNewLine = false
|
||||||
base.autoWrapMode = "n"
|
base.autoWrapMode = "n"
|
||||||
end
|
end
|
||||||
return base
|
return base
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
---`str` should be read in `"rb"` mode from file <br>
|
---`str` should be read in `"rb"` mode from file <br>
|
||||||
---`cfg` see [`getCfg()`](lua://Config)
|
---`cfg` see [`getCfg()`](lua://Config)
|
||||||
---### Config
|
---### Config
|
||||||
---- **textColor**
|
---- **textColor**
|
||||||
---- **backgroundColor**
|
---- **backgroundColor**
|
||||||
---- **fontFamily** use [`getFontFamily()`](lua://FontFamily) to modify
|
---- **fontFamily** use [`getFontFamily()`](lua://FontFamily) to modify
|
||||||
---- **masking** representing x1, y1, x2, y2 of 2 coordinates, concent out of the rectange range won't print
|
---- **masking** representing x1, y1, x2, y2 of 2 coordinates, concent out of the rectange range won't print
|
||||||
---- **autoScroll** if true, if next line is over-height, [`term.scroll()`](https://tweaked.cc/module/term.html#v:scroll) will be called, masking will also be scrolled
|
---- **autoScroll** if true, if next line is over-height, [`term.scroll()`](https://tweaked.cc/module/term.html#v:scroll) will be called, masking will also be scrolled
|
||||||
---- **autoNewLine** if true, the output will be like a `\n` added to the end
|
---- **autoNewLine** if true, the output will be like a `\n` added to the end
|
||||||
---- **autoWrapMode** <br>
|
---- **autoWrapMode** <br>
|
||||||
----- `"n"` do not auto wrap<br>
|
----- `"n"` do not auto wrap<br>
|
||||||
----- `"b"` English letter will not be broken<br>
|
----- `"b"` English letter will not be broken<br>
|
||||||
----- `"-"` English letter will be broken by a `'-'`<br>
|
----- `"-"` English letter will be broken by a `'-'`<br>
|
||||||
---here 'letter' matches regex `(?<![a-zA-Z'])[a-zA-Z']+-?`<br>
|
---here 'letter' matches regex `(?<![a-zA-Z'])[a-zA-Z']+-?`<br>
|
||||||
---actually realized avoid using `luautf8` or regex matching
|
---actually realized avoid using `luautf8` or regex matching
|
||||||
---- **autoWrapLen** the maximum distance a line goes from the terminal's left
|
---- **autoWrapLen** the maximum distance a line goes from the terminal's left
|
||||||
---- **avoidBorder** if true, autoScroll and autoWrap will avoid printing border pixels, which have render issue<br>
|
---- **avoidBorder** if true, autoScroll and autoWrap will avoid printing border pixels, which have render issue<br>
|
||||||
---for example, autoWrap will start new line at pos (2, y) instead of (1, y)
|
---for example, autoWrap will start new line at pos (2, y) instead of (1, y)
|
||||||
---- **tabLen** the count of `' '` to replace `'\t'`
|
---- **tabLen** the count of `' '` to replace `'\t'`
|
||||||
---@param str string
|
---@param str string
|
||||||
---@param cfg Config?
|
---@param cfg Config?
|
||||||
local function printUtf8(str, cfg)
|
local function printUtf8(str, cfg)
|
||||||
local cursorX, cursorY = term.getCursorPos()
|
local cursorX, cursorY = term.getCursorPos()
|
||||||
local termWidth, termHeight = term.getSize()
|
local termWidth, termHeight = term.getSize()
|
||||||
|
|
||||||
local cfg = cfg or getCfg()
|
local cfg = cfg or getCfg()
|
||||||
local oriTextColor, oriBackgroundColor = term.getTextColor(), term.getBackgroundColor()
|
local oriTextColor, oriBackgroundColor = term.getTextColor(), term.getBackgroundColor()
|
||||||
local textColor = cfg.textColor or oriTextColor
|
local textColor = cfg.textColor or oriTextColor
|
||||||
local backgroundColor = cfg.backgroundColor or oriBackgroundColor
|
local backgroundColor = cfg.backgroundColor or oriBackgroundColor
|
||||||
local masking = cfg.masking
|
local masking = cfg.masking
|
||||||
local autoScroll = cfg.autoScroll or true
|
local autoScroll = cfg.autoScroll or true
|
||||||
local autoNewLine = cfg.autoNewLine
|
local autoNewLine = cfg.autoNewLine
|
||||||
local autoWrapMode = cfg.autoWrapMode or "b"
|
local autoWrapMode = cfg.autoWrapMode or "b"
|
||||||
local autoWrapLen = cfg.autoWrapLen or termWidth
|
local autoWrapLen = cfg.autoWrapLen or termWidth
|
||||||
local avoidBorder = cfg.avoidBorder
|
local avoidBorder = cfg.avoidBorder
|
||||||
local fontFamily = cfg.fontFamily or defaultFontFamily
|
local fontFamily = cfg.fontFamily or defaultFontFamily
|
||||||
local tabLen = cfg.tabLen or 2
|
local tabLen = cfg.tabLen or 2
|
||||||
str = string.gsub(str, '\t', string.rep(" ", tabLen))
|
str = string.gsub(str, '\t', string.rep(" ", tabLen))
|
||||||
local fontHeight = fontFamily.maxHeight
|
local fontHeight = fontFamily.maxHeight
|
||||||
if avoidBorder and autoWrapMode ~= "n" then
|
if avoidBorder and autoWrapMode ~= "n" then
|
||||||
autoWrapLen = math.min(termWidth - 1, autoWrapLen)
|
autoWrapLen = math.min(termWidth - 1, autoWrapLen)
|
||||||
cursorX = math.max(2, cursorX)
|
cursorX = math.max(2, cursorX)
|
||||||
cursorY = math.max(2, cursorY)
|
cursorY = math.max(2, cursorY)
|
||||||
end
|
end
|
||||||
local maxHeight = avoidBorder and termHeight - 1 or termHeight
|
local maxHeight = avoidBorder and termHeight - 1 or termHeight
|
||||||
---@type integer[]
|
---@type integer[]
|
||||||
local letterBuffer = {}
|
local letterBuffer = {}
|
||||||
local dashWidth = #getCharMap(45, fontFamily)[1]
|
local dashWidth = #getCharMap(45, fontFamily)[1]
|
||||||
---@type { pos: [integer, integer], code: integer }[]
|
---@type { pos: [integer, integer], code: integer }[]
|
||||||
local charBuffer = {}
|
local charBuffer = {}
|
||||||
|
|
||||||
---@param x integer
|
---@param x integer
|
||||||
---@param y integer
|
---@param y integer
|
||||||
---@return boolean
|
---@return boolean
|
||||||
local function bInMasking(x, y)
|
local function bInMasking(x, y)
|
||||||
---@diagnostic disable-next-line
|
---@diagnostic disable-next-line
|
||||||
return x >= masking[1] and x <= masking[3] and y >= masking[2] and y <= masking[4]
|
return x >= masking[1] and x <= masking[3] and y >= masking[2] and y <= masking[4]
|
||||||
end
|
end
|
||||||
---add new line to charBuffer
|
---add new line to charBuffer
|
||||||
local function posNewLine()
|
local function posNewLine()
|
||||||
cursorX = avoidBorder and 2 or 1
|
cursorX = avoidBorder and 2 or 1
|
||||||
if autoScroll and cursorY + fontHeight > maxHeight then
|
if autoScroll and cursorY + fontHeight > maxHeight then
|
||||||
-- scroll term and masking
|
-- scroll term and masking
|
||||||
term.scroll(fontHeight)
|
term.scroll(fontHeight)
|
||||||
for _, char in ipairs(charBuffer) do
|
for _, char in ipairs(charBuffer) do
|
||||||
char.pos[2] = char.pos[2] - fontHeight
|
char.pos[2] = char.pos[2] - fontHeight
|
||||||
end
|
end
|
||||||
if masking then
|
if masking then
|
||||||
masking[2] = masking[2] - fontHeight
|
masking[2] = masking[2] - fontHeight
|
||||||
masking[4] = masking[4] - fontHeight
|
masking[4] = masking[4] - fontHeight
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
cursorY = cursorY + fontHeight
|
cursorY = cursorY + fontHeight
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
---print char in charBuffer
|
---print char in charBuffer
|
||||||
local function printChar()
|
local function printChar()
|
||||||
local bIsLastReversed = false
|
local bIsLastReversed = false
|
||||||
term.setTextColor(textColor)
|
term.setTextColor(textColor)
|
||||||
term.setBackgroundColor(backgroundColor)
|
term.setBackgroundColor(backgroundColor)
|
||||||
for _, char in ipairs(charBuffer) do
|
for _, char in ipairs(charBuffer) do
|
||||||
---@type bitmap
|
---@type bitmap
|
||||||
local charMap
|
local charMap
|
||||||
local code = char.code
|
local code = char.code
|
||||||
for _, font in ipairs(fontFamily) do
|
for _, font in ipairs(fontFamily) do
|
||||||
if font[code] then
|
if font[code] then
|
||||||
charMap = font[code]
|
charMap = font[code]
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local width, height = #charMap[1], #charMap
|
local width, height = #charMap[1], #charMap
|
||||||
local cursorX, cursorY = unpack(char.pos)
|
local cursorX, cursorY = unpack(char.pos)
|
||||||
if height < fontHeight then
|
if height < fontHeight then
|
||||||
if bIsLastReversed then
|
if bIsLastReversed then
|
||||||
bIsLastReversed = false
|
bIsLastReversed = false
|
||||||
term.setTextColor(textColor)
|
term.setTextColor(textColor)
|
||||||
term.setBackgroundColor(backgroundColor)
|
term.setBackgroundColor(backgroundColor)
|
||||||
end
|
end
|
||||||
for _ = 1, fontHeight - height do
|
for _ = 1, fontHeight - height do
|
||||||
term.setCursorPos(cursorX, cursorY)
|
term.setCursorPos(cursorX, cursorY)
|
||||||
term.write(string.rep(" ", width))
|
term.write(string.rep(" ", width))
|
||||||
cursorY = cursorY + 1
|
cursorY = cursorY + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for y = 1, height do
|
for y = 1, height do
|
||||||
local posY = cursorY + y - 1
|
local posY = cursorY + y - 1
|
||||||
term.setCursorPos(cursorX, posY)
|
term.setCursorPos(cursorX, posY)
|
||||||
local sCharMapBuffer = charMap[y]
|
local sCharMapBuffer = charMap[y]
|
||||||
for x = 1, width do
|
for x = 1, width do
|
||||||
if not masking or bInMasking(cursorX + x - 1, posY) then
|
if not masking or bInMasking(cursorX + x - 1, posY) then
|
||||||
local code = string.byte(sCharMapBuffer, x)
|
local code = string.byte(sCharMapBuffer, x)
|
||||||
if code < 128 then
|
if code < 128 then
|
||||||
code = code + 128
|
code = code + 128
|
||||||
if not bIsLastReversed then
|
if not bIsLastReversed then
|
||||||
bIsLastReversed = true
|
bIsLastReversed = true
|
||||||
term.setTextColor(backgroundColor)
|
term.setTextColor(backgroundColor)
|
||||||
term.setBackgroundColor(textColor)
|
term.setBackgroundColor(textColor)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if bIsLastReversed then
|
if bIsLastReversed then
|
||||||
bIsLastReversed = false
|
bIsLastReversed = false
|
||||||
term.setTextColor(textColor)
|
term.setTextColor(textColor)
|
||||||
term.setBackgroundColor(backgroundColor)
|
term.setBackgroundColor(backgroundColor)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
term.write(string.char(code))
|
term.write(string.char(code))
|
||||||
else
|
else
|
||||||
term.setCursorPos(cursorX + x, posY)
|
term.setCursorPos(cursorX + x, posY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
term.setTextColor(oriTextColor)
|
term.setTextColor(oriTextColor)
|
||||||
term.setBackgroundColor(oriBackgroundColor)
|
term.setBackgroundColor(oriBackgroundColor)
|
||||||
if autoNewLine then
|
if autoNewLine then
|
||||||
term.setCursorPos(1, cursorY + fontHeight)
|
term.setCursorPos(1, cursorY + fontHeight)
|
||||||
else
|
else
|
||||||
term.setCursorPos(cursorX, cursorY)
|
term.setCursorPos(cursorX, cursorY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local bIsLetter = false
|
local bIsLetter = false
|
||||||
local function releaseLetter()
|
local function releaseLetter()
|
||||||
if bIsLetter then
|
if bIsLetter then
|
||||||
if autoWrapMode == "-" then
|
if autoWrapMode == "-" then
|
||||||
local widthSum = cursorX - 1
|
local widthSum = cursorX - 1
|
||||||
local widthBuffer = {}
|
local widthBuffer = {}
|
||||||
for index, letter in ipairs(letterBuffer) do
|
for index, letter in ipairs(letterBuffer) do
|
||||||
widthBuffer[index] = #getCharMap(letter, fontFamily)[1]
|
widthBuffer[index] = #getCharMap(letter, fontFamily)[1]
|
||||||
end
|
end
|
||||||
local ind = 1
|
local ind = 1
|
||||||
local letterBufferLen = #letterBuffer
|
local letterBufferLen = #letterBuffer
|
||||||
local lastDashPos = 1
|
local lastDashPos = 1
|
||||||
|
|
||||||
|
|
||||||
while ind <= letterBufferLen do
|
while ind <= letterBufferLen do
|
||||||
widthSum = widthSum + widthBuffer[ind]
|
widthSum = widthSum + widthBuffer[ind]
|
||||||
if widthSum > autoWrapLen then
|
if widthSum > autoWrapLen then
|
||||||
while widthSum + dashWidth > autoWrapLen do
|
while widthSum + dashWidth > autoWrapLen do
|
||||||
if ind == lastDashPos then
|
if ind == lastDashPos then
|
||||||
-- when have to insert dash in the first character, posNewLine() or throw
|
-- when have to insert dash in the first character, posNewLine() or throw
|
||||||
if ind == 1 and cursorX ~= (avoidBorder and 2 or 1) then
|
if ind == 1 and cursorX ~= (avoidBorder and 2 or 1) then
|
||||||
widthSum = 0
|
widthSum = 0
|
||||||
else
|
else
|
||||||
error("dash too wide or autoWrapLen too small")
|
error("dash too wide or autoWrapLen too small")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
widthSum = widthSum - widthBuffer[ind]
|
widthSum = widthSum - widthBuffer[ind]
|
||||||
ind = ind - 1
|
ind = ind - 1
|
||||||
end
|
end
|
||||||
-- pos letters before dash
|
-- pos letters before dash
|
||||||
for i = lastDashPos, ind do
|
for i = lastDashPos, ind do
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = letterBuffer[i]
|
code = letterBuffer[i]
|
||||||
}
|
}
|
||||||
cursorX = cursorX + widthBuffer[i]
|
cursorX = cursorX + widthBuffer[i]
|
||||||
end
|
end
|
||||||
if widthSum >= 0 then
|
if widthSum >= 0 then
|
||||||
-- add dash
|
-- add dash
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = 45
|
code = 45
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
-- reset
|
-- reset
|
||||||
widthSum = 0
|
widthSum = 0
|
||||||
lastDashPos = ind + 1
|
lastDashPos = ind + 1
|
||||||
posNewLine()
|
posNewLine()
|
||||||
end
|
end
|
||||||
ind = ind + 1
|
ind = ind + 1
|
||||||
end
|
end
|
||||||
-- pos letters after dash
|
-- pos letters after dash
|
||||||
for i = lastDashPos, letterBufferLen do
|
for i = lastDashPos, letterBufferLen do
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = letterBuffer[i]
|
code = letterBuffer[i]
|
||||||
}
|
}
|
||||||
cursorX = cursorX + widthBuffer[i]
|
cursorX = cursorX + widthBuffer[i]
|
||||||
end
|
end
|
||||||
elseif autoWrapMode == "b" then
|
elseif autoWrapMode == "b" then
|
||||||
local widthSum = cursorX - 1
|
local widthSum = cursorX - 1
|
||||||
local widthBuffer = {}
|
local widthBuffer = {}
|
||||||
local ind = 1
|
local ind = 1
|
||||||
local letterBufferLen = #letterBuffer
|
local letterBufferLen = #letterBuffer
|
||||||
while ind <= letterBufferLen do
|
while ind <= letterBufferLen do
|
||||||
local charMapWidth = #getCharMap(letterBuffer[ind], fontFamily)[1]
|
local charMapWidth = #getCharMap(letterBuffer[ind], fontFamily)[1]
|
||||||
widthBuffer[ind] = charMapWidth
|
widthBuffer[ind] = charMapWidth
|
||||||
widthSum = widthSum + charMapWidth
|
widthSum = widthSum + charMapWidth
|
||||||
ind = ind + 1
|
ind = ind + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local forceNewLineFlag = false
|
local forceNewLineFlag = false
|
||||||
if widthSum > autoWrapLen then
|
if widthSum > autoWrapLen then
|
||||||
if cursorX == (avoidBorder and 2 or 1) then
|
if cursorX == (avoidBorder and 2 or 1) then
|
||||||
forceNewLineFlag = true
|
forceNewLineFlag = true
|
||||||
else
|
else
|
||||||
widthSum = widthSum - cursorX + 1
|
widthSum = widthSum - cursorX + 1
|
||||||
if widthSum > autoWrapLen then
|
if widthSum > autoWrapLen then
|
||||||
forceNewLineFlag = true
|
forceNewLineFlag = true
|
||||||
else
|
else
|
||||||
posNewLine()
|
posNewLine()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if forceNewLineFlag then
|
if forceNewLineFlag then
|
||||||
for i = 1, letterBufferLen do
|
for i = 1, letterBufferLen do
|
||||||
if cursorX + widthBuffer[i] > autoWrapLen then
|
if cursorX + widthBuffer[i] > autoWrapLen then
|
||||||
posNewLine()
|
posNewLine()
|
||||||
end
|
end
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = letterBuffer[i]
|
code = letterBuffer[i]
|
||||||
}
|
}
|
||||||
cursorX = cursorX + widthBuffer[i]
|
cursorX = cursorX + widthBuffer[i]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for i = 1, letterBufferLen do
|
for i = 1, letterBufferLen do
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = letterBuffer[i]
|
code = letterBuffer[i]
|
||||||
}
|
}
|
||||||
cursorX = cursorX + widthBuffer[i]
|
cursorX = cursorX + widthBuffer[i]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif autoWrapMode == "n" then
|
elseif autoWrapMode == "n" then
|
||||||
for _, letter in ipairs(letterBuffer) do
|
for _, letter in ipairs(letterBuffer) do
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = letter
|
code = letter
|
||||||
}
|
}
|
||||||
cursorX = cursorX + #getCharMap(letter, fontFamily)[1]
|
cursorX = cursorX + #getCharMap(letter, fontFamily)[1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
letterBuffer = {}
|
letterBuffer = {}
|
||||||
bIsLetter = false
|
bIsLetter = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local lastLR = false
|
local lastLR = false
|
||||||
for _, code in codes(str) do
|
for _, code in codes(str) do
|
||||||
-- handle break line, \r, \n and \r\n will be transferred
|
-- handle break line, \r, \n and \r\n will be transferred
|
||||||
if code == 13 then
|
if code == 13 then
|
||||||
releaseLetter()
|
releaseLetter()
|
||||||
lastLR = true
|
lastLR = true
|
||||||
posNewLine()
|
posNewLine()
|
||||||
elseif code == 10 and not lastLR then
|
elseif code == 10 and not lastLR then
|
||||||
lastLR = false
|
lastLR = false
|
||||||
releaseLetter()
|
releaseLetter()
|
||||||
posNewLine()
|
posNewLine()
|
||||||
|
|
||||||
-- record letter for break line
|
-- record letter for break line
|
||||||
elseif code == 45 and bIsLetter then
|
elseif code == 45 and bIsLetter then
|
||||||
lastLR = false
|
lastLR = false
|
||||||
letterBuffer[#letterBuffer + 1] = code
|
letterBuffer[#letterBuffer + 1] = code
|
||||||
releaseLetter()
|
releaseLetter()
|
||||||
elseif code >= 65 and code <= 90 or (code >= 97 and code <= 122) or code == 39 then
|
elseif code >= 65 and code <= 90 or (code >= 97 and code <= 122) or code == 39 then
|
||||||
lastLR = false
|
lastLR = false
|
||||||
letterBuffer[#letterBuffer + 1] = code
|
letterBuffer[#letterBuffer + 1] = code
|
||||||
bIsLetter = true
|
bIsLetter = true
|
||||||
|
|
||||||
-- pos char
|
-- pos char
|
||||||
else
|
else
|
||||||
lastLR = false
|
lastLR = false
|
||||||
releaseLetter()
|
releaseLetter()
|
||||||
local charMapWidth = #getCharMap(code, fontFamily)[1]
|
local charMapWidth = #getCharMap(code, fontFamily)[1]
|
||||||
if autoWrapMode ~= "n" and cursorX + charMapWidth - 1 > autoWrapLen then
|
if autoWrapMode ~= "n" and cursorX + charMapWidth - 1 > autoWrapLen then
|
||||||
posNewLine()
|
posNewLine()
|
||||||
end
|
end
|
||||||
charBuffer[#charBuffer + 1] = {
|
charBuffer[#charBuffer + 1] = {
|
||||||
pos = { cursorX, cursorY },
|
pos = { cursorX, cursorY },
|
||||||
code = code
|
code = code
|
||||||
}
|
}
|
||||||
cursorX = cursorX + charMapWidth
|
cursorX = cursorX + charMapWidth
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
releaseLetter()
|
releaseLetter()
|
||||||
printChar()
|
printChar()
|
||||||
end
|
end
|
||||||
return {
|
return {
|
||||||
codes = codes,
|
codes = codes,
|
||||||
printUtf8 = printUtf8,
|
printUtf8 = printUtf8,
|
||||||
getFontFamily = getFontFamily,
|
getFontFamily = getFontFamily,
|
||||||
sub = sub,
|
sub = sub,
|
||||||
getCfg = getCfg,
|
getCfg = getCfg,
|
||||||
getCharMap = getCharMap
|
getCharMap = getCharMap
|
||||||
}
|
}
|
||||||
36
README.md
36
README.md
@@ -1,6 +1,30 @@
|
|||||||
all codes have a demostration video on my **bilibili** cannel
|
## 介绍
|
||||||
## catalyst
|
|
||||||
- for mod pack: **create:above and beyond**
|
此仓库克隆自https://github.com/AAAB60/computer-craft-programs/tree/main
|
||||||
- automatically test and form the catalyst formula
|
|
||||||
- finnal output numbers represent the magnet in the corresponding slot of the crate
|
对其进行修改,以共liulikeji程序使用
|
||||||
- using four different containers to simplify`peripheral.find`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 以下为原本介绍
|
||||||
|
一个基于像素打印的utf8打印程序
|
||||||
|
|
||||||
|
> $\color{red} \bf 注意:$
|
||||||
|
> CC 编译器会把utf8字符读作 '?',
|
||||||
|
> `print("你好世界")` 与 `print("????")` 的效果相同, 可以`"rb"`模式读取文件以设置输入
|
||||||
|
|
||||||
|
|
||||||
|
## 如何制作Font
|
||||||
|
- 字体文件返回一个table,键值为utf8编码,值为和对应字体的bitmap。
|
||||||
|
- bitmap为一个包含等长string的table,string中的char属于computer craft定义的2*3像素点阵(如需使用右下角像素,将char的码值减128表示反转backgroundColor 和 textColor)
|
||||||
|
- 单个字体文件中可以有不同尺寸的bitmap,且**需要**有'H'(ascII:72)的bitmap表示该文件中最大bitmap高度
|
||||||
|
- 会以FontFamily出现的最大bitmap高度为基准,最终输出下对齐的文本
|
||||||
|
- FontFamily中**需要**'-'(ascII:45)的bitmap以供自动换行时可能的切断单词使用
|
||||||
|
|
||||||
|
## 技术细节
|
||||||
|
|
||||||
|
- `require`一个fusion-pixel-12px字体,大约消耗**10.5MB**内存
|
||||||
|
- `require`一个fusion-pixel-8px字体,大约消耗**6MB**内存
|
||||||
|
- 8px字符实际占用3格高的字符数, 12px字符实际占用4格高
|
||||||
|
- 字体来自 <a href="https://github.com/TakWolf/fusion-pixel-font/releases"> fusion-pixel-font </a>
|
||||||
|
|||||||
352
catalyst.lua
352
catalyst.lua
@@ -1,352 +0,0 @@
|
|||||||
mags = peripheral.find("create:adjustable_crate")
|
|
||||||
bottler = peripheral.find("minecraft:trapped_chest")
|
|
||||||
shovel = peripheral.find("minecraft:barrel")
|
|
||||||
loader = peripheral.find("minecraft:chest")
|
|
||||||
unloader = peripheral.find("minecraft:hopper")
|
|
||||||
analyser = peripheral.find("thermal:machine_centrifuge")
|
|
||||||
table1 = {["Andesite Reagent"]=1,["Diorite Reagent"]=2,["Granite Reagent"]=3,["Stone Reagent"]=4,["Basalt Reagent"]=5,["Gabbro Reagent"]=6,
|
|
||||||
["Crimson Reagent"]=1,["Orange Reagent"]=2,["Goldenrod Reagent"]=3,["Olive Reagent"]=4,["Azure Reagent"]=5,["Fuchsia Reagent"]=6,
|
|
||||||
["Blazing Reagent"]=1,["Slime Reagent"]=2,["Nether Reagent"]=3,["Obsidian Reagent"]=4,["Gunpowder Reagent"]=5,["Aquatic Reagent"]=6,
|
|
||||||
["Arcane Reagent"]=1,["Apatite Reagent"]=2,["Sulfuric Reagent"]=3,["Nitric Reagent"]=4,["Certus Quartz Reagent"]=5,["Nether Quartz Reagent"]=6,
|
|
||||||
["Zinc Reagent"]=1,["Copper Reagent"]=2,["Iron Reagent"]=3,["Nickel Reagent"]=4,["Lead Reagent"]=5,["Gold Reagent"]=6,
|
|
||||||
["Cinnabar Reagent"]=1,["Lapis Lazuli Reagent"]=2,["Sapphire Reagent"]=3,["Emerald Reagent"]=4,["Ruby Reagent"]=5,["Diamond Reagent"]=6}
|
|
||||||
function tableCopy(b)
|
|
||||||
local a = {}
|
|
||||||
for i ,j in pairs(b) do
|
|
||||||
if type(j) == "table" then
|
|
||||||
local jundge = nil
|
|
||||||
for m,n in pairs(j) do --{} ~= {}
|
|
||||||
jundge = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if jundge then
|
|
||||||
a[i] = tableCopy(j)
|
|
||||||
else a[i] = {}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
a[i] = j
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return a
|
|
||||||
end
|
|
||||||
function tableCompare(a,b)
|
|
||||||
local jundge = true
|
|
||||||
for i = 1,#a do
|
|
||||||
if type(a[i]) == "table" then
|
|
||||||
if #a[i] ~= 0 and not tableCompare(a[i],b[i]) then
|
|
||||||
jundge = false
|
|
||||||
break
|
|
||||||
elseif #a == 0 and #b[i] ~= 0 then
|
|
||||||
jundge = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
elseif a[i] ~= b[i] then
|
|
||||||
jundge = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return jundge
|
|
||||||
end
|
|
||||||
function tableCompare1(a,b)
|
|
||||||
local jundge = false
|
|
||||||
for i = 1,#a do
|
|
||||||
if tableCompare(a[i],b) then
|
|
||||||
jundge = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return jundge
|
|
||||||
end
|
|
||||||
local function push(container,receive,count,toslot,nameDisplay)--(dirt,dirt/"minecraft:chest_0")
|
|
||||||
local num,receiveName = 0,""
|
|
||||||
if type(receive) == "string" then
|
|
||||||
receiveName = receive
|
|
||||||
else
|
|
||||||
receiveName = peripheral.getName(receive)
|
|
||||||
end
|
|
||||||
--negelect modle
|
|
||||||
if nameDisplay == nil then
|
|
||||||
if count ~= nil then
|
|
||||||
for i,j in pairs(container.list()) do
|
|
||||||
num = num + j["count"]
|
|
||||||
container.pushItems(receiveName,i,count - num + j["count"],toslot)
|
|
||||||
if num >= count then break end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i,j in pairs(container.list()) do
|
|
||||||
container.pushItems(receiveName,i,nil,toslot)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if count ~= nil then
|
|
||||||
for i,j in pairs(container.list()) do
|
|
||||||
if container.getItemDetail(i).displayName == nameDisplay then
|
|
||||||
num = num + j["count"]
|
|
||||||
container.pushItems(receiveName,i,count - num + j["count"],toslot)
|
|
||||||
if num >= count then break end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i,j in pairs(container.list()) do
|
|
||||||
if container.getItemDetail(i).displayName == nameDisplay then
|
|
||||||
container.pushItems(receiveName,i,nil,toslot)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local function push1(container,outPutRules)--{{"Dirt","minecraft:chest_1",[num],toslot},{"Dirt","cobblesStone"}}
|
|
||||||
for i,j in pairs(container.list()) do
|
|
||||||
local displayName1,receiveName = container.getItemDetail(i).displayName,""
|
|
||||||
for m,n in pairs(outPutRules) do
|
|
||||||
if type(n[2]) == "string" then
|
|
||||||
receiveName = n[2]
|
|
||||||
else
|
|
||||||
receiveName = peripheral.getName(n[2])
|
|
||||||
end
|
|
||||||
if displayName1 == n[1] then
|
|
||||||
container.pushItems(receiveName,i,n[3],n[4])
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function hop(num)
|
|
||||||
local time = {0.1,0.5,0.9,1.3,1.7}
|
|
||||||
redstone.setOutput("top",true)--0.1,0.5,1,1.5,2
|
|
||||||
sleep(time[num])
|
|
||||||
redstone.setOutput("top",false)
|
|
||||||
end
|
|
||||||
function input(numbers,c)--({1,1,3,5},rc/gc)
|
|
||||||
for o = 1, 4 do
|
|
||||||
for i = 1, 4 - o do
|
|
||||||
shovel.pushItems(peripheral.getName(loader),i,1,i)
|
|
||||||
end
|
|
||||||
mags.pushItems(peripheral.getName(loader),numbers[5-o],1,5-o)
|
|
||||||
hop(4 - o)
|
|
||||||
sleep(0.4)
|
|
||||||
end
|
|
||||||
if c == "rc" then
|
|
||||||
mags.pushItems(peripheral.getName(loader),7,1,5)
|
|
||||||
elseif c == "gc" then
|
|
||||||
mags.pushItems(peripheral.getName(loader),8,1,5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function stop()
|
|
||||||
sleep(10)
|
|
||||||
for i = 1 ,6 do
|
|
||||||
if mags.list()[i]["count"] <= 6 then
|
|
||||||
stop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function step(simulateAnswer1,numbers1,c) --return mutiple results
|
|
||||||
local b,numbers,simulateAnswer = {0,0,0}
|
|
||||||
numbers = tableCopy(numbers1)
|
|
||||||
simulateAnswer = tableCopy(simulateAnswer1)
|
|
||||||
local jundge = nil
|
|
||||||
for i = 1, 4 do
|
|
||||||
if simulateAnswer[i] == numbers[i] then
|
|
||||||
b[3] = b[3] + 1
|
|
||||||
simulateAnswer[i] = nil
|
|
||||||
numbers[i] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = 1 ,4 do
|
|
||||||
if simulateAnswer[i] then
|
|
||||||
for j = 1 ,4 do
|
|
||||||
if simulateAnswer[i] == numbers[j] then
|
|
||||||
b[2] = b[2] + 1
|
|
||||||
simulateAnswer[i] = 7
|
|
||||||
numbers[j] = 7
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
b[1] = 4 - b[2] - b[3]
|
|
||||||
local d = {b}
|
|
||||||
local count = 1
|
|
||||||
if c == "gc" then
|
|
||||||
for i =1,4 do
|
|
||||||
if not simulateAnswer[i] then
|
|
||||||
d[count] = tableCopy(b)
|
|
||||||
d[count][4] = simulateAnswer1[i]
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif c == "rc" then
|
|
||||||
for i = 1,4 do
|
|
||||||
if simulateAnswer[i] == 7 then
|
|
||||||
d[count] = tableCopy(b)
|
|
||||||
d[count][4] = simulateAnswer1[i]
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return d
|
|
||||||
end
|
|
||||||
local function answerFilter(log,answers1)
|
|
||||||
local answers,count,jundge,answers2 = {},1,true,{}
|
|
||||||
if not answers1 then
|
|
||||||
for i1 = 1,6 do
|
|
||||||
for i2 = 1,6 do
|
|
||||||
for i3 = 1,6 do
|
|
||||||
for i4 = 1,6 do
|
|
||||||
answers[count] = {i1,i2,i3,i4}
|
|
||||||
count = count+1
|
|
||||||
end end end end
|
|
||||||
answers2 = tableCopy(answerFilter(log,answers))
|
|
||||||
else
|
|
||||||
answers = tableCopy(answers1)
|
|
||||||
for i,j in pairs(answers) do
|
|
||||||
for i6 = 1,#log do
|
|
||||||
if log[i6]["stepNumber"] and not tableCompare1(step(j,log[i6]["stepNumber"],"rc"),log[i6]["result"]) then
|
|
||||||
jundge = nil
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if jundge then
|
|
||||||
answers2[count] = j
|
|
||||||
count = count+1
|
|
||||||
else jundge = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return answers2
|
|
||||||
end
|
|
||||||
function translate(table)
|
|
||||||
local b = {0,0,0}
|
|
||||||
--output table b{[ash],[minecraft:redstone],[minecraft:glowstone_dust],[catalysed number]}
|
|
||||||
if analyser.list()[2]["name"] == "darkerdepths:ash" then
|
|
||||||
b[1] = analyser.list()[2]["count"]
|
|
||||||
if analyser.list()[3] then
|
|
||||||
if analyser.list()[3]["name"] == "minecraft:redstone" then
|
|
||||||
b[2] = analyser.list()[3]["count"]
|
|
||||||
if analyser.list()[4] then
|
|
||||||
b[3] = analyser.list()[4]["count"]
|
|
||||||
else b[3] = 0
|
|
||||||
end
|
|
||||||
elseif analyser.list()[3]["name"] == "minecraft:glowstone_dust" then
|
|
||||||
b[2] = 0
|
|
||||||
b[3] = analyser.list()[3]["count"]
|
|
||||||
else
|
|
||||||
print("analyser_trash")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif analyser.list()[2]["name"] == "minecraft:redstone" then
|
|
||||||
b[1] = 0
|
|
||||||
b[2] = analyser.list()[2]["count"]
|
|
||||||
if analyser.list()[3] then
|
|
||||||
b[3] = analyser.list()[3]["count"]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print("analyser_trash")
|
|
||||||
end
|
|
||||||
if shovel.list()[5] then
|
|
||||||
b[4] = table[shovel.getItemDetail(5).displayName]
|
|
||||||
end
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
function suggestedInfoValue(a)
|
|
||||||
if a == 1 then print("error a == 1") end
|
|
||||||
local b = {2,6,12,20,30}
|
|
||||||
if a <= 6 then
|
|
||||||
return b[a-1]
|
|
||||||
elseif a <= 16 then
|
|
||||||
return 0.8809*a^2 - 1.158*a + 1
|
|
||||||
else
|
|
||||||
return 0.7435*a^2 + 3.3087*a + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function stepInstruct(log1,answers1)
|
|
||||||
local log = tableCopy(log1)
|
|
||||||
local answers,infoValue,count = nil,0,#log+1
|
|
||||||
if answers1 then
|
|
||||||
answers = tableCopy(answers1)
|
|
||||||
end
|
|
||||||
answers = answerFilter(log,answers)
|
|
||||||
if #answers == 1 then
|
|
||||||
return {answers[1],answers}
|
|
||||||
end
|
|
||||||
local sInfoV = suggestedInfoValue(#answers)
|
|
||||||
for k =1,80 do
|
|
||||||
log[count] = {["stepNumber"] = {math.random(1,6),math.random(1,6),math.random(1,6),math.random(1,6)}}
|
|
||||||
for i,j in pairs(answers) do
|
|
||||||
local temporary = step(j,log[count]["stepNumber"],"rc")
|
|
||||||
for m,n in pairs(temporary) do
|
|
||||||
log[count]["result"] = tableCopy(j)
|
|
||||||
infoValue = infoValue + (#answers - #answerFilter(log,answers))/#temporary
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if infoValue >= sInfoV then
|
|
||||||
return {log[count]["stepNumber"],answers}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
printTable("sInfo "..tostring(sInfoV).." too bigger than "..tostring(infoValue))
|
|
||||||
print("#answers = "..tostring(#answers))
|
|
||||||
error("please restart the program",0)
|
|
||||||
end
|
|
||||||
function printTable(a)
|
|
||||||
if type(a) == "string" then
|
|
||||||
io.write(a)
|
|
||||||
elseif type(a) == "number" then
|
|
||||||
io.write(tostring(a))
|
|
||||||
elseif type(a) == "table" then
|
|
||||||
local count,jundge = 1,nil
|
|
||||||
io.write("{")
|
|
||||||
for i,j in pairs(a) do
|
|
||||||
if jundge then
|
|
||||||
io.write(",")
|
|
||||||
else
|
|
||||||
jundge = true
|
|
||||||
end
|
|
||||||
if i == count then
|
|
||||||
count = count + 1
|
|
||||||
elseif type(i) == "string" then
|
|
||||||
io.write( '["'..i..'"]=')
|
|
||||||
else io.write( '['..i..']=') end
|
|
||||||
printTable(j)
|
|
||||||
end
|
|
||||||
io.write("}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function main()
|
|
||||||
local table = {}
|
|
||||||
for i=1,6 do
|
|
||||||
table[mags.getItemDetail(i).displayName] = i
|
|
||||||
end
|
|
||||||
local log,count,answers = {{["stepNumber"] = {1,2,3,4}}},0,nil
|
|
||||||
--local read = io.read()
|
|
||||||
if true then
|
|
||||||
repeat
|
|
||||||
count = count + 1
|
|
||||||
print("the number "..count.." round")
|
|
||||||
input(log[count]["stepNumber"],"rc")
|
|
||||||
redstone.setOutput("right",true)
|
|
||||||
sleep(0.2)
|
|
||||||
redstone.setOutput("right",false)
|
|
||||||
sleep(5)
|
|
||||||
hop(3)
|
|
||||||
sleep(0.5)
|
|
||||||
shovel.pushItems(peripheral.getName(analyser),4,1)
|
|
||||||
repeat sleep(1) until analyser.list()[2]
|
|
||||||
log[count]["result"] = translate(table)
|
|
||||||
for i = 2 ,4 do
|
|
||||||
analyser.pushItems(peripheral.getName(bottler),i,64)
|
|
||||||
end
|
|
||||||
shovel.pushItems(peripheral.getName(mags),5,1)
|
|
||||||
local temporary = stepInstruct(log,answers)
|
|
||||||
answers = tableCopy(temporary[2])
|
|
||||||
log[count+1] = {["stepNumber"] = tableCopy(temporary[1])}
|
|
||||||
if #answers == 1 then
|
|
||||||
print("finish")
|
|
||||||
printTable(answers[1])
|
|
||||||
print(" ")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
until nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
main()
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
209
utf8ptrint.lua
Normal file
209
utf8ptrint.lua
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
--这是一个简单的打印字符的程序,他使用下方url的字体进行显示
|
||||||
|
--因为字体文件超过cc存储大小所以使用网络加载字体
|
||||||
|
|
||||||
|
--通过printUtf8("字符",文字颜色,背景颜色)来达到类似 print的效果
|
||||||
|
--示例:printUtf8("你好世界! Hello Word!",colors.white,colors.lightGray)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- 从网络加载字库
|
||||||
|
local function loadRemoteFont(url)
|
||||||
|
local response = http.get(url)
|
||||||
|
if not response then
|
||||||
|
error("无法连接到字体服务器")
|
||||||
|
end
|
||||||
|
|
||||||
|
if response.getResponseCode() ~= 200 then
|
||||||
|
error("字体服务器返回错误: " .. response.getResponseCode())
|
||||||
|
end
|
||||||
|
|
||||||
|
local content = response.readAll()
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
-- 使用沙箱环境安全加载字体
|
||||||
|
local sandbox = {}
|
||||||
|
local chunk, err = load(content, "=remoteFont", "t", sandbox)
|
||||||
|
if not chunk then
|
||||||
|
error("加载字体失败: " .. err)
|
||||||
|
end
|
||||||
|
|
||||||
|
local success, result = pcall(chunk)
|
||||||
|
if not success then
|
||||||
|
error("执行字体脚本失败: " .. result)
|
||||||
|
end
|
||||||
|
|
||||||
|
return sandbox.font or sandbox[1] or result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 字体URL
|
||||||
|
local fontUrl = "https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/fonts/fusion-pixel-8px-proportional-zh_hans.lua"
|
||||||
|
local font = loadRemoteFont(fontUrl)
|
||||||
|
|
||||||
|
-- 显示单个字符的函数
|
||||||
|
local function displayChar(charMap, x, y, textColor, backgroundColor)
|
||||||
|
-- 保存原始终端颜色设置
|
||||||
|
local origTextColor = term.getTextColor()
|
||||||
|
local origBackgroundColor = term.getBackgroundColor()
|
||||||
|
|
||||||
|
-- 设置新颜色
|
||||||
|
term.setTextColor(textColor)
|
||||||
|
term.setBackgroundColor(backgroundColor)
|
||||||
|
|
||||||
|
-- 遍历字符位图的每一行
|
||||||
|
for row = 1, #charMap do
|
||||||
|
term.setCursorPos(x, y + row - 1)
|
||||||
|
local line = charMap[row]
|
||||||
|
|
||||||
|
-- 遍历行中的每个像素
|
||||||
|
for col = 1, #line do
|
||||||
|
local byte = string.byte(line, col)
|
||||||
|
|
||||||
|
-- 处理像素颜色
|
||||||
|
if byte < 128 then
|
||||||
|
-- 背景色像素:反转颜色设置
|
||||||
|
term.setTextColor(backgroundColor)
|
||||||
|
term.setBackgroundColor(textColor)
|
||||||
|
term.write(string.char(byte + 128)) -- 转换为可打印字符
|
||||||
|
else
|
||||||
|
-- 前景色像素:正常颜色设置
|
||||||
|
term.setTextColor(textColor)
|
||||||
|
term.setBackgroundColor(backgroundColor)
|
||||||
|
term.write(string.char(byte))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 恢复原始颜色设置
|
||||||
|
term.setTextColor(origTextColor)
|
||||||
|
term.setBackgroundColor(origBackgroundColor)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 显示UTF-8字符串的函数
|
||||||
|
local function displayUtf8String(str, font, x, y, textColor, backgroundColor)
|
||||||
|
-- UTF-8解码器(简化版)
|
||||||
|
local function utf8codes(str)
|
||||||
|
local i = 1
|
||||||
|
return function()
|
||||||
|
if i > #str then return end
|
||||||
|
|
||||||
|
local b1 = string.byte(str, i)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
-- 单字节字符 (ASCII)
|
||||||
|
if b1 < 0x80 then
|
||||||
|
return b1
|
||||||
|
-- 双字节字符
|
||||||
|
elseif b1 >= 0xC0 and b1 < 0xE0 then
|
||||||
|
local b2 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
return (b1 - 0xC0) * 64 + (b2 - 0x80)
|
||||||
|
-- 三字节字符(中文)
|
||||||
|
elseif b1 >= 0xE0 and b1 < 0xF0 then
|
||||||
|
local b2 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
local b3 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
return (b1 - 0xE0) * 4096 + (b2 - 0x80) * 64 + (b3 - 0x80)
|
||||||
|
else
|
||||||
|
-- 不支持的编码,返回空格
|
||||||
|
return 32
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local cursorX = x
|
||||||
|
|
||||||
|
-- 遍历字符串中的所有字符
|
||||||
|
for code in utf8codes(str) do
|
||||||
|
-- 获取字符位图
|
||||||
|
local charMap = font[code]
|
||||||
|
if not charMap then
|
||||||
|
-- 如果字库中没有该字符,使用空格代替
|
||||||
|
charMap = font[32] or {{"\x80"}} -- 空格字符
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 显示字符
|
||||||
|
displayChar(charMap, cursorX, y, textColor, backgroundColor)
|
||||||
|
|
||||||
|
-- 移动到下一个字符位置
|
||||||
|
cursorX = cursorX + #charMap[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local cursorX, cursorY = 1, 1
|
||||||
|
local fontHeight = #font[32] -- 获取字体高度(使用空格字符)
|
||||||
|
|
||||||
|
-- 自定义打印函数(带自动换行和滚动)
|
||||||
|
local function printUtf8(str, textColor, backgroundColor)
|
||||||
|
local width, screenHeight = term.getSize() -- 获取终端尺寸
|
||||||
|
|
||||||
|
-- UTF-8解码器
|
||||||
|
local function utf8codes(str)
|
||||||
|
local i = 1
|
||||||
|
return function()
|
||||||
|
if i > #str then return end
|
||||||
|
|
||||||
|
local b1 = string.byte(str, i)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
if b1 < 0x80 then
|
||||||
|
return b1
|
||||||
|
elseif b1 >= 0xC0 and b1 < 0xE0 then
|
||||||
|
local b2 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
return (b1 - 0xC0) * 64 + (b2 - 0x80)
|
||||||
|
elseif b1 >= 0xE0 and b1 < 0xF0 then
|
||||||
|
local b2 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
local b3 = string.byte(str, i) or 0
|
||||||
|
i = i + 1
|
||||||
|
return (b1 - 0xE0) * 4096 + (b2 - 0x80) * 64 + (b3 - 0x80)
|
||||||
|
else
|
||||||
|
return 32 -- 不支持的字符显示为空格
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 处理字符串中的每个字符
|
||||||
|
for code in utf8codes(str) do
|
||||||
|
-- 处理换行符
|
||||||
|
if code == 10 then -- \n 的 ASCII
|
||||||
|
cursorX = 1
|
||||||
|
cursorY = cursorY + fontHeight
|
||||||
|
else
|
||||||
|
local charMap = font[code] or font[32]
|
||||||
|
local charWidth = #charMap[1]
|
||||||
|
|
||||||
|
-- 检查是否需要换行
|
||||||
|
if cursorX + charWidth - 1 > width then
|
||||||
|
cursorX = 1
|
||||||
|
cursorY = cursorY + fontHeight
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 检查是否需要滚动屏幕
|
||||||
|
if cursorY + fontHeight - 1 > screenHeight then
|
||||||
|
term.scroll(fontHeight)
|
||||||
|
cursorY = cursorY - fontHeight
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 显示字符
|
||||||
|
displayChar(charMap, cursorX, cursorY, textColor, backgroundColor)
|
||||||
|
cursorX = cursorX + charWidth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 自动换行(处理完字符串后)
|
||||||
|
cursorX = 1
|
||||||
|
-- 光标应该位于下一行的顶部,而不是底部
|
||||||
|
cursorY = cursorY + fontHeight
|
||||||
|
|
||||||
|
-- 检查滚动(换行后)
|
||||||
|
if cursorY > screenHeight then
|
||||||
|
term.scroll(fontHeight)
|
||||||
|
cursorY = screenHeight - fontHeight + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return printUtf8
|
||||||
|
|
||||||
Reference in New Issue
Block a user