BearLibTerminal - псевдоконсольное окно для рогалика

Форум библиотеки BeaRLib

Модератор: Apromix

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 19 окт 2019, 19:47

А как в lua вывести текст в центр?

Делаю так:

Код: Выделить всё

T.print(20, 20, T.TK_ALIGN_CENTER, 'text text text')
Что не так?

Аватара пользователя
karagy
Сообщения: 1100
Зарегистрирован: 10 янв 2007, 14:13

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение karagy » 20 окт 2019, 08:39

Версия терминала? и где взять её готовый билд? желательно win32, если речь о lua

В BearLibTerminal_0143 такой print ничего не выводит.
Скрытый текст: ПОКАЗАТЬ

Код: Выделить всё

local BL_BASE = [[C:\Devel\BearLibTerminal_0143]]
local BL_LIB = BL_BASE..[[\Windows32]]
package.cpath = BL_LIB..[[\?.dll;]] .. package.cpath

local T = require "BearLibTerminal"

--for k,v in pairs(T) do print(k, v) end

local function main()

    local proceed = true

    T.open()

    while proceed
    do
        T.clear()

    T.print(20, 18, "text text text")
    T.print(20, 20, T.TK_ALIGN_CENTER, "text text text")
    T.printf(2, 23, "[color=orange]ESC.[/color] Exit")

        T.refresh()

        repeat
            local key = T.read()
            proceed = not (key == T.TK_ESCAPE or key == T.TK_CLOSE)
        until not (proceed and T.has_input())
    end

    T.close()
end

main()

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 20 окт 2019, 12:53

karagy писал(а):
20 окт 2019, 08:39
Версия терминала?
Версия 0.15.3
karagy писал(а):
20 окт 2019, 08:39
такой print ничего не выводит
А мне нужно :)
karagy писал(а):
20 окт 2019, 08:39
и где взять её готовый билд?
Не понял вопроса :) Если lua, то он встроен в терминал, качаем луа и все работает :)

Аватара пользователя
karagy
Сообщения: 1100
Зарегистрирован: 10 янв 2007, 14:13

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение karagy » 20 окт 2019, 13:26

Готовую dll свежего BearLibTerminal - где брать?
Нашел в первом посте этой темы.

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 20 окт 2019, 13:54

Да вобщем не важно, я пошел другим путем :)

Аватара пользователя
karagy
Сообщения: 1100
Зарегистрирован: 10 янв 2007, 14:13

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение karagy » 20 окт 2019, 14:06

Ну, TextAlignment.lua, из старого аналога Omni на луа - работает.

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 20 окт 2019, 14:07

А где код можно посмотреть?

Аватара пользователя
karagy
Сообщения: 1100
Зарегистрирован: 10 янв 2007, 14:13

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение karagy » 20 окт 2019, 14:11

Я его сегодня долго искал в этом треде.
Вот SamplesLua.7z

Если луа потребует модуль "ex" и его нет - то либо поставь, либо закомментируй в SampleOmni.lua строки:

Код: Выделить всё

local ExtendedBasics = require "ExtendedBasics":init(BL_BASE)
local ExtendedInterlayer = require "ExtendedInterlayer"
Ну и в начале SampleOmni.lua задать ваш путь к библиотеке. Например, у меня сейчас dll терминала живет тут:
C:\Devel\BearLibTerminal_0.15.3\Windows32\BearLibTerminal.dll

Соответственно в SampleOmni.lua указано:

Код: Выделить всё

local BL_BASE = [[C:\Devel\BearLibTerminal_0.15.3]]
local BL_LIB = BL_BASE..[[\Windows32]]
package.cpath = BL_LIB..[[\?.dll;]] .. package.cpath
Последний раз редактировалось karagy 20 окт 2019, 14:21, всего редактировалось 1 раз.

Аватара пользователя
Cfyz
Сообщения: 772
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Cfyz » 20 окт 2019, 14:20

Apromix писал(а):А как в lua вывести текст в центр? Делаю так:
Дело в том, что здесь у print лишь две возможные сигнатуры:

Код: Выделить всё

print(x, y, s)
print(x, y, w, h, align, s)
То есть по идее надо задавать прямоугольник, в центре которого надо вывести. Например:

Код: Выделить всё

T.print(0, 0, 40, 40, T.TK_ALIGN_CENTER, 'text text text')
На деле для вывода относительно точки есть возможность указать нули в качестве размера прямоугольника:

Код: Выделить всё

T.print(20, 20, 0, 0, T.TK_ALIGN_CENTER, 'text text text')
Возможно, надо иметь три-четыре варианта функции: print[_wrapped][_aligned].

Кстати, при попытке вызвать функцию с неправильными аргументами (как в вопросе), BLT как честная библиотека ругается на это:

