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

|
||||
|
||||
|
||||
> $\color{red} \bf Note:$
|
||||
> The CC compiler reads UTF-8 characters as '?',
|
||||
> `print("Hello World")` has the same effect as `print("????")`.
|
||||
> To fix this, read files in `"rb"` mode for proper input handling.
|
||||
|
||||
## How to Create Fonts
|
||||
- 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`.
|
||||
- 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 FontFamily **must** include a '-' (ASCII:45) bitmap for potential word splitting during auto-wrapping.
|
||||
|
||||
## Technical Details
|
||||
|
||||
- `require` a fusion-pixel-12px font consumes approximately **10.5MB** 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.
|
||||
- Fonts are sourced from <a href="https://github.com/TakWolf/fusion-pixel-font/releases">fusion-pixel-font</a>.
|
||||
|
||||
<div id="zh"></div>
|
||||
|
||||
## 介绍
|
||||
|
||||
一个基于像素打印的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>
|
||||
<a href=#en>English</a> <a href=#zh>中文</a>
|
||||
|
||||
<div id="en"></div>
|
||||
|
||||
## Introduction
|
||||
|
||||
A pixel-based UTF-8 printing program
|
||||

|
||||
|
||||
|
||||
> $\color{red} \bf Note:$
|
||||
> The CC compiler reads UTF-8 characters as '?',
|
||||
> `print("Hello World")` has the same effect as `print("????")`.
|
||||
> To fix this, read files in `"rb"` mode for proper input handling.
|
||||
|
||||
## How to Create Fonts
|
||||
- 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`.
|
||||
- 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 FontFamily **must** include a '-' (ASCII:45) bitmap for potential word splitting during auto-wrapping.
|
||||
|
||||
## Technical Details
|
||||
|
||||
- `require` a fusion-pixel-12px font consumes approximately **10.5MB** 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.
|
||||
- Fonts are sourced from <a href="https://github.com/TakWolf/fusion-pixel-font/releases">fusion-pixel-font</a>.
|
||||
|
||||
<div id="zh"></div>
|
||||
|
||||
## 介绍
|
||||
|
||||
一个基于像素打印的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>
|
||||
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"
|
||||
local monitor = peripheral.find("monitor")
|
||||
local computer = term.redirect(monitor)
|
||||
|
||||
-- suggested
|
||||
monitor.setTextScale(0.5)
|
||||
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
local function pirntBorderNum()
|
||||
local termWidth, termHeight = term.getSize()
|
||||
local n = math.floor((termWidth - 1) / 10) + 1
|
||||
local str = "0123456789"
|
||||
local tc = string.rep("48", 5)
|
||||
local bc = string.rep("84", 5)
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
for i = 1, n do
|
||||
term.blit(str, tc, bc)
|
||||
end
|
||||
local num = 1
|
||||
local colorToggle = false
|
||||
term.setCursorPos(1, 2)
|
||||
for y = 2, termHeight do
|
||||
term.setCursorPos(1, y)
|
||||
if colorToggle then
|
||||
term.setBackgroundColor(colors.lightGray)
|
||||
term.setTextColor(colors.yellow)
|
||||
colorToggle = false
|
||||
else
|
||||
term.setBackgroundColor(colors.yellow)
|
||||
term.setTextColor(colors.lightGray)
|
||||
colorToggle = true
|
||||
end
|
||||
term.write(tostring(num))
|
||||
|
||||
num = num + 1
|
||||
if num == 10 then
|
||||
num = 0
|
||||
end
|
||||
end
|
||||
term.setCursorPos(2, 2)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
pirntBorderNum()
|
||||
local M = require("utf8textutils")
|
||||
|
||||
-- NOTION:
|
||||
-- CC compiler reads utf8 code as '?'
|
||||
-- "print("你好世界")" will act the same as "print("????")"
|
||||
-- read file in "rb" mode instead
|
||||
local file = fs.open("text", "rb")
|
||||
M.printUtf8(file.readLine())
|
||||
|
||||
local cfg1 = M.getCfg()
|
||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-8px-proportional-zh_hans")
|
||||
cfg1.textColor = colors.blue
|
||||
cfg1.backgroundColor = colors.green
|
||||
cfg1.autoWrapMode = "b"
|
||||
|
||||
M.printUtf8(M.sub(file.readLine(), 3, -1), cfg1)
|
||||
|
||||
local samplestr = "abcdefghijklmnopqrstuvwxyz"
|
||||
local samplestr2 = samplestr:upper()
|
||||
local samplestr1 = "0123456789"
|
||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||
--only if no utf8 character in str
|
||||
M.printUtf8(samplestr, cfg1)
|
||||
M.printUtf8(samplestr2, cfg1)
|
||||
---@module "cctAPI"
|
||||
local monitor = peripheral.find("monitor")
|
||||
local computer = term.redirect(monitor)
|
||||
|
||||
-- suggested
|
||||
monitor.setTextScale(0.5)
|
||||
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
local function pirntBorderNum()
|
||||
local termWidth, termHeight = term.getSize()
|
||||
local n = math.floor((termWidth - 1) / 10) + 1
|
||||
local str = "0123456789"
|
||||
local tc = string.rep("48", 5)
|
||||
local bc = string.rep("84", 5)
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
for i = 1, n do
|
||||
term.blit(str, tc, bc)
|
||||
end
|
||||
local num = 1
|
||||
local colorToggle = false
|
||||
term.setCursorPos(1, 2)
|
||||
for y = 2, termHeight do
|
||||
term.setCursorPos(1, y)
|
||||
if colorToggle then
|
||||
term.setBackgroundColor(colors.lightGray)
|
||||
term.setTextColor(colors.yellow)
|
||||
colorToggle = false
|
||||
else
|
||||
term.setBackgroundColor(colors.yellow)
|
||||
term.setTextColor(colors.lightGray)
|
||||
colorToggle = true
|
||||
end
|
||||
term.write(tostring(num))
|
||||
|
||||
num = num + 1
|
||||
if num == 10 then
|
||||
num = 0
|
||||
end
|
||||
end
|
||||
term.setCursorPos(2, 2)
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
end
|
||||
pirntBorderNum()
|
||||
local M = require("utf8textutils")
|
||||
|
||||
-- NOTION:
|
||||
-- CC compiler reads utf8 code as '?'
|
||||
-- "print("你好世界")" will act the same as "print("????")"
|
||||
-- read file in "rb" mode instead
|
||||
local file = fs.open("text", "rb")
|
||||
M.printUtf8(file.readLine())
|
||||
|
||||
local cfg1 = M.getCfg()
|
||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-8px-proportional-zh_hans")
|
||||
cfg1.textColor = colors.blue
|
||||
cfg1.backgroundColor = colors.green
|
||||
cfg1.autoWrapMode = "b"
|
||||
|
||||
M.printUtf8(M.sub(file.readLine(), 3, -1), cfg1)
|
||||
|
||||
local samplestr = "abcdefghijklmnopqrstuvwxyz"
|
||||
local samplestr2 = samplestr:upper()
|
||||
local samplestr1 = "0123456789"
|
||||
cfg1.fontFamily = M.getFontFamily("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||
--only if no utf8 character in str
|
||||
M.printUtf8(samplestr, cfg1)
|
||||
M.printUtf8(samplestr2, cfg1)
|
||||
M.printUtf8(samplestr1, cfg1)
|
||||
@@ -1,49 +1,49 @@
|
||||
---@module "cctAPI"
|
||||
local monitor = peripheral.find("monitor")
|
||||
local computer = term.redirect(monitor)
|
||||
|
||||
-- suggested
|
||||
monitor.setTextScale(0.5)
|
||||
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
local M = require("utf8textutils")
|
||||
|
||||
---@param str string
|
||||
---@param fps number films per second
|
||||
local function pirntScrolling(str, fps)
|
||||
str = str .. " "
|
||||
local termWidth = term.getSize()
|
||||
local cfg1 = M.getCfg("noauto")
|
||||
cfg1.masking = { 2, 2, termWidth - 1, cfg1.fontFamily.maxHeight + 1 }
|
||||
|
||||
local spf = 1 / fps
|
||||
---@type FontFamily
|
||||
local fontFamily = cfg1.fontFamily
|
||||
local wid = 0
|
||||
for _, code in M.codes(str) do
|
||||
local bm = M.getCharMap(code, fontFamily)
|
||||
wid = wid + #bm[1]
|
||||
end
|
||||
|
||||
local cursorX = 2
|
||||
local cursorY = 2
|
||||
local maskingWidth = cfg1.masking[3] - cfg1.masking[1]
|
||||
local repeatNum = math.max(maskingWidth, wid)
|
||||
while true do
|
||||
cursorX = 2
|
||||
for i = 1, repeatNum do
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
M.printUtf8(str, cfg1)
|
||||
|
||||
term.setCursorPos(cursorX + repeatNum, cursorY)
|
||||
M.printUtf8(str, cfg1)
|
||||
cursorX = cursorX - 1
|
||||
|
||||
os.sleep(spf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pirntScrolling("hello -- by AAAB60", 5)
|
||||
---@module "cctAPI"
|
||||
local monitor = peripheral.find("monitor")
|
||||
local computer = term.redirect(monitor)
|
||||
|
||||
-- suggested
|
||||
monitor.setTextScale(0.5)
|
||||
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
local M = require("utf8textutils")
|
||||
|
||||
---@param str string
|
||||
---@param fps number films per second
|
||||
local function pirntScrolling(str, fps)
|
||||
str = str .. " "
|
||||
local termWidth = term.getSize()
|
||||
local cfg1 = M.getCfg("noauto")
|
||||
cfg1.masking = { 2, 2, termWidth - 1, cfg1.fontFamily.maxHeight + 1 }
|
||||
|
||||
local spf = 1 / fps
|
||||
---@type FontFamily
|
||||
local fontFamily = cfg1.fontFamily
|
||||
local wid = 0
|
||||
for _, code in M.codes(str) do
|
||||
local bm = M.getCharMap(code, fontFamily)
|
||||
wid = wid + #bm[1]
|
||||
end
|
||||
|
||||
local cursorX = 2
|
||||
local cursorY = 2
|
||||
local maskingWidth = cfg1.masking[3] - cfg1.masking[1]
|
||||
local repeatNum = math.max(maskingWidth, wid)
|
||||
while true do
|
||||
cursorX = 2
|
||||
for i = 1, repeatNum do
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
M.printUtf8(str, cfg1)
|
||||
|
||||
term.setCursorPos(cursorX + repeatNum, cursorY)
|
||||
M.printUtf8(str, cfg1)
|
||||
cursorX = cursorX - 1
|
||||
|
||||
os.sleep(spf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pirntScrolling("hello -- by AAAB60", 5)
|
||||
@@ -1,494 +1,494 @@
|
||||
---@module "cctAPI"
|
||||
|
||||
---example:
|
||||
---```
|
||||
---for pos, code in codes("你好world") do
|
||||
--- print(pos, code)
|
||||
---end
|
||||
------>
|
||||
---1 20320
|
||||
---4 22909
|
||||
---7 119
|
||||
---8 111
|
||||
---9 114
|
||||
---10 108
|
||||
---11 100
|
||||
---```
|
||||
---@param str string
|
||||
---@return fun():pos:integer, code:integer
|
||||
local function codes(str)
|
||||
local len = #str
|
||||
local i = 0
|
||||
|
||||
local function illegalChar()
|
||||
error("Illegal UTF-8 character at position " .. tostring(i))
|
||||
end
|
||||
|
||||
return function()
|
||||
i = i + 1
|
||||
---@diagnostic disable-next-line
|
||||
if i > len then return end
|
||||
|
||||
local pos = i
|
||||
local byte = string.byte(str, i)
|
||||
|
||||
-- Single-byte character
|
||||
if byte < 0x80 then
|
||||
return pos, byte
|
||||
|
||||
-- Multi-byte sequences
|
||||
elseif byte >= 0xC0 then
|
||||
local bytes_remaining, code = 0, 0
|
||||
|
||||
if byte < 0xE0 then -- 2-byte sequence
|
||||
bytes_remaining = 1
|
||||
code = byte - 0xC0
|
||||
elseif byte < 0xF0 then -- 3-byte sequence
|
||||
bytes_remaining = 2
|
||||
code = byte - 0xE0
|
||||
elseif byte < 0xF8 then -- 4-byte sequence
|
||||
bytes_remaining = 3
|
||||
code = byte - 0xF0
|
||||
else
|
||||
illegalChar()
|
||||
end
|
||||
|
||||
-- Validate remaining bytes
|
||||
if i + bytes_remaining > len then
|
||||
illegalChar()
|
||||
end
|
||||
|
||||
-- Calculate code point
|
||||
for j = 1, bytes_remaining do
|
||||
i = i + 1
|
||||
local next_byte = string.byte(str, i)
|
||||
if next_byte < 0x80 or next_byte >= 0xC0 then
|
||||
illegalChar()
|
||||
end
|
||||
code = code * 0x40 + (next_byte - 0x80)
|
||||
end
|
||||
|
||||
return pos, code
|
||||
else
|
||||
illegalChar()
|
||||
---@diagnostic disable-next-line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type FontFamily
|
||||
local defaultFontFamily = {
|
||||
maxHeight = 4,
|
||||
[1] = require("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||
}
|
||||
|
||||
---@param str string read in `"rb"` mode from file
|
||||
---@param nStartPos 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`
|
||||
local function sub(str, nStartPos, nEndPos)
|
||||
local charPos = 0
|
||||
local utf8charPosToStr = {}
|
||||
|
||||
for pos, _ in codes(str) do
|
||||
charPos = charPos + 1
|
||||
utf8charPosToStr[charPos] = pos
|
||||
end
|
||||
|
||||
nStartPos = nStartPos or 1
|
||||
nEndPos = nEndPos or charPos
|
||||
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)
|
||||
|
||||
local startByte = utf8charPosToStr[nStartPos]
|
||||
local endByte = utf8charPosToStr[nEndPos + 1] and utf8charPosToStr[nEndPos + 1] - 1 or #str
|
||||
return string.sub(str, startByte, endByte)
|
||||
end
|
||||
|
||||
---@class FontFamily
|
||||
---@field maxHeight integer
|
||||
---@diagnostic disable-next-line
|
||||
---@field [integer] Font get from `require(font_name)`
|
||||
|
||||
---@param ... string module names of font, font should be
|
||||
---@return FontFamily
|
||||
local function getFontFamily(...)
|
||||
local fonts = { maxHeight = 0 }
|
||||
|
||||
for i, path in ipairs({ ... }) do
|
||||
if not fs.exists(path .. ".lua") then
|
||||
error("Font module not found: " .. path)
|
||||
end
|
||||
|
||||
local font = require(path)
|
||||
if not font[72] then
|
||||
error("'H'(ascII:72) not found in font " .. path)
|
||||
end
|
||||
|
||||
fonts[i] = font
|
||||
fonts.maxHeight = math.max(fonts.maxHeight, #font[72])
|
||||
end
|
||||
|
||||
return fonts
|
||||
end
|
||||
---@alias bitmap string[] the bitmap of a character
|
||||
|
||||
---@param code integer
|
||||
---@param fontFamily FontFamily
|
||||
---@return bitmap
|
||||
local function getCharMap(code, fontFamily)
|
||||
local cm
|
||||
for _, font in ipairs(fontFamily) do
|
||||
cm = font[code]
|
||||
if cm then
|
||||
return cm
|
||||
end
|
||||
end
|
||||
error(("char of utf8 %d is not supported"):format(code))
|
||||
end
|
||||
|
||||
---@class Config
|
||||
---@field fontFamily FontFamily?
|
||||
---@field textColor number?
|
||||
---@field backgroundColor number?
|
||||
---@field masking [integer, integer, integer, integer]?
|
||||
---@field autoScroll boolean
|
||||
---@field autoNewLine boolean
|
||||
---@field autoWrapMode "n"|"b"|"-"?
|
||||
---@field autoWrapLen integer?
|
||||
---@field avoidBorder boolean
|
||||
---@field tabLen integer?
|
||||
|
||||
---@see Config
|
||||
---@param preset "noauto"?
|
||||
---@return Config
|
||||
local function getCfg(preset)
|
||||
---@type Config
|
||||
local base = {
|
||||
fontFamily = defaultFontFamily,
|
||||
textColor = nil,
|
||||
backgroundColor = nil,
|
||||
masking = nil,
|
||||
autoScroll = true,
|
||||
autoNewLine = true,
|
||||
autoWrapMode = "b",
|
||||
autoWrapLen = nil,
|
||||
avoidBorder = true,
|
||||
tabLen = 2
|
||||
}
|
||||
if preset == "noauto" then
|
||||
base.autoScroll = false
|
||||
base.autoNewLine = false
|
||||
base.autoWrapMode = "n"
|
||||
end
|
||||
return base
|
||||
end
|
||||
|
||||
|
||||
---`str` should be read in `"rb"` mode from file <br>
|
||||
---`cfg` see [`getCfg()`](lua://Config)
|
||||
---### Config
|
||||
---- **textColor**
|
||||
---- **backgroundColor**
|
||||
---- **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
|
||||
---- **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
|
||||
---- **autoWrapMode** <br>
|
||||
----- `"n"` do not auto wrap<br>
|
||||
----- `"b"` English letter will not be broken<br>
|
||||
----- `"-"` English letter will be broken by a `'-'`<br>
|
||||
---here 'letter' matches regex `(?<![a-zA-Z'])[a-zA-Z']+-?`<br>
|
||||
---actually realized avoid using `luautf8` or regex matching
|
||||
---- **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>
|
||||
---for example, autoWrap will start new line at pos (2, y) instead of (1, y)
|
||||
---- **tabLen** the count of `' '` to replace `'\t'`
|
||||
---@param str string
|
||||
---@param cfg Config?
|
||||
local function printUtf8(str, cfg)
|
||||
local cursorX, cursorY = term.getCursorPos()
|
||||
local termWidth, termHeight = term.getSize()
|
||||
|
||||
local cfg = cfg or getCfg()
|
||||
local oriTextColor, oriBackgroundColor = term.getTextColor(), term.getBackgroundColor()
|
||||
local textColor = cfg.textColor or oriTextColor
|
||||
local backgroundColor = cfg.backgroundColor or oriBackgroundColor
|
||||
local masking = cfg.masking
|
||||
local autoScroll = cfg.autoScroll or true
|
||||
local autoNewLine = cfg.autoNewLine
|
||||
local autoWrapMode = cfg.autoWrapMode or "b"
|
||||
local autoWrapLen = cfg.autoWrapLen or termWidth
|
||||
local avoidBorder = cfg.avoidBorder
|
||||
local fontFamily = cfg.fontFamily or defaultFontFamily
|
||||
local tabLen = cfg.tabLen or 2
|
||||
str = string.gsub(str, '\t', string.rep(" ", tabLen))
|
||||
local fontHeight = fontFamily.maxHeight
|
||||
if avoidBorder and autoWrapMode ~= "n" then
|
||||
autoWrapLen = math.min(termWidth - 1, autoWrapLen)
|
||||
cursorX = math.max(2, cursorX)
|
||||
cursorY = math.max(2, cursorY)
|
||||
end
|
||||
local maxHeight = avoidBorder and termHeight - 1 or termHeight
|
||||
---@type integer[]
|
||||
local letterBuffer = {}
|
||||
local dashWidth = #getCharMap(45, fontFamily)[1]
|
||||
---@type { pos: [integer, integer], code: integer }[]
|
||||
local charBuffer = {}
|
||||
|
||||
---@param x integer
|
||||
---@param y integer
|
||||
---@return boolean
|
||||
local function bInMasking(x, y)
|
||||
---@diagnostic disable-next-line
|
||||
return x >= masking[1] and x <= masking[3] and y >= masking[2] and y <= masking[4]
|
||||
end
|
||||
---add new line to charBuffer
|
||||
local function posNewLine()
|
||||
cursorX = avoidBorder and 2 or 1
|
||||
if autoScroll and cursorY + fontHeight > maxHeight then
|
||||
-- scroll term and masking
|
||||
term.scroll(fontHeight)
|
||||
for _, char in ipairs(charBuffer) do
|
||||
char.pos[2] = char.pos[2] - fontHeight
|
||||
end
|
||||
if masking then
|
||||
masking[2] = masking[2] - fontHeight
|
||||
masking[4] = masking[4] - fontHeight
|
||||
end
|
||||
else
|
||||
cursorY = cursorY + fontHeight
|
||||
end
|
||||
end
|
||||
---print char in charBuffer
|
||||
local function printChar()
|
||||
local bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
for _, char in ipairs(charBuffer) do
|
||||
---@type bitmap
|
||||
local charMap
|
||||
local code = char.code
|
||||
for _, font in ipairs(fontFamily) do
|
||||
if font[code] then
|
||||
charMap = font[code]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local width, height = #charMap[1], #charMap
|
||||
local cursorX, cursorY = unpack(char.pos)
|
||||
if height < fontHeight then
|
||||
if bIsLastReversed then
|
||||
bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
end
|
||||
for _ = 1, fontHeight - height do
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
term.write(string.rep(" ", width))
|
||||
cursorY = cursorY + 1
|
||||
end
|
||||
end
|
||||
for y = 1, height do
|
||||
local posY = cursorY + y - 1
|
||||
term.setCursorPos(cursorX, posY)
|
||||
local sCharMapBuffer = charMap[y]
|
||||
for x = 1, width do
|
||||
if not masking or bInMasking(cursorX + x - 1, posY) then
|
||||
local code = string.byte(sCharMapBuffer, x)
|
||||
if code < 128 then
|
||||
code = code + 128
|
||||
if not bIsLastReversed then
|
||||
bIsLastReversed = true
|
||||
term.setTextColor(backgroundColor)
|
||||
term.setBackgroundColor(textColor)
|
||||
end
|
||||
else
|
||||
if bIsLastReversed then
|
||||
bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
end
|
||||
end
|
||||
term.write(string.char(code))
|
||||
else
|
||||
term.setCursorPos(cursorX + x, posY)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
term.setTextColor(oriTextColor)
|
||||
term.setBackgroundColor(oriBackgroundColor)
|
||||
if autoNewLine then
|
||||
term.setCursorPos(1, cursorY + fontHeight)
|
||||
else
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
end
|
||||
end
|
||||
local bIsLetter = false
|
||||
local function releaseLetter()
|
||||
if bIsLetter then
|
||||
if autoWrapMode == "-" then
|
||||
local widthSum = cursorX - 1
|
||||
local widthBuffer = {}
|
||||
for index, letter in ipairs(letterBuffer) do
|
||||
widthBuffer[index] = #getCharMap(letter, fontFamily)[1]
|
||||
end
|
||||
local ind = 1
|
||||
local letterBufferLen = #letterBuffer
|
||||
local lastDashPos = 1
|
||||
|
||||
|
||||
while ind <= letterBufferLen do
|
||||
widthSum = widthSum + widthBuffer[ind]
|
||||
if widthSum > autoWrapLen then
|
||||
while widthSum + dashWidth > autoWrapLen do
|
||||
if ind == lastDashPos then
|
||||
-- when have to insert dash in the first character, posNewLine() or throw
|
||||
if ind == 1 and cursorX ~= (avoidBorder and 2 or 1) then
|
||||
widthSum = 0
|
||||
else
|
||||
error("dash too wide or autoWrapLen too small")
|
||||
end
|
||||
end
|
||||
widthSum = widthSum - widthBuffer[ind]
|
||||
ind = ind - 1
|
||||
end
|
||||
-- pos letters before dash
|
||||
for i = lastDashPos, ind do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
if widthSum >= 0 then
|
||||
-- add dash
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = 45
|
||||
}
|
||||
end
|
||||
-- reset
|
||||
widthSum = 0
|
||||
lastDashPos = ind + 1
|
||||
posNewLine()
|
||||
end
|
||||
ind = ind + 1
|
||||
end
|
||||
-- pos letters after dash
|
||||
for i = lastDashPos, letterBufferLen do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
elseif autoWrapMode == "b" then
|
||||
local widthSum = cursorX - 1
|
||||
local widthBuffer = {}
|
||||
local ind = 1
|
||||
local letterBufferLen = #letterBuffer
|
||||
while ind <= letterBufferLen do
|
||||
local charMapWidth = #getCharMap(letterBuffer[ind], fontFamily)[1]
|
||||
widthBuffer[ind] = charMapWidth
|
||||
widthSum = widthSum + charMapWidth
|
||||
ind = ind + 1
|
||||
end
|
||||
|
||||
local forceNewLineFlag = false
|
||||
if widthSum > autoWrapLen then
|
||||
if cursorX == (avoidBorder and 2 or 1) then
|
||||
forceNewLineFlag = true
|
||||
else
|
||||
widthSum = widthSum - cursorX + 1
|
||||
if widthSum > autoWrapLen then
|
||||
forceNewLineFlag = true
|
||||
else
|
||||
posNewLine()
|
||||
end
|
||||
end
|
||||
end
|
||||
if forceNewLineFlag then
|
||||
for i = 1, letterBufferLen do
|
||||
if cursorX + widthBuffer[i] > autoWrapLen then
|
||||
posNewLine()
|
||||
end
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
else
|
||||
for i = 1, letterBufferLen do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
end
|
||||
elseif autoWrapMode == "n" then
|
||||
for _, letter in ipairs(letterBuffer) do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letter
|
||||
}
|
||||
cursorX = cursorX + #getCharMap(letter, fontFamily)[1]
|
||||
end
|
||||
end
|
||||
letterBuffer = {}
|
||||
bIsLetter = false
|
||||
end
|
||||
end
|
||||
|
||||
local lastLR = false
|
||||
for _, code in codes(str) do
|
||||
-- handle break line, \r, \n and \r\n will be transferred
|
||||
if code == 13 then
|
||||
releaseLetter()
|
||||
lastLR = true
|
||||
posNewLine()
|
||||
elseif code == 10 and not lastLR then
|
||||
lastLR = false
|
||||
releaseLetter()
|
||||
posNewLine()
|
||||
|
||||
-- record letter for break line
|
||||
elseif code == 45 and bIsLetter then
|
||||
lastLR = false
|
||||
letterBuffer[#letterBuffer + 1] = code
|
||||
releaseLetter()
|
||||
elseif code >= 65 and code <= 90 or (code >= 97 and code <= 122) or code == 39 then
|
||||
lastLR = false
|
||||
letterBuffer[#letterBuffer + 1] = code
|
||||
bIsLetter = true
|
||||
|
||||
-- pos char
|
||||
else
|
||||
lastLR = false
|
||||
releaseLetter()
|
||||
local charMapWidth = #getCharMap(code, fontFamily)[1]
|
||||
if autoWrapMode ~= "n" and cursorX + charMapWidth - 1 > autoWrapLen then
|
||||
posNewLine()
|
||||
end
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = code
|
||||
}
|
||||
cursorX = cursorX + charMapWidth
|
||||
end
|
||||
end
|
||||
releaseLetter()
|
||||
printChar()
|
||||
end
|
||||
return {
|
||||
codes = codes,
|
||||
printUtf8 = printUtf8,
|
||||
getFontFamily = getFontFamily,
|
||||
sub = sub,
|
||||
getCfg = getCfg,
|
||||
getCharMap = getCharMap
|
||||
}
|
||||
---@module "cctAPI"
|
||||
|
||||
---example:
|
||||
---```
|
||||
---for pos, code in codes("你好world") do
|
||||
--- print(pos, code)
|
||||
---end
|
||||
------>
|
||||
---1 20320
|
||||
---4 22909
|
||||
---7 119
|
||||
---8 111
|
||||
---9 114
|
||||
---10 108
|
||||
---11 100
|
||||
---```
|
||||
---@param str string
|
||||
---@return fun():pos:integer, code:integer
|
||||
local function codes(str)
|
||||
local len = #str
|
||||
local i = 0
|
||||
|
||||
local function illegalChar()
|
||||
error("Illegal UTF-8 character at position " .. tostring(i))
|
||||
end
|
||||
|
||||
return function()
|
||||
i = i + 1
|
||||
---@diagnostic disable-next-line
|
||||
if i > len then return end
|
||||
|
||||
local pos = i
|
||||
local byte = string.byte(str, i)
|
||||
|
||||
-- Single-byte character
|
||||
if byte < 0x80 then
|
||||
return pos, byte
|
||||
|
||||
-- Multi-byte sequences
|
||||
elseif byte >= 0xC0 then
|
||||
local bytes_remaining, code = 0, 0
|
||||
|
||||
if byte < 0xE0 then -- 2-byte sequence
|
||||
bytes_remaining = 1
|
||||
code = byte - 0xC0
|
||||
elseif byte < 0xF0 then -- 3-byte sequence
|
||||
bytes_remaining = 2
|
||||
code = byte - 0xE0
|
||||
elseif byte < 0xF8 then -- 4-byte sequence
|
||||
bytes_remaining = 3
|
||||
code = byte - 0xF0
|
||||
else
|
||||
illegalChar()
|
||||
end
|
||||
|
||||
-- Validate remaining bytes
|
||||
if i + bytes_remaining > len then
|
||||
illegalChar()
|
||||
end
|
||||
|
||||
-- Calculate code point
|
||||
for j = 1, bytes_remaining do
|
||||
i = i + 1
|
||||
local next_byte = string.byte(str, i)
|
||||
if next_byte < 0x80 or next_byte >= 0xC0 then
|
||||
illegalChar()
|
||||
end
|
||||
code = code * 0x40 + (next_byte - 0x80)
|
||||
end
|
||||
|
||||
return pos, code
|
||||
else
|
||||
illegalChar()
|
||||
---@diagnostic disable-next-line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type FontFamily
|
||||
local defaultFontFamily = {
|
||||
maxHeight = 4,
|
||||
[1] = require("fonts/fusion-pixel-12px-proportional-zh_hans")
|
||||
}
|
||||
|
||||
---@param str string read in `"rb"` mode from file
|
||||
---@param nStartPos 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`
|
||||
local function sub(str, nStartPos, nEndPos)
|
||||
local charPos = 0
|
||||
local utf8charPosToStr = {}
|
||||
|
||||
for pos, _ in codes(str) do
|
||||
charPos = charPos + 1
|
||||
utf8charPosToStr[charPos] = pos
|
||||
end
|
||||
|
||||
nStartPos = nStartPos or 1
|
||||
nEndPos = nEndPos or charPos
|
||||
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)
|
||||
|
||||
local startByte = utf8charPosToStr[nStartPos]
|
||||
local endByte = utf8charPosToStr[nEndPos + 1] and utf8charPosToStr[nEndPos + 1] - 1 or #str
|
||||
return string.sub(str, startByte, endByte)
|
||||
end
|
||||
|
||||
---@class FontFamily
|
||||
---@field maxHeight integer
|
||||
---@diagnostic disable-next-line
|
||||
---@field [integer] Font get from `require(font_name)`
|
||||
|
||||
---@param ... string module names of font, font should be
|
||||
---@return FontFamily
|
||||
local function getFontFamily(...)
|
||||
local fonts = { maxHeight = 0 }
|
||||
|
||||
for i, path in ipairs({ ... }) do
|
||||
if not fs.exists(path .. ".lua") then
|
||||
error("Font module not found: " .. path)
|
||||
end
|
||||
|
||||
local font = require(path)
|
||||
if not font[72] then
|
||||
error("'H'(ascII:72) not found in font " .. path)
|
||||
end
|
||||
|
||||
fonts[i] = font
|
||||
fonts.maxHeight = math.max(fonts.maxHeight, #font[72])
|
||||
end
|
||||
|
||||
return fonts
|
||||
end
|
||||
---@alias bitmap string[] the bitmap of a character
|
||||
|
||||
---@param code integer
|
||||
---@param fontFamily FontFamily
|
||||
---@return bitmap
|
||||
local function getCharMap(code, fontFamily)
|
||||
local cm
|
||||
for _, font in ipairs(fontFamily) do
|
||||
cm = font[code]
|
||||
if cm then
|
||||
return cm
|
||||
end
|
||||
end
|
||||
error(("char of utf8 %d is not supported"):format(code))
|
||||
end
|
||||
|
||||
---@class Config
|
||||
---@field fontFamily FontFamily?
|
||||
---@field textColor number?
|
||||
---@field backgroundColor number?
|
||||
---@field masking [integer, integer, integer, integer]?
|
||||
---@field autoScroll boolean
|
||||
---@field autoNewLine boolean
|
||||
---@field autoWrapMode "n"|"b"|"-"?
|
||||
---@field autoWrapLen integer?
|
||||
---@field avoidBorder boolean
|
||||
---@field tabLen integer?
|
||||
|
||||
---@see Config
|
||||
---@param preset "noauto"?
|
||||
---@return Config
|
||||
local function getCfg(preset)
|
||||
---@type Config
|
||||
local base = {
|
||||
fontFamily = defaultFontFamily,
|
||||
textColor = nil,
|
||||
backgroundColor = nil,
|
||||
masking = nil,
|
||||
autoScroll = true,
|
||||
autoNewLine = true,
|
||||
autoWrapMode = "b",
|
||||
autoWrapLen = nil,
|
||||
avoidBorder = true,
|
||||
tabLen = 2
|
||||
}
|
||||
if preset == "noauto" then
|
||||
base.autoScroll = false
|
||||
base.autoNewLine = false
|
||||
base.autoWrapMode = "n"
|
||||
end
|
||||
return base
|
||||
end
|
||||
|
||||
|
||||
---`str` should be read in `"rb"` mode from file <br>
|
||||
---`cfg` see [`getCfg()`](lua://Config)
|
||||
---### Config
|
||||
---- **textColor**
|
||||
---- **backgroundColor**
|
||||
---- **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
|
||||
---- **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
|
||||
---- **autoWrapMode** <br>
|
||||
----- `"n"` do not auto wrap<br>
|
||||
----- `"b"` English letter will not be broken<br>
|
||||
----- `"-"` English letter will be broken by a `'-'`<br>
|
||||
---here 'letter' matches regex `(?<![a-zA-Z'])[a-zA-Z']+-?`<br>
|
||||
---actually realized avoid using `luautf8` or regex matching
|
||||
---- **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>
|
||||
---for example, autoWrap will start new line at pos (2, y) instead of (1, y)
|
||||
---- **tabLen** the count of `' '` to replace `'\t'`
|
||||
---@param str string
|
||||
---@param cfg Config?
|
||||
local function printUtf8(str, cfg)
|
||||
local cursorX, cursorY = term.getCursorPos()
|
||||
local termWidth, termHeight = term.getSize()
|
||||
|
||||
local cfg = cfg or getCfg()
|
||||
local oriTextColor, oriBackgroundColor = term.getTextColor(), term.getBackgroundColor()
|
||||
local textColor = cfg.textColor or oriTextColor
|
||||
local backgroundColor = cfg.backgroundColor or oriBackgroundColor
|
||||
local masking = cfg.masking
|
||||
local autoScroll = cfg.autoScroll or true
|
||||
local autoNewLine = cfg.autoNewLine
|
||||
local autoWrapMode = cfg.autoWrapMode or "b"
|
||||
local autoWrapLen = cfg.autoWrapLen or termWidth
|
||||
local avoidBorder = cfg.avoidBorder
|
||||
local fontFamily = cfg.fontFamily or defaultFontFamily
|
||||
local tabLen = cfg.tabLen or 2
|
||||
str = string.gsub(str, '\t', string.rep(" ", tabLen))
|
||||
local fontHeight = fontFamily.maxHeight
|
||||
if avoidBorder and autoWrapMode ~= "n" then
|
||||
autoWrapLen = math.min(termWidth - 1, autoWrapLen)
|
||||
cursorX = math.max(2, cursorX)
|
||||
cursorY = math.max(2, cursorY)
|
||||
end
|
||||
local maxHeight = avoidBorder and termHeight - 1 or termHeight
|
||||
---@type integer[]
|
||||
local letterBuffer = {}
|
||||
local dashWidth = #getCharMap(45, fontFamily)[1]
|
||||
---@type { pos: [integer, integer], code: integer }[]
|
||||
local charBuffer = {}
|
||||
|
||||
---@param x integer
|
||||
---@param y integer
|
||||
---@return boolean
|
||||
local function bInMasking(x, y)
|
||||
---@diagnostic disable-next-line
|
||||
return x >= masking[1] and x <= masking[3] and y >= masking[2] and y <= masking[4]
|
||||
end
|
||||
---add new line to charBuffer
|
||||
local function posNewLine()
|
||||
cursorX = avoidBorder and 2 or 1
|
||||
if autoScroll and cursorY + fontHeight > maxHeight then
|
||||
-- scroll term and masking
|
||||
term.scroll(fontHeight)
|
||||
for _, char in ipairs(charBuffer) do
|
||||
char.pos[2] = char.pos[2] - fontHeight
|
||||
end
|
||||
if masking then
|
||||
masking[2] = masking[2] - fontHeight
|
||||
masking[4] = masking[4] - fontHeight
|
||||
end
|
||||
else
|
||||
cursorY = cursorY + fontHeight
|
||||
end
|
||||
end
|
||||
---print char in charBuffer
|
||||
local function printChar()
|
||||
local bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
for _, char in ipairs(charBuffer) do
|
||||
---@type bitmap
|
||||
local charMap
|
||||
local code = char.code
|
||||
for _, font in ipairs(fontFamily) do
|
||||
if font[code] then
|
||||
charMap = font[code]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local width, height = #charMap[1], #charMap
|
||||
local cursorX, cursorY = unpack(char.pos)
|
||||
if height < fontHeight then
|
||||
if bIsLastReversed then
|
||||
bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
end
|
||||
for _ = 1, fontHeight - height do
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
term.write(string.rep(" ", width))
|
||||
cursorY = cursorY + 1
|
||||
end
|
||||
end
|
||||
for y = 1, height do
|
||||
local posY = cursorY + y - 1
|
||||
term.setCursorPos(cursorX, posY)
|
||||
local sCharMapBuffer = charMap[y]
|
||||
for x = 1, width do
|
||||
if not masking or bInMasking(cursorX + x - 1, posY) then
|
||||
local code = string.byte(sCharMapBuffer, x)
|
||||
if code < 128 then
|
||||
code = code + 128
|
||||
if not bIsLastReversed then
|
||||
bIsLastReversed = true
|
||||
term.setTextColor(backgroundColor)
|
||||
term.setBackgroundColor(textColor)
|
||||
end
|
||||
else
|
||||
if bIsLastReversed then
|
||||
bIsLastReversed = false
|
||||
term.setTextColor(textColor)
|
||||
term.setBackgroundColor(backgroundColor)
|
||||
end
|
||||
end
|
||||
term.write(string.char(code))
|
||||
else
|
||||
term.setCursorPos(cursorX + x, posY)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
term.setTextColor(oriTextColor)
|
||||
term.setBackgroundColor(oriBackgroundColor)
|
||||
if autoNewLine then
|
||||
term.setCursorPos(1, cursorY + fontHeight)
|
||||
else
|
||||
term.setCursorPos(cursorX, cursorY)
|
||||
end
|
||||
end
|
||||
local bIsLetter = false
|
||||
local function releaseLetter()
|
||||
if bIsLetter then
|
||||
if autoWrapMode == "-" then
|
||||
local widthSum = cursorX - 1
|
||||
local widthBuffer = {}
|
||||
for index, letter in ipairs(letterBuffer) do
|
||||
widthBuffer[index] = #getCharMap(letter, fontFamily)[1]
|
||||
end
|
||||
local ind = 1
|
||||
local letterBufferLen = #letterBuffer
|
||||
local lastDashPos = 1
|
||||
|
||||
|
||||
while ind <= letterBufferLen do
|
||||
widthSum = widthSum + widthBuffer[ind]
|
||||
if widthSum > autoWrapLen then
|
||||
while widthSum + dashWidth > autoWrapLen do
|
||||
if ind == lastDashPos then
|
||||
-- when have to insert dash in the first character, posNewLine() or throw
|
||||
if ind == 1 and cursorX ~= (avoidBorder and 2 or 1) then
|
||||
widthSum = 0
|
||||
else
|
||||
error("dash too wide or autoWrapLen too small")
|
||||
end
|
||||
end
|
||||
widthSum = widthSum - widthBuffer[ind]
|
||||
ind = ind - 1
|
||||
end
|
||||
-- pos letters before dash
|
||||
for i = lastDashPos, ind do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
if widthSum >= 0 then
|
||||
-- add dash
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = 45
|
||||
}
|
||||
end
|
||||
-- reset
|
||||
widthSum = 0
|
||||
lastDashPos = ind + 1
|
||||
posNewLine()
|
||||
end
|
||||
ind = ind + 1
|
||||
end
|
||||
-- pos letters after dash
|
||||
for i = lastDashPos, letterBufferLen do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
elseif autoWrapMode == "b" then
|
||||
local widthSum = cursorX - 1
|
||||
local widthBuffer = {}
|
||||
local ind = 1
|
||||
local letterBufferLen = #letterBuffer
|
||||
while ind <= letterBufferLen do
|
||||
local charMapWidth = #getCharMap(letterBuffer[ind], fontFamily)[1]
|
||||
widthBuffer[ind] = charMapWidth
|
||||
widthSum = widthSum + charMapWidth
|
||||
ind = ind + 1
|
||||
end
|
||||
|
||||
local forceNewLineFlag = false
|
||||
if widthSum > autoWrapLen then
|
||||
if cursorX == (avoidBorder and 2 or 1) then
|
||||
forceNewLineFlag = true
|
||||
else
|
||||
widthSum = widthSum - cursorX + 1
|
||||
if widthSum > autoWrapLen then
|
||||
forceNewLineFlag = true
|
||||
else
|
||||
posNewLine()
|
||||
end
|
||||
end
|
||||
end
|
||||
if forceNewLineFlag then
|
||||
for i = 1, letterBufferLen do
|
||||
if cursorX + widthBuffer[i] > autoWrapLen then
|
||||
posNewLine()
|
||||
end
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
else
|
||||
for i = 1, letterBufferLen do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letterBuffer[i]
|
||||
}
|
||||
cursorX = cursorX + widthBuffer[i]
|
||||
end
|
||||
end
|
||||
elseif autoWrapMode == "n" then
|
||||
for _, letter in ipairs(letterBuffer) do
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = letter
|
||||
}
|
||||
cursorX = cursorX + #getCharMap(letter, fontFamily)[1]
|
||||
end
|
||||
end
|
||||
letterBuffer = {}
|
||||
bIsLetter = false
|
||||
end
|
||||
end
|
||||
|
||||
local lastLR = false
|
||||
for _, code in codes(str) do
|
||||
-- handle break line, \r, \n and \r\n will be transferred
|
||||
if code == 13 then
|
||||
releaseLetter()
|
||||
lastLR = true
|
||||
posNewLine()
|
||||
elseif code == 10 and not lastLR then
|
||||
lastLR = false
|
||||
releaseLetter()
|
||||
posNewLine()
|
||||
|
||||
-- record letter for break line
|
||||
elseif code == 45 and bIsLetter then
|
||||
lastLR = false
|
||||
letterBuffer[#letterBuffer + 1] = code
|
||||
releaseLetter()
|
||||
elseif code >= 65 and code <= 90 or (code >= 97 and code <= 122) or code == 39 then
|
||||
lastLR = false
|
||||
letterBuffer[#letterBuffer + 1] = code
|
||||
bIsLetter = true
|
||||
|
||||
-- pos char
|
||||
else
|
||||
lastLR = false
|
||||
releaseLetter()
|
||||
local charMapWidth = #getCharMap(code, fontFamily)[1]
|
||||
if autoWrapMode ~= "n" and cursorX + charMapWidth - 1 > autoWrapLen then
|
||||
posNewLine()
|
||||
end
|
||||
charBuffer[#charBuffer + 1] = {
|
||||
pos = { cursorX, cursorY },
|
||||
code = code
|
||||
}
|
||||
cursorX = cursorX + charMapWidth
|
||||
end
|
||||
end
|
||||
releaseLetter()
|
||||
printChar()
|
||||
end
|
||||
return {
|
||||
codes = codes,
|
||||
printUtf8 = printUtf8,
|
||||
getFontFamily = getFontFamily,
|
||||
sub = sub,
|
||||
getCfg = getCfg,
|
||||
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**
|
||||
- automatically test and form the catalyst formula
|
||||
- finnal output numbers represent the magnet in the corresponding slot of the crate
|
||||
- using four different containers to simplify`peripheral.find`
|
||||
## 介绍
|
||||
|
||||
此仓库克隆自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>
|
||||
|
||||
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