diff --git a/.gitignore b/.gitignore
index 606033f3..72fa6d1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ Debug/voxel_engine
/screenshots
/out
+/misc
/world
/worlds/**/*
/settings.toml
@@ -41,4 +42,4 @@ appimage-build/
*~
/res/content/*
-!/res/content/base
\ No newline at end of file
+!/res/content/base
diff --git a/doc/en/8.Scripting.md b/doc/en/8.Scripting.md
index de5e0ca3..e18ab0ad 100644
--- a/doc/en/8.Scripting.md
+++ b/doc/en/8.Scripting.md
@@ -95,6 +95,26 @@ world.get_seed() -> int
Returns world seed.
+## *pack* library
+
+```python
+pack.get_folder(packid: str) -> str
+```
+
+Returns installed content-pack folder
+
+```python
+pack.is_installed(packid: str) -> bool
+```
+
+Check if the world has specified pack installed
+
+```python
+pack.get_installed() -> array of strings
+```
+
+Returns all installed content-pack ids
+
## *gui* library
Library contains ui elements access functions. Library should not be directly used, because script *layouts/layout_name.xml.lua* already has a generated variable **document** (instance of **Document**)
@@ -161,6 +181,13 @@ inventory.clone(invid: int) -> int
Create inventory copy. Returns the created copy ID.
+```python
+inventory.move(invA: int, slotA: int, invB: int, slotB: int)
+```
+
+Move item from slotA of invA to slotB of invB. invA may be the same as invB.
+If slotB will be chosen automaticly if argument is not specified.
+
## *block* library
```python
@@ -337,6 +364,13 @@ hud.close(layoutid: str)
Remove an element from the screen
+
+```python
+hud.get_block_inventory() -> int
+```
+
+Get open block inventory ID or 0
+
## Block events
```lua
diff --git a/doc/ru/8.Скриптинг.md b/doc/ru/8.Скриптинг.md
index 2b2a7326..82f27159 100644
--- a/doc/ru/8.Скриптинг.md
+++ b/doc/ru/8.Скриптинг.md
@@ -89,6 +89,26 @@ world.get_seed() -> int
Возвращает зерно мира.
+## Библиотека pack
+
+```python
+pack.get_folder(packid: str) -> str
+```
+
+Возвращает путь к папке установленного контент-пака
+
+```python
+pack.is_installed(packid: str) -> bool
+```
+
+Проверяет наличие контент-пака в мире
+
+```python
+pack.get_installed() -> массив строк
+```
+
+Возращает id всех установленных в мире контент-паков
+
## Библиотека gui
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
@@ -155,6 +175,14 @@ inventory.clone(invid: int) -> int
Создает копию инвентаря и возвращает id копии. Если копируемого инвентаря не существует, возвращает 0.
+```python
+inventory.move(invA: int, slotA: int, invB: int, slotB: int)
+```
+
+Перемещает предмет из slotA инвентаря invA в slotB инвентаря invB.
+invA и invB могут указывать на один инвентарь.
+slotB будет выбран автоматически, если не указывать явно.
+
## Библиотека block
```python
@@ -326,6 +354,13 @@ hud.close(layoutid: str)
```
Удаляет элемент с экрана
+
+```python
+hud.get_block_inventory() -> int
+```
+
+Получить ID инвентаря открытого блока или 0
+
## События блоков
```lua
diff --git a/res/content/base/texts/en_US.txt b/res/content/base/texts/en_US.txt
deleted file mode 100644
index 05c8d3dc..00000000
--- a/res/content/base/texts/en_US.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-bazalt=Bazalt
-blue_lamp=Blue Lamp
-brick=Brick
-dirt=Dirt
-flower=Flower
-glass=Glass
-grass_block=Ground
-grass=Tall Grass
-green_lamp=Green Lamp
-lamp=Lamp
-leaves=Leaves
-lightbulb=Bulb
-metal=Metal
-pane=Pane
-pipe=Pipe
-planks=Planks
-red_lamp=Red Lamp
-rust=Rust
-sand=Sand
-stone=Stone
-water=Water
-wood=Wood
\ No newline at end of file
diff --git a/res/content/base/texts/ru_RU.txt b/res/content/base/texts/ru_RU.txt
index 148c0a5a..b72d907e 100644
--- a/res/content/base/texts/ru_RU.txt
+++ b/res/content/base/texts/ru_RU.txt
@@ -1,22 +1,22 @@
-bazalt=Базальт
-blue_lamp=Синяя Лампа
-brick=Кирпич
-dirt=Земля
-flower=Цветок
-glass=Стекло
-grass_block=Дёрн
-grass=Высокая Трава
-green_lamp=Зелёная Лампа
-lamp=Лампа
-leaves=Листва
-lightbulb=Лампочка
-metal=Металл
-pane=Панель
-pipe=Труба
-planks=Доски
-red_lamp=Красная Лампа
-rust=Ржавчина
-sand=Песок
-stone=Камень
-water=Вода
-wood=Бревно
\ No newline at end of file
+bazalt=базальт
+blue lamp=синяя лампа
+brick=кирпич
+dirt=земля
+flower=цветок
+glass=стекло
+grass block=дёрн
+tall grass=высокая трава
+green lamp=зелёная лампа
+lamp=лампа
+leaves=листва
+light bulb=лампочка
+metal=металл
+pane=панель
+pipe=труба
+planks=доски
+red lamp=красная лампа
+rust=ржавчина
+sand=песок
+stone=камень
+water=вода
+wood=бревно
diff --git a/res/layouts/inventory.xml.lua b/res/layouts/inventory.xml.lua
index bc3fc5d2..c2280f15 100644
--- a/res/layouts/inventory.xml.lua
+++ b/res/layouts/inventory.xml.lua
@@ -1,3 +1,8 @@
function inventory_share_func(invid, slotid)
- inventory.set(invid, slotid, 0, 0)
+ local blockinv = hud.get_block_inventory()
+ if blockinv ~= 0 then
+ inventory.move(invid, slotid, blockinv)
+ else
+ inventory.set(invid, slotid, 0, 0)
+ end
end
diff --git a/res/layouts/pages/404.xml b/res/layouts/pages/404.xml
new file mode 100644
index 00000000..c53262bc
--- /dev/null
+++ b/res/layouts/pages/404.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layouts/pages/content.xml b/res/layouts/pages/content.xml
new file mode 100644
index 00000000..c4ff39e2
--- /dev/null
+++ b/res/layouts/pages/content.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layouts/pages/content.xml.lua b/res/layouts/pages/content.xml.lua
new file mode 100644
index 00000000..2a21d57d
--- /dev/null
+++ b/res/layouts/pages/content.xml.lua
@@ -0,0 +1,131 @@
+function on_open(params)
+ if params then
+ mode = params.mode
+ end
+ refresh()
+end
+
+add_packs = {}
+rem_packs = {}
+
+function apply()
+ core.reconfig_packs(add_packs, rem_packs)
+ if mode ~= "world" then
+ menu:back()
+ end
+end
+
+function refresh_changes()
+ document.apply_btn.enabled = (#add_packs>0) or (#rem_packs>0)
+end
+
+function move_pack(id)
+ -- cancel pack addition
+ if table.has(add_packs, id) then
+ document["pack_"..id]:move_into(document.packs_add)
+ table.remove_value(add_packs, id)
+ -- cancel pack removal
+ elseif table.has(rem_packs, id) then
+ document["pack_"..id]:move_into(document.packs_cur)
+ table.remove_value(rem_packs, id)
+ -- add pack
+ elseif table.has(packs_installed, id) then
+ document["pack_"..id]:move_into(document.packs_add)
+ table.insert(rem_packs, id)
+ -- remove pack
+ else
+ document["pack_"..id]:move_into(document.packs_cur)
+ table.insert(add_packs, id)
+ end
+ refresh_changes()
+end
+
+function place_pack(panel, packinfo, callback)
+ if packinfo.error then
+ callback = nil
+ end
+ if packinfo.has_indices then
+ packinfo.id_verbose = packinfo.id.."*"
+ else
+ packinfo.id_verbose = packinfo.id
+ end
+ packinfo.callback = callback
+ panel:add(gui.template("pack", packinfo))
+ if not callback then
+ document["pack_"..packinfo.id].enabled = false
+ end
+end
+
+function check_dependencies(packinfo)
+ if packinfo.dependencies == nil then
+ return
+ end
+ for i,dep in ipairs(packinfo.dependencies) do
+ local depid = dep:sub(2,-1)
+ if dep:sub(1,1) == '!' then
+ if not table.has(packs_all, depid) then
+ return string.format(
+ "%s (%s)", gui.str("error.dependency-not-found"), depid
+ )
+ end
+ if table.has(packs_installed, packinfo.id) then
+ table.insert(required, depid)
+ end
+ end
+ end
+ return
+end
+
+function refresh()
+ packs_installed = pack.get_installed()
+ packs_available = pack.get_available()
+ base_packs = pack.get_base_packs()
+ packs_all = {unpack(packs_installed)}
+ required = {}
+ for i,k in ipairs(packs_available) do
+ table.insert(packs_all, k)
+ end
+
+ local packs_cur = document.packs_cur
+ local packs_add = document.packs_add
+ packs_cur:clear()
+ packs_add:clear()
+
+ for i,id in ipairs(packs_installed) do
+ local packinfo = pack.get_info(id)
+ packinfo.index = i
+ callback = not table.has(base_packs, id) and string.format('move_pack("%s")', id) or nil
+ packinfo.error = check_dependencies(packinfo)
+ place_pack(packs_cur, packinfo, callback)
+ end
+
+ for i,id in ipairs(packs_available) do
+ local packinfo = pack.get_info(id)
+ packinfo.index = i
+ callback = string.format('move_pack("%s")', id)
+ packinfo.error = check_dependencies(packinfo)
+ place_pack(packs_add, packinfo, callback)
+ end
+
+ for i,id in ipairs(packs_installed) do
+ if table.has(required, id) then
+ document["pack_"..id].enabled = false
+ end
+ end
+
+ apply_movements(packs_cur, packs_add)
+ refresh_changes()
+end
+
+function apply_movements(packs_cur, packs_add)
+ for i,id in ipairs(packs_installed) do
+ if table.has(rem_packs, id) then
+ document["pack_"..id]:move_into(packs_add)
+ end
+ end
+ for i,id in ipairs(packs_available) do
+ if table.has(add_packs, id) then
+ document["pack_"..id]:move_into(packs_cur)
+ end
+ end
+end
diff --git a/res/layouts/pages/generators.xml b/res/layouts/pages/generators.xml
new file mode 100644
index 00000000..a67d06b8
--- /dev/null
+++ b/res/layouts/pages/generators.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/res/layouts/pages/generators.xml.lua b/res/layouts/pages/generators.xml.lua
new file mode 100644
index 00000000..dd9b6743
--- /dev/null
+++ b/res/layouts/pages/generators.xml.lua
@@ -0,0 +1,16 @@
+settings = session.get_entry('new_world')
+
+function on_open()
+ local names = core.get_generators()
+ table.sort(names)
+
+ local panel = document.root
+ for _,k in ipairs(names) do
+ panel:add(gui.template("generator", {
+ callback=string.format("settings.generator=%q menu:back()", k),
+ id=k,
+ name=settings.generator_name(k)
+ }))
+ end
+ panel:add("")
+end
diff --git a/res/layouts/pages/languages.xml b/res/layouts/pages/languages.xml
new file mode 100644
index 00000000..38722bed
--- /dev/null
+++ b/res/layouts/pages/languages.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/res/layouts/pages/languages.xml.lua b/res/layouts/pages/languages.xml.lua
new file mode 100644
index 00000000..a064c68c
--- /dev/null
+++ b/res/layouts/pages/languages.xml.lua
@@ -0,0 +1,19 @@
+function on_open()
+ local locales = gui.get_locales_info()
+ local invlocales = {}
+ local names = {}
+ for k, v in pairs(locales) do
+ table.insert(names, v.name)
+ invlocales[v.name] = k
+ end
+ table.sort(names)
+
+ local panel = document.root
+ for _,k in ipairs(names) do
+ panel:add(string.format(
+ "",
+ string.format("core.set_setting('ui.language', %q) menu:back()", invlocales[k]), k
+ ))
+ end
+ panel:add("")
+end
diff --git a/res/layouts/pages/main.xml b/res/layouts/pages/main.xml
new file mode 100644
index 00000000..3ff1c23f
--- /dev/null
+++ b/res/layouts/pages/main.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/res/layouts/pages/main.xml.lua b/res/layouts/pages/main.xml.lua
new file mode 100644
index 00000000..37c348a9
--- /dev/null
+++ b/res/layouts/pages/main.xml.lua
@@ -0,0 +1,6 @@
+function on_open()
+ local worlds = world.get_list()
+ for _, info in ipairs(worlds) do
+ document.worlds:add(gui.template("world", info))
+ end
+end
diff --git a/res/layouts/pages/new_world.xml b/res/layouts/pages/new_world.xml
new file mode 100644
index 00000000..9042ea57
--- /dev/null
+++ b/res/layouts/pages/new_world.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layouts/pages/new_world.xml.lua b/res/layouts/pages/new_world.xml.lua
new file mode 100644
index 00000000..e92d5ae0
--- /dev/null
+++ b/res/layouts/pages/new_world.xml.lua
@@ -0,0 +1,47 @@
+settings = session.get_entry('new_world')
+
+function world_name_validator(name)
+ return name:match("^[%w-\\.\\ ]+$") ~= nil and not world.exists(name)
+end
+
+function save_state()
+ settings.name = document.name_box.text
+ settings.seed = document.seed_box.text
+end
+
+function settings.generator_name(id)
+ local prefix, name = parse_path(id)
+ if prefix == "core" then
+ return gui.str(name, "world.generators")
+ else
+ return id
+ end
+end
+
+function create_world()
+ if not document.name_box.valid then
+ return
+ end
+ local name = document.name_box.text
+ local seed = document.seed_box.text
+ local generator = settings.generator
+ session.reset_entry('new_world')
+ core.new_world(name, seed, generator)
+end
+
+function on_open()
+ document.content_btn.text = string.format(
+ "%s [%s]", gui.str("Content", "menu"), #pack.get_installed()
+ )
+ if settings.generator == nil then
+ settings.generator = core.get_default_generator()
+ end
+ document.generator_btn.text = string.format(
+ "%s: %s",
+ gui.str("World generator", "world"),
+ settings.generator_name(settings.generator)
+ )
+ document.name_box.text = settings.name or ''
+ document.seed_box.text = settings.seed or ''
+ document.seed_box.placeholder = tostring(math.random()):sub(3)
+end
diff --git a/res/layouts/pages/pause.xml b/res/layouts/pages/pause.xml
new file mode 100644
index 00000000..63d827e1
--- /dev/null
+++ b/res/layouts/pages/pause.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/res/layouts/pages/settings.xml b/res/layouts/pages/settings.xml
new file mode 100644
index 00000000..5e0ea285
--- /dev/null
+++ b/res/layouts/pages/settings.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layouts/pages/settings.xml.lua b/res/layouts/pages/settings.xml.lua
new file mode 100644
index 00000000..f21f25c3
--- /dev/null
+++ b/res/layouts/pages/settings.xml.lua
@@ -0,0 +1,15 @@
+function on_open()
+ document.langs_btn.text = string.format(
+ "%s: %s", gui.str("Language", "settings"),
+ gui.get_locales_info()[core.get_setting("ui.language")].name
+ )
+ set_page("s_gfx", "settings_graphics")
+end
+
+function set_page(btn, page)
+ document.s_aud.enabled = true
+ document.s_gfx.enabled = true
+ document.s_ctl.enabled = true
+ document[btn].enabled = false
+ document.menu.page = page
+end
diff --git a/res/layouts/pages/settings_audio.xml b/res/layouts/pages/settings_audio.xml
new file mode 100644
index 00000000..2b3c1818
--- /dev/null
+++ b/res/layouts/pages/settings_audio.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/res/layouts/pages/settings_audio.xml.lua b/res/layouts/pages/settings_audio.xml.lua
new file mode 100644
index 00000000..9b29bd52
--- /dev/null
+++ b/res/layouts/pages/settings_audio.xml.lua
@@ -0,0 +1,33 @@
+function create_setting(id, name, step, postfix)
+ local info = core.get_setting_info(id)
+ postfix = postfix or ""
+ document.root:add(gui.template("track_setting", {
+ id=id,
+ name=gui.str(name, "settings"),
+ value=core.get_setting(id),
+ min=info.min,
+ max=info.max,
+ step=step,
+ postfix=postfix
+ }))
+ update_setting(core.get_setting(id), id, name, postfix)
+end
+
+function update_setting(x, id, name, postfix)
+ core.set_setting(id, x)
+ -- updating label
+ document[id..".L"].text = string.format(
+ "%s: %s%s",
+ gui.str(name, "settings"),
+ core.str_setting(id),
+ postfix
+ )
+end
+
+function on_open()
+ create_setting("audio.volume-master", "Master Volume", 0.01)
+ create_setting("audio.volume-regular", "Regular Sounds", 0.01)
+ create_setting("audio.volume-ui", "UI Sounds", 0.01)
+ create_setting("audio.volume-ambient", "Ambient", 0.01)
+ create_setting("audio.volume-music", "Music", 0.01)
+end
diff --git a/res/layouts/pages/settings_controls.xml b/res/layouts/pages/settings_controls.xml
new file mode 100644
index 00000000..d61e3e5b
--- /dev/null
+++ b/res/layouts/pages/settings_controls.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/res/layouts/pages/settings_controls.xml.lua b/res/layouts/pages/settings_controls.xml.lua
new file mode 100644
index 00000000..a66e17e3
--- /dev/null
+++ b/res/layouts/pages/settings_controls.xml.lua
@@ -0,0 +1,25 @@
+function refresh_sensitivity()
+ document.sensitivity_label.text = string.format(
+ "%s: %s",
+ gui.str("Mouse Sensitivity", "settings"),
+ core.str_setting("camera.sensitivity")
+ )
+end
+
+function change_sensitivity(val)
+ core.set_setting("camera.sensitivity", val)
+ refresh_sensitivity()
+end
+
+function on_open()
+ document.sensitivity_track.value = core.get_setting("camera.sensitivity")
+ refresh_sensitivity()
+
+ local panel = document.bindings_panel
+ local bindings = core.get_bindings()
+ for i,name in ipairs(bindings) do
+ panel:add(gui.template("binding", {
+ id=name, name=gui.str(name)
+ }))
+ end
+end
diff --git a/res/layouts/pages/settings_graphics.xml b/res/layouts/pages/settings_graphics.xml
new file mode 100644
index 00000000..2aa3aeca
--- /dev/null
+++ b/res/layouts/pages/settings_graphics.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/res/layouts/pages/settings_graphics.xml.lua b/res/layouts/pages/settings_graphics.xml.lua
new file mode 100644
index 00000000..835b3746
--- /dev/null
+++ b/res/layouts/pages/settings_graphics.xml.lua
@@ -0,0 +1,44 @@
+function create_setting(id, name, step, postfix)
+ local info = core.get_setting_info(id)
+ postfix = postfix or ""
+ document.root:add(gui.template("track_setting", {
+ id=id,
+ name=gui.str(name, "settings"),
+ value=core.get_setting(id),
+ min=info.min,
+ max=info.max,
+ step=step,
+ postfix=postfix
+ }))
+ update_setting(core.get_setting(id), id, name, postfix)
+end
+
+function update_setting(x, id, name, postfix)
+ core.set_setting(id, x)
+ -- updating label
+ document[id..".L"].text = string.format(
+ "%s: %s%s",
+ gui.str(name, "settings"),
+ core.str_setting(id),
+ postfix
+ )
+end
+
+function create_checkbox(id, name)
+ document.root:add(string.format(
+ "%s",
+ id, core.str_setting(id), gui.str(name, "settings")
+ ))
+end
+
+function on_open()
+ create_setting("chunks.load-distance", "Load Distance", 1)
+ create_setting("chunks.load-speed", "Load Speed", 1)
+ create_setting("graphics.fog-curve", "Fog Curve", 0.1)
+ create_setting("graphics.gamma", "Gamma", 0.05)
+ create_setting("camera.fov", "FOV", 1, "°")
+ create_checkbox("display.fullscreen", "Fullscreen")
+ create_checkbox("display.vsync", "V-Sync")
+ create_checkbox("graphics.backlight", "Backlight")
+ create_checkbox("camera.shaking", "Camera Shaking")
+end
diff --git a/res/layouts/process.xml b/res/layouts/process.xml
new file mode 100644
index 00000000..ccf631d8
--- /dev/null
+++ b/res/layouts/process.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layouts/process.xml.lua b/res/layouts/process.xml.lua
new file mode 100644
index 00000000..44e640e8
--- /dev/null
+++ b/res/layouts/process.xml.lua
@@ -0,0 +1,10 @@
+function on_progress(done, total)
+ local progress = done / total
+ document.progress_label.text = string.format(
+ "%s/%s (%s%%)", done, total, math.floor(progress*100)
+ )
+end
+
+function on_open(title)
+ document.title_label.text = title
+end
diff --git a/res/layouts/reports/missing_content.xml b/res/layouts/reports/missing_content.xml
new file mode 100644
index 00000000..cd8cacb4
--- /dev/null
+++ b/res/layouts/reports/missing_content.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/res/layouts/reports/missing_content.xml.lua b/res/layouts/reports/missing_content.xml.lua
new file mode 100644
index 00000000..8ea78a1c
--- /dev/null
+++ b/res/layouts/reports/missing_content.xml.lua
@@ -0,0 +1,5 @@
+function on_open(report)
+ for i, entry in ipairs(report.content) do
+ document.content_panel:add(gui.template("content_entry", entry))
+ end
+end
diff --git a/res/layouts/templates/binding.xml b/res/layouts/templates/binding.xml
new file mode 100644
index 00000000..643bd5aa
--- /dev/null
+++ b/res/layouts/templates/binding.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layouts/templates/content_entry.xml b/res/layouts/templates/content_entry.xml
new file mode 100644
index 00000000..cfb9ce68
--- /dev/null
+++ b/res/layouts/templates/content_entry.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layouts/templates/generator.xml b/res/layouts/templates/generator.xml
new file mode 100644
index 00000000..51120738
--- /dev/null
+++ b/res/layouts/templates/generator.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/res/layouts/templates/pack.xml b/res/layouts/templates/pack.xml
new file mode 100644
index 00000000..5eb2f74c
--- /dev/null
+++ b/res/layouts/templates/pack.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/res/layouts/templates/track_setting.xml b/res/layouts/templates/track_setting.xml
new file mode 100644
index 00000000..994e5bb3
--- /dev/null
+++ b/res/layouts/templates/track_setting.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/res/layouts/templates/world.xml b/res/layouts/templates/world.xml
new file mode 100644
index 00000000..c20223fc
--- /dev/null
+++ b/res/layouts/templates/world.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/res/preload.json b/res/preload.json
index bc5bc2ac..63c2d238 100644
--- a/res/preload.json
+++ b/res/preload.json
@@ -11,4 +11,3 @@
"gui/crosshair"
]
}
-
diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua
index d8397f57..dcc7f382 100644
--- a/res/scripts/stdlib.lua
+++ b/res/scripts/stdlib.lua
@@ -131,7 +131,9 @@ events = {
}
function events.on(event, func)
- events.handlers[event] = events.handlers[event] or {}
+ -- why an array? length is always = 1
+ -- FIXME: temporary fixed
+ events.handlers[event] = {} -- events.handlers[event] or {}
table.insert(events.handlers[event], func)
end
@@ -175,11 +177,105 @@ Document = {}
function Document.new(docname)
return setmetatable({name=docname}, {
__index=function(self, k)
- return Element.new(self.name, k)
+ local elem = Element.new(self.name, k)
+ rawset(self, k, elem)
+ return elem
end
})
end
+_GUI_ROOT = Document.new("core:root")
+_MENU = _GUI_ROOT.menu
+menu = _MENU
+
+local __post_runnables = {}
+
+function __process_post_runnables()
+ if #__post_runnables then
+ for _, func in ipairs(__post_runnables) do
+ func()
+ end
+ __post_runnables = {}
+ end
+end
+
+function time.post_runnable(runnable)
+ table.insert(__post_runnables, runnable)
+end
+
+function gui.template(name, params)
+ local text = file.read(file.find("layouts/templates/"..name..".xml"))
+ for k,v in pairs(params) do
+ local arg = tostring(v):gsub("'", "\\'"):gsub('"', '\\"')
+ text = text:gsub("(%%{"..k.."})", arg)
+ end
+ text = text:gsub("if%s*=%s*'%%{%w+}'", "if=''")
+ text = text:gsub("if%s*=%s*\"%%{%w+}\"", "if=\"\"")
+ -- remove unsolved properties: attr='%{var}'
+ text = text:gsub("%w+%s*=%s*'%%{%w+}'%s?", "")
+ text = text:gsub("%w+%s*=%s*\"%%{%w+}\"%s?", "")
+ return text
+end
+
+session = {
+ entries={}
+}
+
+function session.get_entry(name)
+ local entry = session.entries[name]
+ if entry == nil then
+ entry = {}
+ session.entries[name] = entry
+ end
+ return entry
+end
+
+function session.reset_entry(name)
+ session.entries[name] = nil
+end
+
+function timeit(func, ...)
+ local tm = time.uptime()
+ func(...)
+ print("[time mcs]", (time.uptime()-tm) * 1000000)
+end
+
+function table.has(t, x)
+ for i,v in ipairs(t) do
+ if v == x then
+ return true
+ end
+ end
+ return false
+end
+
+function table.index(t, x)
+ for i,v in ipairs(t) do
+ if v == x then
+ return i
+ end
+ end
+ return -1
+end
+
+function table.remove_value(t, x)
+ local index = table.index(t, x)
+ if index ~= -1 then
+ table.remove(t, index)
+ end
+end
+
+function table.tostring(t)
+ local s = '['
+ for i,v in ipairs(t) do
+ s = s..tostring(v)
+ if i < #t then
+ s = s..', '
+ end
+ end
+ return s..']'
+end
+
-- Deprecated functions
block_index = block.index
block_name = block.name
diff --git a/res/texts/de_DE.txt b/res/texts/de_DE.txt
index ce6b21ec..0251f395 100644
--- a/res/texts/de_DE.txt
+++ b/res/texts/de_DE.txt
@@ -13,44 +13,44 @@ error.dependency-not-found=Die verwendete Abhängigkeit wurde nicht gefunden
pack.remove-confirm=Alle vom Paket bereitgestellten Inhalte (dauerhaft) aus der Welt löschen?
# Меню
+menu.Apply=Anwenden
+menu.Audio=Klang
+menu.Back to Main Menu=Zurück zum Menü
+menu.Content Error=Inhaltsfehler
+menu.Content=Inhalt
+menu.Continue=Weitermachen
+menu.Controls=Kontrolle
+menu.Create World=Erschaffe eine Welt
+menu.missing-content=Fehlender Inhalt!
menu.New World=Neue Welt
menu.Quit=Ausfahrt
-menu.Continue=Weitermachen
menu.Save and Quit to Menu=Speichern und zum Menü zurückkehren
-menu.missing-content=Fehlender Inhalt!
-menu.Content Error=Inhaltsfehler
-menu.Controls=Kontrolle
-menu.Back to Main Menu=Zurück zum Menü
menu.Settings=Einstellungen
-menu.Content=Inhalt
-menu.Audio=Klang
+
world.Seed=Mais
world.Name=Name
-
world.World generator=Weltgenerator
world.generators.default=Normal
world.generators.flat=Wohnung
-menu.Create World=Erschaffe eine Welt
-
+world.Create World=Welt Erschaffen
world.convert-request=Es gibt Änderungen in den Indizes! Die Welt bekehren?
world.delete-confirm=Die Welt dauerhaft löschen?
# Настройки
+settings.Ambient=Hintergrund
+settings.Backlight=Hintergrundbeleuchtung
+settings.Camera Shaking=Wackelnde Kamera
+settings.Fog Curve=Nebelkurve
+settings.FOV=Sichtlinie
+settings.Language=Sprache
settings.Load Distance=Ladeentfernung
settings.Load Speed=Download-Geschwindigkeit
-settings.Fog Curve=Nebelkurve
-settings.Backlight=Hintergrundbeleuchtung
-settings.V-Sync=Vertikale Synchronisation
-settings.Camera Shaking=Wackelnde Kamera
settings.Master Volume=Allgemeine Lautstärke
+settings.Mouse Sensitivity=Maus-Empfindlichkeit
+settings.Music=Musik
settings.Regular Sounds=Normale Geräusche
settings.UI Sounds=Interface-Sounds
-settings.Ambient=Hintergrund
-settings.Music=Musik
-
-settings.FOV=Sichtlinie
-settings.Mouse Sensitivity=Maus-Empfindlichkeit
-settings.Language=Sprache
+settings.V-Sync=Vertikale Synchronisation
# Управление
movement.forward=Vorwärts
diff --git a/res/texts/en_US.txt b/res/texts/en_US.txt
index 99b97604..94d6774b 100644
--- a/res/texts/en_US.txt
+++ b/res/texts/en_US.txt
@@ -1,7 +1,7 @@
# Menu
menu.missing-content=Missing Content!
world.convert-request=Content indices have changed! Convert world files?
-pack.remove-confirm=Do you want to erase all pack content from the world forever?
+pack.remove-confirm=Do you want to erase all pack(s) content from the world forever?
error.pack-not-found=Could not to find pack
error.dependency-not-found=Dependency pack is not found
world.delete-confirm=Do you want to delete world forever?
@@ -24,4 +24,4 @@ player.build=Place Block
player.flight=Flight
player.noclip=No-clip
camera.zoom=Zoom
-camera.mode=Switch Camera Mode
\ No newline at end of file
+camera.mode=Switch Camera Mode
diff --git a/res/texts/pl_PL.txt b/res/texts/pl_PL.txt
index aebdab1c..39f1a1a7 100644
--- a/res/texts/pl_PL.txt
+++ b/res/texts/pl_PL.txt
@@ -5,38 +5,53 @@ Ok=OK
Cancel=Anulowanie
Back=Powrót
Continue=Kontynuacja
+Add=Dodać
+Converting world...=Konwersja świata w toku...
error.pack-not-found=Nie udało się znaleźć pakietu
# Menu
-menu.New World=Nowy Świat
-menu.Quit=Wyjście
-menu.Continue=Kontynuacja
-menu.Save and Quit to Menu=Zapisz i wyjdź do menu
-menu.missing-content=Brak treści!
-menu.Controls=Zarządzanie
+menu.Apply=Zastosować
+menu.Audio=Dźwięki
menu.Back to Main Menu=Powrót do menu
-menu.Settings=Ustawienia
menu.Content=Treść
+menu.Continue=Kontynuacja
+menu.Controls=Zarządzanie
+menu.Graphics=Grafika
+menu.Create World=Stwórz świat
+menu.missing-content=Brakująca treść!
+menu.New World=Nowy Świat
+menu.Page not found=Strona nie znaleziona
+menu.Quit=Wyjście
+menu.Save and Quit to Menu=Zapisz i wyjdź do menu
+menu.Settings=Ustawienia
+
world.Seed=Ziarno
world.Name=Nazwa
-menu.Create World=Stwórz świat
-
world.World generator=Generator światła
world.generators.default=Ekstremalne
world.generators.flat=Mieszkanie
+world.Create World=Stwórz świat
world.convert-request=Szykują się zmiany w indeksach! Przekształcić świat?
+world.delete-confirm=Trwale usunąć świat?
# Ustawienia
+settings.Ambient=Tło
+settings.Backlight=Podświetlenie
+settings.Camera Shaking=Drżąca kamera
+settings.Fog Curve=Krzywa mgły
+settings.FOV=Wzrok
+settings.Fullscreen=Pełny ekran
+settings.Gamma=Gamma
+settings.Language=Język
settings.Load Distance=Odległość ładowania
settings.Load Speed=Prędkość pobierania
-settings.Fog Curve=Krzywa mgły
-settings.Backlight=Podświetlenie
-settings.V-Sync=Synchronizacja pionowa
-
-settings.FOV=Wzrok
+settings.Master Volume=Głośność główna
settings.Mouse Sensitivity=Wrażliwość myszy
-settings.Language=Język
+settings.Music=Muzyka
+settings.Regular Sounds=Normalne dźwięki
+settings.UI Sounds=Dźwięki interfejsu
+settings.V-Sync=Synchronizacja pionowa
# Zarządzanie
movement.forward=Naprzód
diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt
index 25278d13..04ee4e69 100644
--- a/res/texts/ru_RU.txt
+++ b/res/texts/ru_RU.txt
@@ -10,47 +10,50 @@ Converting world...=Выполняется конвертация мира...
error.pack-not-found=Не удалось найти пакет
error.dependency-not-found=Используемая зависимость не найдена
-pack.remove-confirm=Удалить весь поставляемый паком контент из мира (безвозвратно)?
+pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
# Меню
-menu.New World=Новый Мир
-menu.Quit=Выход
-menu.Continue=Продолжить
-menu.Save and Quit to Menu=Сохранить и Выйти в Меню
-menu.missing-content=Отсутствует Контент!
-menu.Content Error=Ошибка Контента
-menu.Controls=Управление
-menu.Back to Main Menu=Вернуться в Меню
-menu.Settings=Настройки
-menu.Content=Контент
+menu.Apply=Применить
menu.Audio=Звук
+menu.Back to Main Menu=Вернуться в Меню
+menu.Content Error=Ошибка Контента
+menu.Content=Контент
+menu.Continue=Продолжить
+menu.Controls=Управление
+menu.Graphics=Графика
+menu.missing-content=Отсутствует Контент!
+menu.New World=Новый Мир
+menu.Page not found=Страница не найдена
+menu.Quit=Выход
+menu.Save and Quit to Menu=Сохранить и Выйти в Меню
+menu.Settings=Настройки
+
world.Seed=Зерно
world.Name=Название
-
world.World generator=Генератор мира
world.generators.default=Обычный
world.generators.flat=Плоский
-menu.Create World=Создать Мир
-
+world.Create World=Создать Мир
world.convert-request=Есть изменения в индексах! Конвертировать мир?
world.delete-confirm=Удалить мир безвозвратно?
# Настройки
+settings.Ambient=Фон
+settings.Backlight=Подсветка
+settings.Camera Shaking=Тряска Камеры
+settings.Fog Curve=Кривая Тумана
+settings.FOV=Поле Зрения
+settings.Fullscreen=Полный экран
+settings.Gamma=Гамма
+settings.Language=Язык
settings.Load Distance=Дистанция Загрузки
settings.Load Speed=Скорость Загрузки
-settings.Fog Curve=Кривая Тумана
-settings.Backlight=Подсветка
-settings.V-Sync=Вертикальная Синхронизация
-settings.Camera Shaking=Тряска Камеры
settings.Master Volume=Общая Громкость
+settings.Mouse Sensitivity=Чувствительность Мыши
+settings.Music=Музыка
settings.Regular Sounds=Обычные Звуки
settings.UI Sounds=Звуки Интерфейса
-settings.Ambient=Фон
-settings.Music=Музыка
-
-settings.FOV=Поле Зрения
-settings.Mouse Sensitivity=Чувствительность Мыши
-settings.Language=Язык
+settings.V-Sync=Вертикальная Синхронизация
# Управление
movement.forward=Вперёд
@@ -67,4 +70,4 @@ player.attack=Атаковать / Сломать
player.build=Поставить Блок
player.flight=Полёт
camera.zoom=Приближение
-camera.mode=Сменить Режим Камеры
\ No newline at end of file
+camera.mode=Сменить Режим Камеры
diff --git a/res/texts/uk_UA.txt b/res/texts/uk_UA.txt
index 4030d650..175c172f 100644
--- a/res/texts/uk_UA.txt
+++ b/res/texts/uk_UA.txt
@@ -5,19 +5,26 @@ Ok=Гаразд
Cancel=Скасувати
Back=Назад
Continue=Продовжити
+Add=Додати
+Converting world...=Виконується конвертація світу...
error.pack-not-found=Не вдалося знайти пакет
# Меню
-menu.New World=Новий Світ
-menu.Quit=Вихід
-menu.Continue=Продовжити
-menu.Save and Quit to Menu=Зберегти і Вийти в Меню
-menu.missing-content=Відсутній Контент!
-menu.Controls=Керування
+menu.Apply=Застосувати
+menu.Audio=Звук
menu.Back to Main Menu=Повернутися до Меню
-menu.Settings=Налаштування
+menu.Content Error=Помилка Контенту
menu.Content=Контент
+menu.Continue=Продовжити
+menu.Controls=Керування
+menu.Graphics=Графіка
+menu.missing-content=Відсутній Контент!
+menu.New World=Новий Світ
+menu.Page not found=Сторінка не знайдена
+menu.Quit=Вихід
+menu.Save and Quit to Menu=Зберегти і Вийти в Меню
+menu.Settings=Налаштування
world.Seed=Зерно
world.Name=Назва
menu.Create World=Створити Світ
@@ -28,15 +35,22 @@ world.generators.flat=Плоскі
world.convert-request=Є зміни в індексах! Конвертувати світ?
# Налаштування
+settings.Ambient=Фон
+settings.Backlight=Підсвічування
+settings.Camera Shaking=Тряска Камери
+settings.Fog Curve=Крива Туману
+settings.FOV=Поле зору
+settings.Fullscreen=Повний екран
+settings.Gamma=Гамма
+settings.Language=Мова
settings.Load Distance=Дистанція Завантаження
settings.Load Speed=Швидкість Завантаження
-settings.Fog Curve=Крива Туману
-settings.Backlight=Підсвічування
-settings.V-Sync=Вертикальна Синхронізація
-
-settings.FOV=Поле зору
+settings.Master Volume=Загальна Гучність
settings.Mouse Sensitivity=Чутливість Миші
-settings.Language=Мова
+settings.Music=Музика
+settings.Regular Sounds=Звичайні Звуки
+settings.UI Sounds=Звуки інтерфейсу
+settings.V-Sync=Вертикальна Синхронізація
# Керування
movement.forward=Уперед
diff --git a/res/textures/gui/circle.png b/res/textures/gui/circle.png
new file mode 100644
index 00000000..b82a72ee
Binary files /dev/null and b/res/textures/gui/circle.png differ
diff --git a/res/textures/gui/cross.png b/res/textures/gui/cross.png
index 2656b8bc..021a5ef1 100644
Binary files a/res/textures/gui/cross.png and b/res/textures/gui/cross.png differ
diff --git a/res/textures/gui/menubg.png b/res/textures/gui/menubg.png
index e3342a02..54135f36 100644
Binary files a/res/textures/gui/menubg.png and b/res/textures/gui/menubg.png differ
diff --git a/res/textures/gui/no_icon.png b/res/textures/gui/no_icon.png
index 3ad417bf..796058f6 100644
Binary files a/res/textures/gui/no_icon.png and b/res/textures/gui/no_icon.png differ
diff --git a/res/textures/gui/no_world_icon.png b/res/textures/gui/no_world_icon.png
new file mode 100644
index 00000000..afa28095
Binary files /dev/null and b/res/textures/gui/no_world_icon.png differ
diff --git a/res/textures/gui/refresh.png b/res/textures/gui/refresh.png
new file mode 100644
index 00000000..ffbbb387
Binary files /dev/null and b/res/textures/gui/refresh.png differ
diff --git a/src/assets/Assets.cpp b/src/assets/Assets.cpp
index 6dabd8c6..d1c93360 100644
--- a/src/assets/Assets.cpp
+++ b/src/assets/Assets.cpp
@@ -1,112 +1,87 @@
-#include "Assets.h"
+#include "Assets.hpp"
-#include "../audio/audio.h"
-#include "../graphics/Texture.h"
-#include "../graphics/Shader.h"
-#include "../graphics/Atlas.h"
-#include "../graphics/Font.h"
-#include "../frontend/UiDocument.h"
-#include "../logic/scripting/scripting.h"
+#include "../audio/audio.hpp"
+#include "../graphics/core/Texture.hpp"
+#include "../graphics/core/Shader.hpp"
+#include "../graphics/core/Atlas.hpp"
+#include "../graphics/core/Font.hpp"
+#include "../frontend/UiDocument.hpp"
+#include "../logic/scripting/scripting.hpp"
Assets::~Assets() {
}
Texture* Assets::getTexture(std::string name) const {
- auto found = textures.find(name);
- if (found == textures.end())
- return nullptr;
- return found->second.get();
+ auto found = textures.find(name);
+ if (found == textures.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(Texture* texture, std::string name){
- textures.emplace(name, texture);
+ textures.emplace(name, texture);
}
Shader* Assets::getShader(std::string name) const{
- auto found = shaders.find(name);
- if (found == shaders.end())
- return nullptr;
- return found->second.get();
+ auto found = shaders.find(name);
+ if (found == shaders.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(Shader* shader, std::string name){
- shaders.emplace(name, shader);
+ shaders.emplace(name, shader);
}
Font* Assets::getFont(std::string name) const {
- auto found = fonts.find(name);
- if (found == fonts.end())
- return nullptr;
- return found->second.get();
+ auto found = fonts.find(name);
+ if (found == fonts.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(Font* font, std::string name){
- fonts.emplace(name, font);
+ fonts.emplace(name, font);
}
Atlas* Assets::getAtlas(std::string name) const {
- auto found = atlases.find(name);
- if (found == atlases.end())
- return nullptr;
- return found->second.get();
+ auto found = atlases.find(name);
+ if (found == atlases.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(Atlas* atlas, std::string name){
- atlases.emplace(name, atlas);
+ atlases.emplace(name, atlas);
}
audio::Sound* Assets::getSound(std::string name) const {
- auto found = sounds.find(name);
- if (found == sounds.end())
- return nullptr;
- return found->second.get();
+ auto found = sounds.find(name);
+ if (found == sounds.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(audio::Sound* sound, std::string name) {
- sounds.emplace(name, sound);
+ sounds.emplace(name, sound);
}
const std::vector& Assets::getAnimations() {
- return animations;
+ return animations;
}
void Assets::store(const TextureAnimation& animation) {
- animations.emplace_back(animation);
+ animations.emplace_back(animation);
}
UiDocument* Assets::getLayout(std::string name) const {
- auto found = layouts.find(name);
- if (found == layouts.end())
- return nullptr;
- return found->second.get();
+ auto found = layouts.find(name);
+ if (found == layouts.end())
+ return nullptr;
+ return found->second.get();
}
void Assets::store(UiDocument* layout, std::string name) {
- layouts.emplace(name, layout);
-}
-
-void Assets::extend(const Assets& assets) {
- for (auto entry : assets.textures) {
- textures[entry.first] = entry.second;
- }
- for (auto entry : assets.shaders) {
- shaders[entry.first] = entry.second;
- }
- for (auto entry : assets.fonts) {
- fonts[entry.first] = entry.second;
- }
- for (auto entry : assets.atlases) {
- atlases[entry.first] = entry.second;
- }
- for (auto entry : assets.layouts) {
- layouts[entry.first] = entry.second;
- }
- for (auto entry : assets.sounds) {
- sounds[entry.first] = entry.second;
- }
- animations.clear();
- for (auto entry : assets.animations) {
- animations.emplace_back(entry);
- }
+ layouts[name] = std::shared_ptr(layout);
}
diff --git a/src/assets/Assets.h b/src/assets/Assets.h
deleted file mode 100644
index f085ea7e..00000000
--- a/src/assets/Assets.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ASSETS_ASSETS_H_
-#define ASSETS_ASSETS_H_
-
-#include "../graphics/TextureAnimation.h"
-
-#include
-#include
-#include
-#include
-
-class Texture;
-class Shader;
-class Font;
-class Atlas;
-class UiDocument;
-
-namespace audio {
- class Sound;
-}
-
-class Assets {
- std::unordered_map> textures;
- std::unordered_map> shaders;
- std::unordered_map> fonts;
- std::unordered_map> atlases;
- std::unordered_map> layouts;
- std::unordered_map> sounds;
- std::vector animations;
-public:
- ~Assets();
- Texture* getTexture(std::string name) const;
- void store(Texture* texture, std::string name);
-
- Shader* getShader(std::string name) const;
- void store(Shader* shader, std::string name);
-
- Font* getFont(std::string name) const;
- void store(Font* font, std::string name);
-
- Atlas* getAtlas(std::string name) const;
- void store(Atlas* atlas, std::string name);
-
- audio::Sound* getSound(std::string name) const;
- void store(audio::Sound* sound, std::string name);
-
- const std::vector& getAnimations();
- void store(const TextureAnimation& animation);
-
- UiDocument* getLayout(std::string name) const;
- void store(UiDocument* layout, std::string name);
-
- void extend(const Assets& assets);
-};
-
-#endif /* ASSETS_ASSETS_H_ */
diff --git a/src/assets/Assets.hpp b/src/assets/Assets.hpp
new file mode 100644
index 00000000..a9d4b927
--- /dev/null
+++ b/src/assets/Assets.hpp
@@ -0,0 +1,63 @@
+#ifndef ASSETS_ASSETS_HPP_
+#define ASSETS_ASSETS_HPP_
+
+#include "../graphics/core/TextureAnimation.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+class Texture;
+class Shader;
+class Font;
+class Atlas;
+class Assets;
+class UiDocument;
+
+namespace audio {
+ class Sound;
+}
+
+namespace assetload {
+ /// @brief final work to do in the main thread
+ using postfunc = std::function;
+}
+
+class Assets {
+ std::unordered_map> textures;
+ std::unordered_map> shaders;
+ std::unordered_map> fonts;
+ std::unordered_map> atlases;
+ std::unordered_map> layouts;
+ std::unordered_map> sounds;
+ std::vector animations;
+public:
+ Assets() {}
+ Assets(const Assets&) = delete;
+ ~Assets();
+
+ Texture* getTexture(std::string name) const;
+ void store(Texture* texture, std::string name);
+
+ Shader* getShader(std::string name) const;
+ void store(Shader* shader, std::string name);
+
+ Font* getFont(std::string name) const;
+ void store(Font* font, std::string name);
+
+ Atlas* getAtlas(std::string name) const;
+ void store(Atlas* atlas, std::string name);
+
+ audio::Sound* getSound(std::string name) const;
+ void store(audio::Sound* sound, std::string name);
+
+ const std::vector& getAnimations();
+ void store(const TextureAnimation& animation);
+
+ UiDocument* getLayout(std::string name) const;
+ void store(UiDocument* layout, std::string name);
+};
+
+#endif // ASSETS_ASSETS_HPP_
diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp
index 1d27e06e..4fb972c6 100644
--- a/src/assets/AssetsLoader.cpp
+++ b/src/assets/AssetsLoader.cpp
@@ -1,58 +1,74 @@
-#include "AssetsLoader.h"
-#include "Assets.h"
+#include "AssetsLoader.hpp"
-#include "assetload_funcs.h"
+#include "Assets.hpp"
+#include "assetload_funcs.hpp"
+#include "../util/ThreadPool.hpp"
+#include "../constants.hpp"
+#include "../data/dynamic.hpp"
+#include "../debug/Logger.hpp"
+#include "../coders/imageio.hpp"
+#include "../files/files.hpp"
+#include "../files/engine_paths.hpp"
+#include "../content/Content.hpp"
+#include "../content/ContentPack.hpp"
+#include "../graphics/core/Texture.hpp"
+#include "../logic/scripting/scripting.hpp"
#include
#include
-#include "../constants.h"
-#include "../data/dynamic.h"
-#include "../files/files.h"
-#include "../files/engine_paths.h"
-#include "../content/Content.h"
-#include "../content/ContentPack.h"
-#include "../logic/scripting/scripting.h"
+static debug::Logger logger("assets-loader");
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths)
: assets(assets), paths(paths)
{
- addLoader(AssetType::shader, assetload::shader);
- addLoader(AssetType::texture, assetload::texture);
- addLoader(AssetType::font, assetload::font);
- addLoader(AssetType::atlas, assetload::atlas);
+ addLoader(AssetType::shader, assetload::shader);
+ addLoader(AssetType::texture, assetload::texture);
+ addLoader(AssetType::font, assetload::font);
+ addLoader(AssetType::atlas, assetload::atlas);
addLoader(AssetType::layout, assetload::layout);
addLoader(AssetType::sound, assetload::sound);
}
void AssetsLoader::addLoader(AssetType tag, aloader_func func) {
- loaders[tag] = func;
+ loaders[tag] = func;
}
void AssetsLoader::add(AssetType tag, const std::string filename, const std::string alias, std::shared_ptr settings) {
- entries.push(aloader_entry{tag, filename, alias, settings});
+ entries.push(aloader_entry{tag, filename, alias, settings});
}
bool AssetsLoader::hasNext() const {
- return !entries.empty();
+ return !entries.empty();
+}
+
+aloader_func AssetsLoader::getLoader(AssetType tag) {
+ auto found = loaders.find(tag);
+ if (found == loaders.end()) {
+ throw std::runtime_error(
+ "unknown asset tag "+std::to_string(static_cast(tag))
+ );
+ }
+ return found->second;
}
bool AssetsLoader::loadNext() {
- const aloader_entry& entry = entries.front();
- std::cout << " loading " << entry.filename << " as " << entry.alias << std::endl;
- std::cout.flush();
- auto found = loaders.find(entry.tag);
- if (found == loaders.end()) {
- std::cerr << "unknown asset tag " << static_cast(entry.tag) << std::endl;
- return false;
- }
- aloader_func loader = found->second;
- bool status = loader(*this, assets, paths, entry.filename, entry.alias, entry.config);
- entries.pop();
- return status;
+ const aloader_entry& entry = entries.front();
+ logger.info() << "loading " << entry.filename << " as " << entry.alias;
+ try {
+ aloader_func loader = getLoader(entry.tag);
+ auto postfunc = loader(this, paths, entry.filename, entry.alias, entry.config);
+ postfunc(assets);
+ entries.pop();
+ return true;
+ } catch (std::runtime_error& err) {
+ logger.error() << err.what();
+ entries.pop();
+ return false;
+ }
}
-void addLayouts(int env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) {
+void addLayouts(scriptenv env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) {
if (!fs::is_directory(folder)) {
return;
}
@@ -117,11 +133,12 @@ void AssetsLoader::processPreloadList(AssetType tag, dynamic::List* list) {
auto value = list->get(i);
switch (value->type) {
case dynamic::valtype::string:
- processPreload(tag, *value->value.str, nullptr);
+ processPreload(tag, std::get(value->value), nullptr);
break;
case dynamic::valtype::map: {
- auto name = value->value.map->getStr("name");
- processPreload(tag, name, value->value.map);
+ auto map = std::get(value->value);
+ auto name = map->getStr("name");
+ processPreload(tag, name, map);
break;
}
default:
@@ -161,9 +178,11 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/menubg", "gui/menubg");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/delete_icon", "gui/delete_icon");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/no_icon", "gui/no_icon");
+ loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/no_world_icon", "gui/no_world_icon");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/warning", "gui/warning");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/error", "gui/error");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/cross", "gui/cross");
+ loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/refresh", "gui/refresh");
if (content) {
loader.processPreloadConfigs(content);
@@ -179,13 +198,68 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
auto pack = entry.second.get();
auto& info = pack->getInfo();
fs::path folder = info.folder / fs::path("layouts");
- addLayouts(pack->getEnvironment()->getId(), info.id, folder, loader);
+ addLayouts(pack->getEnvironment(), info.id, folder, loader);
}
}
loader.add(AssetType::atlas, TEXTURES_FOLDER+"/blocks", "blocks");
loader.add(AssetType::atlas, TEXTURES_FOLDER+"/items", "items");
}
-const ResPaths* AssetsLoader::getPaths() const {
- return paths;
+bool AssetsLoader::loadExternalTexture(
+ Assets* assets,
+ const std::string& name,
+ std::vector alternatives
+) {
+ if (assets->getTexture(name) != nullptr) {
+ return true;
+ }
+ for (auto& path : alternatives) {
+ if (fs::exists(path)) {
+ try {
+ auto image = imageio::read(path.string());
+ assets->store(Texture::from(image.get()).release(), name);
+ return true;
+ } catch (const std::exception& err) {
+ logger.error() << "error while loading external "
+ << path.u8string() << ": " << err.what();
+ }
+ }
+ }
+ return false;
+}
+
+const ResPaths* AssetsLoader::getPaths() const {
+ return paths;
+}
+
+class LoaderWorker : public util::Worker {
+ AssetsLoader* loader;
+public:
+ LoaderWorker(AssetsLoader* loader) : loader(loader) {
+ }
+
+ assetload::postfunc operator()(const std::shared_ptr& entry) override {
+ aloader_func loadfunc = loader->getLoader(entry->tag);
+ return loadfunc(loader, loader->getPaths(), entry->filename, entry->alias, entry->config);
+ }
+};
+
+std::shared_ptr AssetsLoader::startTask(runnable onDone) {
+ auto pool = std::make_shared<
+ util::ThreadPool
+ >(
+ "assets-loader-pool",
+ [=](){return std::make_shared(this);},
+ [=](assetload::postfunc& func) {
+ func(assets);
+ }
+ );
+ pool->setOnComplete(onDone);
+ while (!entries.empty()) {
+ const aloader_entry& entry = entries.front();
+ auto ptr = std::make_shared(entry);
+ pool->enqueueJob(ptr);
+ entries.pop();
+ }
+ return pool;
}
diff --git a/src/assets/AssetsLoader.h b/src/assets/AssetsLoader.h
deleted file mode 100644
index 5de43150..00000000
--- a/src/assets/AssetsLoader.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef ASSETS_ASSETS_LOADER_H
-#define ASSETS_ASSETS_LOADER_H
-
-#include
-#include
-#include
-#include
-#include