Код: Выделить всё

> lua52 test1.wlua

lua52: luaterminal_print: invalid number or types of arguments
stack traceback:
        [C]: in function 'print'
        test1.wlua:5: in main chunk
        [C]: in ?
И если ошибочный вызов тихо ничего не делает -- значит информация об ошибке где-то теряется. Возможно стоит посмотреть где, потому что так будет сложнее дебажить.
Пытается раскуклиться

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 20 окт 2019, 14:23

Спасибо за помощь!!! С дебагом у движка серьезные проблемы, пока не пойму, почему дебажная инфа не выводится хотя бы в лог.

Аватара пользователя
karagy
Сообщения: 1100
Зарегистрирован: 10 янв 2007, 14:13

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение karagy » 20 окт 2019, 14:24

У меня в 0.14.3 молчала о ошибке.
В 0.15.3 - нормально ругается.

И да, если вызов через wlua - то консоли не будет.
Это нормальная практика - девел и отладка в lua, а в продакшен с - wlua (если в продакшене не нужна родная консоль)

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 20 окт 2019, 14:34

Ну вот, в терминале все красиво выводится посередке, как и в оригинале :D :D :D Скрин

На практике довольно часто нужно именно такую print(x, y, alignment, text)

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Apromix » 08 ноя 2019, 20:42

Ошибочка кажись -> скрин

Иногда за часик тестирования до десятка таких файликов набирается :D

Аватара пользователя
thefish
Сообщения: 22
Зарегистрирован: 18 июн 2012, 22:37

Работа Go + BLT (на Linux)

Сообщение thefish » 12 ноя 2019, 15:06

Про Windows и Mac в контексте связки Go + BLT, я говорить не буду, поскольку не ел устриц. С Linux, которая моя основная рабочая ось - другая история, здесь вносят свой шарм особенности работы линкера. Дело в том, что BLT написана на C. Но! есть готовые биндинги для Go,

НО! В Terminal/Include/Go по умолчанию указаны такие флаги линкера CGO (стр 25)

Код: Выделить всё

// #cgo LDFLAGS: -lBearLibTerminal
Что подразумевает глобальную видимость библиотеки. Увы, пока пакета с BLT для распространенных дистрибутивов Linux нет. Поэтому беде нужно помочь руками.

Первый метод

Сначала вручную показать линкеру, что такая библиотека есть, и потом перезагрузить кеш путей к библиотекам (пример для Ubuntu):

Код: Выделить всё

$ sudo echo "/path/to/libbearterminal.so" > /etc/ld.so.conf.d/libbearterminal.conf && sudo ldconfig
Проблема тут в том, что эту же операцию придется проделать всем, кто захочет запустить ваше приложение с BLT. Вопреки распространенному стереотипу - доля красноглазых пользователей Linux с каждым годом падает, и эта консольная магия для большинства уже некомильфо.

Второй метод

Способ второй, более удобный. Редактируем файл с биндингами (BearLibTerminal.go) примерно следующим образом:

Код: Выделить всё

// #cgo LDFLAGS: -L. -Wl,-rpath -Wl,./ -lBearLibTerminal
// #include <stdlib.h>
// #include <BearLibTerminal.h>
import "C"
(знатоки С, простите если что не так, я этими флагами вообще пользоваться не умею)

Далее - собираем минимальное приложение с blt:

Код: Выделить всё

go build -o test
Проверяем, что относительные пути записались в бинарник:

Код: Выделить всё

objdump -p test | grep RPATH
Результат должен быть примерно таким:

Код: Выделить всё

RPATH                ./
Ура! Теперь кладем libBearLibTerminal.so прямо в папку с main.go (или рядом с уже скомпилированным бинарником) и запускаем прям оттуда. Теперь бинарники будут искать библиотеку в той же папке, где находятся они сами.

Теперь при дистрибуции приложения можно просто положить .so / .dll / .dylib файл библиотеки рядом, и все будет работать!

Горутины и многопоточность

Вторая кочка, на которой мне пришлось споткнуться - то то, что вызов любой своей функции не из main thread BLT воспринимает крайне нервно, и сыпет фатальными ошибками типа [fatal] 'input_read' was not called from the main thread. Это неприятно, тк часто Го выбирают именно за многопоточность из коробки. Но справедливости ради: точно так же ведет себя и большинство других библиотек связанных с рендером и вводом-выводом, тот же SDL например. Так что воспринимайте это как милую особенность использования CGO.

Лекарство тут ровно одно - вызывать сишные foreign functions из main thread.

Для реализации этого требования мне показалась полезной следующая конструкция:

Код: Выделить всё

package main 

import "runtime"

...


// Рецепт чтобы убежать от [fatal] 'refresh' was not called from the main thread
// https://github.com/golang/go/wiki/LockOSThread
func init() {
	runtime.LockOSThread()
}

type GameState struct {
	Mainfunc     chan func()
}

// do запускает функцию f в контексте main thread.
func (g *GameState) Do(f func()) {
	done := make(chan struct{}, 1)
	g.Mainfunc <- func() {
		f()
		f = nil //zero pointer в замыкание
		done <- struct{}{}
	}
	<-done
}


var State = GameState{
	Mainfunc:     make(chan func()), //блокирующий канал(!)
}
// И где-то в Main Loop делаем примерно так:
func MainLoop(state *GameState) {
	...
	for {
	//В этом select обработка ввода, рендер, пеерколючение состояний интерфейса итп
	select {
	...
	case f <-State.Mainfunc:
		f() //выполняем в main thread вызовы в сишную библиотеку
		break
	    }
	...
	}
...
State - это обычный Value Object, экземпляр типа GameState. Я его использую как контейнер для важных для игры данных - географии уровня, состояния объектов и мобов, разных тикеров, каналов для рендера и ввода-вывода итп. Так как он глобальный (или просто передается всюду по аргументам), то именно в него встроен метод Do.

Если нам скажем в пакете, где описывается некий предмет, надо нарисовать при его поднятии какой-то супер-эффект на экране - мы поступаем вот так:

Код: Выделить всё

package item

import "main"
import blt "some.repo.ru/user/bearlibterminal"
//в эту переменную при инициализации ставится ссылка на глобальный State 
var State *main.GameState 

//функция скажем поднятия особенного предмета...
func (item *SpecialItem) Pickup() {
	
    ....
    //выполняем строго в main thread
    State.Do(func() {
        renderSuperEffect()
    })
}
...
//тут собственно отрисовка эффекта
func renderSuperEffect() {
	...
	blt.Layer(0)
	blt.Print(x,y, "WAAAGH")
	...
}
Здесь renderSuperEffect - непосредственная реализация эффекта, doSuperEffect - запихивает в очередь на выполнения в main thread эту самую реализацию. Которая с успехом выполняется в main loop.

Правда, я бы рекомендовал пользоваться этим фокусом с осторожностью. Гораздо более надежным представляется просто вызов всех функций использующих C-библиотеку из main thread.

PS Результат использования Go + BearLibTerminal можно посмотреть здесь
Последний раз редактировалось thefish 13 ноя 2019, 20:58, всего редактировалось 3 раза.

Аватара пользователя
Cfyz
Сообщения: 772
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BearLibTerminal - псевдоконсольное окно для рогалика

Сообщение Cfyz » 13 ноя 2019, 18:39

thefish, любопытные моменты и очень правильные замечания.
thefish писал(а):

Код: Выделить всё

#cgo LDFLAGS: -L. -Wl,-rpath -Wl,./ -lBearLibTerminal
Думаю я это даже в официальную версию включу, только разве что вместо "." наверное стоит использовать "./lib". Ну и надо посмотреть как в CGO задавать флаги (точнее, переменные) не перетирая -- разработчик может захотеть определить их самостоятельно в окружении сборки.

Кстати, вместо /etc/ld.so.conf.d обычно используют LD_LIBRARY_PATH -- ей проще заткнуть поиск нестандартно расположенных библиотек, а для перманентного эффекта делается скрипт, который выставляет переменную и вызывает лежащий рядом бинарник приложения. Не решение, но заплатка, имеющая право на жизнь.

Ну и если перечислять варианты, то самым простым, наверное, было бы скопировать .so в /usr/local/lib; или в $HOME/.local/lib, если дистрибутив достаточно свежий. Но как и с /etc, в общем виде это требует прав и потому не комильфо.

Вообще жаль, что с бинарниками в Go так плохо. Ситуация патовая: в языке нет ни бинарных пакетов (фактически, пакетов вообще нет), ни какого-нибудь вменяемого PInvoke. Пользователю библиотеки придется спускаться до C, что можно немного скрыть, но не более.

thefish писал(а):Лекарство тут ровно одно - вызывать сишные foreign functions из main thread. Для реализации этого требования мне показалась полезной следующая конструкция:
В целом, единственное корректное универсальное решение. Эдакий пул потоков наоборот =). Есть мысль, что такую функциональность можно встроить в библиотеку -- в конце концов, Go не единственное место, где может захотеться многопоточности -- но у решения на стороне программы есть один неочевидный плюс в "атомарности" выполнения действий. Если просто "в лоб" сделать интерфейс библиотеки опционально многопоточным, то параллельные вызовы color/layer/put/print и т. д. смешаются в недетерминированную кучу.
Пытается раскуклиться

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость