This commit is contained in:
@clasher113 2024-01-21 15:42:38 +02:00
commit b80e36f008
51 changed files with 1337 additions and 250 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: ['https://www.donationalerts.com/r/mihailris']

31
.github/ISSUE_TEMPLATE/bug.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: Найден баг
about: Создайте отчет, чтобы помочь нам исправить этот баг
title: BUG
labels: bug, wontfix
assignees: ''
---
**Опишите ошибку**
Четкое и краткое описание ошибки.
**Для воспроизведения**
Шаги для воспроизведения поведения:
1. Перейдите в раздел «...»
2. Нажмите «....»
3. Прокрутите вниз до «....»
4. См. ошибку
**Ожидаемое поведение**
Четкое и краткое описание того, что вы ожидаете.
**Скриншоты**
Если применимо, добавьте снимки экрана, которые помогут объяснить вашу проблему.
**Техническая информация (заполните следующую информацию):**
- ОС: [например. Windows 10]
- Версия [например. 0.17]
**Дополнительный контекст**
Добавьте сюда любой другой контекст проблемы.

20
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@ -0,0 +1,20 @@
---
name: Новая фича
about: Новая идея для этого проекта
title: 'ENHANCEMENT '
labels: enhancement
assignees: ''
---
**Связан ли ваш запрос на добавление функции с проблемой? Пожалуйста, опишите.**
Четкое и краткое описание проблемы. Бывший. Я всегда расстраиваюсь, когда [...]
**Опишите желаемое решение**
Четкое и краткое описание того, чего вы хотите.
**Опишите альтернативы, которые вы рассматривали**
Четкое и краткое описание любых альтернативных решений или функций, которые вы рассматривали.
**Дополнительный контекст**
Добавьте сюда любой другой контекст или снимки экрана о запросе функции.

12
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,12 @@
---
name: Вопрос
about: Вопрос другого характера
title: QUESTION
labels: question
assignees: ''
---
**Опишите свой вопрос**
Кратко и понятно опишите ваш вопрос.
Перед созданием этого запроса убедитесь, что ранее не были созданы подобные.

5
.gitignore vendored
View File

@ -25,11 +25,16 @@ Debug/voxel_engine
.settings
.cproject
.project
.fleet
.git
/Default/
AppDir
appimage-build/
# for vcpkg
/vcpkg/
.gitmodules
# macOS folder attributes
*.DS_Store

View File

@ -1,3 +1,8 @@
option(VOXELENGINE_BUILD_WINDOWS_VCPKG OFF)
if(VOXELENGINE_BUILD_WINDOWS_VCPKG AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake")
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
endif()
cmake_minimum_required(VERSION 3.15)
project(VoxelEngine)
@ -28,8 +33,10 @@ if(VOXELENGINE_BUILD_APPDIR)
install(TARGETS VoxelEngine DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/AppDir/usr/bin)
endif()
if(MSVC)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL "RelWithDebInfo"))
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Release>:Release>")
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2)
@ -45,16 +52,52 @@ else()
-Wwrite-strings -Wno-unused-parameter)
endif()
if(VOXELENGINE_BUILD_WINDOWS_VCPKG AND WIN32)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/.git")
find_package(Git QUIET)
if(GIT_FOUND)
message(STATUS "Adding vcpkg as a git submodule...")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule add https://github.com/microsoft/vcpkg.git vcpkg WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
else()
message(FATAL_ERROR "Git not found, cannot add vcpkg submodule.")
endif()
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/.git")
message(STATUS "Initializing and updating vcpkg submodule...")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E chdir vcpkg ./bootstrap-vcpkg.bat WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE_UPPER)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/res ${CMAKE_BINARY_DIR}/${CONFIG_TYPE_UPPER}/res)
endforeach()
endif()
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(OpenAL REQUIRED)
# luajit has no CMakeLists.txt to use it as subdirectory, so install it
find_package(Lua REQUIRED)
find_package(ZLIB REQUIRED)
if (WIN32)
set(PNGLIB spng)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/glfw)
if(VOXELENGINE_BUILD_WINDOWS_VCPKG)
set(LUA_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/packages/luajit_x64-windows/lib/lua51.lib")
set(LUA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/packages/luajit_x64-windows/include/luajit")
find_package(glfw3 REQUIRED)
find_package(spng REQUIRED)
find_package(glm REQUIRED)
set(PNGLIB spng::spng)
else()
find_package(Lua REQUIRED)
set(PNGLIB spng)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/glfw)
endif()
else()
# luajit has no CMakeLists.txt to use it as subdirectory, so install it manually
find_package(Lua REQUIRED)
find_package(PNG REQUIRED)
set(PNGLIB PNG::PNG)
endif()
@ -75,7 +118,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif()
include_directories(${LUA_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${LIBS} glfw OpenGL::GL ${OPENAL_LIBRARY} GLEW::GLEW ${PNGLIB} ${LUA_LIBRARIES} ${CMAKE_DL_LIBS})
target_link_libraries(${PROJECT_NAME} ${LIBS} glfw OpenGL::GL ${OPENAL_LIBRARY} GLEW::GLEW ZLIB::ZLIB ${PNGLIB} ${LUA_LIBRARIES} ${CMAKE_DL_LIBS})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

47
Dockerfile Normal file
View File

@ -0,0 +1,47 @@
# Build docker container: docker build -t voxel-engine .
# Build project: docker run --rm -it -v$(pwd):/project voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build"
# Run project in docker: docker run --rm -it -v$(pwd):/project -v/tmp/.X11-unix:/tmp/.X11-unix -v${XAUTHORITY}:/home/user/.Xauthority:ro -eDISPLAY --network=host voxel-engine ./build/VoxelEngine
FROM debian:bullseye-slim
LABEL Description="Docker container for building VoxelEngine for Linux"
# Install dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \
git \
g++ \
make \
cmake \
xauth \
gdb \
gdbserver \
libglfw3-dev \
libglfw3 \
libglew-dev \
libglm-dev \
libpng-dev \
libopenal-dev \
libluajit-5.1-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# CMake missing LUA_INCLUDE_DIR and LUA_LIBRARIES fix:
RUN ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a \
&& ln -s /usr/include/luajit-2.1 /usr/include/lua
# Install LuaJIT:
RUN git clone https://luajit.org/git/luajit.git \
&& cd luajit \
&& make && make install INSTALL_INC=/usr/include/lua \
&& cd .. && rm -rf luajit
# Create default user, due to:
# - Build and test artifacts have user permissions and not root permissions
# - Don't give root privileges from host to containers (security)
ARG USER=user
ARG UID=1000
ARG GID=1000
RUN useradd -m ${USER} --uid=${UID}
USER ${UID}:${GID}
# Project workspace
WORKDIR /project

View File

@ -10,7 +10,7 @@
- <kbd>**Tab**</kbd> - open inventory
- <kbd>**W**</kbd> <kbd>**A**</kbd> <kbd>**S**</kbd> <kbd>**D**</kbd> - movement
- <kbd>**Space**</kbd> - jump
- <kbd>**LMB**</kbd> - remove block
- <kbd>**LMB**</kbd> - remove block
- <kbd>**RMB**</kbd> - place block
- <kbd>**F**</kbd> - toggle flight mode
- <kbd>**N**</kbd> - noclip mode
@ -76,3 +76,44 @@ brew install glfw3 glew glm libpng lua luajit openal-soft
```
If homebrew for some reason could not install the necessary packages: ```lua luajit openal-soft```, then download, install and compile them manually (Lua, LuaJIT and OpenAL).
## Build using Docker
### Step 0. Install docker on your system
See https://docs.docker.com/engine/install
### Step 1. Build docker container
```
docker build -t voxel-engine .
```
### Step 2. Build project using the docker container
```
docker run --rm -it -v$(pwd):/project voxel-engine bash -c "cmake -DCMAKE_BUILD_TYPE=Release -Bbuild && cmake --build build"
```
### Step 3. Run project using the docker container
```
docker run --rm -it -v$(pwd):/project -v/tmp/.X11-unix:/tmp/.X11-unix -v${XAUTHORITY}:/home/user/.Xauthority:ro -eDISPLAY --network=host voxel-engine ./build/VoxelEngine
```
## Build with CMake and vcpkg for Windows
```sh
git clone --recursive https://github.com/MihailRis/VoxelEngine-Cpp.git
cd VoxelEngine-Cpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_WINDOWS_VCPKG=ON ..
del CMakeCache.txt
rmdir /s /q CMakeFiles
cmake -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_WINDOWS_VCPKG=ON ..
cmake --build . --config Release
```
note: you can use ```rm CMakeCache.txt``` and ```rm -rf CMakeFiles``` while using Git Bash
If you have issues during the vcpkg integration, try navigate to ```vcpkg\downloads``` and extract PowerShell-[version]-win-x86 to ```vcpkg\downloads\tools``` as powershell-core-[version]-windows. Then rerun ```cmake -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_WINDOWS_VCPKG=ON ..```

View File

@ -16,7 +16,7 @@ void main(){
float depth = (a_distance/256.0);
float alpha = a_color.a * tex_color.a;
// anyway it's any alpha-test alternative required
if (alpha < 0.1f)
if (alpha < 0.3f)
discard;
f_color = mix(a_color * tex_color, vec4(fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
f_color.a = alpha;

View File

@ -24,6 +24,7 @@ world.Name=Назва
menu.Create World=Стварыць Свет
world.convert-request=Ёсць змены ў індэксах! Канвертаваць свет?
world.delete-confirm=Выдаліць свет незваротна?
# Настройки
settings.Load Distance=Дыстанцыя Загрузкі

View File

@ -2,6 +2,7 @@
menu.missing-content=Missing Content!
world.convert-request=Content indices have changed! Convert world files?
error.pack-not-found=Could not to find pack
world.delete-confirm=Do you want to delete world forever?
# Bindings
movement.forward=Forward

View File

@ -12,8 +12,9 @@ error.pack-not-found=Pakettia ei löytynyt!
menu.New World = Uusi Maailma
menu.Quit=Poistu
menu.Continue=Jatka
menu.Save and Quit to Menu=Tallenna ja Takaisin valikoon
menu.Save and Quit to Menu=Tallenna ja poistu valikkoon
menu.missing-content=Puuttuu jotkut lisäosat!
menu.Content Error=Sisältövirhe!
menu.Controls=Ohjaus
menu.Back to Main Menu=Takaisin Valikoon
menu.Settings=Asetukset
@ -23,12 +24,13 @@ menu.Name=Nimi
menu.Create World=Luo Maailma
world.convert-request=Indeksit vaihdettu! Lataa maailma uudeleen?
world.delete-confirm=Poistetaanko maailma ikuisesti?
# Настройки
settings.Load Distance=Lataus Alue
settings.Load Speed=Lataus Nopeus
settings.Fog Curve=Sumun valaistus
settings.Backlight=Valaistus
settings.Load Distance=Latausalue
settings.Load Speed=Latausnopeus
settings.Fog Curve=Sumun tiheys
settings.Backlight=Taustavalo
settings.V-Sync=Pystytahdistus
settings.FOV=Näkökenttä
@ -41,8 +43,8 @@ movement.back=Taaksepäin
movement.left=Vaseemalle
movement.right=Oikealle
movement.jump=Hyppy
movement.sprint=Kiihtyvyys
movement.crouch=Istu alas
movement.sprint=Juoksu
movement.crouch=Hiipiä
movement.cheat=Huijata
hud.inventory=Varasto
player.pick=Ottaa lohko
@ -50,4 +52,4 @@ player.attack=Lyödä / Rikkoa
player.build=Aseta lohko
player.flight=Lento
camera.zoom=Lähentäminen
camera.mode=Vaihda Kameratila
camera.mode=Vaihda Kameratila

View File

@ -24,6 +24,7 @@ world.Name=Название
menu.Create World=Создать Мир
world.convert-request=Есть изменения в индексах! Конвертировать мир?
world.delete-confirm=Удалить мир безвозвратно?
# Настройки
settings.Load Distance=Дистанция Загрузки

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View File

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 132 B

View File

@ -58,7 +58,8 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, bool allAssets) {
loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background");
loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/menubg.png", "menubg");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg");
loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon");
loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal");
}
loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks");

View File

@ -2,6 +2,7 @@
#include <stdexcept>
#include "gzip.h"
#include "byte_utils.h"
using namespace json;
@ -148,12 +149,21 @@ static Map* object_from_binary(ByteReader& reader) {
}
std::unique_ptr<Map> json::from_binary(const ubyte* src, size_t size) {
ByteReader reader(src, size);
std::unique_ptr<Value> value (value_from_binary(reader));
if (value->type != valtype::map) {
throw std::runtime_error("root value is not an object");
if (size < 2) {
throw std::runtime_error("bytes length is less than 2");
}
if (src[0] == gzip::MAGIC[0] && src[1] == gzip::MAGIC[1]) {
// reading compressed document
auto data = gzip::decompress(src, size);
return from_binary(data.data(), data.size());
} else {
ByteReader reader(src, size);
std::unique_ptr<Value> value (value_from_binary(reader));
if (value->type != valtype::map) {
throw std::runtime_error("root value is not an object");
}
std::unique_ptr<Map> obj (value->value.map);
value->value.map = nullptr;
return obj;
}
std::unique_ptr<Map> obj (value->value.map);
value->value.map = nullptr;
return obj;
}

View File

@ -5,6 +5,7 @@
#include "../typedefs.h"
namespace gzip {
const unsigned char MAGIC[] = "\x1F\x8B";
std::vector<ubyte> compress(const ubyte* src, size_t size);
std::vector<ubyte> decompress(const ubyte* src, size_t size);
}

View File

@ -172,6 +172,7 @@ void ContentLoader::loadBlock(Block* def, std::string name, fs::path file) {
root->flag("sky-light-passing", def->skyLightPassing);
root->num("draw-group", def->drawGroup);
root->str("picking-item", def->pickingItem);
root->str("script-name", def->scriptName);
}
void ContentLoader::loadCustomBlockModel(Block* def, dynamic::Map* primitives) {
@ -233,6 +234,8 @@ void ContentLoader::loadItem(ItemDef* def, std::string name, fs::path file) {
}
root->str("icon", def->icon);
root->str("placing-block", def->placingBlock);
root->str("script-name", def->scriptName);
root->num("stack-size", def->stackSize);
// item light emission [r, g, b] where r,g,b in range [0..15]
auto emissionarr = root->list("emission");
@ -247,7 +250,7 @@ void ContentLoader::loadBlock(Block* def, std::string full, std::string name) {
auto folder = pack->folder;
fs::path configFile = folder/fs::path("blocks/"+name+".json");
fs::path scriptfile = folder/fs::path("scripts/"+name+".lua");
fs::path scriptfile = folder/fs::path("scripts/"+def->scriptName+".lua");
loadBlock(def, full, configFile);
if (fs::is_regular_file(scriptfile)) {
scripting::load_block_script(full, scriptfile, &def->rt.funcsset);
@ -258,7 +261,7 @@ void ContentLoader::loadItem(ItemDef* def, std::string full, std::string name) {
auto folder = pack->folder;
fs::path configFile = folder/fs::path("items/"+name+".json");
fs::path scriptfile = folder/fs::path("scripts/"+name+".lua");
fs::path scriptfile = folder/fs::path("scripts/"+def->scriptName+".lua");
loadItem(def, full, configFile);
if (fs::is_regular_file(scriptfile)) {
scripting::load_item_script(full, scriptfile, &def->rt.funcsset);

View File

@ -46,7 +46,7 @@ Engine::Engine(EngineSettings& settings, EnginePaths* paths)
}
auto resdir = paths->getResources();
scripting::initialize(paths);
scripting::initialize(this);
std::cout << "-- loading assets" << std::endl;
std::vector<fs::path> roots {resdir};

View File

@ -1,146 +1,334 @@
#include "InventoryView.h"
#include <iostream>
#include <glm/glm.hpp>
#include "BlocksPreview.h"
#include "LevelFrontend.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../assets/Assets.h"
#include "../graphics/Atlas.h"
#include "../graphics/Shader.h"
#include "../graphics/Batch2D.h"
#include "../graphics/GfxContext.h"
#include "../graphics/Font.h"
#include "../content/Content.h"
#include "../items/ItemDef.h"
#include "../items/Inventory.h"
#include "../maths/voxmaths.h"
#include "../objects/Player.h"
#include "../voxels/Block.h"
#include "../frontend/gui/controls.h"
#include "../util/stringutil.h"
InventoryLayout::InventoryLayout(glm::vec2 size) : size(size) {}
void InventoryLayout::add(SlotLayout slot) {
slots.push_back(slot);
}
void InventoryLayout::setSize(glm::vec2 size) {
this->size = size;
}
void InventoryLayout::setOrigin(glm::vec2 origin) {
this->origin = origin;
}
glm::vec2 InventoryLayout::getSize() const {
return size;
}
glm::vec2 InventoryLayout::getOrigin() const {
return origin;
}
std::vector<SlotLayout>& InventoryLayout::getSlots() {
return slots;
}
SlotLayout::SlotLayout(
glm::vec2 position,
bool background,
bool itemSource,
itemsharefunc shareFunc,
slotcallback rightClick
)
: position(position),
background(background),
itemSource(itemSource),
shareFunc(shareFunc),
rightClick(rightClick) {}
InventoryPanel::InventoryPanel(
glm::vec2 position,
glm::vec2 size,
glm::vec4 color)
: position(position), size(size), color(color) {}
InventoryBuilder::InventoryBuilder()
: layout(std::make_unique<InventoryLayout>(glm::vec2()))
{}
void InventoryBuilder::addGrid(
int cols, int rows,
glm::vec2 coord,
int padding,
SlotLayout slotLayout)
{
const int slotSize = InventoryView::SLOT_SIZE;
const int interval = InventoryView::SLOT_INTERVAL;
uint width = cols * (slotSize + interval) - interval + padding*2;
uint height = rows * (slotSize + interval) - interval + padding*2;
auto lsize = layout->getSize();
if (coord.x + width > lsize.x) {
lsize.x = coord.x + width;
}
if (coord.y + height > lsize.y) {
lsize.y = coord.y + height;
}
layout->setSize(lsize);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
glm::vec2 position (
col * (slotSize + interval) + padding,
row * (slotSize + interval) + padding
);
auto builtSlot = slotLayout;
builtSlot.position = position;
layout->add(builtSlot);
}
}
}
std::unique_ptr<InventoryLayout> InventoryBuilder::build() {
return std::unique_ptr<InventoryLayout>(layout.release());
}
SlotView::SlotView(
ItemStack& stack,
LevelFrontend* frontend,
InventoryInteraction* interaction,
const Content* content,
SlotLayout layout)
: UINode(glm::vec2(), glm::vec2(InventoryView::SLOT_SIZE)),
frontend(frontend),
interaction(interaction),
content(content),
stack(stack),
layout(layout) {
color(glm::vec4(0, 0, 0, 0.2f));
}
// performance disaster
void SlotView::draw(Batch2D* batch, Assets* assets) {
glm::vec2 coord = calcCoord();
int slotSize = InventoryView::SLOT_SIZE;
glm::vec4 tint(1.0f);
glm::vec4 color = color_;
if (hover_ || highlighted) {
tint *= 1.333f;
color = glm::vec4(1, 1, 1, 0.2f);
}
batch->color = color;
if (color.a > 0.0) {
batch->texture(nullptr);
if (highlighted) {
batch->rect(coord.x-4, coord.y-4, slotSize+8, slotSize+8);
} else {
batch->rect(coord.x, coord.y, slotSize, slotSize);
}
}
batch->color = glm::vec4(1.0f);
Shader* uiShader = assets->getShader("ui");
Viewport viewport(Window::width, Window::height);
GfxContext ctx(nullptr, viewport, batch);
auto preview = frontend->getBlocksPreview();
auto indices = content->getIndices();
ItemDef* item = indices->getItemDef(stack.getItemId());
switch (item->iconType) {
case item_icon_type::none:
break;
case item_icon_type::block:
batch->render();
{
GfxContext subctx = ctx.sub();
subctx.depthTest(true);
subctx.cullFace(true);
Block* cblock = content->requireBlock(item->icon);
preview->begin(&subctx.getViewport());
preview->draw(cblock, coord.x, coord.y, slotSize, tint);
}
uiShader->use();
batch->begin();
break;
case item_icon_type::sprite: {
size_t index = item->icon.find(':');
std::string name = item->icon.substr(index+1);
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
if (index == std::string::npos) {
batch->texture(assets->getTexture(name));
} else {
std::string atlasname = item->icon.substr(0, index);
Atlas* atlas = assets->getAtlas(atlasname);
if (atlas && atlas->has(name)) {
region = atlas->get(name);
batch->texture(atlas->getTexture());
}
}
batch->rect(
coord.x, coord.y, slotSize, slotSize,
0, 0, 0, region, false, true, tint);
break;
}
}
if (stack.getCount() > 1) {
auto font = assets->getFont("normal");
std::wstring text = std::to_wstring(stack.getCount());
int x = coord.x+slotSize-text.length()*8;
int y = coord.y+slotSize-16;
batch->color = glm::vec4(0, 0, 0, 1.0f);
font->draw(batch, text, x+1, y+1);
batch->color = glm::vec4(1.0f);
font->draw(batch, text, x, y);
}
}
void SlotView::setHighlighted(bool flag) {
highlighted = flag;
}
bool SlotView::isHighlighted() const {
return highlighted;
}
void SlotView::clicked(gui::GUI* gui, int button) {
ItemStack& grabbed = interaction->getGrabbedItem();
if (button == mousecode::BUTTON_1) {
if (Events::pressed(keycode::LEFT_SHIFT)) {
if (layout.shareFunc) {
layout.shareFunc(stack);
}
return;
}
if (!layout.itemSource && stack.accepts(grabbed)) {
stack.move(grabbed, content->getIndices());
} else {
if (layout.itemSource) {
if (grabbed.isEmpty()) {
grabbed.set(stack);
} else {
grabbed.clear();
}
} else {
std::swap(grabbed, stack);
}
}
} else if (button == mousecode::BUTTON_2) {
if (layout.rightClick) {
layout.rightClick(stack, grabbed);
return;
}
if (layout.itemSource)
return;
if (grabbed.isEmpty()) {
if (!stack.isEmpty()) {
grabbed.set(stack);
int halfremain = stack.getCount() / 2;
grabbed.setCount(stack.getCount() - halfremain);
stack.setCount(halfremain);
}
} else {
if (stack.isEmpty()) {
stack.set(grabbed);
stack.setCount(1);
} else {
stack.setCount(stack.getCount()+1);
}
grabbed.setCount(grabbed.getCount()-1);
}
}
}
InventoryView::InventoryView(
int columns,
const Content* content,
LevelFrontend* frontend,
std::vector<itemid_t> items)
: content(content),
InventoryInteraction* interaction,
std::shared_ptr<Inventory> inventory,
std::unique_ptr<InventoryLayout> layout)
: Container(glm::vec2(), glm::vec2()),
content(content),
indices(content->getIndices()),
items(items),
inventory(inventory),
layout(std::move(layout)),
frontend(frontend),
columns(columns) {
interaction(interaction) {
size(this->layout->getSize());
color(glm::vec4(0, 0, 0, 0.5f));
}
InventoryView::~InventoryView() {
}
InventoryView::~InventoryView() {}
void InventoryView::setPosition(int x, int y) {
position.x = x;
position.y = y;
}
void InventoryView::build() {
int index = 0;
for (auto& slot : layout->getSlots()) {
ItemStack& item = inventory->getSlot(index);
int InventoryView::getWidth() const {
return columns * iconSize + (columns-1) * interval + padding.x * 2;
}
int InventoryView::getHeight() const {
uint inv_rows = ceildiv(items.size(), columns);
return inv_rows * iconSize + (inv_rows-1) * interval + padding.y * 2;
}
void InventoryView::setSlotConsumer(slotconsumer consumer) {
this->consumer = consumer;
}
void InventoryView::setItems(std::vector<itemid_t> items) {
this->items = items;
}
void InventoryView::actAndDraw(const GfxContext* ctx) {
Assets* assets = frontend->getAssets();
Shader* uiShader = assets->getShader("ui");
auto viewport = ctx->getViewport();
uint inv_w = getWidth();
uint inv_h = getHeight();
int xs = position.x + padding.x;
int ys = position.y + padding.y;
glm::vec4 tint (1.0f);
int mx = Events::cursor.x;
int my = Events::cursor.y;
// background
auto batch = ctx->getBatch2D();
batch->texture(nullptr);
batch->color = glm::vec4(0.0f, 0.0f, 0.0f, 0.5f);
batch->rect(position.x, position.y, inv_w, inv_h);
batch->render();
// blocks & items
if (Events::scroll) {
scroll -= Events::scroll * (iconSize+interval);
auto view = std::make_shared<SlotView>(
item, frontend, interaction, content, slot
);
if (!slot.background) {
view->color(glm::vec4());
}
slots.push_back(view.get());
add(view, slot.position);
index++;
}
scroll = std::min(scroll, int(inv_h-viewport.getHeight()));
scroll = std::max(scroll, 0);
auto blocksPreview = frontend->getBlocksPreview();
// todo: optimize
{
Window::clearDepth();
GfxContext subctx = ctx->sub();
subctx.depthTest(true);
subctx.cullFace(true);
uint index = 0;
for (uint i = 0; i < items.size(); i++) {
ItemDef* item = indices->getItemDef(items[i]);
int x = xs + (iconSize+interval) * (index % columns);
int y = ys + (iconSize+interval) * (index / columns) - scroll;
if (y < -int(iconSize+interval) || y >= int(viewport.getHeight())) {
index++;
continue;
}
if (mx > x && mx < x + (int)iconSize && my > y && my < y + (int)iconSize) {
tint.r *= 1.2f;
tint.g *= 1.2f;
tint.b *= 1.2f;
if (Events::jclicked(mousecode::BUTTON_1)) {
if (consumer) {
consumer(items[i]);
}
}
} else {
tint = glm::vec4(1.0f);
}
switch (item->iconType) {
case item_icon_type::none:
break;
case item_icon_type::block: {
Block* cblock = content->requireBlock(item->icon);
blocksPreview->begin(&ctx->getViewport());
blocksPreview->draw(cblock, x, y, iconSize, tint);
break;
}
case item_icon_type::sprite: {
batch->begin();
uiShader->use();
size_t index = item->icon.find(':');
std::string name = item->icon.substr(index+1);
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
if (index == std::string::npos) {
batch->texture(assets->getTexture(name));
} else {
std::string atlasname = item->icon.substr(0, index);
Atlas* atlas = assets->getAtlas(atlasname);
if (atlas && atlas->has(name)) {
region = atlas->get(name);
batch->texture(atlas->getTexture());
}
}
batch->rect(x, y, 48, 48, 0, 0, 0, region, false, true, glm::vec4(1.0f));
batch->render();
break;
}
}
index++;
}
}
uiShader->use();
}
void InventoryView::setSelected(int index) {
for (int i = 0; i < int(slots.size()); i++) {
auto slot = slots[i];
slot->setHighlighted(i == index);
}
}
void InventoryView::setCoord(glm::vec2 coord) {
Container::setCoord(coord - layout->getOrigin());
}
void InventoryView::setInventory(std::shared_ptr<Inventory> inventory) {
this->inventory = inventory;
}
InventoryLayout* InventoryView::getLayout() const {
return layout.get();
}
// performance disaster x2
void InventoryView::draw(Batch2D* batch, Assets* assets) {
Container::draw(batch, assets);
Window::clearDepth();
}
void InventoryView::drawBackground(Batch2D* batch, Assets* assets) {
glm::vec2 coord = calcCoord();
batch->texture(nullptr);
batch->color = color_;
batch->rect(coord.x-1, coord.y-1, size_.x+2, size_.y+2);
}

View File

@ -5,46 +5,150 @@
#include <functional>
#include <glm/glm.hpp>
#include "../frontend/gui/UINode.h"
#include "../frontend/gui/panels.h"
#include "../frontend/gui/controls.h"
#include "../items/ItemStack.h"
#include "../typedefs.h"
class Batch2D;
class Assets;
class GfxContext;
class Content;
class ContentIndices;
class LevelFrontend;
class Inventory;
typedef std::function<void(itemid_t)> slotconsumer;
typedef std::function<void(ItemStack&)> itemsharefunc;
typedef std::function<void(ItemStack&, ItemStack&)> slotcallback;
class InventoryView {
class InventoryInteraction;
struct SlotLayout {
glm::vec2 position;
bool background;
bool itemSource;
itemsharefunc shareFunc;
slotcallback rightClick;
SlotLayout(glm::vec2 position,
bool background,
bool itemSource,
itemsharefunc shareFunc,
slotcallback rightClick);
};
// temporary unused
struct InventoryPanel {
glm::vec2 position;
glm::vec2 size;
glm::vec4 color;
InventoryPanel(glm::vec2 position,
glm::vec2 size,
glm::vec4 color);
};
class InventoryLayout {
glm::vec2 size;
glm::vec2 origin;
std::vector<SlotLayout> slots;
public:
InventoryLayout(glm::vec2 size);
void add(SlotLayout slot);
void setSize(glm::vec2 size);
void setOrigin(glm::vec2 origin);
glm::vec2 getSize() const;
glm::vec2 getOrigin() const;
std::vector<SlotLayout>& getSlots();
};
class InventoryBuilder {
std::unique_ptr<InventoryLayout> layout;
public:
InventoryBuilder();
void addGrid(
int cols, int rows,
glm::vec2 coord,
int padding,
SlotLayout slotLayout);
std::unique_ptr<InventoryLayout> build();
};
class SlotView : public gui::UINode {
LevelFrontend* frontend;
InventoryInteraction* interaction;
const Content* const content;
ItemStack& stack;
bool highlighted = false;
SlotLayout layout;
public:
SlotView(ItemStack& stack,
LevelFrontend* frontend,
InventoryInteraction* interaction,
const Content* content,
SlotLayout layout);
virtual void draw(Batch2D* batch, Assets* assets) override;
void setHighlighted(bool flag);
bool isHighlighted() const;
virtual void clicked(gui::GUI*, int) override;
};
class InventoryView : public gui::Container {
const Content* content;
const ContentIndices* indices;
std::vector<itemid_t> items;
slotconsumer consumer = nullptr;
std::shared_ptr<Inventory> inventory;
std::unique_ptr<InventoryLayout> layout;
LevelFrontend* frontend;
InventoryInteraction* interaction;
std::vector<SlotView*> slots;
int scroll = 0;
int columns;
uint iconSize = 48;
uint interval = 4;
glm::ivec2 padding {interval, interval};
glm::ivec2 position {0, 0};
public:
InventoryView(
int columns,
const Content* content,
LevelFrontend* frontend,
std::vector<itemid_t> items);
InventoryInteraction* interaction,
std::shared_ptr<Inventory> inventory,
std::unique_ptr<InventoryLayout> layout);
virtual ~InventoryView();
virtual void actAndDraw(const GfxContext* ctx);
void build();
void setItems(std::vector<itemid_t> items);
virtual void draw(Batch2D* batch, Assets* assets) override;
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
void setPosition(int x, int y);
int getWidth() const;
int getHeight() const;
void setSlotConsumer(slotconsumer consumer);
void setInventory(std::shared_ptr<Inventory> inventory);
virtual void setCoord(glm::vec2 coord) override;
InventoryLayout* getLayout() const;
void setSelected(int index);
static const int SLOT_INTERVAL = 4;
static const int SLOT_SIZE = 48;
};
class InventoryInteraction {
ItemStack grabbedItem;
public:
InventoryInteraction() = default;
ItemStack& getGrabbedItem() {
return grabbedItem;
}
};
#endif // FRONTEND_INVENTORY_VIEW_H_

View File

@ -28,6 +28,8 @@
#include "../settings.h"
#include "../engine.h"
#include "../items/ItemDef.h"
#include "../items/ItemStack.h"
#include "../items/Inventory.h"
#include "LevelFrontend.h"
#include "graphics/Skybox.h"
@ -169,8 +171,10 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible
shader->uniform3f("u_cameraPos", camera->position);
shader->uniform1i("u_cubemap", 1);
{
itemid_t id = level->player->getChosenItem();
ItemDef* item = indices->getItemDef(id);
auto player = level->player;
auto inventory = player->getInventory();
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
ItemDef* item = indices->getItemDef(stack.getItemId());
assert(item != nullptr);
float multiplier = 0.5f;
shader->uniform3f("u_torchlightColor",

View File

@ -40,7 +40,6 @@ PagesControl* GUI::getMenu() {
}
void GUI::actMouse(float delta) {
auto hover = container->getAt(Events::cursor, nullptr);
if (this->hover && this->hover != hover) {
this->hover->hover(false);
@ -53,7 +52,7 @@ void GUI::actMouse(float delta) {
}
this->hover = hover;
if (Events::jclicked(0)) {
if (Events::jclicked(mousecode::BUTTON_1)) {
if (pressed == nullptr && this->hover) {
pressed = hover;
pressed->click(this, Events::cursor.x, Events::cursor.y);
@ -73,6 +72,14 @@ void GUI::actMouse(float delta) {
pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y);
pressed = nullptr;
}
if (hover) {
for (int i = mousecode::BUTTON_1; i < mousecode::BUTTON_1+12; i++) {
if (Events::jclicked(i)) {
hover->clicked(this, i);
}
}
}
}
void GUI::act(float delta) {
@ -100,13 +107,6 @@ void GUI::act(float delta) {
if (Events::clicked(mousecode::BUTTON_1)) {
focus->mouseMove(this, Events::cursor.x, Events::cursor.y);
}
if (prevfocus == focus){
for (int i = mousecode::BUTTON_1; i < mousecode::BUTTON_1+12; i++) {
if (Events::jclicked(i)) {
focus->clicked(this, i);
}
}
}
}
}
}

View File

@ -10,8 +10,6 @@ using gui::Align;
using glm::vec2;
using glm::vec4;
#include <iostream>
UINode::UINode(vec2 coord, vec2 size) : coord(coord), size_(size) {
}
@ -78,9 +76,20 @@ bool UINode::isInside(glm::vec2 pos) {
}
shared_ptr<UINode> UINode::getAt(vec2 pos, shared_ptr<UINode> self) {
if (!interactive) {
return nullptr;
}
return isInside(pos) ? self : nullptr;
}
bool UINode::isInteractive() const {
return interactive && visible();
}
void UINode::setInteractive(bool flag) {
interactive = flag;
}
vec2 UINode::calcCoord() const {
if (parent) {
return coord + parent->calcCoord() + parent->contentOffset();

View File

@ -30,6 +30,7 @@ namespace gui {
bool hover_ = false;
bool pressed_ = false;
bool focused_ = false;
bool interactive = true;
Align align_ = Align::left;
UINode* parent = nullptr;
UINode(glm::vec2 coord, glm::vec2 size);
@ -74,9 +75,12 @@ namespace gui {
virtual bool isInside(glm::vec2 pos);
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
virtual bool isInteractive() const;
virtual void setInteractive(bool flag);
virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);};
glm::vec2 calcCoord() const;
void setCoord(glm::vec2 coord);
virtual void setCoord(glm::vec2 coord);
glm::vec2 size() const;
virtual void size(glm::vec2 size);
void _size(glm::vec2 size);

View File

@ -62,8 +62,21 @@ void Label::size(vec2 sizenew) {
UINode::size(vec2(UINode::size().x, sizenew.y));
}
// ================================= Image ====================================
Image::Image(string texture, vec2 size) : UINode(vec2(), size), texture(texture) {
}
void Image::draw(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
batch->texture(assets->getTexture(texture));
batch->color = color_;
batch->rect(coord.x, coord.y, size_.x, size_.y, 0, 0, 0, UVRegion(), false, true, color_);
}
// ================================= Button ===================================
Button::Button(shared_ptr<UINode> content, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) {
Button::Button(shared_ptr<UINode> content, glm::vec4 padding)
: Panel(content->size()+vec2(padding[0]+padding[2]+content->margin()[0]+content->margin()[2],
padding[1]+padding[3]+content->margin()[1]+content->margin()[3]), padding, 0) {
add(content);
scrollable(false);
}
@ -100,6 +113,11 @@ Button* Button::textSupplier(wstringsupplier supplier) {
}
return this;
}
void Button::setHoverColor(glm::vec4 color) {
hoverColor = color;
}
void Button::drawBackground(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
batch->texture(nullptr);
@ -133,6 +151,35 @@ void Button::textAlign(Align align) {
}
}
// ============================== RichButton ==================================
RichButton::RichButton(vec2 size) : Container(vec2(), size) {
}
void RichButton::mouseRelease(GUI* gui, int x, int y) {
UINode::mouseRelease(gui, x, y);
if (isInside(vec2(x, y))) {
for (auto callback : actions) {
callback(gui);
}
}
}
RichButton* RichButton::listenAction(onaction action) {
actions.push_back(action);
return this;
}
void RichButton::setHoverColor(glm::vec4 color) {
hoverColor = color;
}
void RichButton::drawBackground(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
batch->texture(nullptr);
batch->color = (ispressed() ? pressedColor : (hover_ ? hoverColor : color_));
batch->rect(coord.x, coord.y, size_.x, size_.y);
}
// ================================ TextBox ===================================
TextBox::TextBox(wstring placeholder, vec4 padding)
: Panel(vec2(200,32), padding, 0, false),

View File

@ -43,6 +43,15 @@ namespace gui {
virtual void size(glm::vec2 size) override;
};
class Image : public UINode {
protected:
std::string texture;
public:
Image(std::string texture, glm::vec2 size);
virtual void draw(Batch2D* batch, Assets* assets) override;
};
class Button : public Panel {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
@ -55,7 +64,7 @@ namespace gui {
glm::vec4 padding=glm::vec4(2.0f),
glm::vec4 margin=glm::vec4(1.0f));
virtual void drawBackground(Batch2D* batch, Assets* assets);
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
@ -68,6 +77,24 @@ namespace gui {
virtual std::wstring text() const;
virtual Button* textSupplier(wstringsupplier supplier);
virtual void setHoverColor(glm::vec4 color);
};
class RichButton : public Container {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.15f, 0.75f};
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
public:
RichButton(glm::vec2 size);
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
virtual void mouseRelease(GUI*, int x, int y) override;
virtual RichButton* listenAction(onaction action);
virtual void setHoverColor(glm::vec4 color);
};
class TextBox : public Panel {

View File

@ -18,6 +18,9 @@ Container::Container(vec2 coord, vec2 size) : UINode(coord, size) {
}
shared_ptr<UINode> Container::getAt(vec2 pos, shared_ptr<UINode> self) {
if (!interactive) {
return nullptr;
}
if (!isInside(pos)) return nullptr;
for (auto node : nodes) {
if (!node->visible())
@ -58,7 +61,7 @@ void Container::act(float delta) {
void Container::scrolled(int value) {
int diff = (actualLength-size().y);
if (diff > 0 && scrollable_) {
scroll += value * 20;
scroll += value * 40;
if (scroll > 0)
scroll = 0;
if (-scroll > diff) {
@ -98,6 +101,11 @@ void Container::add(UINode* node) {
add(shared_ptr<UINode>(node));
}
void Container::add(shared_ptr<UINode> node, glm::vec2 coord) {
node->setCoord(coord);
add(node);
}
void Container::remove(shared_ptr<UINode> selected) {
selected->setParent(nullptr);
nodes.erase(std::remove_if(nodes.begin(), nodes.end(),
@ -190,15 +198,12 @@ void Panel::refresh() {
node->refresh();
maxh = fmax(maxh, y+margin.y+node->size().y+margin.w+padding.w);
}
bool increased = maxh > size.y;
if (resizing_) {
if (maxLength_)
this->size(vec2(glm::min(maxLength_, (int)(x+padding.z)), size.y));
else
this->size(vec2(x+padding.z, size.y));
}
if (increased)
refresh();
actualLength = size.y;
}
}
@ -273,4 +278,4 @@ void PagesControl::reset() {
Container::remove(current_.panel);
current_ = Page{nullptr};
}
}
}

View File

@ -39,6 +39,7 @@ namespace gui {
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void add(std::shared_ptr<UINode> node);
virtual void add(UINode* node);
virtual void add(std::shared_ptr<UINode> node, glm::vec2 coord);
virtual void remove(std::shared_ptr<UINode> node);
virtual void scrolled(int value) override;
virtual void scrollable(bool flag);

View File

@ -44,6 +44,7 @@
#include "../engine.h"
#include "../core_defs.h"
#include "../items/ItemDef.h"
#include "../items/Inventory.h"
using glm::vec2;
using glm::vec3;
@ -163,26 +164,142 @@ void HudRenderer::createDebugPanel(Engine* engine) {
panel->refresh();
}
std::shared_ptr<InventoryView> HudRenderer::createContentAccess() {
auto level = frontend->getLevel();
auto content = level->content;
auto indices = content->getIndices();
auto player = level->player;
auto inventory = player->getInventory();
int itemsCount = indices->countItemDefs();
auto accessInventory = std::make_shared<Inventory>(itemsCount);
for (int id = 1; id < itemsCount; id++) {
accessInventory->getSlot(id-1).set(ItemStack(id, 1));
}
const int slotSize = InventoryView::SLOT_SIZE;
const int interval = InventoryView::SLOT_INTERVAL;
int padding = 8;
int columns = 8;
int rows = ceildiv(itemsCount-1, columns);
uint cawidth = columns * (slotSize + interval) - interval + padding;
uint caheight = rows * (slotSize + interval) - interval + padding*2;
auto layout = std::make_unique<InventoryLayout>(glm::vec2(cawidth, caheight));
for (int i = 0; i < itemsCount-1; i++) {
int row = i / columns;
int col = i % columns;
glm::vec2 position (
col * slotSize + (col-1) * interval + padding,
row * slotSize + (row-1) * interval + padding
);
layout->add(SlotLayout(position, false, true,
[=](ItemStack& item) {
auto copy = ItemStack(item);
inventory->move(copy, indices);
},
[=](ItemStack& item, ItemStack& grabbed) {
inventory->getSlot(player->getChosenSlot()).set(item);
}));
}
auto contentAccess = std::make_shared<InventoryView>(
content,
frontend,
interaction.get(),
accessInventory,
std::move(layout)
);
contentAccess->build();
return contentAccess;
}
std::shared_ptr<InventoryView> HudRenderer::createHotbar() {
auto level = frontend->getLevel();
auto player = level->player;
auto inventory = player->getInventory();
auto content = level->content;
const int slotSize = InventoryView::SLOT_SIZE;
const int interval = InventoryView::SLOT_INTERVAL;
int padding = 4;
uint width = 10 * (slotSize + interval) - interval + padding*2;
uint height = slotSize + padding * 2;
auto layout = std::make_unique<InventoryLayout>(glm::vec2(width, height));
for (int i = 0; i < 10; i++) {
glm::vec2 position (i * (slotSize + interval) + padding, padding);
layout->add(SlotLayout(position, false, false, nullptr, nullptr));
}
layout->setOrigin(glm::vec2(width / 2, 0));
auto view = std::make_shared<InventoryView>(
content,
frontend,
interaction.get(),
inventory,
std::move(layout)
);
view->build();
view->setInteractive(false);
return view;
}
std::shared_ptr<InventoryView> HudRenderer::createInventory() {
auto level = frontend->getLevel();
auto player = level->player;
auto inventory = player->getInventory();
auto content = level->content;
SlotLayout slotLayout(glm::vec2(), true, false, [=](ItemStack& stack) {
stack.clear();
}, nullptr);
int columns = 10;
int rows = ceildiv(inventory->size(), columns);
int padding = 4;
InventoryBuilder builder;
builder.addGrid(columns, rows, glm::vec2(), padding, slotLayout);
auto layout = builder.build();
auto view = std::make_shared<InventoryView>(
content,
frontend,
interaction.get(),
inventory,
std::move(layout)
);
view->build();
return view;
}
HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend)
: assets(engine->getAssets()),
gui(engine->getGUI()),
frontend(frontend) {
auto level = frontend->getLevel();
frontend(frontend)
{
auto menu = gui->getMenu();
auto content = level->content;
auto indices = content->getIndices();
std::vector<itemid_t> items;
for (itemid_t id = 1; id < indices->countItemDefs(); id++) {
items.push_back(id);
}
contentAccess.reset(new InventoryView(8, content, frontend, items));
contentAccess->setSlotConsumer([=](blockid_t id) {
level->player->setChosenItem(id);
});
interaction = std::make_unique<InventoryInteraction>();
grabbedItemView = std::make_shared<SlotView>(
interaction->getGrabbedItem(),
frontend,
interaction.get(),
frontend->getLevel()->content,
SlotLayout(glm::vec2(), false, false, nullptr, nullptr)
);
grabbedItemView->color(glm::vec4());
grabbedItemView->setInteractive(false);
hotbarView.reset(new InventoryView(1, content, frontend, std::vector<itemid_t> {0}));
contentAccess = createContentAccess();
contentAccessPanel = std::make_shared<Panel>(
contentAccess->size(), vec4(0.0f), 0.0f
);
contentAccessPanel->color(glm::vec4());
contentAccessPanel->add(contentAccess);
contentAccessPanel->scrollable(true);
hotbarView = createHotbar();
inventoryView = createInventory();
uicamera = new Camera(vec3(), 1);
uicamera->perspective = false;
@ -191,10 +308,18 @@ HudRenderer::HudRenderer(Engine* engine, LevelFrontend* frontend)
createDebugPanel(engine);
menu->reset();
gui->add(this->debugPanel);
gui->add(debugPanel);
gui->add(contentAccessPanel);
gui->add(hotbarView);
gui->add(inventoryView);
gui->add(grabbedItemView);
}
HudRenderer::~HudRenderer() {
gui->remove(grabbedItemView);
gui->remove(inventoryView);
gui->remove(hotbarView);
gui->remove(contentAccessPanel);
gui->remove(debugPanel);
delete uicamera;
}
@ -206,7 +331,12 @@ void HudRenderer::drawDebug(int fps){
}
void HudRenderer::update(bool visible) {
auto level = frontend->getLevel();
auto player = level->player;
auto menu = gui->getMenu();
menu->visible(pause);
if (!visible && inventoryOpen) {
inventoryOpen = false;
}
@ -232,13 +362,35 @@ void HudRenderer::update(bool visible) {
if ((pause || inventoryOpen) == Events::_cursor_locked) {
Events::toggleCursor();
}
glm::vec2 invSize = contentAccessPanel->size();
inventoryView->visible(inventoryOpen);
contentAccessPanel->visible(inventoryOpen);
contentAccessPanel->size(glm::vec2(invSize.x, Window::height));
for (int i = keycode::NUM_1; i <= keycode::NUM_9; i++) {
if (Events::jpressed(i)) {
player->setChosenSlot(i - keycode::NUM_1);
}
}
if (Events::jpressed(keycode::NUM_0)) {
player->setChosenSlot(9);
}
if (!inventoryOpen && Events::scroll) {
int slot = player->getChosenSlot();
slot = (slot + Events::scroll) % 10;
if (slot < 0) {
slot += 10;
}
player->setChosenSlot(slot);
}
}
void HudRenderer::drawOverlay(const GfxContext& ctx) {
if (pause) {
Shader* uishader = assets->getShader("ui");
uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
uishader->uniformMatrix("u_projview", uicamera->getProjView());
const Viewport& viewport = ctx.getViewport();
const uint width = viewport.getWidth();
@ -271,12 +423,11 @@ void HudRenderer::draw(const GfxContext& ctx){
Shader* uishader = assets->getShader("ui");
uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
uishader->uniformMatrix("u_projview", uicamera->getProjView());
// Draw selected item preview
hotbarView->setPosition(width-60, height-60);
hotbarView->setItems({player->getChosenItem()});
hotbarView->actAndDraw(&ctx);
hotbarView->setCoord(glm::vec2(width/2, height-65));
hotbarView->setSelected(player->getChosenSlot());
// Crosshair
batch->begin();
@ -289,10 +440,20 @@ void HudRenderer::draw(const GfxContext& ctx){
}
if (inventoryOpen) {
// draw content access panel (all available items)
contentAccess->setPosition(viewport.getWidth()-contentAccess->getWidth(), 0);
contentAccess->actAndDraw(&ctx);
auto caLayout = contentAccess->getLayout();
auto invLayout = inventoryView->getLayout();
float caWidth = caLayout->getSize().x;
glm::vec2 invSize = invLayout->getSize();
float width = viewport.getWidth();
inventoryView->setCoord(glm::vec2(
glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x),
height/2-invSize.y/2
));
contentAccessPanel->setCoord(glm::vec2(width-caWidth, 0));
}
grabbedItemView->setCoord(glm::vec2(Events::cursor));
batch->render();
}

View File

@ -15,12 +15,15 @@ class Assets;
class Player;
class Level;
class Engine;
class SlotView;
class InventoryView;
class LevelFrontend;
class InventoryInteraction;
namespace gui {
class GUI;
class UINode;
class Panel;
}
class HudRenderer {
@ -34,13 +37,21 @@ class HudRenderer {
bool inventoryOpen = false;
bool pause = false;
std::unique_ptr<InventoryView> contentAccess;
std::unique_ptr<InventoryView> hotbarView;
std::shared_ptr<gui::Panel> contentAccessPanel;
std::shared_ptr<InventoryView> contentAccess;
std::shared_ptr<InventoryView> hotbarView;
std::shared_ptr<InventoryView> inventoryView;
std::shared_ptr<gui::UINode> debugPanel;
std::unique_ptr<InventoryInteraction> interaction;
std::shared_ptr<SlotView> grabbedItemView;
gui::GUI* gui;
LevelFrontend* frontend;
void createDebugPanel(Engine* engine);
std::shared_ptr<InventoryView> createContentAccess();
std::shared_ptr<InventoryView> createHotbar();
std::shared_ptr<InventoryView> createInventory();
public:
HudRenderer(Engine* engine, LevelFrontend* frontend);
~HudRenderer();

View File

@ -195,13 +195,40 @@ Panel* create_worlds_panel(Engine* engine) {
if (!entry.is_directory()) {
continue;
}
auto name = entry.path().filename().u8string();
auto btn = new Button(util::str2wstr_utf8(name),
vec4(10.0f, 8.0f, 10.0f, 8.0f));
auto folder = entry.path();
auto name = folder.filename().u8string();
auto namews = util::str2wstr_utf8(name);
auto btn = std::make_shared<RichButton>(vec2(390, 46));
btn->color(vec4(1.0f, 1.0f, 1.0f, 0.1f));
btn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
auto label = std::make_shared<Label>(namews);
label->setInteractive(false);
btn->add(label, vec2(8, 8));
btn->listenAction([=](GUI*) {
open_world(name, engine);
});
auto image = std::make_shared<Image>("gui/delete_icon", vec2(32, 32));
image->color(vec4(1, 1, 1, 0.5f));
auto delbtn = std::make_shared<Button>(image, vec4(2));
delbtn->color(vec4(0.0f));
delbtn->setHoverColor(vec4(1.0f, 1.0f, 1.0f, 0.17f));
btn->add(delbtn, vec2(330, 3));
delbtn->listenAction([=](GUI* gui) {
guiutil::confirm(gui, langs::get(L"delete-confirm", L"world")+
L" ("+util::str2wstr_utf8(folder.u8string())+L")", [=]()
{
std::cout << "deleting " << folder.u8string() << std::endl;
fs::remove_all(folder);
menus::refresh_menus(engine, gui->getMenu());
});
});
panel->add(btn);
}
}

View File

@ -73,7 +73,7 @@ void MenuScreen::draw(float delta) {
uint height = Window::height;
batch->begin();
batch->texture(engine->getAssets()->getTexture("menubg"));
batch->texture(engine->getAssets()->getTexture("gui/menubg"));
batch->rect(0, 0,
width, height, 0, 0, 0,
UVRegion(0, 0, width/64, height/64),

74
src/items/Inventory.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "Inventory.h"
Inventory::Inventory(size_t size) : slots(size) {
}
ItemStack& Inventory::getSlot(size_t index) {
return slots[index];
}
size_t Inventory::findEmptySlot(size_t begin, size_t end) const {
end = std::min(slots.size(), end);
for (size_t i = begin; i < end; i++) {
if (slots[i].isEmpty()) {
return i;
}
}
return npos;
}
size_t Inventory::findSlotByItem(itemid_t id, size_t begin, size_t end) {
end = std::min(slots.size(), end);
for (size_t i = begin; i < end; i++) {
if (slots[i].getItemId() == id) {
return i;
}
}
return npos;
}
void Inventory::move(
ItemStack& item,
const ContentIndices* indices,
size_t begin,
size_t end)
{
end = std::min(slots.size(), end);
for (size_t i = begin; i < end && !item.isEmpty(); i++) {
ItemStack& slot = slots[i];
if (slot.accepts(item)) {
slot.move(item, indices);
}
}
}
void Inventory::read(const dynamic::Map* src) {
auto slotsarr = src->list("slots");
size_t slotscount = std::min(slotsarr->size(), slots.size());
for (size_t i = 0; i < slotscount; i++) {
auto item = slotsarr->map(i);
itemid_t id = item->getInt("id", ITEM_EMPTY);
itemcount_t count = item->getInt("count", 0);
auto& slot = slots[i];
slot.set(ItemStack(id, count));
}
}
std::unique_ptr<dynamic::Map> Inventory::write() const {
auto map = std::make_unique<dynamic::Map>();
auto& slotsarr = map->putList("slots");
for (size_t i = 0; i < slots.size(); i++) {
auto& item = slots[i];
itemid_t id = item.getItemId();
itemcount_t count = item.getCount();
auto& slotmap = slotsarr.putMap();
slotmap.put("id", id);
if (count) {
slotmap.put("count", count);
}
}
return map;
}
const size_t Inventory::npos = -1;

41
src/items/Inventory.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef ITEMS_INVENTORY_H_
#define ITEMS_INVENTORY_H_
#include <vector>
#include <memory>
#include "ItemStack.h"
#include "../typedefs.h"
#include "../data/dynamic.h"
class ContentIndices;
class Inventory {
std::vector<ItemStack> slots;
public:
Inventory(size_t size);
ItemStack& getSlot(size_t index);
size_t findEmptySlot(size_t begin=0, size_t end=-1) const;
size_t findSlotByItem(itemid_t id, size_t begin=0, size_t end=-1);
inline size_t size() const {
return slots.size();
}
void move(
ItemStack& item,
const ContentIndices* indices,
size_t begin=0,
size_t end=-1);
/* deserializing inventory */
void read(const dynamic::Map* src);
/* serializing inventory */
std::unique_ptr<dynamic::Map> write() const;
static const size_t npos;
};
#endif // ITEMS_INVENTORY_H_

View File

@ -22,6 +22,7 @@ class ItemDef {
public:
std::string const name;
itemcount_t stackSize = 64;
bool generated = false;
uint8_t emission[4] {0, 0, 0, 0};
@ -29,6 +30,7 @@ public:
std::string icon = "blocks:notfound";
std::string placingBlock = "core:air";
std::string scriptName = name.substr(name.find(':')+1);
struct {
itemid_t id;

40
src/items/ItemStack.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "ItemStack.h"
#include "ItemDef.h"
#include "../content/Content.h"
ItemStack::ItemStack() : item(ITEM_EMPTY), count(0) {
}
ItemStack::ItemStack(itemid_t item, itemcount_t count) : item(item), count(count) {
}
void ItemStack::set(const ItemStack& item) {
this->item = item.item;
this->count = item.count;
}
bool ItemStack::accepts(const ItemStack& other) const {
if (isEmpty()) {
return true;
}
return item == other.getItemId();
}
void ItemStack::move(ItemStack& item, const ContentIndices* indices) {
auto def = indices->getItemDef(item.getItemId());
int count = std::min(item.count, def->stackSize-this->count);
if (isEmpty()) {
set(ItemStack(item.getItemId(), count));
} else {
setCount(this->count + count);
}
item.setCount(item.count-count);
}
void ItemStack::setCount(itemcount_t count) {
this->count = count;
if (count == 0) {
item = 0;
}
}

40
src/items/ItemStack.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef ITEMS_ITEM_STACK_H_
#define ITEMS_ITEM_STACK_H_
#include "../typedefs.h"
#include "../constants.h"
class ContentIndices;
class ItemStack {
itemid_t item;
itemcount_t count;
public:
ItemStack();
ItemStack(itemid_t item, itemcount_t count);
void set(const ItemStack& item);
void setCount(itemcount_t count);
bool accepts(const ItemStack& item) const;
void move(ItemStack& item, const ContentIndices* indices);
inline void clear() {
set(ItemStack(0, 0));
}
inline bool isEmpty() const {
return item == ITEM_EMPTY;
}
inline itemid_t getItemId() const {
return item;
}
inline itemcount_t getCount() const {
return count;
}
};
#endif // ITEMS_ITEM_STACK_H_

View File

@ -7,12 +7,11 @@
#include "../voxels/voxel.h"
#include "../voxels/Block.h"
#include "../constants.h"
#include "../typedefs.h"
#include <memory>
#include <iostream>
using std::shared_ptr;
Lighting::Lighting(const Content* content, Chunks* chunks)
: content(content), chunks(chunks) {
auto indices = content->getIndices();
@ -31,7 +30,7 @@ Lighting::~Lighting(){
void Lighting::clear(){
for (unsigned int index = 0; index < chunks->volume; index++){
shared_ptr<Chunk> chunk = chunks->chunks[index];
auto chunk = chunks->chunks[index];
if (chunk == nullptr)
continue;
Lightmap* lightmap = chunk->lightmap;
@ -98,10 +97,10 @@ void Lighting::onChunkLoaded(int cx, int cz){
const Block* const* blockDefs = content->getIndices()->getBlockDefs();
const Chunk* chunk = chunks->getChunk(cx, cz);
for (unsigned int y = 0; y < CHUNK_H; y++){
for (unsigned int z = 0; z < CHUNK_D; z++){
for (unsigned int x = 0; x < CHUNK_W; x++){
voxel vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x];
for (uint y = 0; y < CHUNK_H; y++){
for (uint z = 0; z < CHUNK_D; z++){
for (uint x = 0; x < CHUNK_W; x++){
voxel& vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x];
const Block* block = blockDefs[vox.id];
int gx = x + cx * CHUNK_W;
int gz = z + cz * CHUNK_D;

View File

@ -8,6 +8,7 @@
#include "../content/Content.h"
#include "../lighting/Lighting.h"
#include "../util/timeutil.h"
#include "../maths/fastmaths.h"
#include "scripting/scripting.h"
@ -89,7 +90,10 @@ void BlocksController::randomTick(int tickid, int parts) {
// timeutil::ScopeLogTimer timer(5000+tickid);
const int w = chunks->w;
const int d = chunks->d;
int segments = 4;
int segheight = CHUNK_H / segments;
auto indices = level->content->getIndices();
for (uint z = padding; z < d-padding; z++){
for (uint x = padding; x < w-padding; x++){
int index = z * w + x;
@ -98,13 +102,11 @@ void BlocksController::randomTick(int tickid, int parts) {
std::shared_ptr<Chunk> chunk = chunks->chunks[index];
if (chunk == nullptr || !chunk->isLighted())
continue;
int segments = 4;
int segheight = CHUNK_H / segments;
for (int s = 0; s < segments; s++) {
for (int i = 0; i < 3; i++) {
int bx = rand() % CHUNK_W;
int by = rand() % segheight + s * segheight;
int bz = rand() % CHUNK_D;
for (int i = 0; i < 4; i++) {
int bx = fastmaths::rand() % CHUNK_W;
int by = fastmaths::rand() % segheight + s * segheight;
int bz = fastmaths::rand() % CHUNK_D;
const voxel& vox = chunk->voxels[(by * CHUNK_D + bz) * CHUNK_W + bx];
Block* block = indices->getBlockDef(vox.id);
if (block->rt.funcsset.randupdate) {

View File

@ -40,11 +40,11 @@ void ChunksController::update(int64_t maxDuration) {
timeutil::Timer timer;
if (loadVisible()) {
int64_t mcs = timer.stop();
avgDurationMcs = mcs * 0.2 + avgDurationMcs * 0.8;
if (mcstotal + max(avgDurationMcs, mcs) * 2 < maxDuration * 1000) {
if (mcstotal + mcs * 2 < maxDuration * 1000) {
mcstotal += mcs;
continue;
}
mcstotal += mcs;
}
break;
}
@ -74,8 +74,8 @@ bool ChunksController::loadVisible(){
if (surrounding == MIN_SURROUNDING && !chunk->isLighted()) {
if (!chunk->isLoadedLights()) {
lighting->buildSkyLight(chunk->x, chunk->z);
}
lighting->onChunkLoaded(chunk->x, chunk->z);
}
lighting->onChunkLoaded(chunk->x, chunk->z);
chunk->setLighted(true);
return true;
}

View File

@ -13,6 +13,8 @@
#include "../window/Events.h"
#include "../window/input.h"
#include "../items/ItemDef.h"
#include "../items/ItemStack.h"
#include "../items/Inventory.h"
#include "scripting/scripting.h"
#include "BlocksController.h"
@ -239,7 +241,9 @@ void PlayerController::updateInteraction(){
int z = iend.z;
uint8_t states = 0;
ItemDef* item = indices->getItemDef(player->getChosenItem());
auto inventory = player->getInventory();
ItemStack& stack = inventory->getSlot(player->getChosenSlot());
ItemDef* item = indices->getItemDef(stack.getItemId());
Block* def = indices->getBlockDef(item->rt.placingBlock);
if (def && def->rotatable){
const std::string& name = def->rotations.name;
@ -285,7 +289,7 @@ void PlayerController::updateInteraction(){
scripting::on_block_interact(player, target, x, y, z);
return;
}
if (target->model != BlockModel::xsprite){
if (!target->replaceable){
x = (iend.x)+(norm.x);
y = (iend.y)+(norm.y);
z = (iend.z)+(norm.z);
@ -311,7 +315,18 @@ void PlayerController::updateInteraction(){
}
if (Events::jactive(BIND_PLAYER_PICK)){
Block* block = indices->getBlockDef(chunks->get(x,y,z)->id);
player->setChosenItem(block->rt.pickingItem);
itemid_t id = block->rt.pickingItem;
auto inventory = player->getInventory();
size_t slotid = inventory->findSlotByItem(id);
if (slotid == Inventory::npos) {
slotid = player->getChosenSlot();
} else {
player->setChosenSlot(slotid);
}
ItemStack& stack = inventory->getSlot(slotid);
if (stack.getItemId() != id) {
stack.set(ItemStack(id, 1));
}
}
} else {
selectedBlockId = -1;

View File

@ -13,6 +13,7 @@
#include "../../voxels/voxel.h"
#include "../../lighting/Lighting.h"
#include "../../logic/BlocksController.h"
#include "../../engine.h"
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
lua_pushinteger(L, x);
@ -27,7 +28,25 @@ inline void luaL_openlib(lua_State* L, const char* name, const luaL_Reg* libfunc
lua_setglobal(L, name);
}
/* == world library ==*/
/* == pack library == */
static int l_pack_get_folder(lua_State* L) {
std::string packName = lua_tostring(L, 1);
for (auto& pack : scripting::engine->getContentPacks()) {
if (pack.id == packName) {
lua_pushstring(L, (pack.folder.u8string()+"/").c_str());
return 1;
}
}
lua_pushstring(L, "");
return 1;
}
static const luaL_Reg packlib [] = {
{"get_folder", l_pack_get_folder},
{NULL, NULL}
};
/* == world library == */
static int l_world_get_day_time(lua_State* L) {
lua_pushnumber(L, scripting::level->world->daytime);
return 1;
@ -266,6 +285,7 @@ static int l_is_replaceable_at(lua_State* L) {
lua_setglobal(L, NAME))
void apilua::create_funcs(lua_State* L) {
luaL_openlib(L, "pack", packlib, 0);
luaL_openlib(L, "world", worldlib, 0);
luaL_openlib(L, "player", playerlib, 0);

View File

@ -11,19 +11,19 @@
#include "../../voxels/Block.h"
#include "../../items/ItemDef.h"
#include "../../logic/BlocksController.h"
#include "../../engine.h"
#include "api_lua.h"
using namespace scripting;
namespace scripting {
extern lua_State* L;
extern EnginePaths* paths;
}
Engine* scripting::engine = nullptr;
lua_State* scripting::L = nullptr;
Level* scripting::level = nullptr;
const Content* scripting::content = nullptr;
EnginePaths* scripting::paths = nullptr;
BlocksController* scripting::blocks = nullptr;
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
@ -58,8 +58,8 @@ int call_func(lua_State* L, int argc, const std::string& name) {
return 1;
}
void scripting::initialize(EnginePaths* paths) {
scripting::paths = paths;
void scripting::initialize(Engine* engine) {
scripting::engine = engine;
L = luaL_newstate();
if (L == nullptr) {
@ -87,7 +87,7 @@ void scripting::on_world_load(Level* level, BlocksController* blocks) {
scripting::level = level;
scripting::content = level->content;
scripting::blocks = blocks;
auto paths = scripting::engine->getPaths();
fs::path file = paths->getResources()/fs::path("scripts/world.lua");
std::string src = files::read_string(file);
luaL_loadbuffer(L, src.c_str(), src.length(), file.string().c_str());

View File

@ -3,7 +3,7 @@
namespace fs = std::filesystem;
class EnginePaths;
class Engine;
class Content;
class Level;
class Block;
@ -14,11 +14,12 @@ struct item_funcs_set;
class BlocksController;
namespace scripting {
extern Engine* engine;
extern const Content* content;
extern Level* level;
extern BlocksController* blocks;
void initialize(EnginePaths* paths);
void initialize(Engine* engine);
void on_world_load(Level* level, BlocksController* blocks);
void on_world_quit();
void update_block(const Block* block, int x, int y, int z);

17
src/maths/fastmaths.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef MATHS_FASTMATHS_H_
#define MATHS_FASTMATHS_H_
namespace fastmaths {
static unsigned int g_seed;
inline void srand(int seed) {
g_seed = seed;
}
inline int rand(void) {
g_seed = (214013*g_seed+2531011);
return (g_seed>>16)&0x7FFF;
}
}
#endif // MATHS_FASTMATHS_H_

View File

@ -5,6 +5,7 @@
#include "../world/Level.h"
#include "../window/Events.h"
#include "../window/Camera.h"
#include "../items/Inventory.h"
#include <glm/glm.hpp>
@ -18,12 +19,16 @@ const float JUMP_FORCE = 8.0f;
Player::Player(glm::vec3 position, float speed) :
speed(speed),
chosenItem(0),
chosenSlot(0),
camera(new Camera(position, glm::radians(90.0f))),
spCamera(new Camera(position, glm::radians(90.0f))),
tpCamera(new Camera(position, glm::radians(90.0f))),
currentCamera(camera),
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f))) {
hitbox(new Hitbox(position, glm::vec3(0.3f,0.9f,0.3f))),
inventory(new Inventory(40)) {
}
Player::~Player() {
}
void Player::update(
@ -118,14 +123,18 @@ void Player::teleport(glm::vec3 position) {
hitbox->position = position;
}
void Player::setChosenItem(itemid_t id) {
chosenItem = id;
void Player::setChosenSlot(int index) {
chosenSlot = index;
}
itemid_t Player::getChosenItem() const {
return chosenItem;
int Player::getChosenSlot() const {
return chosenSlot;
}
float Player::getSpeed() const {
return speed;
}
std::shared_ptr<Inventory> Player::getInventory() const {
return inventory;
}

View File

@ -9,6 +9,7 @@
class Camera;
class Hitbox;
class Inventory;
class PhysicsSolver;
class Chunks;
class Level;
@ -30,11 +31,12 @@ struct PlayerInput {
class Player {
float speed;
itemid_t chosenItem;
int chosenSlot;
public:
std::shared_ptr<Camera> camera, spCamera, tpCamera;
std::shared_ptr<Camera> currentCamera;
std::unique_ptr<Hitbox> hitbox;
std::shared_ptr<Inventory> inventory;
bool flight = false;
bool noclip = false;
bool debug = false;
@ -43,15 +45,17 @@ public:
glm::vec2 cam = {};
Player(glm::vec3 position, float speed);
~Player() = default;
~Player();
void teleport(glm::vec3 position);
void update(Level* level, PlayerInput& input, float delta);
void setChosenItem(itemid_t id);
void setChosenSlot(int index);
itemid_t getChosenItem() const;
int getChosenSlot() const;
float getSpeed() const;
std::shared_ptr<Inventory> getInventory() const;
};
#endif /* SRC_OBJECTS_PLAYER_H_ */

View File

@ -81,7 +81,7 @@ public:
std::vector<glm::vec3> modelExtraPoints = {}; //initially made for tetragons
std::vector<UVRegion> modelUVs = {}; // boxes' tex-UVs also there
uint8_t emission[4] {0, 0, 0, 0};
unsigned char drawGroup = 0;
ubyte drawGroup = 0;
BlockModel model = BlockModel::block;
bool lightPassing = false;
bool skyLightPassing = false;
@ -95,6 +95,7 @@ public:
AABB hitbox;
BlockRotProfile rotations;
std::string pickingItem = name+BLOCK_ITEM_SUFFIX;
std::string scriptName = name.substr(name.find(':')+1);
struct {
blockid_t id;

14
vcpkg.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "voxelengine",
"version-string": "1.0.0",
"dependencies": [
"opengl",
"openal-soft",
"glfw3",
"glew",
"glm",
"libspng",
"zlib",
"luajit"
]
}