mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-12 06:21:50 +00:00
Merge branch 'main' into refactor-world-renderer
This commit is contained in:
commit
a8886bccfb
18 changed files with 404 additions and 118 deletions
|
|
@ -18,19 +18,86 @@ Bytearray.insert(arr, {5, 3, 6})
|
||||||
|
|
||||||
assert(#arr == 12)
|
assert(#arr == 12)
|
||||||
Bytearray.insert(arr, 2, 8)
|
Bytearray.insert(arr, 2, 8)
|
||||||
assert(#arr == 13)
|
asserts.equals(13, #arr)
|
||||||
for i=1,10 do
|
for i=1,10 do
|
||||||
assert(arr[i] == 10 - i)
|
assert(arr[i] == 10 - i)
|
||||||
end
|
end
|
||||||
print(#arr, arr:get_capacity())
|
print(#arr, arr:get_capacity())
|
||||||
arr:trim()
|
arr:trim()
|
||||||
assert(#arr == arr:get_capacity())
|
asserts.equals(#arr, arr:get_capacity())
|
||||||
|
|
||||||
arr = Bytearray({0, 2, 7, 1, 16, 75, 25})
|
arr = Bytearray({0, 2, 7, 1, 16, 75, 25})
|
||||||
assert(arr[6] == 75)
|
assert(arr[6] == 75)
|
||||||
|
|
||||||
arr:insert(2, {5, 6})
|
arr:insert(2, {5, 6})
|
||||||
|
|
||||||
assert(arr[#arr] == 25)
|
asserts.equals(25, arr[#arr])
|
||||||
assert(arr[2] == 5)
|
asserts.equals(5, arr[2])
|
||||||
assert(arr[3] == 6)
|
asserts.equals(6, arr[3])
|
||||||
|
|
||||||
|
-- =============================
|
||||||
|
|
||||||
|
arr = Bytearray({254, 255, 255, 255, 255, 255, 255, 255})
|
||||||
|
asserts.equals(U64view(arr)[1], ctypes.uint64(2) ^ 64 - 2)
|
||||||
|
asserts.equals(I64view(arr)[1], -2)
|
||||||
|
asserts.equals(U32view(arr)[1], 2 ^ 32 - 2)
|
||||||
|
asserts.equals(I32view(arr)[1], -2)
|
||||||
|
asserts.equals(U16view(arr)[1], 2 ^ 16 - 2)
|
||||||
|
asserts.equals(I16view(arr)[1], -2)
|
||||||
|
asserts.equals(I8view(arr)[1], -2)
|
||||||
|
|
||||||
|
asserts.equals(I8view(arr)[2], -1)
|
||||||
|
asserts.equals(I32view(arr)[2], -1)
|
||||||
|
|
||||||
|
arr = Bytearray({0xFF, 0x7F})
|
||||||
|
local arri16 = I16view(arr)
|
||||||
|
local arru16 = U16view(arr)
|
||||||
|
asserts.equals(arri16[1], 32767)
|
||||||
|
|
||||||
|
arru16[1] = arru16[1] + 1
|
||||||
|
asserts.equals(arri16[1], -32768)
|
||||||
|
asserts.equals(arru16[1], 32768)
|
||||||
|
|
||||||
|
arr = Bytearray({0x9A, 0x99, 0x59, 0x40}) -- approx. equal 3.4 in hexadecimal representation of single-precision float number.
|
||||||
|
local arrflt = FLTview(arr)
|
||||||
|
local arru32 = U32view(arr)
|
||||||
|
asserts.equals(arrflt[1], 3.4000000953674316)
|
||||||
|
asserts.equals(arru32[1], 0x4059999A)
|
||||||
|
|
||||||
|
arrflt[1] = arrflt[1] + 0.1
|
||||||
|
asserts.equals(arrflt[1], 3.5)
|
||||||
|
asserts.equals(arru32[1], 0x40600000) -- hexadecimal representation of 3.5 single-precision float number.
|
||||||
|
|
||||||
|
arr = Bytearray({0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 9, 64}) -- hexadecimal representation of 3.141592653589793 double-precision float number.
|
||||||
|
assert(DBLview(arr)[1] == 3.141592653589793)
|
||||||
|
|
||||||
|
-- =============================================
|
||||||
|
|
||||||
|
function barrtostr(barr)
|
||||||
|
local outstr = ""
|
||||||
|
for i = 1, #barr do
|
||||||
|
local lastfmt = ""
|
||||||
|
if i ~= #barr then lastfmt = "|" end
|
||||||
|
outstr = outstr .. barr[i] .. lastfmt
|
||||||
|
end
|
||||||
|
return outstr
|
||||||
|
end
|
||||||
|
|
||||||
|
arr = Bytearray({0, 5, 34, 87, 21, 0, 210})
|
||||||
|
asserts.equals(barrtostr(arr), "0|5|34|87|21|0|210")
|
||||||
|
arr:move(2, 3, 4)
|
||||||
|
asserts.equals(barrtostr(arr), "0|5|5|34|87|21|210")
|
||||||
|
|
||||||
|
local arr2 = Bytearray({1, 2, 3, 4, 6, 7, 8})
|
||||||
|
asserts.equals(barrtostr(arr2), "1|2|3|4|6|7|8")
|
||||||
|
arr:copy(4, arr2, 2, 3)
|
||||||
|
asserts.equals(barrtostr(arr2), "1|34|87|21|6|7|8")
|
||||||
|
|
||||||
|
arr:fill(nil, nil, 192)
|
||||||
|
asserts.equals(barrtostr(arr), "192|192|192|192|192|192|192")
|
||||||
|
arr:fill(nil, 3, 233)
|
||||||
|
asserts.equals(barrtostr(arr), "233|233|233|233|233|233|233")
|
||||||
|
arr:fill(2, nil, 254)
|
||||||
|
asserts.equals(barrtostr(arr), "254|254|254|254|254|254|254")
|
||||||
|
arr:fill(2, 2, 66)
|
||||||
|
asserts.equals(barrtostr(arr), "254|66|66|254|254|254|254")
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ Subsections:
|
||||||
- [block](scripting/builtins/libblock.md)
|
- [block](scripting/builtins/libblock.md)
|
||||||
- [byteutil](scripting/builtins/libbyteutil.md)
|
- [byteutil](scripting/builtins/libbyteutil.md)
|
||||||
- [cameras](scripting/builtins/libcameras.md)
|
- [cameras](scripting/builtins/libcameras.md)
|
||||||
|
- [ctypes](scripting/builtins/libctypes.md)
|
||||||
- [entities](scripting/builtins/libentities.md)
|
- [entities](scripting/builtins/libentities.md)
|
||||||
- [file](scripting/builtins/libfile.md)
|
- [file](scripting/builtins/libfile.md)
|
||||||
- [gfx.blockwraps](scripting/builtins/libgfx-blockwraps.md)
|
- [gfx.blockwraps](scripting/builtins/libgfx-blockwraps.md)
|
||||||
|
|
|
||||||
28
doc/en/scripting/builtins/libctypes.md
Normal file
28
doc/en/scripting/builtins/libctypes.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# *ctypes* Library
|
||||||
|
|
||||||
|
A library for safe work with C types.
|
||||||
|
|
||||||
|
| ctypes.\<name\> | C-Type | Minimum | Maximum |
|
||||||
|
| --------------- | -------- | -------------------- | -------------------- |
|
||||||
|
| uint8 | uint8_t | 0 | 255 |
|
||||||
|
| uint16 | uint16_t | 0 | 65535 |
|
||||||
|
| uint32 | uint32_t | 0 | 4294967295 |
|
||||||
|
| uint64 | uint64_t | 0 | 18446744073709551615 |
|
||||||
|
| int8 | int8_t | -128 | 127 |
|
||||||
|
| int16 | int16_t | -32768 | 32767 |
|
||||||
|
| int32 | int32_t | -2147483648 | 2147483647 |
|
||||||
|
| int64 | int64_t | -9223372036854775808 | 9223372036854775807 |
|
||||||
|
|
||||||
|
|
||||||
|
Usage examples:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local x = ctypes.uint64(1234)
|
||||||
|
print(x) --> 1234ULL (cdata)
|
||||||
|
local y = ctypes.uint64("18446744073709551615")
|
||||||
|
print(y) --> 18446744073709551615ULL (cdata)
|
||||||
|
print(x + y) --> 1233ULL
|
||||||
|
|
||||||
|
local z = tonumber(x)
|
||||||
|
print(z) --> 1234 (number)
|
||||||
|
```
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
- [block](scripting/builtins/libblock.md)
|
- [block](scripting/builtins/libblock.md)
|
||||||
- [byteutil](scripting/builtins/libbyteutil.md)
|
- [byteutil](scripting/builtins/libbyteutil.md)
|
||||||
- [cameras](scripting/builtins/libcameras.md)
|
- [cameras](scripting/builtins/libcameras.md)
|
||||||
|
- [ctypes](scripting/builtins/libctypes.md)
|
||||||
- [entities](scripting/builtins/libentities.md)
|
- [entities](scripting/builtins/libentities.md)
|
||||||
- [file](scripting/builtins/libfile.md)
|
- [file](scripting/builtins/libfile.md)
|
||||||
- [gfx.blockwraps](scripting/builtins/libgfx-blockwraps.md)
|
- [gfx.blockwraps](scripting/builtins/libgfx-blockwraps.md)
|
||||||
|
|
|
||||||
28
doc/ru/scripting/builtins/libctypes.md
Normal file
28
doc/ru/scripting/builtins/libctypes.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Библиотека *ctypes*
|
||||||
|
|
||||||
|
Библиотека для безопасной работы с типами языка С.
|
||||||
|
|
||||||
|
| ctypes.\<name\> | С-тип | Минимум | Максимум |
|
||||||
|
| ------------- | -------- | -------------------- | -------------------- |
|
||||||
|
| uint8 | uint8_t | 0 | 255 |
|
||||||
|
| uint16 | uint16_t | 0 | 65535 |
|
||||||
|
| uint32 | uint32_t | 0 | 4294967295 |
|
||||||
|
| uint64 | uint64_t | 0 | 18446744073709551615 |
|
||||||
|
| int8 | int8_t | -128 | 127 |
|
||||||
|
| int16 | int16_t | -32768 | 32767 |
|
||||||
|
| int32 | int32_t | -2147483648 | 2147483647 |
|
||||||
|
| int64 | int64_t | -9223372036854775808 | 9223372036854775807 |
|
||||||
|
|
||||||
|
|
||||||
|
Примеры использования:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local x = ctypes.uint64(1234)
|
||||||
|
print(x) --> 1234ULL (cdata)
|
||||||
|
local y = ctypes.uint64("18446744073709551615")
|
||||||
|
print(y) --> 18446744073709551615ULL (cdata)
|
||||||
|
print(x + y) --> 1233ULL
|
||||||
|
|
||||||
|
local z = tonumber(x)
|
||||||
|
print(z) --> 1234 (number)
|
||||||
|
```
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
*Bytearray* - динамический байтовый массив, реализованный через LuaJIT FFI. По нему можно итерироваться стандартными функциями **pairs** и **ipairs**
|
*Bytearray* - динамический байтовый массив, реализованный через LuaJIT FFI. По нему можно итерироваться стандартными функциями **pairs** и **ipairs**
|
||||||
|
|
||||||
|
<small>Примечание касаемо условных обозначений в документации: псведотип `posint` означает натуральное (положительное ненулевое целое) число.</small>
|
||||||
|
|
||||||
## Основное
|
## Основное
|
||||||
### Создание массива
|
### Создание массива
|
||||||
```lua
|
```lua
|
||||||
|
|
@ -22,29 +24,64 @@ bytes:insert(index: int, value: int)
|
||||||
-- Удаляет элемент(ы), если передан `count`, удалит `count` кол-во элементов с выбранного индекса.
|
-- Удаляет элемент(ы), если передан `count`, удалит `count` кол-во элементов с выбранного индекса.
|
||||||
bytes:remove(index: int, [опционально] count: int)
|
bytes:remove(index: int, [опционально] count: int)
|
||||||
|
|
||||||
-- Очищает массив
|
-- Очищает массив.
|
||||||
bytes:clear()
|
bytes:clear()
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Заполняет массив определённым байтом полностью либо в определённом диапазоне.
|
||||||
|
Логика работы следующая: если параметр size или index равны nil, то указанным байтом будет заполнен весь массив,
|
||||||
|
иначе будет заполнен диапазон внутри массива начиная с индекса index и размером size.
|
||||||
|
В случае выхода заполняемого блока за границы массива генерирует соответствующую ошибку.
|
||||||
|
]]
|
||||||
|
bytes:fill(index: posint/nil, size: posint/nil, byte: uint8)
|
||||||
|
|
||||||
-- Создаёт новый Bytearray, содержащий копию части данных с offset до offset+length
|
-- Создаёт новый Bytearray, содержащий копию части данных с offset до offset+length
|
||||||
bytes:slice(offset: int, length: int) -> Bytearray
|
bytes:slice(offset: int, length: int) -> Bytearray
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Копирует блок байт из исходного массива, начиная с индекса srcindex, в массив dst, начиная в нём с индекса dstindex.
|
||||||
|
В случае выхода за границы исходного, конечного массива, либо при некорректном значении параметра size генерирует соответствующую ошибку.
|
||||||
|
]]
|
||||||
|
bytes:copy(srcindex: posint, dst: Bytearray, dstindex: posint, size: posint)
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Безопасно копирует перекрывающиеся области памяти (байт) в пределах одного массива.
|
||||||
|
В случае выхода за пределы массива начального или конечного диапазона байт генерирует соответствующую ошибку.
|
||||||
|
]]
|
||||||
|
bytes:move(fromindex: posint, toindex: posint, size: posint)
|
||||||
```
|
```
|
||||||
|
|
||||||
## View
|
## View
|
||||||
|
|
||||||
Это "вьюшки" поверх Bytearray, которые интерпретируют его байты как массив чисел другого размера - **без копирования данных**.
|
Это "вьюшки" поверх Bytearray, которые интерпретируют его байты как массив чисел другого размера - **без копирования данных**.
|
||||||
|
|
||||||
Не имеет своих методов, является просто объектной ссылкой на оригинальный Bytearray.
|
Практически не имеют своих методов, являются простыми объектными ссылками на оригинальный Bytearray.
|
||||||
|
|
||||||
| Класс | Тип элементов | Размер |
|
| Класс | Тип элементов | Размер |
|
||||||
| ------------ | ------------------ | ------- |
|
| ------------ | ------------------ | --------- |
|
||||||
| `I16view` | `int16_t` | 2 байта |
|
| `I8view` | `int8_t` | 1 байт |
|
||||||
| `U16view` | `uint16_t` | 2 байта |
|
| `I16view` | `int16_t` | 2 байта |
|
||||||
| `I32view` | `int32_t` | 4 байта |
|
| `U16view` | `uint16_t` | 2 байта |
|
||||||
| `U32view` | `uint32_t` | 4 байта |
|
| `I32view` | `int32_t` | 4 байта |
|
||||||
|
| `U32view` | `uint32_t` | 4 байта |
|
||||||
|
| `I64view` | `int64_t` | 8 байт |
|
||||||
|
| `U64view` | `uint64_t` | 8 байт |
|
||||||
|
| `FLTview` | `float` | 4 байта* |
|
||||||
|
| `DBLview` | `double` | 8 байт* |
|
||||||
|
|
||||||
---
|
<small>* Размеры "оригинальных" C-шных типов являются платформозависимыми и их точный размер не описан в стандарте языка. В данной таблице предоставлены наиболее распространённые размеры типов.</small>
|
||||||
|
|
||||||
### Пример использования
|
### Специфические методы "вьюшек"
|
||||||
|
|
||||||
|
```lua
|
||||||
|
--[[
|
||||||
|
Возвращает размер типа вьюшки. Результат тот же, что и от применения оператора sizeof() из языка C для данного типа.
|
||||||
|
Полезно для вьюшек, использующих C-шные типы нефиксированного размера, например те же float или double.
|
||||||
|
]]
|
||||||
|
view:typesize() -> posint
|
||||||
|
```
|
||||||
|
|
||||||
|
## Пример использования
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local bytes = Bytearray({1, 0, 2, 0, 250, 255})
|
local bytes = Bytearray({1, 0, 2, 0, 250, 255})
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ function util.drop(ppos, itemid, count, data, pickup_delay)
|
||||||
}})
|
}})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function calc_loot(loot_table)
|
function util.calc_loot(loot_table)
|
||||||
local results = {}
|
local results = {}
|
||||||
for _, loot in ipairs(loot_table) do
|
for _, loot in ipairs(loot_table) do
|
||||||
local chance = loot.chance or 1
|
local chance = loot.chance or 1
|
||||||
|
|
@ -37,7 +37,7 @@ end
|
||||||
function util.block_loot(blockid)
|
function util.block_loot(blockid)
|
||||||
local lootscheme = block.properties[blockid]["base:loot"]
|
local lootscheme = block.properties[blockid]["base:loot"]
|
||||||
if lootscheme then
|
if lootscheme then
|
||||||
return calc_loot(lootscheme)
|
return util.calc_loot(lootscheme)
|
||||||
end
|
end
|
||||||
return {{item=block.get_picking_item(blockid), count=1}}
|
return {{item=block.get_picking_item(blockid), count=1}}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
local dirtid = block.index("base:dirt")
|
||||||
|
local grass_blockid = block.index("base:grass_block")
|
||||||
|
|
||||||
local offsets = {}
|
local offsets = {}
|
||||||
for lx=-1,1 do
|
for lx=-1,1 do
|
||||||
for ly=-1,1 do
|
for ly=-1,1 do
|
||||||
|
|
@ -8,18 +11,17 @@ for lx=-1,1 do
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_random_update(x, y, z)
|
function on_random_update(x, y, z)
|
||||||
local dirtid = block.index('base:dirt');
|
|
||||||
if block.is_solid_at(x, y+1, z) then
|
if block.is_solid_at(x, y+1, z) then
|
||||||
block.set(x, y, z, dirtid, 0)
|
block.set(x, y, z, dirtid, 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local grassblockid = block.index('base:grass_block')
|
|
||||||
for _, offset in ipairs(offsets) do
|
for _, offset in ipairs(offsets) do
|
||||||
local nx, ny, nz = x + offset[1], y + offset[2], z + offset[3]
|
local nx, ny, nz = x + offset[1], y + offset[2], z + offset[3]
|
||||||
|
|
||||||
if block.get(nx, ny, nz) == dirtid and
|
if block.get(nx, ny, nz) == dirtid and
|
||||||
not block.is_solid_at(nx, ny + 1, nz) then
|
not block.is_solid_at(nx, ny + 1, nz) then
|
||||||
block.set(nx, ny, nz, grassblockid, 0)
|
block.set(nx, ny, nz, grass_blockid, 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -179,40 +179,40 @@ function place_pack(panel, packinfo, callback, position_func)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local Version = {};
|
local Version = {}
|
||||||
|
|
||||||
function Version.matches_pattern(version)
|
function Version.matches_pattern(version)
|
||||||
for _, letter in string.gmatch(version, "%.+") do
|
local t = string.split(version, ".")
|
||||||
if type(letter) ~= "number" or letter ~= "." then
|
if #t ~= 2 and #t ~= 3 then return false end
|
||||||
return false;
|
|
||||||
end
|
|
||||||
|
|
||||||
local t = string.split(version, ".");
|
for i = 1, #t do
|
||||||
|
local matched = string.match(t[i], "^%d+$")
|
||||||
return #t == 2 or #t == 3;
|
if not matched then return false end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.__equal(ver1, ver2)
|
function Version.__equal(ver1, ver2)
|
||||||
return ver1[1] == ver2[1] and ver1[2] == ver2[2] and ver1[3] == ver2[3];
|
return ver1[1] == ver2[1] and ver1[2] == ver2[2] and ver1[3] == ver2[3]
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.__greater(ver1, ver2)
|
function Version.__greater(ver1, ver2)
|
||||||
if ver1[1] ~= ver2[1] then return ver1[1] > ver2[1] end;
|
if ver1[1] ~= ver2[1] then return ver1[1] > ver2[1] end
|
||||||
if ver1[2] ~= ver2[2] then return ver1[2] > ver2[2] end;
|
if ver1[2] ~= ver2[2] then return ver1[2] > ver2[2] end
|
||||||
return ver1[3] > ver2[3];
|
return ver1[3] > ver2[3]
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.__less(ver1, ver2)
|
function Version.__less(ver1, ver2)
|
||||||
return Version.__greater(ver2, ver1);
|
return Version.__greater(ver2, ver1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.__greater_or_equal(ver1, ver2)
|
function Version.__greater_or_equal(ver1, ver2)
|
||||||
return not Version.__less(ver1, ver2);
|
return not Version.__less(ver2, ver1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.__less_or_equal(ver1, ver2)
|
function Version.__less_or_equal(ver1, ver2)
|
||||||
return not Version.__greater(ver1, ver2);
|
return not Version.__greater(ver1, ver2)
|
||||||
end
|
end
|
||||||
|
|
||||||
Version.operators = {
|
Version.operators = {
|
||||||
|
|
@ -224,40 +224,39 @@ Version.operators = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Version.compare(op, ver1, ver2)
|
function Version.compare(op, ver1, ver2)
|
||||||
ver1 = string.split(ver1, ".");
|
ver1 = string.split(ver1, ".")
|
||||||
ver2 = string.split(ver2, ".");
|
ver2 = string.split(ver2, ".")
|
||||||
|
|
||||||
local comparison_func = Version.operators[op];
|
local comparison_func = Version.operators[op];
|
||||||
|
|
||||||
if comparison_func then
|
if comparison_func then
|
||||||
return comparison_func(ver1, ver2);
|
return comparison_func(ver1, ver2)
|
||||||
else
|
else
|
||||||
return false;
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Version.parse(version)
|
function Version.parse(version)
|
||||||
local op = string.sub(version, 1, 2);
|
local op = string.sub(version, 1, 2)
|
||||||
if op == ">=" or op == "<=" then
|
if op == ">=" or op == "<=" then
|
||||||
return op, string.sub(version, #op + 1);
|
return op, string.sub(version, #op + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
op = string.sub(version, 1, 1);
|
op = string.sub(version, 1, 1);
|
||||||
if op == ">" or op == "<" then
|
if op == ">" or op == "<" then
|
||||||
return op, string.sub(version, #op + 1);
|
return op, string.sub(version, #op + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
return "=", version;
|
return "=", version
|
||||||
end
|
end
|
||||||
|
|
||||||
local function compare_version(dependent_version, actual_version)
|
local function compare_version(op, dependent_version, actual_version)
|
||||||
if Version.matches_pattern(dependent_version) and Version.matches_pattern(actual_version) then
|
if Version.matches_pattern(dependent_version) and Version.matches_pattern(actual_version) then
|
||||||
local op, dep_ver = Version.parse_version(dependent_version);
|
return Version.compare(op, dep_ver, actual_version)
|
||||||
Version.compare(op, dep_ver, actual_version);
|
|
||||||
elseif dependent_version == "*" or dependent_version == actual_version then
|
elseif dependent_version == "*" or dependent_version == actual_version then
|
||||||
return true;
|
return true
|
||||||
else
|
else
|
||||||
return false;
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -277,15 +276,15 @@ function check_dependencies(packinfo)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local dep_pack = pack.get_info(depid);
|
local dep_pack = pack.get_info(depid)
|
||||||
|
local op, ver = Version.parse(depver)
|
||||||
|
|
||||||
if not compare_version(depver, dep_pack.version) then
|
if not compare_version(op, ver, dep_pack.version) then
|
||||||
local op, ver = Version.parse(depver)
|
|
||||||
return string.format(
|
return string.format(
|
||||||
"%s: %s != %s (%s)",
|
"%s: %s != %s (%s)",
|
||||||
gui.str("error.dependency-version-not-met"),
|
gui.str("error.dependency-version-not-met"),
|
||||||
dep_pack.version, ver, depid
|
dep_pack.version, ver, depid
|
||||||
);
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
if table.has(packs_installed, packinfo.id) then
|
if table.has(packs_installed, packinfo.id) then
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@ local FFI = ffi
|
||||||
|
|
||||||
FFI.cdef[[
|
FFI.cdef[[
|
||||||
void* malloc(size_t);
|
void* malloc(size_t);
|
||||||
|
void* realloc(void*, size_t);
|
||||||
void free(void*);
|
void free(void*);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char* bytes;
|
unsigned char* bytes;
|
||||||
int size;
|
int size;
|
||||||
int capacity;
|
int capacity;
|
||||||
} bytearray_t;
|
} bytearray_t;
|
||||||
|
void* memmove(void*, const void*, size_t);
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local free = FFI.C.free
|
local free = FFI.C.free
|
||||||
|
|
@ -22,12 +24,33 @@ local GC_THRESHOLD = 50 * 1024 * 1024
|
||||||
|
|
||||||
local function malloc(size)
|
local function malloc(size)
|
||||||
local raw = FFI.C.malloc(size)
|
local raw = FFI.C.malloc(size)
|
||||||
if raw == nil then
|
if not raw then
|
||||||
return nil
|
error("failed memory allocation of " .. size .. " bytes")
|
||||||
end
|
end
|
||||||
|
|
||||||
allocated_bytes = allocated_bytes + size
|
allocated_bytes = allocated_bytes + size
|
||||||
|
if allocated_bytes >= GC_THRESHOLD then
|
||||||
|
collectgarbage("step", 200)
|
||||||
|
allocated_bytes = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return raw
|
||||||
|
end
|
||||||
|
|
||||||
|
local function realloc(buff, size, throwerror)
|
||||||
|
if throwerror == nil then throwerror = true end
|
||||||
|
|
||||||
|
if size <= 0 then
|
||||||
|
free(buff)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local raw = FFI.C.realloc(buff, size)
|
||||||
|
if not raw and throwerror then
|
||||||
|
error("failed memory reallocation of block " .. buff .. " to new size " .. size)
|
||||||
|
end
|
||||||
|
|
||||||
|
allocated_bytes = allocated_bytes + size
|
||||||
if allocated_bytes >= GC_THRESHOLD then
|
if allocated_bytes >= GC_THRESHOLD then
|
||||||
collectgarbage("step", 200)
|
collectgarbage("step", 200)
|
||||||
allocated_bytes = 0
|
allocated_bytes = 0
|
||||||
|
|
@ -38,23 +61,17 @@ end
|
||||||
|
|
||||||
local function grow_buffer(self, elems)
|
local function grow_buffer(self, elems)
|
||||||
local new_capacity = math.ceil(self.capacity / 0.75 + elems)
|
local new_capacity = math.ceil(self.capacity / 0.75 + elems)
|
||||||
local prev = self.bytes
|
self.bytes = realloc(self.bytes, new_capacity)
|
||||||
self.bytes = malloc(new_capacity)
|
|
||||||
FFI.copy(self.bytes, prev, self.size)
|
|
||||||
self.capacity = new_capacity
|
self.capacity = new_capacity
|
||||||
free(prev)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function trim_buffer(self)
|
local function trim_buffer(self)
|
||||||
if self.size == self.capacity then
|
if self.size == self.capacity then return end
|
||||||
return
|
local new_bytes = realloc(self.bytes, self.size, false)
|
||||||
|
if new_bytes then
|
||||||
|
self.bytes = new_bytes
|
||||||
|
self.capacity = self.size
|
||||||
end
|
end
|
||||||
local size = self.size
|
|
||||||
local prev = self.bytes
|
|
||||||
self.bytes = malloc(size)
|
|
||||||
FFI.copy(self.bytes, prev, self.size)
|
|
||||||
self.capacity = size
|
|
||||||
free(prev)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function count_elements(b)
|
local function count_elements(b)
|
||||||
|
|
@ -125,15 +142,21 @@ local function clear(self)
|
||||||
self.size = 0
|
self.size = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function reserve(self, new_capacity)
|
local function fill(self, index, size, byte)
|
||||||
if new_capacity <= self.capacity then
|
if index ~= nil and size ~= nil and size > 0 then
|
||||||
return
|
if index < 1 or index + size - 1 > self.size then
|
||||||
|
error("selected fill range is out of array bounds")
|
||||||
|
end
|
||||||
|
FFI.fill(self.bytes + index - 1, size, byte)
|
||||||
|
else
|
||||||
|
FFI.fill(self.bytes, self.size, byte)
|
||||||
end
|
end
|
||||||
local prev = self.bytes
|
end
|
||||||
self.bytes = malloc(new_capacity)
|
|
||||||
FFI.copy(self.bytes, prev, self.size)
|
local function reserve(self, new_capacity)
|
||||||
|
if new_capacity <= self.capacity then return end
|
||||||
|
self.bytes = realloc(self.bytes, new_capacity)
|
||||||
self.capacity = new_capacity
|
self.capacity = new_capacity
|
||||||
free(prev)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_capacity(self)
|
local function get_capacity(self)
|
||||||
|
|
@ -150,22 +173,46 @@ local function slice(self, offset, length)
|
||||||
length = self.size - offset + 1
|
length = self.size - offset + 1
|
||||||
end
|
end
|
||||||
local buffer = malloc(length)
|
local buffer = malloc(length)
|
||||||
if not buffer then
|
|
||||||
error("malloc(" .. length .. ") returned NULL")
|
|
||||||
end
|
|
||||||
FFI.copy(buffer, self.bytes + (offset - 1), length)
|
FFI.copy(buffer, self.bytes + (offset - 1), length)
|
||||||
return bytearray_type(buffer, length, length)
|
return bytearray_type(buffer, length, length)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function copy(self, srcindex, dst, dstindex, size)
|
||||||
|
if size <= 0 then error("size of byte range must be positive non-zero integer") end
|
||||||
|
if srcindex < 1 or srcindex + size - 1 > self.size then
|
||||||
|
error("specified source byte range is out of source array bounds")
|
||||||
|
end
|
||||||
|
if dstindex < 1 or dstindex + size - 1 > dst.size then
|
||||||
|
error("specified destination byte range is out of destination array bounds")
|
||||||
|
end
|
||||||
|
|
||||||
|
FFI.copy(dst.bytes + dstindex - 1, self.bytes + srcindex - 1, size)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function move(self, fromindex, toindex, size)
|
||||||
|
if size <= 0 then error("size of byte range must be positive non-zero integer") end
|
||||||
|
if fromindex < 1 or fromindex + size - 1 > self.size then
|
||||||
|
error("specified source byte range is out of array bounds")
|
||||||
|
end
|
||||||
|
if toindex < 1 or toindex + size - 1 > self.size then
|
||||||
|
error("specified destination byte range is out of array bounds")
|
||||||
|
end
|
||||||
|
|
||||||
|
FFI.C.memmove(self.bytes + toindex - 1, self.bytes + fromindex - 1, size)
|
||||||
|
end
|
||||||
|
|
||||||
local bytearray_methods = {
|
local bytearray_methods = {
|
||||||
append=append,
|
append = append,
|
||||||
insert=insert,
|
insert = insert,
|
||||||
remove=remove,
|
remove = remove,
|
||||||
trim=trim_buffer,
|
trim = trim_buffer,
|
||||||
clear=clear,
|
clear = clear,
|
||||||
reserve=reserve,
|
reserve = reserve,
|
||||||
get_capacity=get_capacity,
|
get_capacity = get_capacity,
|
||||||
slice=slice,
|
slice = slice,
|
||||||
|
fill = fill,
|
||||||
|
copy = copy,
|
||||||
|
move = move
|
||||||
}
|
}
|
||||||
|
|
||||||
local bytearray_mt = {
|
local bytearray_mt = {
|
||||||
|
|
@ -256,7 +303,8 @@ local function FFIBytearray_as_string(bytes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function create_FFIview_class(name, typename, typesize)
|
local function create_FFIview_class(name, typename)
|
||||||
|
local typesize = FFI.sizeof(typename)
|
||||||
local ptrtype = typename .. "*"
|
local ptrtype = typename .. "*"
|
||||||
local FFIview_mt = {
|
local FFIview_mt = {
|
||||||
__index = function(self, key)
|
__index = function(self, key)
|
||||||
|
|
@ -291,27 +339,44 @@ local function create_FFIview_class(name, typename, typesize)
|
||||||
return i, ptr[i - 1]
|
return i, ptr[i - 1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end,
|
||||||
}
|
}
|
||||||
return function (bytes)
|
return setmetatable({}, {
|
||||||
local x = setmetatable({
|
__call = function (self, bytes)
|
||||||
bytes=bytes,
|
local x = setmetatable({
|
||||||
}, FFIview_mt)
|
bytes=bytes,
|
||||||
return x
|
}, FFIview_mt)
|
||||||
end
|
return x
|
||||||
|
end,
|
||||||
|
__index = {
|
||||||
|
typesize = function()
|
||||||
|
return typesize
|
||||||
|
end
|
||||||
|
}
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local FFII16view = create_FFIview_class("FFII16view", "int16_t", 2)
|
local FFII8view = create_FFIview_class("FFII8view", "int8_t")
|
||||||
local FFIU16view = create_FFIview_class("FFIU16view", "uint16_t", 2)
|
local FFII16view = create_FFIview_class("FFII16view", "int16_t")
|
||||||
local FFII32view = create_FFIview_class("FFII32view", "int32_t", 4)
|
local FFIU16view = create_FFIview_class("FFIU16view", "uint16_t")
|
||||||
local FFIU32view = create_FFIview_class("FFIU32view", "uint32_t", 4)
|
local FFII32view = create_FFIview_class("FFII32view", "int32_t")
|
||||||
|
local FFIU32view = create_FFIview_class("FFIU32view", "uint32_t")
|
||||||
|
local FFII64view = create_FFIview_class("FFII64view", "int64_t")
|
||||||
|
local FFIU64view = create_FFIview_class("FFIU64view", "uint64_t")
|
||||||
|
local FFIFLTview = create_FFIview_class("FFIFLTview", "float")
|
||||||
|
local FFIDBLview = create_FFIview_class("FFIDBLview", "double")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
|
FFIBytearray = setmetatable(FFIBytearray, FFIBytearray),
|
||||||
FFIBytearray_as_string = FFIBytearray_as_string,
|
FFIBytearray_as_string = FFIBytearray_as_string,
|
||||||
FFIBytearray_as_ptr = FFIBytearray_as_ptr,
|
FFIBytearray_as_ptr = FFIBytearray_as_ptr,
|
||||||
|
FFII8view = FFII8view,
|
||||||
FFIU16view = FFIU16view,
|
FFIU16view = FFIU16view,
|
||||||
FFII16view = FFII16view,
|
FFII16view = FFII16view,
|
||||||
FFIU32view = FFIU32view,
|
FFIU32view = FFIU32view,
|
||||||
FFII32view = FFII32view,
|
FFII32view = FFII32view,
|
||||||
|
FFIU64view = FFIU64view,
|
||||||
|
FFII64view = FFII64view,
|
||||||
|
FFIFLTview = FFIFLTview,
|
||||||
|
FFIDBLview = FFIDBLview,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
res/modules/internal/ctypes.lua
Normal file
38
res/modules/internal/ctypes.lua
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
local FFI = ffi
|
||||||
|
|
||||||
|
FFI.cdef[[
|
||||||
|
unsigned long long strtoull(const char* nptr, char** endptr, int base);
|
||||||
|
long long strtoll(const char* nptr, char** endptr, int base);
|
||||||
|
]]
|
||||||
|
|
||||||
|
local this = {}
|
||||||
|
|
||||||
|
local function create_integral_type(ctype_name, signed)
|
||||||
|
local parse_func = signed and FFI.C.strtoll or FFI.C.strtoull
|
||||||
|
return function(value, base)
|
||||||
|
value = value or 0
|
||||||
|
local typename = type(value)
|
||||||
|
if typename == "number" then
|
||||||
|
return FFI.cast(ctype_name, value)
|
||||||
|
elseif typename == "string" then
|
||||||
|
if type(base) ~= "number" then
|
||||||
|
base = 10
|
||||||
|
end
|
||||||
|
return parse_func(value, nil, base)
|
||||||
|
end
|
||||||
|
error(string.format("invalid value type: %s", typename))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
this.uint8 = create_integral_type("uint8_t", false)
|
||||||
|
this.uint16 = create_integral_type("uint16_t", false)
|
||||||
|
this.uint32 = create_integral_type("uint32_t", false)
|
||||||
|
this.uint64 = create_integral_type("uint64_t", false)
|
||||||
|
|
||||||
|
this.int8 = create_integral_type("int8_t", true)
|
||||||
|
this.int16 = create_integral_type("int16_t", true)
|
||||||
|
this.int32 = create_integral_type("int32_t", true)
|
||||||
|
this.int64 = create_integral_type("int64_t", true)
|
||||||
|
|
||||||
|
return this
|
||||||
|
|
@ -311,12 +311,19 @@ local bytearray = require "core:internal/bytearray"
|
||||||
Bytearray = bytearray.FFIBytearray
|
Bytearray = bytearray.FFIBytearray
|
||||||
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
||||||
Bytearray_as_ptr = bytearray.FFIBytearray_as_ptr
|
Bytearray_as_ptr = bytearray.FFIBytearray_as_ptr
|
||||||
|
I8view = bytearray.FFII8view
|
||||||
U16view = bytearray.FFIU16view
|
U16view = bytearray.FFIU16view
|
||||||
I16view = bytearray.FFII16view
|
I16view = bytearray.FFII16view
|
||||||
U32view = bytearray.FFIU32view
|
U32view = bytearray.FFIU32view
|
||||||
I32view = bytearray.FFII32view
|
I32view = bytearray.FFII32view
|
||||||
|
U64view = bytearray.FFIU64view
|
||||||
|
I64view = bytearray.FFII64view
|
||||||
|
FLTview = bytearray.FFIFLTview
|
||||||
|
DBLview = bytearray.FFIDBLview
|
||||||
Bytearray_construct = function(...) return Bytearray(...) end
|
Bytearray_construct = function(...) return Bytearray(...) end
|
||||||
|
|
||||||
|
ctypes = require "core:internal/ctypes"
|
||||||
|
|
||||||
bit.compile = require "core:bitwise/compiler"
|
bit.compile = require "core:bitwise/compiler"
|
||||||
bit.execute = require "core:bitwise/executor"
|
bit.execute = require "core:bitwise/executor"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ struct CoreParameters {
|
||||||
std::filesystem::path userFolder = ".";
|
std::filesystem::path userFolder = ".";
|
||||||
std::filesystem::path scriptFile;
|
std::filesystem::path scriptFile;
|
||||||
std::filesystem::path projectFolder;
|
std::filesystem::path projectFolder;
|
||||||
|
std::filesystem::path logFile;
|
||||||
std::string debugServerString;
|
std::string debugServerString;
|
||||||
int tps = 20;
|
int tps = 20;
|
||||||
int subProcessDepth = 0;
|
int subProcessDepth = 0;
|
||||||
|
|
|
||||||
|
|
@ -403,6 +403,7 @@ static int l_start_background_instance(lua::State* L) {
|
||||||
"--script", io::resolve(scriptPath).u8string(),
|
"--script", io::resolve(scriptPath).u8string(),
|
||||||
"--sub-depth", std::to_string(engine->getCoreParameters()
|
"--sub-depth", std::to_string(engine->getCoreParameters()
|
||||||
.subProcessDepth + 1),
|
.subProcessDepth + 1),
|
||||||
|
"--log", io::resolve(outputPath).u8string(),
|
||||||
};
|
};
|
||||||
args.emplace_back("--project");
|
args.emplace_back("--project");
|
||||||
args.emplace_back(io::resolve(engine->getProject().path).u8string());
|
args.emplace_back(io::resolve(engine->getProject().path).u8string());
|
||||||
|
|
@ -417,11 +418,9 @@ static int l_start_background_instance(lua::State* L) {
|
||||||
if (handle == -1) {
|
if (handle == -1) {
|
||||||
throw std::runtime_error("sub-processes limit exceeded");
|
throw std::runtime_error("sub-processes limit exceeded");
|
||||||
}
|
}
|
||||||
::processes[handle] = platform::new_engine_instance(
|
::processes[handle] =
|
||||||
std::move(args),
|
platform::new_engine_instance(std::move(args), "", true);
|
||||||
outputPath.empty() ? "" : io::resolve(outputPath),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
return lua::pushinteger(L, handle);
|
return lua::pushinteger(L, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,17 +161,13 @@ static LuaCanvas& require_canvas(State* L, int idx) {
|
||||||
static int l_clear(State* L) {
|
static int l_clear(State* L) {
|
||||||
auto& canvas = require_canvas(L, 1);
|
auto& canvas = require_canvas(L, 1);
|
||||||
auto& image = canvas.getData();
|
auto& image = canvas.getData();
|
||||||
ubyte* data = image.getData();
|
size_t pixelscount = image.getWidth() * image.getHeight();
|
||||||
RGBA rgba {};
|
uint32_t* data = reinterpret_cast<uint32_t*>(image.getData());
|
||||||
|
|
||||||
if (gettop(L) == 1) {
|
if (gettop(L) == 1) {
|
||||||
std::fill(data, data + image.getDataSize(), 0);
|
std::fill(data, data + pixelscount, 0);
|
||||||
return 0;
|
} else {
|
||||||
}
|
std::fill(data, data + pixelscount, get_rgba(L, 2).rgba);
|
||||||
rgba = get_rgba(L, 2);
|
|
||||||
size_t pixels = image.getWidth() * image.getHeight();
|
|
||||||
const size_t channels = 4;
|
|
||||||
for (size_t i = 0; i < pixels * channels; i++) {
|
|
||||||
data[i] = rgba.arr[i % channels];
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/main.cpp
10
src/main.cpp
|
|
@ -7,6 +7,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
static debug::Logger logger("main");
|
static debug::Logger logger("main");
|
||||||
|
|
||||||
static void sigterm_handler(int signum) {
|
static void sigterm_handler(int signum) {
|
||||||
|
|
@ -36,7 +37,14 @@ int main(int argc, char** argv) {
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
std::signal(SIGINT, sigterm_handler);
|
std::signal(SIGINT, sigterm_handler);
|
||||||
#endif
|
#endif
|
||||||
debug::Logger::init(coreParameters.userFolder.string() + "/latest.log");
|
std::filesystem::path logFile = coreParameters.logFile;
|
||||||
|
if (logFile.empty()) {
|
||||||
|
logFile = coreParameters.userFolder.string() + "/latest"s +
|
||||||
|
(coreParameters.subProcessDepth > 0
|
||||||
|
? ".sub" + std::to_string(coreParameters.subProcessDepth)
|
||||||
|
: "") + ".log"s;
|
||||||
|
}
|
||||||
|
debug::Logger::init(logFile.u8string());
|
||||||
platform::configure_encoding();
|
platform::configure_encoding();
|
||||||
|
|
||||||
auto& engine = Engine::getInstance();
|
auto& engine = Engine::getInstance();
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,10 @@ static bool perform_keyword(
|
||||||
params.subProcessDepth = reader.nextInt();
|
params.subProcessDepth = reader.nextInt();
|
||||||
return true;
|
return true;
|
||||||
}, "<depth>", "sub-process depth"),
|
}, "<depth>", "sub-process depth"),
|
||||||
|
ArgC("--log", [](auto& params, auto& reader) -> bool {
|
||||||
|
params.logFile = reader.next();
|
||||||
|
return true;
|
||||||
|
}, "<file>", "target log file"),
|
||||||
ArgC("--help", [](auto&, auto&) -> bool {
|
ArgC("--help", [](auto&, auto&) -> bool {
|
||||||
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
std::cout << "VoxelCore v" << ENGINE_VERSION_STRING << "\n\n";
|
||||||
std::cout << "Command-line arguments:\n";
|
std::cout << "Command-line arguments:\n";
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
namespace platform::internal {
|
namespace platform::internal {
|
||||||
std::filesystem::path get_executable_path();
|
std::filesystem::path get_executable_path();
|
||||||
}
|
}
|
||||||
|
|
@ -356,7 +358,7 @@ std::unique_ptr<Process> platform::new_engine_instance(
|
||||||
if (!outputFile.empty()) {
|
if (!outputFile.empty()) {
|
||||||
si.dwFlags |= STARTF_USESTDHANDLES;
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
si.hStdOutput = CreateFileW(
|
si.hStdOutput = CreateFileW(
|
||||||
toWString(outputFile.u8string()).data(),
|
toWString(outputFile.empty() ? outputFile.u8string() : "NUL"s).data(),
|
||||||
GENERIC_WRITE,
|
GENERIC_WRITE,
|
||||||
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
@ -434,6 +436,9 @@ std::unique_ptr<Process> platform::new_engine_instance(
|
||||||
if (subProcess) {
|
if (subProcess) {
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
|
if (outputFile.empty()) {
|
||||||
|
outputFile = "/dev/null";
|
||||||
|
}
|
||||||
int fd = open(
|
int fd = open(
|
||||||
outputFile.string().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644
|
outputFile.string().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue