Compare commits

17 Commits

Author SHA1 Message Date
milkwx3 032b38833d Обновить README.md
Build / build (push) Has been cancelled
2026-07-16 19:34:32 +00:00
milkwx3 78a2fc0b06 Обновить README.md
Build / build (push) Has been cancelled
2026-07-08 10:05:24 +00:00
literallyMilk 5e77586a8d README.md is a Markdown file, duh
Build / build (push) Has been cancelled
2026-07-08 13:03:47 +03:00
literallyMilk a8ca1edaef Added compiling for Windows
Build / build (push) Has been cancelled
2026-07-08 13:01:49 +03:00
literallyMilk 54a7662952 Added compiling for Windows 2026-07-08 13:01:32 +03:00
milkwx3 04d1969084 Added day&night cycle. Also fixed world loading
Build / build (push) Has been cancelled
2026-07-07 22:02:10 +03:00
milkwx3 7ab2d5a083 Huge skylight optimizations. Also fixed the submodules. 2026-07-04 01:48:50 +03:00
milkwx3 85ddc90883 Colored block lighting 2026-06-24 20:25:11 +03:00
milkwx3 d02d751275 Added a basic skylight engine. Currently it's really laggy.
Also tried fixing the autobuild action since it fetches the repo without submodules.
2026-06-24 18:58:15 +03:00
milkwx3 3ad54bd59d Remove internal server cuz we have it in the networking branch.
Minor refactoring (changed all Chunk* world or Chunk world[] to World world)
2026-06-24 16:00:56 +03:00
zippw cf53a42620 Merge pull request 'Фикс подмодулей' (#5) from submodules-fix into main
Reviewed-on: milkwx4/CubeGame#5
2026-06-24 01:46:07 +07:00
zippw 66a04d3119 Merge pull request 'CI - фикс двойной архивации.' (#6) from ci-doublezip-fix into main
Reviewed-on: milkwx4/CubeGame#6
2026-06-24 01:45:51 +07:00
h1n1 73c2aaadfb Ошибся в одной букве
this is not serious at all...

Изза того что ошибся в одной букве, Linux-овая сборка не появлялась в артефактах
2026-06-20 23:45:20 +07:00
h1n1 b1dfcd9eda Перепутал "name" и "path" в CI 2026-06-20 23:14:15 +07:00
h1n1 1b04ebe068 Fix: Убрал архивацию перед тем как залить артефакт 2026-06-20 23:06:28 +07:00
h1n1 8b1538c602 Удаление шага "Fetch Libraries" из CI 2026-06-20 22:46:07 +07:00
h1n1 5aeb2eb8c0 Fix: подмодули 2026-06-20 22:39:54 +07:00
46 changed files with 3956 additions and 1801 deletions
+6 -39
View File
@@ -11,13 +11,15 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
submodules: recursive
- name: Install build tools - name: Install build tools
run: | run: |
# echo "deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu noble main" | sudo tee /tmp/only.list # echo "deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu noble main" | sudo tee /tmp/only.list
# sudo apt-get update -o Dir::Etc::sourcelist=/tmp/only.list -o Dir::Etc::sourceparts="-" -qq # sudo apt-get update -o Dir::Etc::sourcelist=/tmp/only.list -o Dir::Etc::sourceparts="-" -qq
sudo apt update sudo apt update
sudo apt install -y build-essential cmake zip unzip make libxrandr-dev g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 libxinerama-dev libxcursor-dev libxi-dev libgl-dev sudo apt install -y build-essential cmake zip unzip make libxrandr-dev g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 g++-mingw-w64-i686 gcc-mingw-w64-i686 libxinerama-dev libxcursor-dev libxi-dev libgl-dev
- name: Build makeheaders - name: Build makeheaders
run: | run: |
@@ -25,61 +27,26 @@ jobs:
make make
cd .. cd ..
- name: Fetch libraries
run: |
cd ${{ gitea.workspace }}/src/libraries
rm enet -r
rm Lua -r
rm raylib -r
rm yaml-cpp -r
wget https://github.com/lsalzman/enet/archive/refs/heads/master.zip
unzip master.zip
mv enet-master enet
rm master.zip
wget https://github.com/walterschell/Lua/archive/refs/heads/master.zip
unzip master.zip
mv Lua-master Lua
rm master.zip
wget https://github.com/raysan5/raylib/archive/refs/heads/master.zip
unzip master.zip
mv raylib-master raylib
rm master.zip
wget https://github.com/jbeder/yaml-cpp/archive/refs/heads/master.zip
unzip master.zip
mv yaml-cpp-master yaml-cpp
rm master.zip
ls -r
cd ../..
- name: Compile - name: Compile
run: | run: |
chmod +x ${{ gitea.workspace }}/compile.sh chmod +x ${{ gitea.workspace }}/compile.sh
sh ${{ gitea.workspace }}/compile.sh sh ${{ gitea.workspace }}/compile.sh
zip -r release-linux.zip OUTPUT-Linux || true
zip -r release-w64.zip OUTPUT-w64 || true
zip -r release-w32.zip OUTPUT-w32 || true
- name: Upload Linux Release - name: Upload Linux Release
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: release-linux name: release-linux
path: release-linux.zip path: OUTPUT-Linux
- name: Upload Windows64 Release - name: Upload Windows64 Release
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: release-w64 name: release-w64
path: release-w64.zip path: OUTPUT-w64
- name: Upload Windows32 Release - name: Upload Windows32 Release
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: release-w32 name: release-w32
path: release-w32.zip path: OUTPUT-w32
+3 -1
View File
@@ -8,4 +8,6 @@ __UTILS__
snapshots snapshots
OUTPUT-Linux OUTPUT-Linux
OUTPUT-w64 OUTPUT-w64
OUTPUT-w32 OUTPUT-w32
makeheaders/makeheaders.exe
makeheaders/makeheaders
+12
View File
@@ -0,0 +1,12 @@
[submodule "src/libraries/enet"]
path = src/libraries/enet
url = https://github.com/lsalzman/enet
[submodule "src/libraries/Lua"]
path = src/libraries/Lua
url = https://github.com/walterschell/Lua
[submodule "src/libraries/raylib"]
path = src/libraries/raylib
url = https://github.com/raysan5/raylib
[submodule "src/libraries/yaml-cpp"]
path = src/libraries/yaml-cpp
url = https://github.com/jbeder/yaml-cpp
+33
View File
@@ -0,0 +1,33 @@
# Compiling
### NOTICE: Clone the repository with `-recursive`, e.g `git clone ... -recursive`
## Compiling on Linux
1) Install tools.
### Debian-based distros:
#### Essential stuff:
```sh
sudo apt install build-essential cmake zip unzip make libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev
```
#### If you also want to compile for Windows:
```sh
sudo apt install g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 g++-mingw-w64-i686 gcc-mingw-w64-i686
```
### Arch-based distros:
#### Essential stuff:
```sh
sudo pacman -S --needed base-devel cmake zip unzip libxcursor libxinerama libxi libxrandr wayland-utils mesa glu libglvnd alsa-lib pulseaudio
```
#### If you also want to compile for Windows:
```sh
sudo pacman -S --needed mingw-w64-gcc
```
2) Run `compile.sh` to compile for Linux, 64-bit Windows & 32-bit Windows.
Run `compile_linux.sh` to compile for Linux only.
## Compiling on Windows
1) Install [CMake](https://cmake.org/download/), [Ninja](https://ninja-build.org/) and [MinGW](https://www.mingw-w64.org/).
Try them out in the terminal: `cmake -version`, `ninja --version`, `gcc -version`, `g++ -version`.
If some are missing, add them to PATH.
2) From the terminal, run `compile.ps1`.
+15
View File
@@ -0,0 +1,15 @@
cd makeheaders
make
cd ..
./makeheaders/makeheaders.exe -h src/helpers/vars.hpp src/helpers/chunks.cpp src/helpers/debug.cpp src/helpers/entities.cpp src/helpers/input.cpp src/helpers/menu.cpp src/helpers/mesher.cpp src/helpers/networking.cpp src/helpers/utils.cpp src/helpers/inlines.hpp src/helpers/inventory.cpp src/helpers/locale.cpp src/helpers/recipes.cpp src/helpers/particles.cpp src/helpers/player.cpp src/helpers/multisound.cpp -v > tmp.hpp
Get-Content .\additions.hpp, .\tmp.hpp | Out-File .\src\helpers\common.hpp -Encoding UTF8
rm tmp.hpp
echo Building x86-64 Windows...
rm build
cmake -DCMAKE_TOOLCHAIN_FILE='toolchains/mingw-w64-native.cmake' . -DWIN32=ON -DWIN32=true -B build -G "Ninja"
cmake --build build
mkdir OUTPUT-w64
cp build/src/RCRAFT.exe OUTPUT-w64/CubeGame.exe
cp -r data/resources OUTPUT-w64
+4
View File
@@ -1,5 +1,9 @@
#/usr/bin/bash #/usr/bin/bash
cd makeheaders
make
cd ..
sh compile_linux.sh sh compile_linux.sh
sh compile_windows_64.sh sh compile_windows_64.sh
sh compile_windows.sh sh compile_windows.sh
+4 -8
View File
@@ -1,17 +1,13 @@
#/usr/bin/bash #/usr/bin/bash
./makeheaders/makeheaders -h src/helpers/vars.hpp src/helpers/chunks.cpp src/helpers/debug.cpp src/helpers/entities.cpp src/helpers/input.cpp src/helpers/menu.cpp src/helpers/mesher.cpp src/helpers/networking.cpp src/helpers/utils.cpp src/helpers/inlines.hpp src/helpers/inventory.cpp src/helpers/locale.cpp src/helpers/recipes.cpp src/helpers/particles.cpp src/helpers/player.cpp src/helpers/multisound.cpp src/helpers/svlib.cpp -v > tmp.hpp ./makeheaders/makeheaders -h src/helpers/vars.hpp src/helpers/chunks.cpp src/helpers/debug.cpp src/helpers/entities.cpp src/helpers/input.cpp src/helpers/menu.cpp src/helpers/mesher.cpp src/helpers/networking.cpp src/helpers/utils.cpp src/helpers/inlines.hpp src/helpers/inventory.cpp src/helpers/locale.cpp src/helpers/recipes.cpp src/helpers/particles.cpp src/helpers/player.cpp src/helpers/multisound.cpp -v > tmp.hpp
cat additions.hpp tmp.hpp > src/helpers/common.hpp cat additions.hpp tmp.hpp > src/helpers/common.hpp
rm tmp.hpp rm tmp.hpp
echo Building x86-64 Linux... echo Building x86-64 Linux...
rm -rf build rm -rf build
cmake -B build -DUNIX=ON -DUNIX=true cmake -B build -DUNIX=ON -DUNIX=true -DCMAKE_BUILD_TYPE=Debug
cd build cmake --build build
make -j12
cd ..
mkdir OUTPUT-Linux mkdir OUTPUT-Linux
cp build/src/RCRAFT OUTPUT-Linux/CubeGame cp build/src/RCRAFT OUTPUT-Linux/CubeGame
cp -r data/resources OUTPUT-Linux cp -r data/resources OUTPUT-Linux
mkdir OUTPUT-Linux/user
mkdir OUTPUT-Linux/user/worlds
+2 -6
View File
@@ -7,11 +7,7 @@ rm tmp.hpp
echo Building i686 Windows... echo Building i686 Windows...
rm -rf build rm -rf build
cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/mingw-w32.cmake -DWIN32=ON -DWIN32=true -B build cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/mingw-w32.cmake -DWIN32=ON -DWIN32=true -B build
cd build cmake --build build
make -j12
cd ..
mkdir OUTPUT-w32 mkdir OUTPUT-w32
cp build/src/RCRAFT.exe OUTPUT-w32/CubeGame.exe cp build/src/RCRAFT.exe OUTPUT-w32/CubeGame.exe
cp -r data/resources OUTPUT-w32 cp -r data/resources OUTPUT-w32
mkdir OUTPUT-w32/user
mkdir OUTPUT-w32/user/worlds
+2 -6
View File
@@ -7,11 +7,7 @@ rm tmp.hpp
echo Building x86-64 Windows... echo Building x86-64 Windows...
rm -rf build rm -rf build
cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/mingw-w64.cmake -DWIN32=ON -DWIN32=true -B build cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/mingw-w64.cmake -DWIN32=ON -DWIN32=true -B build
cd build cmake --build build
make -j12
cd ..
mkdir OUTPUT-w64 mkdir OUTPUT-w64
cp build/src/RCRAFT.exe OUTPUT-w64/CubeGame.exe cp build/src/RCRAFT.exe OUTPUT-w64/CubeGame.exe
cp -r data/resources OUTPUT-w64 cp -r data/resources OUTPUT-w64
mkdir OUTPUT-w64/user
mkdir OUTPUT-w64/user/worlds
-64
View File
@@ -1,64 +0,0 @@
211d25
413d42
5c5b63
7c808b
a5b0b6
d6dede
ffffff
dcded1
aab1a1
7b8375
585f57
3c3c3c
635d5a
8d837d
b4aea4
dedcd1
eadedf
bcacb1
8f8189
685d66
643747
b2434d
e55858
fa8971
ffb999
ffe0b7
ffbdc1
ef93b5
c971a2
944e89
4c3d57
5d558f
777dc4
96b1e7
bedef6
aae3db
5ac5ce
4694a8
346376
2a3b4a
29684a
379648
79b547
b8cf61
f3db6f
f4ba7a
e79055
ce6442
944940
91555d
b76f6b
cd9383
e1ba9e
facafb
d49ce5
9f76b8
725689
edb762
fcfbc9
de9463
b66a4d
333f29
4e5c2c
708939
Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

+6 -8
View File
@@ -14,12 +14,14 @@ speed_up: Fly faster
fly: Toggle flying fly: Toggle flying
chat: Open chat chat: Open chat
swap_mouse: Swap LMB/RMB swap_mouse: Swap LMB/RMB
inventory: Open inventory
# Menu # Menu
select_level: Singleplayer select_level: Singleplayer
multiplayer: Multiplayer multiplayer: Multiplayer
join: Join join: Join
exit: Exit exit: Exit
options: Options options: Options
create_world: Create world
# Multiplayer errors # Multiplayer errors
error_notfound: Host not found! error_notfound: Host not found!
error_internal: Internal enet error! error_internal: Internal enet error!
@@ -41,21 +43,17 @@ item.dirt: "Dirt"
item.sand: "Sand" item.sand: "Sand"
item.water: "Water" item.water: "Water"
item.planks: "Wooden Planks" item.planks: "Wooden Planks"
item.gray_bricks: "Gray Bricks" item.stone_bricks: "Stone Bricks"
item.red_bricks: "Red Bricks" item.copper_block: "Copper Block"
item.blue_bricks: "Blue Bricks" item.silver_block: "Silver Block"
item.green_bricks: "Green Bricks" item.gold_block: "Gold Block"
item.glass: "Glass" item.glass: "Glass"
item.log: "Log" item.log: "Log"
item.spruce_planks: "Spruce Planks" item.spruce_planks: "Spruce Planks"
item.red_block: "Red Block" item.red_block: "Red Block"
item.green_block: "Green Block" item.green_block: "Green Block"
item.blue_block: "Blue Block" item.blue_block: "Blue Block"
item.yellow_block: "Yellow Block"
item.cyan_block: "Cyan Block"
item.magenta_block: "Magenta Block"
item.white_block: "White Block" item.white_block: "White Block"
item.black_block: "Black Block"
item.leaves: "Leaves" item.leaves: "Leaves"
item.copper_ore: "Copper Ore" item.copper_ore: "Copper Ore"
item.silver_ore: "Silver Ore" item.silver_ore: "Silver Ore"
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 628 B

+37
View File
@@ -0,0 +1,37 @@
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragPosition;
in vec3 fragNormal;
uniform sampler2D texture0;
uniform vec4 sunlightColor;
uniform vec3 lightDir;
out vec4 finalColor;
void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
vec3 N = normalize(fragNormal);
vec3 L = normalize(lightDir);
float ndotl = max(dot(N, L), 0.0);
float ambient = 0.1;
float sunfactor = ambient + (1.0 - ambient) * ndotl;
sunfactor *= 1+min(0, L.y);
vec3 Lmoon = normalize(-lightDir);
float ndotlMoon = max(dot(N, Lmoon), 0.0);
float moonfactor = (ambient + (1.0 - ambient) * ndotlMoon) * 8;
moonfactor *= max(0, -L.y);
// In fragColor, 'r' is blocklight R, 'g' is blocklight G, 'b' is blocklight B and 'a' is sunlight
texelColor.r *= fragColor.a * sunlightColor.r * (sunfactor+moonfactor) + fragColor.r;
texelColor.g *= fragColor.a * sunlightColor.g * (sunfactor+moonfactor) + fragColor.g;
texelColor.b *= fragColor.a * sunlightColor.b * (sunfactor+moonfactor) + fragColor.b;
finalColor = texelColor;
}
+32
View File
@@ -0,0 +1,32 @@
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
uniform mat4 matNormal;
// Output vertex attributes (to fragment shader)
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragNormal;
// NOTE: Add your custom variables here
void main()
{
// Send vertex attributes to fragment shader
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
// Calculate final vertex position
gl_Position = mvp*vec4(vertexPosition, 1.0);
}
+46
View File
@@ -0,0 +1,46 @@
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragPosition;
in vec3 fragNormal;
uniform sampler2D texture0;
uniform vec4 sunlightColor;
uniform vec4 skyColor;
uniform vec3 lightDir;
out vec4 finalColor;
void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
vec3 N = normalize(fragNormal);
vec3 L = normalize(lightDir);
float ndotl = max(dot(N, L), 0.0);
float ambient = 0.1;
float sunfactor = ambient + (1.0 - ambient) * ndotl;
sunfactor *= 1+min(0, L.y);
vec3 Lmoon = normalize(-lightDir);
float ndotlMoon = max(dot(N, Lmoon), 0.0);
float moonfactor = (ambient + (1.0 - ambient) * ndotlMoon) * 8;
moonfactor *= max(0, -L.y);
// In fragColor, 'r' is blocklight R, 'g' is blocklight G, 'b' is blocklight B and 'a' is sunlight
float sunlight = fragColor.a;
texelColor.r *= sunlight * sunlightColor.r * (sunfactor+moonfactor) + fragColor.r;
texelColor.g *= sunlight * sunlightColor.g * (sunfactor+moonfactor) + fragColor.g;
texelColor.b *= sunlight * sunlightColor.b * (sunfactor+moonfactor) + fragColor.b;
float highlight = texelColor.a;
if(highlight < 0.25) highlight = 0;
float highlight_final = abs(N.y)*highlight * 4;
vec3 highlightColor = sunlightColor.rgb*highlight_final*sunlight;
highlightColor.r += fragColor.r*highlight_final;
highlightColor.g += fragColor.g*highlight_final;
highlightColor.b += fragColor.b*highlight_final;
finalColor = texelColor + vec4(highlightColor, min(1.0, highlight_final));
}
+34
View File
@@ -0,0 +1,34 @@
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
uniform mat4 matNormal;
uniform float time;
// Output vertex attributes (to fragment shader)
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragNormal;
// NOTE: Add your custom variables here
void main()
{
// Send vertex attributes to fragment shader
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
// Calculate final vertex position
vec3 pos = vertexPosition + vec3(0, sin(time * 2.0 + vertexPosition.x * 1.5) / 20.0 + cos(time * 2.0 + vertexPosition.z * 1.5) / 20.0-0.1, 0);
gl_Position = mvp*vec4(pos, 1.0);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.
+1 -1
View File
@@ -5,7 +5,7 @@ add_subdirectory(helpers)
set(YAML_BUILD_SHARED_LIBS OFF) set(YAML_BUILD_SHARED_LIBS OFF)
set(YAML_MSVC_SHARED_RT OFF) set(YAML_MSVC_SHARED_RT OFF)
set(OPENGL_VERSION 1.1) set(OPENGL_VERSION 3.3)
add_subdirectory(libraries/raylib) add_subdirectory(libraries/raylib)
add_subdirectory(libraries/enet) add_subdirectory(libraries/enet)
+2441
View File
File diff suppressed because it is too large Load Diff
-659
View File
@@ -1,659 +0,0 @@
//----------------------------------------------------------------------------------------
//
// siv::PerlinNoise
// Perlin noise library for modern C++
//
// Copyright (C) 2013-2021 Ryo Suzuki <reputeless@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//----------------------------------------------------------------------------------------
# pragma once
# include <cstdint>
# include <algorithm>
# include <array>
# include <iterator>
# include <numeric>
# include <random>
# include <type_traits>
# if __has_include(<concepts>) && defined(__cpp_concepts)
# include <concepts>
# endif
// Library major version
# define SIVPERLIN_VERSION_MAJOR 3
// Library minor version
# define SIVPERLIN_VERSION_MINOR 0
// Library revision version
# define SIVPERLIN_VERSION_REVISION 0
// Library version
# define SIVPERLIN_VERSION ((SIVPERLIN_VERSION_MAJOR * 100 * 100) + (SIVPERLIN_VERSION_MINOR * 100) + (SIVPERLIN_VERSION_REVISION))
// [[nodiscard]] for constructors
# if (201907L <= __has_cpp_attribute(nodiscard))
# define SIVPERLIN_NODISCARD_CXX20 [[nodiscard]]
# else
# define SIVPERLIN_NODISCARD_CXX20
# endif
// std::uniform_random_bit_generator concept
# if __cpp_lib_concepts
# define SIVPERLIN_CONCEPT_URBG template <std::uniform_random_bit_generator URBG>
# define SIVPERLIN_CONCEPT_URBG_ template <std::uniform_random_bit_generator URBG>
# else
# define SIVPERLIN_CONCEPT_URBG template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>* = nullptr>
# define SIVPERLIN_CONCEPT_URBG_ template <class URBG, std::enable_if_t<std::conjunction_v<std::is_invocable<URBG&>, std::is_unsigned<std::invoke_result_t<URBG&>>>>*>
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Y
# define SIVPERLIN_DEFAULT_Y (0.12345)
# endif
// arbitrary value for increasing entropy
# ifndef SIVPERLIN_DEFAULT_Z
# define SIVPERLIN_DEFAULT_Z (0.34567)
# endif
namespace siv
{
template <class Float>
class BasicPerlinNoise
{
public:
static_assert(std::is_floating_point_v<Float>);
///////////////////////////////////////
//
// Typedefs
//
using state_type = std::array<std::uint8_t, 256>;
using value_type = Float;
using default_random_engine = std::mt19937;
using seed_type = typename default_random_engine::result_type;
///////////////////////////////////////
//
// Constructors
//
SIVPERLIN_NODISCARD_CXX20
constexpr BasicPerlinNoise() noexcept;
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(seed_type seed);
SIVPERLIN_CONCEPT_URBG
SIVPERLIN_NODISCARD_CXX20
explicit BasicPerlinNoise(URBG&& urbg);
///////////////////////////////////////
//
// Reseed
//
void reseed(seed_type seed);
SIVPERLIN_CONCEPT_URBG
void reseed(URBG&& urbg);
///////////////////////////////////////
//
// Serialization
//
[[nodiscard]]
constexpr const state_type& serialize() const noexcept;
constexpr void deserialize(const state_type& state) noexcept;
///////////////////////////////////////
//
// Noise (The result is in the range [-1, 1])
//
[[nodiscard]]
value_type noise1D(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Noise (The result is remapped to the range [0, 1])
//
[[nodiscard]]
value_type noise1D_01(value_type x) const noexcept;
[[nodiscard]]
value_type noise2D_01(value_type x, value_type y) const noexcept;
[[nodiscard]]
value_type noise3D_01(value_type x, value_type y, value_type z) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result can be out of the range [-1, 1])
//
[[nodiscard]]
value_type octave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped to the range [-1, 1])
//
[[nodiscard]]
value_type octave1D_11(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_11(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_11(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is clamped and remapped to the range [0, 1])
//
[[nodiscard]]
value_type octave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type octave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized to the range [-1, 1])
//
[[nodiscard]]
value_type normalizedOctave1D(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
///////////////////////////////////////
//
// Octave noise (The result is normalized and remapped to the range [0, 1])
//
[[nodiscard]]
value_type normalizedOctave1D_01(value_type x, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave2D_01(value_type x, value_type y, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
[[nodiscard]]
value_type normalizedOctave3D_01(value_type x, value_type y, value_type z, std::int32_t octaves, value_type persistence = value_type(0.5)) const noexcept;
private:
state_type m_permutation;
};
using PerlinNoise = BasicPerlinNoise<double>;
namespace perlin_detail
{
////////////////////////////////////////////////
//
// These functions are provided for consistency.
// You may get different results from std::shuffle() with different standard library implementations.
//
SIVPERLIN_CONCEPT_URBG
[[nodiscard]]
inline std::uint64_t Random(const std::uint64_t max, URBG&& urbg)
{
return (urbg() % (max + 1));
}
template <class RandomIt, class URBG>
inline void Shuffle(RandomIt first, RandomIt last, URBG&& urbg)
{
if (first == last)
{
return;
}
using difference_type = typename std::iterator_traits<RandomIt>::difference_type;
for (RandomIt it = first + 1; it < last; ++it)
{
const std::uint64_t n = static_cast<std::uint64_t>(it - first);
std::iter_swap(it, first + static_cast<difference_type>(Random(n, std::forward<URBG>(urbg))));
}
}
//
////////////////////////////////////////////////
template <class Float>
[[nodiscard]]
inline constexpr Float Fade(const Float t) noexcept
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Lerp(const Float a, const Float b, const Float t) noexcept
{
return (a + (b - a) * t);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Grad(const std::uint8_t hash, const Float x, const Float y, const Float z) noexcept
{
const std::uint8_t h = hash & 15;
const Float u = h < 8 ? x : y;
const Float v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
template <class Float>
[[nodiscard]]
inline constexpr Float Remap_01(const Float x) noexcept
{
return (x * Float(0.5) + Float(0.5));
}
template <class Float>
[[nodiscard]]
inline constexpr Float Clamp_11(const Float x) noexcept
{
return std::clamp(x, Float(-1.0), Float(1.0));
}
template <class Float>
[[nodiscard]]
inline constexpr Float RemapClamp_01(const Float x) noexcept
{
if (x <= Float(-1.0))
{
return Float(0.0);
}
else if (Float(1.0) <= x)
{
return Float(1.0);
}
return (x * Float(0.5) + Float(0.5));
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave1D(const Noise& noise, Float x, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise1D(x) * amplitude);
x *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave2D(const Noise& noise, Float x, Float y, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise2D(x, y) * amplitude);
x *= 2;
y *= 2;
amplitude *= persistence;
}
return result;
}
template <class Noise, class Float>
[[nodiscard]]
inline auto Octave3D(const Noise& noise, Float x, Float y, Float z, const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += (noise.noise3D(x, y, z) * amplitude);
x *= 2;
y *= 2;
z *= 2;
amplitude *= persistence;
}
return result;
}
template <class Float>
[[nodiscard]]
inline constexpr Float MaxAmplitude(const std::int32_t octaves, const Float persistence) noexcept
{
using value_type = Float;
value_type result = 0;
value_type amplitude = 1;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += amplitude;
amplitude *= persistence;
}
return result;
}
}
///////////////////////////////////////
template <class Float>
inline constexpr BasicPerlinNoise<Float>::BasicPerlinNoise() noexcept
: m_permutation{ 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 } {}
template <class Float>
inline BasicPerlinNoise<Float>::BasicPerlinNoise(const seed_type seed)
{
reseed(seed);
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline BasicPerlinNoise<Float>::BasicPerlinNoise(URBG&& urbg)
{
reseed(std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline void BasicPerlinNoise<Float>::reseed(const seed_type seed)
{
reseed(default_random_engine{ seed });
}
template <class Float>
SIVPERLIN_CONCEPT_URBG_
inline void BasicPerlinNoise<Float>::reseed(URBG&& urbg)
{
std::iota(m_permutation.begin(), m_permutation.end(), uint8_t{ 0 });
perlin_detail::Shuffle(m_permutation.begin(), m_permutation.end(), std::forward<URBG>(urbg));
}
///////////////////////////////////////
template <class Float>
inline constexpr const typename BasicPerlinNoise<Float>::state_type& BasicPerlinNoise<Float>::serialize() const noexcept
{
return m_permutation;
}
template <class Float>
inline constexpr void BasicPerlinNoise<Float>::deserialize(const state_type& state) noexcept
{
m_permutation = state;
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D(const value_type x) const noexcept
{
return noise3D(x,
static_cast<value_type>(SIVPERLIN_DEFAULT_Y),
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D(const value_type x, const value_type y) const noexcept
{
return noise3D(x,
y,
static_cast<value_type>(SIVPERLIN_DEFAULT_Z));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D(const value_type x, const value_type y, const value_type z) const noexcept
{
const value_type _x = std::floor(x);
const value_type _y = std::floor(y);
const value_type _z = std::floor(z);
const std::int32_t ix = static_cast<std::int32_t>(_x) & 255;
const std::int32_t iy = static_cast<std::int32_t>(_y) & 255;
const std::int32_t iz = static_cast<std::int32_t>(_z) & 255;
const value_type fx = (x - _x);
const value_type fy = (y - _y);
const value_type fz = (z - _z);
const value_type u = perlin_detail::Fade(fx);
const value_type v = perlin_detail::Fade(fy);
const value_type w = perlin_detail::Fade(fz);
const std::uint8_t A = (m_permutation[ix & 255] + iy) & 255;
const std::uint8_t B = (m_permutation[(ix + 1) & 255] + iy) & 255;
const std::uint8_t AA = (m_permutation[A] + iz) & 255;
const std::uint8_t AB = (m_permutation[(A + 1) & 255] + iz) & 255;
const std::uint8_t BA = (m_permutation[B] + iz) & 255;
const std::uint8_t BB = (m_permutation[(B + 1) & 255] + iz) & 255;
const value_type p0 = perlin_detail::Grad(m_permutation[AA], fx, fy, fz);
const value_type p1 = perlin_detail::Grad(m_permutation[BA], fx - 1, fy, fz);
const value_type p2 = perlin_detail::Grad(m_permutation[AB], fx, fy - 1, fz);
const value_type p3 = perlin_detail::Grad(m_permutation[BB], fx - 1, fy - 1, fz);
const value_type p4 = perlin_detail::Grad(m_permutation[(AA + 1) & 255], fx, fy, fz - 1);
const value_type p5 = perlin_detail::Grad(m_permutation[(BA + 1) & 255], fx - 1, fy, fz - 1);
const value_type p6 = perlin_detail::Grad(m_permutation[(AB + 1) & 255], fx, fy - 1, fz - 1);
const value_type p7 = perlin_detail::Grad(m_permutation[(BB + 1) & 255], fx - 1, fy - 1, fz - 1);
const value_type q0 = perlin_detail::Lerp(p0, p1, u);
const value_type q1 = perlin_detail::Lerp(p2, p3, u);
const value_type q2 = perlin_detail::Lerp(p4, p5, u);
const value_type q3 = perlin_detail::Lerp(p6, p7, u);
const value_type r0 = perlin_detail::Lerp(q0, q1, v);
const value_type r1 = perlin_detail::Lerp(q2, q3, v);
return perlin_detail::Lerp(r0, r1, w);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise1D_01(const value_type x) const noexcept
{
return perlin_detail::Remap_01(noise1D(x));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise2D_01(const value_type x, const value_type y) const noexcept
{
return perlin_detail::Remap_01(noise2D(x, y));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::noise3D_01(const value_type x, const value_type y, const value_type z) const noexcept
{
return perlin_detail::Remap_01(noise3D(x, y, z));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave1D(*this, x, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave2D(*this, x, y, octaves, persistence);
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Octave3D(*this, x, y, z, octaves, persistence);
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_11(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_11(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_11(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Clamp_11(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::octave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::RemapClamp_01(octave3D(x, y, z, octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave1D(x, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave2D(x, y, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return (octave3D(x, y, z, octaves, persistence) / perlin_detail::MaxAmplitude(octaves, persistence));
}
///////////////////////////////////////
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave1D_01(const value_type x, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave1D(x, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave2D_01(const value_type x, const value_type y, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave2D(x, y, octaves, persistence));
}
template <class Float>
inline typename BasicPerlinNoise<Float>::value_type BasicPerlinNoise<Float>::normalizedOctave3D_01(const value_type x, const value_type y, const value_type z, const std::int32_t octaves, const value_type persistence) const noexcept
{
return perlin_detail::Remap_01(normalizedOctave3D(x, y, z, octaves, persistence));
}
}
# undef SIVPERLIN_NODISCARD_CXX20
# undef SIVPERLIN_CONCEPT_URBG
# undef SIVPERLIN_CONCEPT_URBG_
+1 -1
View File
@@ -15,7 +15,6 @@ add_library(helpers STATIC
particles.cpp particles.cpp
player.cpp player.cpp
multisound.cpp multisound.cpp
svlib.cpp
) )
if (WIN32) if (WIN32)
@@ -24,6 +23,7 @@ if (WIN32)
target_link_libraries(helpers INTERFACE winmm ws2_32) target_link_libraries(helpers INTERFACE winmm ws2_32)
endif() endif()
add_compile_options(-Wno-narrowing)
execute_process(COMMAND date +v.%yw%W OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND date +v.%yw%W OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
add_compile_definitions(GAME_VERSION="${BUILD_DATE}") add_compile_definitions(GAME_VERSION="${BUILD_DATE}")
+522 -110
View File
@@ -1,3 +1,4 @@
#include <unordered_set>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "common.hpp" #include "common.hpp"
@@ -6,10 +7,14 @@
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <queue>
#define FNL_IMPL
#include "../FastNoiseLite.h"
#define HUMIDITY_OFFSET 12.3f #define HUMIDITY_OFFSET 12.3f
#define CAVE_OFFSET 45.6f #define CAVE_OFFSET 45.6f
#define SCALE 0.01f #define SCALE 0.1f
#define CAVE_COEFF 0.06 #define CAVE_COEFF 0.06
#define EDGES_FADE 64 #define EDGES_FADE 64
#define CLOUD_SCALE 0.25f #define CLOUD_SCALE 0.25f
@@ -17,11 +22,13 @@
#define BIOME_FOREST 0 #define BIOME_FOREST 0
#define BIOME_TAIGA 1 #define BIOME_TAIGA 1
static const siv::PerlinNoise perlin; static fnl_state perlin;
static fnl_state perlin2;
static fnl_state perlinLofi;
static int world_type = 0; static int world_type = 0;
const BlockDef BLOCKS[] = { std::vector<BlockDef> BLOCKS = {
BlockDef{ "air", R_Translucent, B_Stone, 0, 0, 0}, BlockDef{ "air", R_Translucent, B_Stone, 0, 0, 0},
BlockDef{ "stone", R_Normal, B_Stone, 7, 0, 3}, BlockDef{ "stone", R_Normal, B_Stone, 7, 0, 3},
BlockDef{ "grass", R_TriSide, B_Grass, 1, 0, 0, 1, 2}, BlockDef{ "grass", R_TriSide, B_Grass, 1, 0, 0, 1, 2},
@@ -29,21 +36,21 @@ const BlockDef BLOCKS[] = {
BlockDef{ "sand", R_Normal, B_Dirt, 2, 0, 4}, BlockDef{ "sand", R_Normal, B_Dirt, 2, 0, 4},
BlockDef{ "water", R_Translucent, B_Stone, 0, 0, 14}, BlockDef{ "water", R_Translucent, B_Stone, 0, 0, 14},
BlockDef{ "planks", R_Normal, B_Wood, 3, 0, 11}, BlockDef{ "planks", R_Normal, B_Wood, 3, 0, 11},
BlockDef{ "gray_bricks", R_Normal, B_Stone, 5, 1, 16}, BlockDef{ "stone_bricks", R_Normal, B_Stone, 5, 1, 16},
BlockDef{ "red_bricks", R_Normal, B_Stone, 5, 1, 17}, BlockDef{ "copper_block", R_Normal, B_Stone, 5, 1, 17},
BlockDef{ "blue_bricks", R_Normal, B_Stone, 5, 1, 18}, BlockDef{ "silver_block", R_Normal, B_Stone, 5, 1, 18},
BlockDef{ "green_bricks", R_Normal, B_Stone, 5, 1, 19}, BlockDef{ "gold_block", R_Normal, B_Stone, 5, 1, 19},
BlockDef{ "glass", R_Translucent, B_Stone, 3, 1, 12}, BlockDef{ "glass", R_Translucent, B_Stone, 3, 1, 12},
BlockDef{ "log", R_TriSide, B_Wood, 5, 0, 10, 9, 10}, BlockDef{ "log", R_TriSide, B_Wood, 5, 0, 10, 9, 10},
BlockDef{ "spruce_planks", R_Normal, B_Wood, 3, 0, 13}, BlockDef{ "spruce_planks", R_Normal, B_Wood, 3, 0, 13},
BlockDef{ "spruce_log", R_TriSide, B_Wood, 5, 0, 21, 20, 21}, BlockDef{ "spruce_log", R_TriSide, B_Wood, 5, 0, 21, 20, 21},
BlockDef{ "workbench", R_TranslucentAllSides, B_Stone, 3, 0, 23, 22, 23}, BlockDef{ "workbench", R_TranslucentAllSides, B_Stone, 3, 0, 23, 22, 23},
BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 22}, BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 22},
BlockDef{ "yellow_block", R_Normal, B_Stone, 5, 0, 23}, BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 23},
BlockDef{ "cyan_block", R_Normal, B_Stone, 5, 0, 24}, BlockDef{ "red_block", R_Normal, B_Stone, 5, 0, 24},
BlockDef{ "magenta_block", R_Normal, B_Stone, 5, 0, 25}, BlockDef{ "green_block", R_Normal, B_Stone, 5, 0, 25},
BlockDef{ "white_block", R_Normal, B_Stone, 5, 0, 26}, BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 26},
BlockDef{ "black_block", R_Normal, B_Stone, 5, 0, 27}, BlockDef{ "white_block", R_Normal, B_Stone, 5, 0, 27},
BlockDef{ "leaves", R_TranslucentAllSides, B_Grass, 1, 0, 28}, BlockDef{ "leaves", R_TranslucentAllSides, B_Grass, 1, 0, 28},
BlockDef{ "copper_ore", R_Normal, B_Stone, 7, 1, 5}, BlockDef{ "copper_ore", R_Normal, B_Stone, 7, 1, 5},
BlockDef{ "silver_ore", R_Normal, B_Stone, 7, 2, 6}, BlockDef{ "silver_ore", R_Normal, B_Stone, 7, 2, 6},
@@ -51,33 +58,52 @@ const BlockDef BLOCKS[] = {
BlockDef{ "coal_ore", R_Normal, B_Stone, 7, 0, 8}, BlockDef{ "coal_ore", R_Normal, B_Stone, 7, 0, 8},
BlockDef{ "unobtainium", R_Normal, B_Stone, 7, 999, 3}, // Bedrock? BlockDef{ "unobtainium", R_Normal, B_Stone, 7, 999, 3}, // Bedrock?
}; };
BlockDef &GetBlockDefinition(int id) {
return BLOCKS[id];
}
void LoadBlocks() {
}
int GetNumericIDFromString(std::string s) { int GetNumericIDFromString(std::string s) {
int count = sizeof(BLOCKS) / sizeof(BLOCKS[0]); for (int i = 0; i < BLOCKS.size(); ++i) {
for (int i = 0; i < count; ++i) {
if (BLOCKS[i].name == s) return i; if (BLOCKS[i].name == s) return i;
} }
return -1; return -1;
} }
static std::bitset<256> marked; static std::bitset<256> marked;
static int GetBlockRegularWorld(int x, int y, int z) { static int GetBlockRegularWorld(int _x, int y, int _z) {
float fade_x = (fmax(EDGES_FADE - x, 0) + fmax(EDGES_FADE - WORLD_SIZE_BLOCKS + x, 0)) / (float)EDGES_FADE; int x = _x + 0;
float fade_z = (fmax(EDGES_FADE - z, 0) + fmax(EDGES_FADE - WORLD_SIZE_BLOCKS + z, 0)) / (float)EDGES_FADE; int z = _z + 0;
float fade = 1 - (fade_x + fade_z); const int SEA_HEIGHT = 64;
const int BEACH_DEPTH = 3;
const float heightBias = 24;
float p0 = fnlGetNoise3D(&perlin, (float)x, y / 2.0f, z);
float p1 = fnlGetNoise3D(&perlin2, x, y / 2.0f, z);
float pr = fnlGetNoise3D(&perlinLofi, x, y / 2.0f, z)*12.75f;
float P = 0;
if(pr >= 1) P = p1;
if(pr <= 0) P = p0;
if(pr>0&&pr<1) P = Lerp(p0, p1, pr);
float density = P + (WORLD_HEIGHT-(y+60)) / heightBias;
if(density > 0.5f) {
return BLOCK_STONE;
}
if(density > 0) {
return BLOCK_DIRT;
}
if(y < SEA_HEIGHT) {
return BLOCK_WATERS;
}
//float height0 = (fnlGetNoise3D(&perlin, x, y, z) + 1.0f ) / 2.0f * 8.0f;
//float height1 = (fnlGetNoise3D(&perlin2, x, y, z) + 1.0f ) / 2.0f * 16.0f;
const int SEA_HEIGHT = 32; // sea surface y //int height = Lerp(height0, height1, fnlGetNoise2D(&perlinLofi, x, z)) + 26 + 48;
const int BEACH_DEPTH = 3; // how many blocks below surface become sand //float dist = Vector2Distance({(float)x, (float)z}, {MAX_WORLD_SIZE*CHUNK_SIZE/2, MAX_WORLD_SIZE*CHUNK_SIZE/2});
float height0 = (perlin.noise2D((double)x * 1.5f * SCALE, (double)z * 1.5f * SCALE) + 1.0f ) / 2.0f * 16.0f; //height = Lerp(32, height, fmin(1.0f, -fmin(0.0f, dist - (MAX_WORLD_SIZE*CHUNK_SIZE/2)-48)/96.0f));
float mountains = pow((perlin.noise2D((double)x * 0.5f, (double)z * 0.5f * SCALE) + 1.0f ) / 2.0f, 16); /*if (y <= height) {
float height1 = (perlin.noise2D((double)x * 4.5f * SCALE, (double)z * 4.5f * SCALE) + 1.0f ) / 2.0f * 24.0f * mountains; //if(caveNoise < 0.02f) return BLOCK_AIR;
int height = floor((height0 + height1) * fade) + 26;
float caveNoise = fabs(perlin.noise3D((double)x * 1.0f * SCALE + CAVE_OFFSET, (double)y * 4.0f * SCALE + CAVE_OFFSET, (double)z * 1.0f * SCALE + CAVE_OFFSET));
if (y <= height) {
if(caveNoise < 0.02f) return BLOCK_AIR;
if (y == height) { if (y == height) {
if (height <= SEA_HEIGHT) { if (height <= SEA_HEIGHT) {
return BLOCK_SAND; return BLOCK_SAND;
@@ -89,27 +115,119 @@ static int GetBlockRegularWorld(int x, int y, int z) {
if (y > height - BEACH_DEPTH && height <= SEA_HEIGHT + 2) { if (y > height - BEACH_DEPTH && height <= SEA_HEIGHT + 2) {
return BLOCK_SAND; return BLOCK_SAND;
} }
if(caveNoise < 0.2f || y < 4) return BLOCK_STONE; //if(caveNoise < 0.2f || y < 4) return BLOCK_STONE;
return BLOCK_DIRT; return BLOCK_DIRT;
} }
if (y <= SEA_HEIGHT && height < SEA_HEIGHT) { if (y <= SEA_HEIGHT && height < SEA_HEIGHT) {
return BLOCK_WATERS; return BLOCK_WATERS;
} }*/
return BLOCK_AIR; return BLOCK_AIR;
} }
int GetBlock(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
return fetch_block(world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ);
}
int GetHighestBlock(World &world, int x, int z) {
if(CheckOOBWorld(x, 0, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
return world.chunks[GetIndexWorld(cx, cz)].highestBlock[GetIndexChunk2D(locX, locZ)];
}
int GetSkyLight(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 15;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = (light >> 12) & 0xF;
return skyLight;
}
int GetRLight(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = (light >> 8) & 0xF;
return skyLight;
}
int GetGLight(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = (light >> 4) & 0xF;
return skyLight;
}
int GetBLight(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = light & 0xF;
return skyLight;
}
Color GetSunlightColor();
Color GetLight(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return {0, 0, 0, 0};
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = powf(((light >> 12) & 0xF) / 15.0f, 1) * 255;
Color r = {((light >> 8) & 0xF) * 16, 0, 0, 255};
Color g = {0, ((light >> 4) & 0xF) * 16, 0, 255};
Color b = {0, 0, ((light >> 0) & 0xF) * 16, 255};
Color sun = GetSunlightColor();
return {
fmax((int)skyLight * (sun.r/255.0f), (int)r.r),
fmax((int)skyLight * (sun.g/255.0f), (int)g.g),
fmax((int)skyLight * (sun.b/255.0f), (int)b.b),
255
};
}
Color GetLightMesher(World &world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return {0, 0, 0, 0};
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
uint16_t light = world.chunks[GetIndexWorld(cx, cz)].light[GetIndexChunk(locX, y, locZ)];
int skyLight = powf(((light >> 12) & 0xF) / 15.0f, 1) * 255;
return {
((light >> 8) & 0xF) * 16,
((light >> 4) & 0xF) * 16,
((light >> 0) & 0xF) * 16,
skyLight
};
}
bool CanTick(int blockType) { // TODO: make smarter in case other blocks can tick too! bool CanTick(int blockType) { // TODO: make smarter in case other blocks can tick too!
return blockType == BLOCK_SAND; return blockType == BLOCK_SAND;
} }
bool GetCloud(int x, int z) { bool GetCloud(int x, int z) {
return (perlin.noise2D((x / 8) * 1.5f * CLOUD_SCALE, (z / 8) * 1.5f * CLOUD_SCALE) + 1.0f) / 2.0f > 0.5f; //return (perlin.noise2D((x / 8) * 1.5f * CLOUD_SCALE, (z / 8) * 1.5f * CLOUD_SCALE) + 1.0f) / 2.0f > 0.5f;
return false;
} }
static int GetBlockCaveWorld(int x, int y, int z) { static int GetBlockCaveWorld(int x, int y, int z) {
float caveNoise = (perlin.noise3D((float)x * 3.0f * SCALE + CAVE_OFFSET, (float)y * 3.0f * SCALE + CAVE_OFFSET, (float)z * 3.0f * SCALE + CAVE_OFFSET) + 1.0f) / 2.0f; /*float caveNoise = (perlin.noise3D((float)x * 3.0f * SCALE + CAVE_OFFSET, (float)y * 3.0f * SCALE + CAVE_OFFSET, (float)z * 3.0f * SCALE + CAVE_OFFSET) + 1.0f) / 2.0f;
if(caveNoise > 0.5f) { if(caveNoise > 0.5f) {
return BLOCK_STONE; return BLOCK_STONE;
} }*/
return BLOCK_AIR; return BLOCK_AIR;
} }
static int has_block(int x, int y, int z) static int has_block(int x, int y, int z)
@@ -174,15 +292,15 @@ void SetBlockChunk(Chunk *c, int x, int y, int z, int t) {
} }
} }
} }
void RebuildHeightmap(Chunk *c) { void RebuildHeightmap(Chunk &c) {
for (int x = 0; x < CHUNK_SIZE; x++) for (int x = 0; x < CHUNK_SIZE; x++)
{ {
for (int z = 0; z < CHUNK_SIZE; z++) for (int z = 0; z < CHUNK_SIZE; z++)
{ {
for (int y = WORLD_HEIGHT-1; y >= 0; y--) for (int y = WORLD_HEIGHT-1; y >= 0; y--)
{ {
if(c->blocks[GetIndexChunk(x,y,z)] != 0) { if(c.blocks[GetIndexChunk(x,y,z)] != 0) {
c->highestBlock[GetIndexChunk2D(x, z)] = y; c.highestBlock[GetIndexChunk2D(x, z)] = y;
break; break;
} }
} }
@@ -195,21 +313,63 @@ int GetBiome(int sx, int sy) {
void SetBlockChunkFast(Chunk *c, int i, int t) { void SetBlockChunkFast(Chunk *c, int i, int t) {
c->blocks[i] = t; c->blocks[i] = t;
} }
void SetBlock(Chunk world[], int x, int y, int z, int t) { void SetBlock(World &world, int x, int y, int z, int t) {
if(CheckOOBWorld(x, y, z)) { return; } if(CheckOOBWorld(x, y, z)) { return; }
int locX = x % CHUNK_SIZE; int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE; int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE; int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE; int cz = z / CHUNK_SIZE;
SetBlockChunk(&world[GetIndexWorld(cx, cz)], locX, y, locZ, t); SetBlockChunk(&world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ, t);
} }
void SetLightChunk(Chunk *c, int x, int y, int z, uint8_t sky, uint8_t r, uint8_t g, uint8_t b) {
int target = c->light[GetIndexChunk(x,y,z)];
if(sky > 0) {
target |= sky << 12;
}
if(r > 0) {
target |= r << 8;
}
if(g > 0) {
target |= g << 4;
}
if(b > 0) {
target |= b;
}
c->light[GetIndexChunk(x,y,z)] = target;
}
void SetLight(World &world, int x, int y, int z, uint8_t sky, uint8_t r, uint8_t g, uint8_t b) {
if(CheckOOBWorld(x, y, z)) { return; }
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
SetLightChunk(&world.chunks[GetIndexWorld(cx, cz)], locX, y, locZ, sky, r, g, b);
}
void InitWorldgen(int worldType) { void InitWorldgen(int worldType) {
const siv::PerlinNoise::seed_type seed = 123456u; perlin = fnlCreateState();
const siv::PerlinNoise perlin{ seed }; perlin.noise_type = FNL_NOISE_OPENSIMPLEX2;
perlin.fractal_type = FNL_FRACTAL_FBM;
perlin.frequency = 0.00522f;
perlin.octaves = 8;
perlinLofi = fnlCreateState();
perlinLofi.noise_type = FNL_NOISE_OPENSIMPLEX2;
perlinLofi.fractal_type = FNL_FRACTAL_FBM;
perlinLofi.frequency = 0.01671f;
perlinLofi.octaves = 4;
perlin2 = fnlCreateState();
perlin2.noise_type = FNL_NOISE_OPENSIMPLEX2;
perlin2.fractal_type = FNL_FRACTAL_FBM;
perlin2.frequency = 0.00522f;
perlin2.octaves = 8;
constexpr size_t MAX = 128; // allowed range: 0..MAX-1 constexpr size_t MAX = 128; // allowed range: 0..MAX-1
for (int i = 0; i < sizeof(BLOCKS) / sizeof(BlockDef); i++) for (int i = 0; i < BLOCKS.size(); i++)
{ {
BlockDef def = BLOCKS[i]; BlockDef def = GetBlockDefinition(i);
if(def.render == R_Translucent || def.render == R_TranslucentAllSides || def.render == R_TranslucentTriSide) { if(def.render == R_Translucent || def.render == R_TranslucentAllSides || def.render == R_TranslucentTriSide) {
marked.set(i); marked.set(i);
} }
@@ -224,21 +384,16 @@ Chunk GenerateChunk(int _x, int _y) {
Chunk new_chunk = { 0 }; Chunk new_chunk = { 0 };
new_chunk.x = _x; new_chunk.x = _x;
new_chunk.z = _y; new_chunk.z = _y;
memset(&new_chunk.light, 0, sizeof(new_chunk.light));
for (int y = 0; y < WORLD_HEIGHT; y++)
for (int x = 0; x < CHUNK_SIZE; x++) for (int x = 0; x < CHUNK_SIZE; x++)
{ for (int z = 0; z < CHUNK_SIZE; z++) {
for (int y = 0; y < WORLD_HEIGHT; y++) int id = has_block(_x * CHUNK_SIZE + x,y,_y * CHUNK_SIZE + z);
{ SetBlockChunk(&new_chunk, x, y, z, id);
for (int z = 0; z < CHUNK_SIZE; z++)
{
int id = has_block(_x * CHUNK_SIZE + x,y,_y * CHUNK_SIZE + z);
SetBlockChunk(&new_chunk, x, y, z, id);
}
}
} }
return new_chunk; return new_chunk;
} }
void GenerateWorldAdditional(Chunk world[]) { void GenerateWorldAdditional(World &world) {
int biome = GetBiome(0, 0); int biome = GetBiome(0, 0);
SetRandomSeed(0); SetRandomSeed(0);
switch (world_type) switch (world_type)
@@ -247,36 +402,11 @@ void GenerateWorldAdditional(Chunk world[]) {
for (int x = 0; x < WORLD_SIZE_BLOCKS; x++) for (int x = 0; x < WORLD_SIZE_BLOCKS; x++)
{ {
for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) { for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) {
Chunk c = world[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)]; Chunk c = world.chunks[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)];
int highestY = c.highestBlock[GetIndexChunk2D(x % CHUNK_SIZE, z % CHUNK_SIZE)]; int highestY = c.highestBlock[GetIndexChunk2D(x % CHUNK_SIZE, z % CHUNK_SIZE)];
int b = fetch_block(c, x % CHUNK_SIZE, highestY, z % CHUNK_SIZE); int b = fetch_block(c, x % CHUNK_SIZE, highestY, z % CHUNK_SIZE);
for (int _ = 0; _ < GetRandomValue(0, 6); _++) if(b == BLOCK_DIRT) {
{ SetBlock(world, x, highestY, z, BLOCK_GRASS);
if(GetRandomValue(0, 800) == 0) {
int max = GetRandomValue(10, 120);
Vector3 pos = {x, GetRandomValue(12, WORLD_HEIGHT-32), z};
Vector3 direction = {GetRandomValue(-100, 100) / 100.0f, GetRandomValue(-100, -5) / 100.0f, GetRandomValue(-100, 100) / 100.0f};
int radius = 2;
for (int _ = 0; _ < max; _++)
{
for (int x = -radius; x < radius; x++)
{
for (int y = -radius; y < radius; y++)
{
for (int z = -radius; z < radius; z++)
{
if(Vector3Distance({pos.x + x, pos.y + y, pos.z + z}, pos) <= radius) {
if(!CheckOOBWorld(pos.x + x, pos.y + y, pos.z + z)) {
SetBlock(world, pos.x + x, pos.y + y, pos.z + z, 0);
}
}
}
}
}
direction += {GetRandomValue(-100, 100) / 100.0f, GetRandomValue(-100, -5) / 100.0f, GetRandomValue(-100, 100) / 100.0f};
pos += direction;
}
}
} }
for (int _ = 0; _ < GetRandomValue(8, 24); _++) for (int _ = 0; _ < GetRandomValue(8, 24); _++)
{ {
@@ -314,10 +444,10 @@ void GenerateWorldAdditional(Chunk world[]) {
for (int x = 0; x < WORLD_SIZE_BLOCKS; x++) for (int x = 0; x < WORLD_SIZE_BLOCKS; x++)
{ {
for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) { for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) {
Chunk c = world[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)]; Chunk c = world.chunks[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)];
int highestY = c.highestBlock[GetIndexChunk2D(x % CHUNK_SIZE, z % CHUNK_SIZE)]; int highestY = c.highestBlock[GetIndexChunk2D(x % CHUNK_SIZE, z % CHUNK_SIZE)];
int b = fetch_block(c, x % CHUNK_SIZE, highestY, z % CHUNK_SIZE); int b = fetch_block(c, x % CHUNK_SIZE, highestY, z % CHUNK_SIZE);
if(b == BLOCK_GRASS && GetRandomValue(0, 100) < 4 && biome == BIOME_FOREST) { // Regular trees if(b == BLOCK_GRASS && GetRandomValue(0, 100) == 0 && biome == BIOME_FOREST) { // Regular trees
SetBlock(world, x, highestY, z, BLOCK_DIRT); SetBlock(world, x, highestY, z, BLOCK_DIRT);
int maxY = GetRandomValue(5, 7); int maxY = GetRandomValue(5, 7);
for (int y = 1; y < maxY; y++) for (int y = 1; y < maxY; y++)
@@ -334,7 +464,7 @@ void GenerateWorldAdditional(Chunk world[]) {
SetBlock(world, x, wy, z, 12); // log SetBlock(world, x, wy, z, 12); // log
} }
} }
if(b == BLOCK_GRASS && GetRandomValue(0, 100) < 2 && biome == BIOME_TAIGA) { // Spruce if(b == BLOCK_GRASS && GetRandomValue(0, 100) == 0 && biome == BIOME_TAIGA) { // Spruce
SetBlock(world, x, highestY, z, BLOCK_DIRT); SetBlock(world, x, highestY, z, BLOCK_DIRT);
int maxY = 8; int maxY = 8;
for (int y = 1; y < maxY; y++) for (int y = 1; y < maxY; y++)
@@ -421,62 +551,293 @@ void GenerateWorldAdditional(Chunk world[]) {
break; break;
} }
} }
void TickBlock(Chunk world[], int wx, int wy, int wz) { void TickBlock(World &world, int wx, int wy, int wz) {
if(CheckOOBWorld(wx, wy, wz)) return; if(CheckOOBWorld(wx, wy, wz)) return;
int tile = GetBlock(world, wx, wy, wz); int tile = GetBlock(world, wx, wy, wz);
if(tile == BLOCK_SAND) { if(tile == BLOCK_SAND) {
if(GetBlock(world, wx, wy-1, wz) == 0) { if(GetBlock(world, wx, wy-1, wz) == 0) {
SetBlockNetwork(world, wx, wy, wz, 0); SetBlockNetwork(world, wx, wy, wz, 0);
Entity temp = NewEntity(0); Entity temp = NewEntity();
temp.type = 4; temp.type = 4;
temp.position = (Vector3){wx, wy, wz}; temp.position = (Vector3){wx, wy, wz};
temp.velocity = {0, 0, 0}; temp.velocity = {0, 0, 0};
temp.data[1] = BLOCK_SAND; temp.data[1] = BLOCK_SAND;
//AddEntity(temp); AddEntity(temp);
} }
} }
} }
void TickChunk(Chunk *chunk, Chunk *world, int wx, int wz) { void TickChunk(Chunk *chunk, World &world, int wx, int wz) {
for (int y = WORLD_HEIGHT-1; y > 1; y--) { for (int y = WORLD_HEIGHT-1; y > 1; y--) {
for (int x = 0; x < CHUNK_SIZE; x++) for (int x = 0; x < CHUNK_SIZE; x++)
{ {
for (int z = 0; z < CHUNK_SIZE; z++) for (int z = 0; z < CHUNK_SIZE; z++)
{ {
TickBlock(world, x, y, z); int tile = fetch_block_ptr(chunk, x, y, z);
if(tile == BLOCK_SAND) {
if(fetch_block_ptr(chunk, x, y-1, z) == 0) {
SetBlockChunk(chunk, x, y, z, 0);
Entity temp = NewEntity();
temp.type = 4;
temp.position = (Vector3){((int)wx * CHUNK_SIZE + x), y, ((int)wz * CHUNK_SIZE + z)};
temp.velocity = {0, 0, 0};
temp.data[1] = BLOCK_SAND;
AddEntity(temp);
chunk->isDirty = true;
}
}
if(false) { // tile == BLOCK_WATERS
int rx = GetRandomValue(-1, 1);
int rz = GetRandomValue(-1, 1);
for (int _y = 0; _y >= -1; _y--)
{
if(GetBlock(world, wx+x+rx, y+_y, wz+z+rz) == 0) {
SetBlockChunk(chunk, x, y+_y, z, 0);
SetBlock(world, wx+x+rx, y+_y, wz+z+rz, BLOCK_WATERS);
chunk->isDirty = true;
continue;
}
}
}
} }
} }
} }
} }
void RebuildOpaqueMask(Chunk *chunk) { struct LightNode {
Vector3I position;
int value;
};
void RebuildOpaqueMask(Chunk &chunk) {
const int GROUP = 16; const int GROUP = 16;
const int GROUPS = CHUNK_DATA_SIZE / GROUP; const int GROUPS = CHUNK_DATA_SIZE / GROUP;
uint16_t oMask[GROUPS] = { 0 }; uint16_t oMask[GROUPS] = { 0 };
uint16_t aMask[GROUPS] = { 0 }; uint16_t aMask[GROUPS] = { 0 };
uint8_t blocks[CHUNK_DATA_SIZE]; uint8_t blocks[CHUNK_DATA_SIZE];
memcpy(blocks, chunk->blocks, sizeof(blocks)); memcpy(blocks, chunk.blocks, sizeof(blocks));
for (int i = 0; i < CHUNK_DATA_SIZE; ++i) { for (int i = 0; i < CHUNK_DATA_SIZE; ++i) {
int g = i / GROUP; int g = i / GROUP;
int bit = i % GROUP; int bit = i % GROUP;
if (chunk->blocks[i] == 0) { if (chunk.blocks[i] == 0) {
aMask[g] |= 1 << bit; aMask[g] |= 1 << bit;
} }
if (!IsTranslucent(chunk->blocks[i])) { if (!IsTranslucent(chunk.blocks[i])) {
oMask[g] |= 1 << bit; oMask[g] |= 1 << bit;
} }
} }
memcpy(chunk->opaqueMask, oMask, sizeof(oMask)); memcpy(chunk.opaqueMask, oMask, sizeof(oMask));
memcpy(chunk->airMask, aMask, sizeof(aMask)); memcpy(chunk.airMask, aMask, sizeof(aMask));
} }
void RebuildLighting(World &world, int startX, int startZ) {
const Vector3I dirs[6] = { (Vector3I){ 1, 0, 0 }, (Vector3I){ -1, 0, 0 }, (Vector3I){ 0, 1, 0 }, (Vector3I){ 0,-1, 0 }, (Vector3I){ 0, 0, 1 }, (Vector3I){ 0, 0,-1 } };
// sky lighting
std::queue<LightNode> nodes;
for (int cx = -1; cx <= 1; cx++)
{
for (int cz = -1; cz <= 1; cz++) {
Chunk &chunk = world.chunks[GetIndexWorld(startX+cx, startZ+cz)];
memset(&chunk.light, 0, sizeof(chunk.light));
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
int highest = chunk.highestBlock[GetIndexChunk2D(x, z)];
const int neighbors[4] = {
chunk.highestBlock[GetIndexChunk2D(x-1, z)],
chunk.highestBlock[GetIndexChunk2D(x+1, z)],
chunk.highestBlock[GetIndexChunk2D(x, z-1)],
chunk.highestBlock[GetIndexChunk2D(x, z+1)]
};
int highestNeighbor = fmax(neighbors[0], fmax(neighbors[1], fmax(neighbors[2], neighbors[3])));
Vector3I pos = { x + chunk.x * CHUNK_SIZE, highest + 1, z + chunk.z * CHUNK_SIZE };
for (int y = highest + 1; y <= WORLD_HEIGHT; ++y)
{
SetLightChunk(&chunk, x, y, z, 15, 0, 0, 0);
}
if (highest == highestNeighbor) continue;
for (int y = highest+1; y < highestNeighbor+1; y++)
{
if (
GetSkyLight(world, pos.x-1, y, pos.z) < 15 && !TestOpaqueMaskWorld(world, pos.x-1, y, pos.z)
) nodes.push({(Vector3I){pos.x-1, y, pos.z}, 15});
if (
GetSkyLight(world, pos.x+1, y, pos.z) < 15 && !TestOpaqueMaskWorld(world, pos.x+1, y, pos.z)
) nodes.push({(Vector3I){pos.x+1, y, pos.z}, 15});
if (
GetSkyLight(world, pos.x, y, pos.z-1) < 15 && !TestOpaqueMaskWorld(world, pos.x, y, pos.z-1)
) nodes.push({(Vector3I){pos.x, y, pos.z-1}, 15});
if (
GetSkyLight(world, pos.x, y, pos.z+1) < 15 && !TestOpaqueMaskWorld(world, pos.x, y, pos.z+1)
) nodes.push({(Vector3I){pos.x, y, pos.z+1}, 15});
}
}
}
}
}
while (!nodes.empty()) {
LightNode node = nodes.front();
nodes.pop();
for (int i = 0; i < 6; i++) {
int newValue = node.value - 1;
if (newValue <= 0) continue;
Vector3I newPos = {
node.position.x + dirs[i].x,
node.position.y + dirs[i].y,
node.position.z + dirs[i].z
};
if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue;
if (TestOpaqueMaskWorld(world, newPos.x, newPos.y, newPos.z)) continue;
if (GetSkyLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue;
SetLight(world, newPos.x, newPos.y, newPos.z, newValue, 0, 0, 0);
nodes.push({ newPos, newValue });
}
}
// red lighting
std::queue<LightNode> nodesR;
for (int cx = -1; cx <= 1; cx++)
{
for (int cz = -1; cz <= 1; cz++) {
Chunk &chunk = world.chunks[GetIndexWorld(startX+cx, startZ+cz)];
for (int i = 0; i < CHUNK_DATA_SIZE; i++)
{
int x, y, z;
GetXYZFromIndex(i, &x, &y, &z);
if (CheckOOBWorld(x, y, z)) continue;
if(chunk.blocks[i] != 18 && chunk.blocks[i] != 21) continue;
Vector3I pos = { x + chunk.x * CHUNK_SIZE, y, z + chunk.z * CHUNK_SIZE };
LightNode node{pos, 15};
nodesR.push(node);
}
}
}
while (!nodesR.empty()) {
LightNode node = nodesR.front();
nodesR.pop();
for (int i = 0; i < 6; i++) {
Vector3I newPos = {
node.position.x + dirs[i].x,
node.position.y + dirs[i].y,
node.position.z + dirs[i].z
};
if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue;
if (TestOpaqueMaskWorld(world, newPos.x, newPos.y, newPos.z)) continue;
int newValue = node.value - 1;
if (newValue <= 0) continue;
if (GetRLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue;
SetLight(world, newPos.x, newPos.y, newPos.z, 0, newValue, 0, 0);
nodesR.push({ newPos, newValue });
}
}
// green lighting
std::queue<LightNode> nodesG;
for (int cx = -1; cx <= 1; cx++)
{
for (int cz = -1; cz <= 1; cz++) {
Chunk &chunk = world.chunks[GetIndexWorld(startX+cx, startZ+cz)];
for (int i = 0; i < CHUNK_DATA_SIZE; i++)
{
int x, y, z;
GetXYZFromIndex(i, &x, &y, &z);
if (CheckOOBWorld(x, y, z)) continue;
if(chunk.blocks[i] != 19 && chunk.blocks[i] != 21) continue;
Vector3I pos = { x + chunk.x * CHUNK_SIZE, y, z + chunk.z * CHUNK_SIZE };
LightNode node{pos, 15};
nodesG.push(node);
}
}
}
while (!nodesG.empty()) {
LightNode node = nodesG.front();
nodesG.pop();
for (int i = 0; i < 6; i++) {
Vector3I newPos = {
node.position.x + dirs[i].x,
node.position.y + dirs[i].y,
node.position.z + dirs[i].z
};
if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue;
if (TestOpaqueMaskWorld(world, newPos.x, newPos.y, newPos.z)) continue;
int newValue = node.value - 1;
if (newValue <= 0) continue;
if (GetGLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue;
SetLight(world, newPos.x, newPos.y, newPos.z, 0, 0, newValue, 0);
nodesG.push({ newPos, newValue });
}
}
// blue lighting
std::queue<LightNode> nodesB;
for (int cx = -1; cx <= 1; cx++)
{
for (int cz = -1; cz <= 1; cz++) {
Chunk &chunk = world.chunks[GetIndexWorld(startX+cx, startZ+cz)];
for (int i = 0; i < CHUNK_DATA_SIZE; i++)
{
int x, y, z;
GetXYZFromIndex(i, &x, &y, &z);
if (CheckOOBWorld(x, y, z)) continue;
if(chunk.blocks[i] != 20 && chunk.blocks[i] != 21) continue;
Vector3I pos = { x + chunk.x * CHUNK_SIZE, y, z + chunk.z * CHUNK_SIZE };
LightNode node{pos, 15};
nodesB.push(node);
}
}
}
while (!nodesB.empty()) {
LightNode node = nodesB.front();
nodesB.pop();
for (int i = 0; i < 6; i++) {
Vector3I newPos = {
node.position.x + dirs[i].x,
node.position.y + dirs[i].y,
node.position.z + dirs[i].z
};
if (CheckOOBWorld(newPos.x, newPos.y, newPos.z)) continue;
if (TestOpaqueMaskWorld(world, newPos.x, newPos.y, newPos.z)) continue;
int newValue = node.value - 1;
if (newValue <= 0) continue;
if (GetBLight(world, newPos.x, newPos.y, newPos.z) >= newValue) continue;
SetLight(world, newPos.x, newPos.y, newPos.z, 0, 0, 0, newValue);
nodesB.push({ newPos, newValue });
}
}
}
#ifndef SERVER #ifndef SERVER
//Generates an opaque CRD (ChunkRenderData). Outputs the CRD. //Generates an opaque CRD (ChunkRenderData). Outputs the CRD.
ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) { ChunkRenderData GenerateCRDOpaque(Chunk &chunk, World &world) {
struct ChunkRenderData new_chunk = { 0 }; struct ChunkRenderData new_chunk = { 0 };
uint16_t mask[CHUNK_DATA_SIZE/16]; uint16_t *mask = chunk.opaqueMask;
memcpy(mask, chunk.opaqueMask, sizeof(chunk.opaqueMask));
const int cxw = chunk.x * CHUNK_SIZE; const int cxw = chunk.x * CHUNK_SIZE;
const int cxz = chunk.z * CHUNK_SIZE; const int cxz = chunk.z * CHUNK_SIZE;
@@ -492,8 +853,6 @@ ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) {
int _x = bit; int _x = bit;
int y = step >> 4; int y = step >> 4;
int _z = step & 0xF; int _z = step & 0xF;
//int _x, y, _z;
//GetXYZFromIndex(i2, &_x, &y, &_z);
if (!TestMask(mask, i2)) continue; // Skip if this is translucent if (!TestMask(mask, i2)) continue; // Skip if this is translucent
int x = _x + cxw; int x = _x + cxw;
@@ -519,7 +878,7 @@ ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) {
} }
//Generates a translucent CRD (ChunkRenderData). Outputs the CRD. //Generates a translucent CRD (ChunkRenderData). Outputs the CRD.
ChunkRenderData GenerateCRDTranslucent(Chunk chunk, Chunk world[]) { ChunkRenderData GenerateCRDTranslucent(Chunk chunk, World &world) {
struct ChunkRenderData new_chunk = { 0 }; struct ChunkRenderData new_chunk = { 0 };
uint16_t *mask0= chunk.opaqueMask; uint16_t *mask0= chunk.opaqueMask;
uint16_t *mask = chunk.airMask; uint16_t *mask = chunk.airMask;
@@ -544,6 +903,55 @@ ChunkRenderData GenerateCRDTranslucent(Chunk chunk, Chunk world[]) {
new_chunk.sides[i2] = 0xFF; new_chunk.sides[i2] = 0xFF;
continue; continue;
} }
if(BLOCKS[fetch_block(chunk, _x, y, _z)].name == "water") {
continue;
}
int x = _x + chunk.x * CHUNK_SIZE;
int z = _z + chunk.z * CHUNK_SIZE;
bool l = (_x > 0) ? !TestMask(mask, i2-1) : !TestAirMaskWorld(world, x - 1, y, z);
bool r = (_x < CHUNK_SIZE-1) ? !TestMask(mask, i2+1) : !TestAirMaskWorld(world, x + 1, y, z);
bool u = (y==WORLD_HEIGHT-1) ? false : !TestMask(mask, i2+CHUNK_SIZE_SQR);
bool d = (y==0) ? true : !TestMask(mask, i2-CHUNK_SIZE_SQR);
bool b = (_z==0) ? !TestAirMaskWorld(world, x, y, z - 1) : !TestMask(mask, i2-CHUNK_SIZE);
bool f = (_z==CHUNK_SIZE-1) ? !TestAirMaskWorld(world, x, y, z + 1) : !TestMask(mask, i2+CHUNK_SIZE);
new_chunk.sides[i2] = pack6(
!l,
!r,
!u,
!d,
!b,
!f
);
}
}
return new_chunk;
}
//Generates a CRD for water (ChunkRenderData). Outputs the CRD.
ChunkRenderData GenerateCRDWater(Chunk chunk, World &world) {
struct ChunkRenderData new_chunk = { 0 };
uint16_t *mask0= chunk.opaqueMask;
uint16_t *mask = chunk.airMask;
for (int step = 0; step < CHUNK_DATA_SIZE/16; ++step)
{
uint16_t m = ~(mask[step]);
if(m == 0) continue;
while (m) {
int bit = __builtin_ctz(m);
m &= m - 1;
int i2 = (step<<4) + bit;
int _x = bit;
int y = step >> 4;
int _z = step & 0xF;
if (TestMask(mask0, i2)) {
new_chunk.sides[i2] = 0;
continue;
};
if(BLOCKS[fetch_block(chunk, _x, y, _z)].name != "water") {
continue;
}
int x = _x + chunk.x * CHUNK_SIZE; int x = _x + chunk.x * CHUNK_SIZE;
int z = _z + chunk.z * CHUNK_SIZE; int z = _z + chunk.z * CHUNK_SIZE;
bool l = (_x > 0) ? !TestMask(mask, i2-1) : !TestAirMaskWorld(world, x - 1, y, z); bool l = (_x > 0) ? !TestMask(mask, i2-1) : !TestAirMaskWorld(world, x - 1, y, z);
@@ -567,7 +975,7 @@ ChunkRenderData GenerateCRDTranslucent(Chunk chunk, Chunk world[]) {
#endif #endif
#define SAVE_FORMAT 0 #define SAVE_FORMAT 0
void SaveWorld(Chunk world[], const char* path) { void SaveWorld(World &world, const char* path) {
std::ofstream data(path, std::ios::binary); std::ofstream data(path, std::ios::binary);
if (!data) return; if (!data) return;
@@ -576,7 +984,7 @@ void SaveWorld(Chunk world[], const char* path) {
data.write(&fmt, 1); data.write(&fmt, 1);
for (int i = 0; i < MAX_WORLD_AREA; ++i) { for (int i = 0; i < MAX_WORLD_AREA; ++i) {
const Chunk &c = world[i]; const Chunk &c = world.chunks[i];
std::vector<uint8_t> temp; std::vector<uint8_t> temp;
int last_type = -1; int last_type = -1;
@@ -614,7 +1022,8 @@ void SaveWorld(Chunk world[], const char* path) {
} }
void Debug_Write(const std::string &stuff); void Debug_Write(const std::string &stuff);
bool LoadWorld(Chunk world[], const char* path) {
bool LoadWorld(World &world, const char* path) {
std::ifstream data(path, std::ios::binary); std::ifstream data(path, std::ios::binary);
if (!data) return false; if (!data) return false;
@@ -643,19 +1052,22 @@ bool LoadWorld(Chunk world[], const char* path) {
return false; return false;
} }
} }
Chunk *c = &world[i]; Chunk c = {0};
c.x = i % 16;
c.z = i >> 4;
int outIndex = 0; int outIndex = 0;
for (size_t p = 0; p + 1 < size; p += 2) { for (size_t p = 0; p + 1 < size; p += 2) {
uint8_t count = temp[p]; uint8_t count = temp[p];
uint8_t value = temp[p + 1]; uint8_t value = temp[p + 1];
for (uint8_t k = 0; k < count; ++k) { for (uint8_t k = 0; k < count; ++k) {
SetBlockChunkFast(c, outIndex++, value); SetBlockChunkFast(&c, outIndex++, value);
} }
} }
while (outIndex < CHUNK_DATA_SIZE) { while (outIndex < CHUNK_DATA_SIZE) {
SetBlockChunkFast(c, outIndex++, 0); SetBlockChunkFast(&c, outIndex++, 0);
} }
RebuildHeightmap(c); RebuildHeightmap(c);
memcpy(&world.chunks[i], &c, sizeof(c));
} }
free(temp); free(temp);
return true; return true;
+102 -75
View File
@@ -1,4 +1,4 @@
#ifdef WIN32 // FUCK WINDOWS #ifdef WIN32 // FUCK WINDOWS
#include "external/fix_win32_compatibility.h" #include "external/fix_win32_compatibility.h"
#undef PlaySound #undef PlaySound
#endif #endif
@@ -9,8 +9,8 @@
#undef PlaySound #undef PlaySound
#undef Sound #undef Sound
#endif #endif
#include <functional>
#include "glfw_keycodes_to_string.h" #include "glfw_keycodes_to_string.h"
#include "../PerlinNoise.hpp"
#include "raylib.h" #include "raylib.h"
#include "raymath.h" #include "raymath.h"
#include <stdint.h> #include <stdint.h>
@@ -62,16 +62,12 @@
#define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS #define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS
#define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw #define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw
#define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max) #define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max)
#define NET_ARG_ENTITYSPAWN 0x0A // uint16_t entityWorldID, uint8_t entityTypeID, uint16_t x, uint16_t y, uint16_t z, uint8_t data[8]
#define NET_ARG_ENTITYMOVE 0x0B // uint16_t entityWorldID, uint16_t x, uint16_t y, uint16_t z
#define NET_ARG_PLRSKIN 0x0C // Byte 1 - ID, bytes 2-3 - size, rest is skin
#define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw #define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw
#define NET_ARG_BLOCKDELTA 0x81 // Block X, block Y, block Z, block type #define NET_ARG_BLOCKDELTA 0x81 // Block X, block Y, block Z, block type
#define NET_ARG_REQWORLD 0x82 // No additional data #define NET_ARG_REQWORLD 0x82 // No additional data
#define NET_ARG_REQPLAYERS 0x83 // No additional data #define NET_ARG_REQPLAYERS 0x83 // No additional data
#define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw #define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw
#define NET_ARG_MESSAGEC 0x85 // All is message (64b max) #define NET_ARG_MESSAGEC 0x85 // All is message (64b max)
#define NET_ARG_PLRSKINSET 0x86 // Byte 1 - ID, bytes 2-3 - size, rest is skin
#define NET_ERROR_DSCN 0x00 #define NET_ERROR_DSCN 0x00
#define NET_ERROR_NOTFOUND 0x01 #define NET_ERROR_NOTFOUND 0x01
#define NET_ERROR_FAILED 0x02 #define NET_ERROR_FAILED 0x02
@@ -79,11 +75,10 @@
#define GAME_NAME "CubeGame" #define GAME_NAME "CubeGame"
#define GAME_VERSION_INT 0 #define GAME_VERSION_INT 0
#define DEFAULT_FONT_SIZE 16 #define DEFAULT_FONT_SIZE 16
#define TPS 30.0 #define TPS 30
#define TPS_DIV 1.0 / TPS #define TPS_DIV 1.0 / TPS
#define RENDER_DISTANCE 16 #define RENDER_DISTANCE 16
#define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE
#define PIXUNIT 1.0f / 16.0f
#define MAX_HP 100 #define MAX_HP 100
#define PATH_APPEND "resources/" #define PATH_APPEND "resources/"
#define PATH_APPEND_USER "user/" #define PATH_APPEND_USER "user/"
@@ -91,6 +86,8 @@
#define INVENTORY_WIDTH 8 #define INVENTORY_WIDTH 8
#define INVENTORY_HEIGHT 6 #define INVENTORY_HEIGHT 6
#define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT #define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT
#define WORLD_TIME_SECONDS (24*60)
#define WORLD_TIME_TICKS WORLD_TIME_SECONDS*TPS
enum BlockType { enum BlockType {
B_Wood, B_Wood,
B_Stone, B_Stone,
@@ -157,7 +154,7 @@ struct Chunk {
uint16_t opaqueMask[CHUNK_DATA_SIZE/16]; uint16_t opaqueMask[CHUNK_DATA_SIZE/16];
uint16_t airMask[CHUNK_DATA_SIZE/16]; uint16_t airMask[CHUNK_DATA_SIZE/16];
uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE]; uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE];
uint16_t light[CHUNK_DATA_SIZE];
}; };
#if !defined(SERVER) #if !defined(SERVER)
typedef struct ChunkRenderData ChunkRenderData; typedef struct ChunkRenderData ChunkRenderData;
@@ -200,24 +197,33 @@ struct Quad2D {
#endif #endif
typedef struct Vector3I Vector3I; typedef struct Vector3I Vector3I;
struct Vector3I { struct Vector3I {
int x; int x, y, z;
int y; bool operator==(const Vector3I& other) const {
int z; return (x == other.x && y == other.y && z == other.z);
};
};
typedef struct Vector3IHash Vector3IHash;
struct Vector3IHash {
size_t operator()(const Vector3I& p) const noexcept {
size_t h1 = std::hash<int>{}(p.x);
size_t h2 = std::hash<int>{}(p.y);
size_t h3 = std::hash<int>{}(p.z);
return h1 ^ (h2 << 1) ^ (h3 << 2);
}
}; };
typedef struct Entity Entity; typedef struct Entity Entity;
struct Entity { struct Entity {
uint16_t id;
uint8_t type; uint8_t type;
uint8_t id;
uint8_t damage_flash; uint8_t damage_flash;
uint8_t data[4]; uint8_t data[16];
uint8_t data_sv[8];
bool free;
float smoothing; float smoothing;
float health; float health;
float lifetime; float lifetime;
Vector3 position; Vector3 position;
Vector3 velocity; Vector3 velocity;
unsigned short yaw; unsigned short yaw;
bool free;
}; };
typedef struct NetPlayer NetPlayer; typedef struct NetPlayer NetPlayer;
struct NetPlayer { struct NetPlayer {
@@ -229,9 +235,6 @@ struct NetPlayer {
float x; float x;
float y; float y;
float z; float z;
std::string nickname;
Texture2D texture;
std::vector<uint8_t> skin;
}; };
typedef struct MemInfo MemInfo; typedef struct MemInfo MemInfo;
struct MemInfo { struct MemInfo {
@@ -297,28 +300,46 @@ struct Particle {
int lifetime; int lifetime;
int data[8]; int data[8];
}; };
extern const BlockDef BLOCKS[]; typedef struct World World;
struct World {
Chunk chunks[MAX_WORLD_AREA];
};
BlockDef&GetBlockDefinition(int id);
void LoadBlocks();
int GetBlock(World&world,int x,int y,int z);
int GetHighestBlock(World&world,int x,int z);
int GetSkyLight(World&world,int x,int y,int z);
int GetRLight(World&world,int x,int y,int z);
int GetGLight(World&world,int x,int y,int z);
int GetBLight(World&world,int x,int y,int z);
Color GetSunlightColor();
Color GetLight(World&world,int x,int y,int z);
Color GetLightMesher(World&world,int x,int y,int z);
bool CanTick(int blockType); bool CanTick(int blockType);
bool GetCloud(int x,int z); bool GetCloud(int x,int z);
bool IsTranslucent(int blockType); bool IsTranslucent(int blockType);
void SetBlockChunk(Chunk *c,int x,int y,int z,int t); void SetBlockChunk(Chunk *c,int x,int y,int z,int t);
void RebuildHeightmap(Chunk *c); void RebuildHeightmap(Chunk&c);
int GetBiome(int sx,int sy); int GetBiome(int sx,int sy);
void SetBlockChunkFast(Chunk *c,int i,int t); void SetBlockChunkFast(Chunk *c,int i,int t);
void SetBlock(Chunk world[],int x,int y,int z,int t); void SetBlock(World&world,int x,int y,int z,int t);
void SetLightChunk(Chunk *c,int x,int y,int z,uint8_t sky,uint8_t r,uint8_t g,uint8_t b);
void SetLight(World&world,int x,int y,int z,uint8_t sky,uint8_t r,uint8_t g,uint8_t b);
void InitWorldgen(int worldType); void InitWorldgen(int worldType);
Vector3 WorldPosition(int cx,int cz,int localX,int y,int localZ); Vector3 WorldPosition(int cx,int cz,int localX,int y,int localZ);
Chunk GenerateChunk(int _x,int _y); Chunk GenerateChunk(int _x,int _y);
void GenerateWorldAdditional(Chunk world[]); void GenerateWorldAdditional(World&world);
void TickBlock(Chunk world[],int wx,int wy,int wz); void TickBlock(World&world,int wx,int wy,int wz);
void TickChunk(Chunk *chunk,Chunk *world,int wx,int wz); void TickChunk(Chunk *chunk,World&world,int wx,int wz);
void RebuildOpaqueMask(Chunk *chunk); void RebuildOpaqueMask(Chunk&chunk);
void RebuildLighting(World&world,int startX,int startZ);
#if !defined(SERVER) #if !defined(SERVER)
ChunkRenderData GenerateCRDOpaque(const Chunk&chunk,Chunk world[]); ChunkRenderData GenerateCRDOpaque(Chunk&chunk,World&world);
ChunkRenderData GenerateCRDTranslucent(Chunk chunk,Chunk world[]); ChunkRenderData GenerateCRDTranslucent(Chunk chunk,World&world);
ChunkRenderData GenerateCRDWater(Chunk chunk,World&world);
#endif #endif
void SaveWorld(Chunk world[],const char *path); void SaveWorld(World&world,const char *path);
bool LoadWorld(Chunk world[],const char *path); bool LoadWorld(World&world,const char *path);
extern long nsTotal; extern long nsTotal;
void Debug_StartMeasure(); void Debug_StartMeasure();
#if defined(WIN32) #if defined(WIN32)
@@ -330,34 +351,49 @@ bool Debug_GetProcessMemory(MemInfo&out);
#if !defined(WIN32) #if !defined(WIN32)
bool Debug_GetProcessMemory(MemInfo&out); bool Debug_GetProcessMemory(MemInfo&out);
#endif #endif
#if !defined(SERVER)
extern Camera camera; extern Camera camera;
#endif
extern Camera3D camera; extern Camera3D camera;
#if !defined(SERVER) #if !defined(SERVER)
extern Camera camera; extern Camera camera;
#endif
extern Font fnt; extern Font fnt;
#if !defined(SERVER)
extern Font fnt; extern Font fnt;
#endif
extern Texture2D terrain; extern Texture2D terrain;
#endif
extern Texture2D terrain; extern Texture2D terrain;
#if !defined(SERVER) #if !defined(SERVER)
extern Texture2D terrain; extern Texture2D terrain;
extern Texture2D terrain; extern Texture2D terrain;
#endif extern Texture2D playerTex;
extern Texture2D nekitTex; extern Texture2D playerTex;
extern Texture2D bomb; extern Texture2D bomb;
extern Sound nekit_idle; extern Sound nekit_idle;
void EntitiesInit(); void EntitiesInit();
extern bool online; extern bool online;
#if !defined(SERVER)
extern bool online; extern bool online;
#endif #endif
#if !(!defined(SERVER))
extern bool online;
#endif
#if !defined(SERVER)
extern Vector3 player_position;
#endif
extern Vector3 player_position;
#if !defined(SERVER)
extern Vector3 player_velocity;
#endif
extern Vector3 player_velocity;
#if !defined(SERVER)
void TakeDamage(float amount); void TakeDamage(float amount);
void SetBlockNetwork(Chunk world[],int bx,int by,int bz,int t); void SetBlockNetwork(World&world,int bx,int by,int bz,int t);
Entity NewEntity(int id); #endif
Entity NewEntity();
void AddEntity(Entity ent);
void UpdateEntities(World&world,float dt);
extern float globalCounter; extern float globalCounter;
#if !defined(SERVER) #if !defined(SERVER)
void DrawEntities(float dt);
extern bool swap_mouse; extern bool swap_mouse;
bool InputGetLMB(); bool InputGetLMB();
bool InputGetLMBDown(); bool InputGetLMBDown();
@@ -372,7 +408,6 @@ extern int currentlySelected;
extern GameState state; extern GameState state;
extern Texture2D cubemap; extern Texture2D cubemap;
int TryConnect(const char *hostname); int TryConnect(const char *hostname);
void InitSingleplayer();
void GameModeCleanup(); void GameModeCleanup();
void DrawBackground(); void DrawBackground();
void InitMenu(); void InitMenu();
@@ -390,14 +425,13 @@ void DrawMainMenu();
void _LoadWorld(const char *path); void _LoadWorld(const char *path);
void DrawWorldSelect(); void DrawWorldSelect();
void DrawMultiplayer(); void DrawMultiplayer();
void ExitSingleplayer();
void DrawPauseMenu(); void DrawPauseMenu();
extern char bufferChat[MAX_MESSAGE_LENGTH]; extern char bufferChat[MAX_MESSAGE_LENGTH];
char *DrawChat(); char *DrawChat();
void DrawLogoCenter(); void DrawLogoCenter();
#endif #endif
#if !defined(LEGACY_GL) && !defined(SERVER) #if !defined(LEGACY_GL) && !defined(SERVER)
MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData,Chunk chunk,int chunkWorldX,int chunkWorldY,uint8_t sideMask); MeshData GenerateChunkMesh(World&world,ChunkRenderData chunkRenderData,Chunk chunk,int chunkWorldX,int chunkWorldY,uint8_t sideMask);
MeshData MergeMeshData(const MeshData&a,const MeshData&b); MeshData MergeMeshData(const MeshData&a,const MeshData&b);
MeshData CreateCubeMeshData(const BlockDef&def,float cx,float cy,float cz); MeshData CreateCubeMeshData(const BlockDef&def,float cx,float cy,float cz);
Mesh GenChunkMesh(MeshData meshData); Mesh GenChunkMesh(MeshData meshData);
@@ -414,10 +448,12 @@ const char *Pathify(const char *src);
const char *PathifyUser(const char *src); const char *PathifyUser(const char *src);
#if !defined(SERVER) #if !defined(SERVER)
void DrawCubeTexture(Texture2D texture,Vector3 position,float width,float height,float length,Color color,int offsetX,int offsetY,int sizeX,int sizeY); void DrawCubeTexture(Texture2D texture,Vector3 position,float width,float height,float length,Color color,int offsetX,int offsetY,int sizeX,int sizeY);
void DrawCubeBlock(Texture2D texture,Vector3 position,float width,float height,float length,BlockDef def); void DrawCubeBlock(Texture2D texture,Vector3 position,float width,float height,float length,BlockDef def,Color tint);
void DrawTextCodepoint3D(Font font,int codepoint,Vector3 position,float fontSize,bool backface,Color tint); void DrawTextCodepoint3D(Font font,int codepoint,Vector3 position,float fontSize,bool backface,Color tint);
void DrawText3D(Font font,const char *text,Vector3 position,float fontSize,float fontSpacing,float lineSpacing,bool backface,Color tint); void DrawText3D(Font font,const char *text,Vector3 position,float fontSize,float fontSpacing,float lineSpacing,bool backface,Color tint);
#endif #endif
RenderTexture2D LoadRenderTextureDepthTex(int width,int height);
void UnloadRenderTextureDepthTex(RenderTexture2D target);
inline uint8_t pack6(bool b0,bool b1,bool b2,bool b3,bool b4,bool b5){ inline uint8_t pack6(bool b0,bool b1,bool b2,bool b3,bool b4,bool b5){
return (uint8_t)( return (uint8_t)(
((uint8_t)(b0 ? 1 : 0) << 0) | ((uint8_t)(b0 ? 1 : 0) << 0) |
@@ -437,49 +473,53 @@ inline void unpack6(uint8_t v,bool *b0,bool *b1,bool *b2,bool *b3,bool *b4,bool
*b5 = (v >> 5) & 1; *b5 = (v >> 5) & 1;
}; };
inline void GetXYZFromIndex(int index,int *x,int *y,int *z){ inline void GetXYZFromIndex(int index,int *x,int *y,int *z){
*x = index & 15; *y = index / (CHUNK_SIZE * CHUNK_SIZE);
int tmp = index << 4; int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
*z = tmp & 15; *z = rem / CHUNK_SIZE;
*y = tmp << 4; *x = rem % CHUNK_SIZE;
}; };
inline int GetIndexChunk(int x,int y,int z){ inline int GetIndexChunk(int x,int y,int z){
if(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE) return 0; if(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE) return 0;
return x + CHUNK_SIZE * (z + CHUNK_SIZE* y); return x + CHUNK_SIZE * (z + CHUNK_SIZE * y);
}; };
inline int GetIndexChunk2D(int x,int z){ inline int GetIndexChunk2D(int x,int z){
if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0; if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0;
return x + CHUNK_SIZE * z; return x + CHUNK_SIZE * z;
}; };
inline bool CheckOOBWorld(int x,int y,int z){
return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS);
};
inline bool CheckOOBWorldChunk(int x,int z){
return (x < 0 || z < 0 || x >= MAX_WORLD_SIZE || z >= MAX_WORLD_SIZE);
};
inline int GetIndexWorld(int x,int z){ inline int GetIndexWorld(int x,int z){
if(CheckOOBWorld(x << 4, 0, z << 4)) return 0;
return x + MAX_WORLD_SIZE * z; return x + MAX_WORLD_SIZE * z;
}; };
inline void GetXZFromIndex(int index,int *x,int *z){ inline void GetXZFromIndex(int index,int *x,int *z){
*z = index / MAX_WORLD_SIZE; *z = index / MAX_WORLD_SIZE;
*x = index % MAX_WORLD_SIZE; *x = index % MAX_WORLD_SIZE;
}; };
inline bool TestMask(uint16_t *maskArray,int position){ inline bool TestMask(const uint16_t *maskArray,int position){
if (position < 0 || position >= CHUNK_DATA_SIZE) return false;
int index = position >> 4; int index = position >> 4;
int bit = position & 15; int bit = position & 15;
int maskArrayLen = CHUNK_DATA_SIZE << 4;
return (maskArray[index] & (1u << bit)) != 0; return (maskArray[index] & (1u << bit)) != 0;
}; };
inline bool CheckOOBWorld(int x,int y,int z){
return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS);
};
inline bool CheckOOBChunk(int x,int y,int z){ inline bool CheckOOBChunk(int x,int y,int z){
return (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE); return (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE);
}; };
inline bool TestOpaqueMaskWorld(Chunk world[],int x,int y,int z){ inline bool TestOpaqueMaskWorld(const World&world,int x,int y,int z){
if(CheckOOBWorld(x, y, z)) return true; if(CheckOOBWorld(x, y, z)) return true;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)]; const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15); const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->opaqueMask, localIndex); return TestMask(c.opaqueMask, localIndex);
}; };
inline bool TestAirMaskWorld(Chunk world[],int x,int y,int z){ inline bool TestAirMaskWorld(const World&world,int x,int y,int z){
if(CheckOOBWorld(x, y, z)) return true; if(CheckOOBWorld(x, y, z)) return true;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)]; const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15); const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->airMask, localIndex); return TestMask(c.airMask, localIndex);
}; };
inline int fetch_block(Chunk chunk,int x,int y,int z){ inline int fetch_block(Chunk chunk,int x,int y,int z){
if(x<0||x>=CHUNK_SIZE||y<0||y>=WORLD_HEIGHT||z<0||z>=CHUNK_SIZE) return 0; if(x<0||x>=CHUNK_SIZE||y<0||y>=WORLD_HEIGHT||z<0||z>=CHUNK_SIZE) return 0;
@@ -489,14 +529,6 @@ inline int fetch_block_ptr(Chunk *chunk,int x,int y,int z){
if(x<0||x>=CHUNK_SIZE||y<0||y>=WORLD_HEIGHT||z<0||z>=CHUNK_SIZE) return 0; if(x<0||x>=CHUNK_SIZE||y<0||y>=WORLD_HEIGHT||z<0||z>=CHUNK_SIZE) return 0;
return chunk->blocks[GetIndexChunk(x, y, z)]; return chunk->blocks[GetIndexChunk(x, y, z)];
}; };
inline int GetBlock(Chunk world[],int x,int y,int z){
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
return fetch_block(world[GetIndexWorld(cx, cz)], locX, y, locZ);
};
inline void *grow(void *ptr,size_t oldBytes,size_t newBytes){ inline void *grow(void *ptr,size_t oldBytes,size_t newBytes){
if (!ptr) return malloc(newBytes); if (!ptr) return malloc(newBytes);
return realloc(ptr, newBytes); return realloc(ptr, newBytes);
@@ -582,7 +614,6 @@ extern InventoryItem inventory[INVENTORY_SIZE];
#endif #endif
extern InventoryItem inventory[INVENTORY_SIZE]; extern InventoryItem inventory[INVENTORY_SIZE];
#if !defined(SERVER) #if !defined(SERVER)
extern Texture2D playerTex;
extern bool inventoryOpen; extern bool inventoryOpen;
extern InventoryItem *movingItem; extern InventoryItem *movingItem;
void DrawItem(InventoryItem item,int x,int y); void DrawItem(InventoryItem item,int x,int y);
@@ -594,13 +625,13 @@ void HotbarAddItemLots(Item *registry,int damage,int amount);
void InitHotbar(); void InitHotbar();
void DrawHotbar(); void DrawHotbar();
InventoryItem HotbarGetSelected(); InventoryItem HotbarGetSelected();
void DrawSelectedItem(); void DrawSelectedItem(Color tint);
void CloseInventory(); void CloseInventory();
void UpdateHotbar(); void UpdateHotbar();
void LocaleUpdate(); void LocaleUpdate();
void LoadRecipes(); void LoadRecipes();
#endif #endif
void ParticlesUpdate(float dt,Chunk world[]); void ParticlesUpdate(float dt,World&world);
void ParticlesDraw(); void ParticlesDraw();
void AddParticle(Particle part); void AddParticle(Particle part);
Particle NewParticle(Vector3 position); Particle NewParticle(Vector3 position);
@@ -609,14 +640,10 @@ extern float player_health;
extern float player_attack_time; extern float player_attack_time;
extern float player_place_time; extern float player_place_time;
extern float player_break_parts_time; extern float player_break_parts_time;
extern Vector3 player_position;
extern Vector3 player_velocity;
void SavePlayerData(); void SavePlayerData();
bool LoadPlayerData(); bool LoadPlayerData();
void MS_PlaySound(Sound src,float pitch,float volume,Vector3 position); void MS_PlaySound(Sound src,float pitch,float volume,Vector3 position);
void MS_Update(float dt,Camera camera); void MS_Update(float dt,Camera camera);
void ServerNetworkUpdate();
void StopInternalServer();
#define INTERFACE 0 #define INTERFACE 0
#define EXPORT_INTERFACE 0 #define EXPORT_INTERFACE 0
#define LOCAL_INTERFACE 0 #define LOCAL_INTERFACE 0
+149 -13
View File
@@ -9,36 +9,46 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#define PIXUNIT 1.0f / 16.0f
#ifndef SERVER
extern Camera camera; extern Camera camera;
extern Font fnt; extern Font fnt;
extern Texture2D terrain; extern Texture2D terrain;
Texture2D nekitTex; Texture2D playerTex;
Texture2D bomb; Texture2D bomb;
Sound nekit_idle; Sound nekit_idle;
void EntitiesInit() { void EntitiesInit() {
nekitTex = LoadTexture(Pathify("nekit.png")); playerTex = LoadTexture(Pathify("player.png"));
bomb = LoadTexture(Pathify("bomb.png")); bomb = LoadTexture(Pathify("bomb.png"));
nekit_idle = LoadSound(Pathify("sound/nekit/idle.ogg")); nekit_idle = LoadSound(Pathify("sound/nekit/idle.ogg"));
} }
extern bool online; extern bool online;
extern Vector3 player_position;
extern Vector3 player_velocity;
void TakeDamage(float amount); void TakeDamage(float amount);
void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t); void SetBlockNetwork(World &world, int bx, int by, int bz, int t);
#else
bool online = true;
#endif
Entity NewEntity(int id) { std::list<Entity> entities;
Entity NewEntity() {
Entity ent; Entity ent;
ent.id = id; ent.id = entities.size();
ent.type = 0; ent.type = 0;
ent.yaw = 0; ent.yaw = 0;
ent.free = false; ent.free = false;
return ent; return ent;
} }
void AddEntity(std::list<Entity> entities, Entity ent) { void AddEntity(Entity ent) {
entities.push_back(ent); entities.push_back(ent);
} }
static void UpdateEntityPhysics(Chunk world[], Entity& ent, float dt) { static void UpdateEntityPhysics(World &world, Entity& ent, float dt) {
Vector3 velocityTgt = Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}); Vector3 velocityTgt = Vector3Add(ent.velocity, {0, -dt * 20.0f, 0});
Vector3 tgt = Vector3Add(ent.position, Vector3Scale(velocityTgt, dt)); Vector3 tgt = Vector3Add(ent.position, Vector3Scale(velocityTgt, dt));
Vector3 final = ent.position; Vector3 final = ent.position;
@@ -57,7 +67,7 @@ static void UpdateEntityPhysics(Chunk world[], Entity& ent, float dt) {
ent.velocity = velocityTgt; ent.velocity = velocityTgt;
ent.position = final; ent.position = final;
} }
void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) { void UpdateEntities(World &world, float dt) {
if(entities.size() > 0) { if(entities.size() > 0) {
int idx = 0; int idx = 0;
for(Entity& ent : entities) { for(Entity& ent : entities) {
@@ -83,6 +93,9 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
Vector3 direction = Vector3Normalize(Vector3Subtract(target, ent.position)); Vector3 direction = Vector3Normalize(Vector3Subtract(target, ent.position));
float degYaw = -atan2f(direction.z, direction.x) * RAD2DEG + 90; float degYaw = -atan2f(direction.z, direction.x) * RAD2DEG + 90;
if(GetRandomValue(0, 2000) == 0) {
MS_PlaySound(nekit_idle, GetRandomValue(75,125)/100.0f, 1.0f, ent.position);
}
ent.velocity = Vector3Add(ent.velocity, (Vector3){direction.x * 20.0f, 0, direction.z * 20.0f}*dt); ent.velocity = Vector3Add(ent.velocity, (Vector3){direction.x * 20.0f, 0, direction.z * 20.0f}*dt);
if(GetBlock(world, (int)ent.position.x, (int)ent.position.y-1, (int)ent.position.z) && GetRandomValue(0, 100) == 0) { if(GetBlock(world, (int)ent.position.x, (int)ent.position.y-1, (int)ent.position.z) && GetRandomValue(0, 100) == 0) {
ent.velocity.y += 10.0f; ent.velocity.y += 10.0f;
@@ -97,8 +110,54 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
if(ent.health < 0.1f) { if(ent.health < 0.1f) {
ent.free = true; ent.free = true;
} }
if(ent.data[2] < 90)
ent.data[2]++;
ent.yaw = (unsigned short)(degYaw/360.0f*65535); ent.yaw = (unsigned short)(degYaw/360.0f*65535);
} }
/*if(ent.type == 3) {
Vector3 velocityTgt = Vector3Clamp(Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}), {-30.0f, -30.0f, -30.0f}, {30.0f, 30.0f, 30.0f});
Vector3 tgt = Vector3Add(ent.position, Vector3Scale(velocityTgt, dt));
Vector3 final = ent.position;
if(!GetBlock(world, (int)tgt.x, (int)final.y, (int)final.z)) {
final.x = tgt.x;
}
if(!GetBlock(world, (int)final.x, (int)tgt.y, (int)final.z)) {
final.y = tgt.y;
}
else {
velocityTgt.y = -velocityTgt.y / 2.0f;
velocityTgt = Vector3Scale(velocityTgt, 0.9f);
}
if(!GetBlock(world, (int)final.x, (int)final.y, (int)tgt.z)) {
final.z = tgt.z;
}
Entity* entp = &ent;
entp->yaw = 0;
entp->position = final;
entp->velocity = velocityTgt;
if(ent.lifetime > 5.0f) {
int radius = 3;
for (int x = -radius; x < radius; x++)
{
for (int y = -radius; y < radius; y++)
{
for (int z = -radius; z < radius; z++)
{
if(Vector3Distance({final.x + x, final.y + y, final.z + z}, final) <= radius) {
if(!CheckOOBWorld(final.x + x, final.y + y, final.z + z)) {
#ifndef SERVER
SetBlockNetwork(world, final.x + x, final.y + y, final.z + z, 0);
#endif
}
}
}
}
}
entp->free = true;
}
idx++;
}*/
if(ent.type == 4) { if(ent.type == 4) {
Vector3 velocityTgt = Vector3Clamp(Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}), {-30.0f, -30.0f, -30.0f}, {30.0f, 30.0f, 30.0f}); Vector3 velocityTgt = Vector3Clamp(Vector3Add(ent.velocity, {0, -dt * 20.0f, 0}), {-30.0f, -30.0f, -30.0f}, {30.0f, 30.0f, 30.0f});
@@ -125,7 +184,7 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
} }
Entity* entp = &ent; Entity* entp = &ent;
if(hit) { if(hit) {
SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data_sv[1]); SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data[1]);
entp->free = true; entp->free = true;
} }
entp->yaw = 0; entp->yaw = 0;
@@ -144,8 +203,8 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
} }
} }
float globalCounter = 0; float globalCounter = 0;
#ifndef SERVER
void DrawEntities(std::list<Entity> entities, float dt) { void DrawEntities(float dt) {
globalCounter += dt; globalCounter += dt;
for(Entity& ent : entities) { for(Entity& ent : entities) {
ent.smoothing += dt; ent.smoothing += dt;
@@ -222,13 +281,90 @@ void DrawEntities(std::list<Entity> entities, float dt) {
rlPopMatrix(); rlPopMatrix();
} }
if(ent.type == 1) { if(ent.type == 1) {
Color color = WHITE;
Vector3 posLerp = Vector3Add(ent.position, {-0.5f, -0.1f, -0.5f});
float time = ent.lifetime * 4.0f;
float armWave0 = sinf(time * PI);
float armWave1 = -abs(cosf(time * PI));
float headWave = cosf(time * PI);
posLerp = Vector3Add(posLerp, {0, abs(sinf(time * PI)) * 0.1f, 0});
Vector3 headPivot = Vector3Add(posLerp, (Vector3){0, 16*PIXUNIT, 0});
float yaw = -ent.yaw / 65535.0f * 360.0f - 90;
rlPushMatrix();
rlTranslatef(posLerp.x, posLerp.y, posLerp.z);
rlRotatef(yaw, 0, 1, 0);
rlTranslatef(-posLerp.x, -posLerp.y, -posLerp.z);
//
rlPushMatrix();
rlTranslatef(headPivot.x, headPivot.y, headPivot.z);
rlRotatef(25.0f * armWave0, 1, 0, 0);
rlRotatef(25.0f * headWave, 0, 0, 1);
// Head
DrawCubeTexture(playerTex, {0, 4*PIXUNIT, 0}, 8*PIXUNIT, 8*PIXUNIT, 8*PIXUNIT, WHITE, 8, 8, 8, 8);
rlPopMatrix();
Vector3 leftPivot = Vector3Add(posLerp, (Vector3){-6*PIXUNIT, 1.25f - 5*PIXUNIT, 0});
Vector3 rightPivot = Vector3Add(posLerp, (Vector3){6*PIXUNIT, 1.25f - 5*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z);
rlRotatef(45.0f * armWave0, 1, 0, 0);
rlRotatef(45.0f * armWave1, 0, 0, 1);
DrawCubeTexture(playerTex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4);
rlPopMatrix();
rlPushMatrix();
rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z);
rlRotatef(-45.0f * armWave0, 1, 0, 0);
rlRotatef(-45.0f * armWave1, 0, 0, 1);
DrawCubeTexture(playerTex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4);
rlPopMatrix();
Vector3 body = Vector3Add(posLerp, {0, 1.25f - 10*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(body.x, body.y, body.z);
DrawCubeTexture(playerTex, Vector3Zero(), 8*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 20, 20, 8, 4);
rlPopMatrix();
leftPivot = Vector3Add(posLerp, (Vector3){-2*PIXUNIT, 1.25f - 14*PIXUNIT, 0});
rightPivot = Vector3Add(posLerp, (Vector3){2*PIXUNIT, 1.25f - 14*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z);
rlRotatef(-45.0f * armWave0, 1, 0, 0);
DrawCubeTexture(playerTex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4);
rlPopMatrix();
rlPushMatrix();
rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z);
rlRotatef(45.0f * armWave0, 1, 0, 0);
DrawCubeTexture(playerTex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4);
rlPopMatrix();
rlPopMatrix();
Vector3 dir = Vector3Subtract(camera.position, ent.position);
rlPushMatrix();
rlTranslatef(ent.position.x, ent.position.y + 1.5f, ent.position.z);
rlRotatef(atan2f(dir.x, dir.z) * RAD2DEG, 0.0f, 1.0f, 0.0f);
rlRotatef(90.0f, 1.0f, 0.0f, 0.0f);
char name[12];
sprintf(name, "Player %d", (int)ent.data[0]);
DrawText3D(fnt, name, {-MeasureTextEx(fnt, name, PIXUNIT * 4, 0).x * 1.5f, 0, 0}, PIXUNIT * 4, PIXUNIT, 1, true, WHITE);
rlPopMatrix();
} }
if(ent.type == 3) { if(ent.type == 3) {
DrawCube(pos_lerped, 1, 1, 1, RED); DrawCube(pos_lerped, 1, 1, 1, RED);
} }
if(ent.type == 4) { if(ent.type == 4) {
DrawCubeBlock(terrain, pos_lerped, 1,1,1, BLOCKS[ent.data[1]]); DrawCubeBlock(terrain, pos_lerped, 1,1,1, GetBlockDefinition(ent.data[1]), WHITE);
} }
} }
} }
#endif
+24 -28
View File
@@ -20,23 +20,31 @@ inline void unpack6(uint8_t v, bool *b0, bool *b1, bool *b2, bool *b3, bool *b4,
*b5 = (v >> 5) & 1; *b5 = (v >> 5) & 1;
} }
inline void GetXYZFromIndex(int index, int *x, int *y, int *z) { inline void GetXYZFromIndex(int index, int* x, int* y, int* z) {
*x = index & 15; *y = index / (CHUNK_SIZE * CHUNK_SIZE);
int tmp = index << 4; int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
*z = tmp & 15; *z = rem / CHUNK_SIZE;
*y = tmp << 4; *x = rem % CHUNK_SIZE;
} }
inline int GetIndexChunk(int x, int y, int z) { inline int GetIndexChunk(int x, int y, int z) {
if(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE) return 0; if(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE) return 0;
return x + CHUNK_SIZE * (z + CHUNK_SIZE* y); return x + CHUNK_SIZE * (z + CHUNK_SIZE * y);
} }
inline int GetIndexChunk2D(int x, int z) { inline int GetIndexChunk2D(int x, int z) {
if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0; if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0;
return x + CHUNK_SIZE * z; return x + CHUNK_SIZE * z;
} }
inline bool CheckOOBWorld(int x, int y, int z) {
return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS);
}
inline bool CheckOOBWorldChunk(int x, int z) {
return (x < 0 || z < 0 || x >= MAX_WORLD_SIZE || z >= MAX_WORLD_SIZE);
}
inline int GetIndexWorld(int x, int z) { inline int GetIndexWorld(int x, int z) {
if(CheckOOBWorld(x << 4, 0, z << 4)) return 0;
return x + MAX_WORLD_SIZE * z; return x + MAX_WORLD_SIZE * z;
} }
@@ -45,32 +53,29 @@ inline void GetXZFromIndex(int index, int *x, int *z) {
*x = index % MAX_WORLD_SIZE; *x = index % MAX_WORLD_SIZE;
} }
inline bool TestMask(uint16_t *maskArray, int position) inline bool TestMask(const uint16_t *maskArray, int position)
{ {
if (position < 0 || position >= CHUNK_DATA_SIZE) return false;
int index = position >> 4; int index = position >> 4;
int bit = position & 15; int bit = position & 15;
int maskArrayLen = CHUNK_DATA_SIZE << 4;
return (maskArray[index] & (1u << bit)) != 0; return (maskArray[index] & (1u << bit)) != 0;
} }
inline bool CheckOOBWorld(int x, int y, int z) {
return (x < 0 || y < 0 || z < 0 || x >= WORLD_SIZE_BLOCKS || y >= WORLD_HEIGHT || z >= WORLD_SIZE_BLOCKS);
}
inline bool CheckOOBChunk(int x, int y, int z) { inline bool CheckOOBChunk(int x, int y, int z) {
return (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE); return (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_HEIGHT || z >= CHUNK_SIZE);
} }
inline bool TestOpaqueMaskWorld(Chunk world[], int x, int y, int z) { inline bool TestOpaqueMaskWorld(const World& world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return true; if(CheckOOBWorld(x, y, z)) return true;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)]; const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15); const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->opaqueMask, localIndex); return TestMask(c.opaqueMask, localIndex);
} }
inline bool TestAirMaskWorld(Chunk world[], int x, int y, int z) { inline bool TestAirMaskWorld(const World& world, int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return true; if(CheckOOBWorld(x, y, z)) return true;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)]; const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15); const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->airMask, localIndex); return TestMask(c.airMask, localIndex);
} }
inline int fetch_block(Chunk chunk, int x, int y, int z) { inline int fetch_block(Chunk chunk, int x, int y, int z) {
@@ -83,15 +88,6 @@ inline int fetch_block_ptr(Chunk *chunk, int x, int y, int z) {
return chunk->blocks[GetIndexChunk(x, y, z)]; return chunk->blocks[GetIndexChunk(x, y, z)];
} }
inline int GetBlock(Chunk world[], int x, int y, int z) {
if(CheckOOBWorld(x, y, z)) return 0;
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / CHUNK_SIZE;
int cz = z / CHUNK_SIZE;
return fetch_block(world[GetIndexWorld(cx, cz)], locX, y, locZ);
}
inline void *grow(void *ptr, size_t oldBytes, size_t newBytes) { inline void *grow(void *ptr, size_t oldBytes, size_t newBytes) {
if (!ptr) return malloc(newBytes); if (!ptr) return malloc(newBytes);
return realloc(ptr, newBytes); return realloc(ptr, newBytes);
+4 -4
View File
@@ -63,7 +63,7 @@ Vector2 InputGetWalkAxis() {
float y = 0; float y = 0;
if(isJoystick) { if(isJoystick) {
x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X); x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_X);
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y); y = -GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_Y);
if(abs(x) < 0.5f) { if(abs(x) < 0.5f) {
x = 0; x = 0;
} }
@@ -84,8 +84,8 @@ Vector2 InputGetLookAxis() {
float x = 0; float x = 0;
float y = 0; float y = 0;
if(isJoystick) { if(isJoystick) {
x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X); x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*3.0f;
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y); y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*3.0f;
if(abs(x) < 0.1f) { if(abs(x) < 0.1f) {
x = 0; x = 0;
} }
@@ -108,6 +108,7 @@ Vector2 InputGetDPAD() {
if (IsGamepadButtonPressed(0, GAMEPAD_BUTTON_LEFT_FACE_RIGHT)) { x = 1; } if (IsGamepadButtonPressed(0, GAMEPAD_BUTTON_LEFT_FACE_RIGHT)) { x = 1; }
if (IsGamepadButtonPressed(0, GAMEPAD_BUTTON_LEFT_FACE_LEFT)) { x = -1; } if (IsGamepadButtonPressed(0, GAMEPAD_BUTTON_LEFT_FACE_LEFT)) { x = -1; }
} }
return {x, y}; return {x, y};
} }
void InputWriteControls() { void InputWriteControls() {
@@ -135,7 +136,6 @@ void InputInit() {
{ {
controls[key] = val; controls[key] = val;
} }
swap_mouse = config["Swap mouse buttons"].as<bool>(); swap_mouse = config["Swap mouse buttons"].as<bool>();
} }
+11 -11
View File
@@ -6,7 +6,7 @@
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <rlgl.h> #include <rlgl.h>
#define PIXUNIT 1.0f / 16.0f
InventoryItem hotbar[ITEMS]; InventoryItem hotbar[ITEMS];
InventoryItem inventory[INVENTORY_SIZE]; InventoryItem inventory[INVENTORY_SIZE];
static uint8_t selected = 0; static uint8_t selected = 0;
@@ -40,7 +40,7 @@ void DrawItem(InventoryItem item, int x, int y) {
if(item.item->type == IType_Block) { if(item.item->type == IType_Block) {
atlas = terrain; atlas = terrain;
atl_size = ATLAS_SIZE_W; atl_size = ATLAS_SIZE_W;
tex = BLOCKS[item.damage].textureTop; tex = GetBlockDefinition(item.damage).textureTop;
} }
DrawTexturePro(atlas, DrawTexturePro(atlas,
{ {
@@ -198,9 +198,9 @@ static bool GetTaggedItem(std::string tag, InventoryItem* item) {
bool isBlock; bool isBlock;
bool found; bool found;
for(int blk = 0; blk < MAX_BLOCK_ID; blk++) { for(int blk = 0; blk < MAX_BLOCK_ID; blk++) {
if(IDTagMatch(tag, BLOCKS[blk].name)) { if(IDTagMatch(tag, GetBlockDefinition(blk).name)) {
isBlock = true; isBlock = true;
id = GetNumericIDFromString(BLOCKS[blk].name); id = GetNumericIDFromString(GetBlockDefinition(blk).name);
found = true; found = true;
break; break;
}; };
@@ -307,7 +307,7 @@ void DrawHotbar() {
if(item.item != nullptr) { if(item.item != nullptr) {
bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id); bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id);
bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id; bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id;
bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[item.damage].name); bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, GetBlockDefinition(item.damage).name);
bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id); bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id);
if(blockCond || genericCond || tagBlockCond || tagItemCond) { if(blockCond || genericCond || tagBlockCond || tagItemCond) {
items.push_back(i); items.push_back(i);
@@ -366,7 +366,7 @@ void DrawHotbar() {
if(item.item != nullptr) { if(item.item != nullptr) {
bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id); bool blockCond = item.item->type == IType_Block && ingredient.type == IType_Block && item.damage == GetNumericIDFromString(ingredient.id);
bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id; bool genericCond = item.item->type != IType_Block && ingredient.type == IType_Generic && item.item->id == ingredient.id;
bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[item.damage].name); bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, GetBlockDefinition(item.damage).name);
bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id); bool tagItemCond = item.item->type != IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, item.item->id);
if(blockCond || genericCond || tagBlockCond || tagItemCond) { if(blockCond || genericCond || tagBlockCond || tagItemCond) {
items[i] = ingredient.quantity; items[i] = ingredient.quantity;
@@ -432,7 +432,7 @@ void DrawHotbar() {
DrawItem(*movingItem, GetMouseX(), GetMouseY()); DrawItem(*movingItem, GetMouseX(), GetMouseY());
std::string name = "item."+movingItem->item->id; std::string name = "item."+movingItem->item->id;
if(movingItem->item->type == IType_Block) { if(movingItem->item->type == IType_Block) {
name = "item."+BLOCKS[movingItem->damage].name; name = "item."+GetBlockDefinition(movingItem->damage).name;
} }
DrawTextB(LocaleGet(name).c_str(), GetMouseX()-16, GetMouseY()+56, 16, WHITE); DrawTextB(LocaleGet(name).c_str(), GetMouseX()-16, GetMouseY()+56, 16, WHITE);
} }
@@ -441,7 +441,7 @@ void DrawHotbar() {
InventoryItem HotbarGetSelected() { InventoryItem HotbarGetSelected() {
return hotbar[selected]; return hotbar[selected];
} }
void DrawSelectedItem() { void DrawSelectedItem(Color tint) {
InventoryItem item = hotbar[selected]; InventoryItem item = hotbar[selected];
Vector3 center = {-0.75f, -0.45f, 0.5f}; Vector3 center = {-0.75f, -0.45f, 0.5f};
rlPushMatrix(); rlPushMatrix();
@@ -458,16 +458,16 @@ void DrawSelectedItem() {
rlRotatef(-45, 1, 0, 0); rlRotatef(-45, 1, 0, 0);
rlRotatef(25, 0, 0, 1); rlRotatef(25, 0, 0, 1);
DrawCubeTexture(playerTex, {0, -12*PIXUNIT/2, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4); DrawCubeTexture(playerTex, {0, -12*PIXUNIT/2, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, tint, 44,20,4,4);
if(item.item != nullptr) { if(item.item != nullptr) {
if(item.item->type == IType_Block) { if(item.item->type == IType_Block) {
DrawCubeBlock(terrain, {0, -12*PIXUNIT - 0.25f, 0}, 0.5f, 0.5f, 0.5f, BLOCKS[item.damage]); DrawCubeBlock(terrain, {0, -12*PIXUNIT - 0.25f, 0}, 0.5f, 0.5f, 0.5f, GetBlockDefinition(item.damage), tint);
} }
else { else {
UVCorners left = GetUVTex(item.item->texture); UVCorners left = GetUVTex(item.item->texture);
rlSetTexture(item_atlas.id); rlSetTexture(item_atlas.id);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(tint.r, tint.g, tint.b, 255);
rlNormal3f(1.0f, 0.0f, 0.0f); rlNormal3f(1.0f, 0.0f, 0.0f);
const float size = 0.5f; const float size = 0.5f;
rlTexCoord2f(left.corner0.x, left.corner0.y); rlVertex3f(0, -12*PIXUNIT - size, 0.25f - size); rlTexCoord2f(left.corner0.x, left.corner0.y); rlVertex3f(0, -12*PIXUNIT - size, 0.25f - size);
+7 -6
View File
@@ -29,7 +29,7 @@ static int MakeUIPOI(int x, int y) {
std::unordered_set<uint32_t> ui_pois; std::unordered_set<uint32_t> ui_pois;
int TryConnect(const char* hostname); int TryConnect(const char* hostname);
void InitSingleplayer(); //void InitSingleplayer();
void GameModeCleanup(); void GameModeCleanup();
static int mouseX = -1; static int mouseX = -1;
@@ -488,10 +488,10 @@ void DrawWorldSelect() {
DrawBackground(); DrawBackground();
int i = 0; int i = 0;
for(std::filesystem::path path : worldList) { for(std::filesystem::path path : worldList) {
if(Button(reinterpret_cast<const char*>(path.filename().u8string().c_str()), GetScreenWidth()/2-64, i*48+8, 128, 0)) { if(Button(reinterpret_cast<const char*>(path.filename().string().c_str()), GetScreenWidth()/2-64, i*48+8, 128, 0)) {
online = false; online = false;
SetTargetFPS(-1); SetTargetFPS(-1);
_LoadWorld(reinterpret_cast<const char*>(path.u8string().c_str())); _LoadWorld(reinterpret_cast<const char*>(path.string().c_str()));
return; return;
} }
i++; i++;
@@ -503,7 +503,8 @@ void DrawWorldSelect() {
} }
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48, 128, 0)) { if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48, 128, 0)) {
UIResetMousePos(); UIResetMousePos();
InitSingleplayer(); InitWorldgen(0);
state = GAME_STATE_LOADING;
return; return;
} }
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48-48, 128, 0)) { if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48-48, 128, 0)) {
@@ -550,12 +551,12 @@ void DrawMultiplayer() {
EndDrawing(); EndDrawing();
UIHandleControls(); UIHandleControls();
} }
void ExitSingleplayer();
void DrawPauseMenu() { void DrawPauseMenu() {
UIBegin(); UIBegin();
DrawRectangle(0,0,GetScreenWidth(),GetScreenHeight(),Fade(GRAY,0.5f)); DrawRectangle(0,0,GetScreenWidth(),GetScreenHeight(),Fade(GRAY,0.5f));
if (Button(LocaleGet("exit").c_str(), GetScreenWidth()/2-64, 48, 128, 0)) { if (Button(LocaleGet("exit").c_str(), GetScreenWidth()/2-64, 48, 128, 0)) {
ExitSingleplayer(); GameModeCleanup();
UIResetMousePos(); UIResetMousePos();
return; return;
} }
+22 -21
View File
@@ -10,7 +10,7 @@
#ifndef SERVER #ifndef SERVER
#ifndef LEGACY_GL #ifndef LEGACY_GL
MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask) MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask)
{ {
MeshData out = {0}; MeshData out = {0};
@@ -23,17 +23,20 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
std::vector<unsigned short> indices; std::vector<unsigned short> indices;
int face = 0; int face = 0;
for (int x = 0; x < CHUNK_SIZE; ++x) for (int index = 0; index < CHUNK_DATA_SIZE; index++)
for (int y = 0; y < WORLD_HEIGHT; ++y)
for (int z = 0; z < CHUNK_SIZE; ++z)
{ {
int index = GetIndexChunk(x,y,z);
uint8_t crdata = chunkRenderData.sides[index]; uint8_t crdata = chunkRenderData.sides[index];
if (crdata == 0) continue; if (crdata == 0) continue;
int x, y, z;
GetXYZFromIndex(index, &x, &y, &z);
int wx = (chunkWorldX * CHUNK_SIZE + x);
int wy = (y);
int wz = (chunkWorldY * CHUNK_SIZE + z);
int this_block = fetch_block(chunk, x,y,z); int this_block = fetch_block(chunk, x,y,z);
BlockDef definition = BLOCKS[this_block]; BlockDef definition = GetBlockDefinition(this_block);
UVCorners UVside = GetUVTex(definition.textureSide); UVCorners UVside = GetUVTex(definition.textureSide);
UVCorners UVtop = GetUVTex(definition.textureTop); UVCorners UVtop = GetUVTex(definition.textureTop);
@@ -45,10 +48,7 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
bool shaded = chunk.highestBlock[GetIndexChunk2D(x, z)] != y; bool shaded = chunk.highestBlock[GetIndexChunk2D(x, z)] != y;
Color color = {255, 255, 255, 255}; Color color = {255, 255, 255, 255};
Color colorShaded = {128, 128, 172, 255}; Color colorShaded = {128, 128, 172, 255};
float wx = (float)(chunkWorldX * CHUNK_SIZE + x);
float wy = (float)(y);
float wz = (float)(chunkWorldY * CHUNK_SIZE + z);
/*if(GetCloud(wx, wz)) { /*if(GetCloud(wx, wz)) {
color = ColorLerp(color, colorShaded, 0.5f); color = ColorLerp(color, colorShaded, 0.5f);
}*/ }*/
@@ -72,7 +72,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
colors.push_back(colorShaded); Color clr = GetLightMesher(world, wx-1, wy, wz);
colors.push_back(clr);
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
@@ -111,7 +112,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
colors.push_back(colorShaded); Color clr = GetLightMesher(world, wx+1, wy, wz);
colors.push_back(clr);
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
@@ -150,7 +152,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
colors.push_back(colorShaded); Color clr = GetLightMesher(world, wx, wy-1, wz);
colors.push_back(clr);
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
@@ -189,12 +192,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
if(shaded) { Color clr = GetLightMesher(world, wx, wy+1, wz);
colors.push_back(colorShaded); colors.push_back(clr);
}
else {
colors.push_back(color);
}
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
@@ -233,7 +232,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
colors.push_back(colorShaded); Color clr = GetLightMesher(world, wx, wy, wz+1);
colors.push_back(clr);
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
@@ -272,7 +272,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]); positions.push_back(verts[3]);
normals.push_back(normal); normals.push_back(normal);
colors.push_back(colorShaded); Color clr = GetLightMesher(world, wx, wy, wz-1);
colors.push_back(clr);
uvs.push_back(corners[0]); uvs.push_back(corners[0]);
uvs.push_back(corners[1]); uvs.push_back(corners[1]);
+3 -3
View File
@@ -87,17 +87,17 @@ void BroadcastPacketR(ENetHost* server, void* data, int len)
void SerializeFloat2Data(float v, void *target, int offset) { void SerializeFloat2Data(float v, void *target, int offset) {
uint8_t *buf = (uint8_t*)target + offset; uint8_t *buf = (uint8_t*)target + offset;
if (!isfinite(v)) { if (!isfinite(v)) { // handle NaN/Inf as zero (choose policy)
buf[0] = 0; buf[0] = 0;
buf[1] = 0; buf[1] = 0;
return; return;
} }
if (v < 0.0f) v = 0.0f; if (v < 0.0f) v = 0.0f;
if (v > 255.0f) v = 255.0f; if (v > 255.0f) v = 255.0f; // clamp to representable range
int intpart = (int)floorf(v); int intpart = (int)floorf(v);
float frac = v - (float)intpart; float frac = v - (float)intpart;
int frac_byte = (int)floorf(frac * 255.0f + 0.5f); int frac_byte = (int)floorf(frac * 255.0f + 0.5f); // round to nearest
if (frac_byte < 0) frac_byte = 0; if (frac_byte < 0) frac_byte = 0;
if (frac_byte > 255) frac_byte = 255; if (frac_byte > 255) frac_byte = 255;
buf[0] = (uint8_t)intpart; buf[0] = (uint8_t)intpart;
+6 -5
View File
@@ -65,11 +65,12 @@ static void DrawParticle(Particle particle, Color color)
rlSetTexture(0); rlSetTexture(0);
} }
void ParticlesUpdate(float dt, Chunk world[]) { void ParticlesUpdate(float dt, World &world) {
particles.remove_if([](Particle x) { return x.lifetime > 200; }); //particles.remove_if([](Particle x) { return x.lifetime > 0; });
for (Particle &part : particles) particles.remove_if([](Particle x) { return true; });
/*for (Particle &part : particles)
{ {
part.lifetime++; art.lifetime++;p
if(part.physicsType == Phys_Falling) { if(part.physicsType == Phys_Falling) {
Vector3 velocityTgt = Vector3Clamp(Vector3Add(part.velocity, {0, -dt * 9.8f, 0}), {-30.0f, -30.0f, 0-30.0f}, {30.0f, 30.0f, 30.0f}); Vector3 velocityTgt = Vector3Clamp(Vector3Add(part.velocity, {0, -dt * 9.8f, 0}), {-30.0f, -30.0f, 0-30.0f}, {30.0f, 30.0f, 30.0f});
@@ -99,7 +100,7 @@ void ParticlesUpdate(float dt, Chunk world[]) {
part.position = final; part.position = final;
part.velocity = velocityTgt; part.velocity = velocityTgt;
} }
} }*/
} }
void ParticlesDraw() { void ParticlesDraw() {
for (Particle part : particles) for (Particle part : particles)
+1 -1
View File
@@ -49,7 +49,7 @@ void LoadRecipes() {
try try
{ {
Recipe _recipe; Recipe _recipe;
const std::string path = dir_entry.path().u8string(); const std::string path = dir_entry.path().string();
std::cout << "loading " << path << std::endl; std::cout << "loading " << path << std::endl;
YAML::Node recipe = YAML::LoadFile(path); YAML::Node recipe = YAML::LoadFile(path);
_recipe.requiredStation = recipe["station"].as<std::string>(); _recipe.requiredStation = recipe["station"].as<std::string>();
-419
View File
@@ -1,419 +0,0 @@
#include "common.hpp"
#include <iostream>
#include <cstring>
#include <list>
#include <unordered_set>
#include <vector>
#include <string>
#include <memory>
#include <filesystem>
#include <lua.hpp>
#include <atomic>
static std::list<NetPlayer> players;
static std::list<Entity> entities;
static Chunk world[MAX_WORLD_AREA];
static ENetHost* server;
struct LuaPlugin {
std::string name;
lua_State* L;
bool has_on_connect = false;
bool has_on_disconnect = false;
bool has_on_packet = false;
};
static std::vector<std::unique_ptr<LuaPlugin>> plugins;
static int l_server_send(lua_State* L) {
int peer_id = (int)luaL_checkinteger(L, 1);
size_t len;
const char* data = luaL_checklstring(L, 2, &len);
for (const NetPlayer &p : players) {
if (p.id == peer_id) {
SendPacketR(p.peer, (void*)data, (int)len);
break;
}
}
return 0;
}
static int l_server_broadcast(lua_State* L) {
size_t len;
const char* data = luaL_checklstring(L, 1, &len);
if (len > 0) {
BroadcastPacketR(server, (void*)data, (int)len);
}
return 0;
}
static int l_get_players(lua_State* L) {
lua_newtable(L);
int idx = 1;
for (const NetPlayer &p : players) {
lua_pushinteger(L, p.id);
lua_rawseti(L, -2, idx++);
}
return 1;
}
static void RegisterLuaAPI(lua_State* L) {
lua_newtable(L);
lua_pushcfunction(L, l_server_send);
lua_setfield(L, -2, "send");
lua_pushcfunction(L, l_server_broadcast);
lua_setfield(L, -2, "broadcast");
lua_pushcfunction(L, l_get_players);
lua_setfield(L, -2, "get_players");
lua_setglobal(L, "server");
}
static bool LoadPluginFile(const std::filesystem::path& path) {
auto plugin = std::make_unique<LuaPlugin>();
plugin->name = path.filename().string();
plugin->L = luaL_newstate();
if (!plugin->L) return false;
luaL_openlibs(plugin->L);
RegisterLuaAPI(plugin->L);
int rc = luaL_dofile(plugin->L, path.string().c_str());
if (rc != LUA_OK) {
const char* err = lua_tostring(plugin->L, -1);
std::cerr << "Error loading plugin " << plugin->name << ": " << (err ? err : "unknown") << std::endl;
lua_close(plugin->L);
return false;
}
lua_getglobal(plugin->L, "on_connect");
if (lua_isfunction(plugin->L, -1)) plugin->has_on_connect = true;
lua_pop(plugin->L, 1);
lua_getglobal(plugin->L, "on_disconnect");
if (lua_isfunction(plugin->L, -1)) plugin->has_on_disconnect = true;
lua_pop(plugin->L, 1);
lua_getglobal(plugin->L, "on_packet");
if (lua_isfunction(plugin->L, -1)) plugin->has_on_packet = true;
lua_pop(plugin->L, 1);
plugins.push_back(std::move(plugin));
std::cout << "Loaded plugin: " << path.filename().string() << std::endl;
return true;
}
static void LoadPluginsFromFolder(const std::string& folder) {
try {
if (!std::filesystem::exists(folder)) {
std::cout << "Plugins folder does not exist; skipping: " << folder << std::endl;
return;
}
for (auto& p : std::filesystem::directory_iterator(folder)) {
if (!p.is_regular_file()) continue;
auto ext = p.path().extension().string();
if (ext == ".lua") LoadPluginFile(p.path());
}
} catch (const std::exception& e) {
std::cerr << "Error enumerating plugins: " << e.what() << std::endl;
}
}
static void CallPluginOnConnect(int peer_id) {
for (auto &pl : plugins) {
if (!pl->has_on_connect) continue;
lua_State* L = pl->L;
lua_getglobal(L, "on_connect");
lua_pushinteger(L, peer_id);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
std::cerr << "Plugin " << pl->name << " on_connect error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
}
static void CallPluginOnDisconnect(int peer_id) {
for (auto &pl : plugins) {
if (!pl->has_on_disconnect) continue;
lua_State* L = pl->L;
lua_getglobal(L, "on_disconnect");
lua_pushinteger(L, peer_id);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
std::cerr << "Plugin " << pl->name << " on_disconnect error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
}
static void CallPluginOnPacket(int peer_id, const unsigned char* data, int len) {
for (auto &pl : plugins) {
if (!pl->has_on_packet) continue;
lua_State* L = pl->L;
lua_getglobal(L, "on_packet");
lua_pushinteger(L, peer_id);
lua_pushlstring(L, (const char*)data, len);
if (lua_pcall(L, 2, 0, 0) != LUA_OK) {
std::cerr << "Plugin " << pl->name << " on_packet error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
}
}
static int PeerToPlayerID(ENetPeer* peer) {
for (const NetPlayer &p : players) {
if (p.addr == peer->address.host && p.port == peer->address.port) return p.id;
}
return -1;
}
static bool CompareAddress(NetPlayer plr, ENetPeer* peer) {
return plr.addr == peer->address.host && plr.port == (int)(peer->address.port);
}
static void SendPlayerSkin(ENetPeer* peer, NetPlayer plr) {
unsigned char responseD[plr.skin.size()+4];
responseD[0] = NET_ARG_PLRSKIN;
responseD[1] = (plr.skin.size() & 0xFF00) << 8;
responseD[2] = plr.skin.size() & 0xFF;
memcpy(responseD+4, plr.skin.data(), plr.skin.size());
SendPacketR(peer, responseD, plr.skin.size()+4);
}
static void ParseData(ENetPacket* packet, ENetPeer* peer) {
int len = packet->dataLength;
unsigned char data[len];
memcpy(&data, packet->data, len);
int pid = PeerToPlayerID(peer);
if (pid >= 0) CallPluginOnPacket(pid, data, len);
unsigned char response[16];
switch (data[0])
{
case NET_ARG_REQWORLD:
puts("Client requested world; sending");
for (int i = 0; i < 256; i++)
{
unsigned char responseChunk[2+CHUNK_DATA_SIZE+CHUNK_SIZE*CHUNK_SIZE];
responseChunk[0] = NET_ARG_CHUNKF;
responseChunk[1] = i;
memcpy(responseChunk+2, world[i].blocks, CHUNK_DATA_SIZE);
memcpy(responseChunk+2+CHUNK_DATA_SIZE, world[i].highestBlock, CHUNK_SIZE*CHUNK_SIZE);
SendPacket(peer, responseChunk, sizeof(responseChunk));
}
break;
case NET_ARG_PLAYERMOVE:
response[0] = NET_ARG_ECHOMOVE;
for (NetPlayer &plr : players)
{
if(CompareAddress(plr, peer)) {
float x = DeserializeFloat(data[1], data[2]);
float y = DeserializeFloat(data[3], data[4]);
float z = DeserializeFloat(data[5], data[6]);
plr.x = x;
plr.y = y;
plr.z = z;
response[1] = plr.id;
}
}
response[2] = data[1]; response[3] = data[2];
response[4] = data[3]; response[5] = data[4];
response[6] = data[5]; response[7] = data[6];
response[8] = data[7];
BroadcastPacketR(server, response, 9);
break;
case NET_ARG_PLAYERYAW:
response[0] = NET_ARG_ECHOYAW;
for (NetPlayer &plr : players)
{
if(CompareAddress(plr, peer)) {
response[1] = plr.id;
plr.yaw = data[1];
response[2] = plr.yaw;
}
}
BroadcastPacketR(server, response, 3);
break;
case NET_ARG_REQPLAYERS:
puts("Client requested players; sending");
for (NetPlayer &plr : players)
{
unsigned char responseP[9];
responseP[0] = NET_ARG_PLRREG;
if(!CompareAddress(plr, peer)) {
SerializeFloat2Data(plr.x, responseP, 2);
SerializeFloat2Data(plr.y, responseP, 4);
SerializeFloat2Data(plr.z, responseP, 6);
responseP[1] = plr.id;
responseP[8] = plr.yaw;
SendPacketR(peer, responseP, 9);
SendPlayerSkin(peer, plr);
}
}
for (Entity &ent : entities)
{
unsigned char responseP[10+8];
responseP[0] = NET_ARG_ENTITYSPAWN;
responseP[1] = ent.id & 0xFF00 >> 8;
responseP[2] = ent.id & 0xFF;
responseP[3] = ent.type;
SerializeFloat2Data(ent.position.x, responseP, 4);
SerializeFloat2Data(ent.position.y, responseP, 6);
SerializeFloat2Data(ent.position.z, responseP, 8);
for (int i = 0; i < 8; i++)
{
responseP[i+10] = ent.data_sv[i];
}
SendPacketR(peer, responseP, 18);
}
break;
case NET_ARG_BLOCKDELTA:
response[0] = NET_ARG_BLOCK;
for (NetPlayer &plr : players)
{
if(CompareAddress(plr, peer)) {
unsigned char responseB[6];
responseB[0] = NET_ARG_BLOCK;
responseB[1] = plr.id;
responseB[2] = data[1];
responseB[3] = data[2];
responseB[4] = data[3];
responseB[5] = data[4];
SetBlock(world, data[1], data[2], data[3], data[4]);
BroadcastPacketR(server, responseB, 6);
}
}
break;
case NET_ARG_PLRSKINSET:
{
NetPlayer tmp;
for (NetPlayer &plr : players)
{
if(plr.id == data[1]) {
int size = (data[2] << 8) | data[3];
std::cout << size << std::endl;
for (int i = 0; i < size; i++)
{
plr.skin.push_back(data[4+i]);
}
tmp = plr;
break;
}
}
for (NetPlayer &plr : players)
{
if(!CompareAddress(plr, peer)) {
SendPlayerSkin(peer, tmp);
}
}
break;
}
default:
break;
}
}
static int FirstFreeID(const std::list<NetPlayer>& players) {
std::unordered_set<int> used;
used.reserve(players.size());
for (const auto &p : players) used.insert(p.id);
int id = 0;
while (used.find(id) != used.end()) ++id;
return id;
}
static bool serverStarted = false;
void StartInternalServer(std::atomic_bool& started) {
int worldType = 0;
InitWorldgen(worldType);
std::cout << "Building chunks..." << std::endl;
Chunk chunk = GenerateChunk(8, 8);
for (int x = 0; x < MAX_WORLD_SIZE; x++)
{
for (int y = 0; y < MAX_WORLD_SIZE; y++)
{
memcpy(&world[x + y * MAX_WORLD_SIZE], &chunk, sizeof(Chunk));
}
}
LoadPluginsFromFolder("plugins");
std::cout << "Starting server..." << std::endl;
server = StartServer();
std::cout << "Serving on port: " << PORT << std::endl;
serverStarted = true;
started = true;
Entity test = NewEntity(0);
test.type = 2;
test.position = {0, 64, 0};
entities.push_back(test);
}
void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt);
void ServerNetworkUpdate() {
if(serverStarted) {
UpdateEntities(entities, world, TPS_DIV);
ENetEvent event;
while(enet_host_service (server, &event, 1000 / TPS) > 0)
{
switch (event.type)
{
int id;
char response[2];
case ENET_EVENT_TYPE_CONNECT:
printf ("A new client connected from %x:%u.\n",
event.peer -> address.host,
event.peer -> address.port);
response[0] = NET_ARG_PLRID;
id = FirstFreeID(players);
response[1] = id;
SendPacketR(event.peer, response, sizeof(response));
{
NetPlayer netPlayer;
netPlayer.id = id;
netPlayer.addr = event.peer->address.host;
netPlayer.port = (int)(event.peer->address.port);
netPlayer.peer = event.peer;
players.push_back(netPlayer);
response[0] = NET_ARG_PLRCON;
response[1] = netPlayer.id;
BroadcastPacketR(server, response, sizeof(response));
}
CallPluginOnConnect(id);
break;
case ENET_EVENT_TYPE_RECEIVE:
ParseData(event.packet, event.peer);
enet_packet_destroy (event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf ("%s disconnected.\n", event.peer -> data);
event.peer -> data = NULL;
for (auto it = players.begin(); it != players.end(); ++it) {
if (CompareAddress(*it, event.peer)) {
char responseD[2];
responseD[0] = NET_ARG_PLRDCN;
responseD[1] = it->id;
BroadcastPacketR(server, (unsigned char*)responseD, sizeof(responseD));
int disconnected_id = it->id;
it = players.erase(it);
// notify plugins
CallPluginOnDisconnect(disconnected_id);
break;
}
}
break;
}
}
}
}
void StopInternalServer() {
for (auto &pl : plugins) {
lua_close(pl->L);
}
enet_host_destroy(server);
}
+56 -3
View File
@@ -87,7 +87,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
rlSetTexture(0); rlSetTexture(0);
} }
void DrawCubeBlock(Texture2D texture, Vector3 position, float width, float height, float length, BlockDef def) void DrawCubeBlock(Texture2D texture, Vector3 position, float width, float height, float length, BlockDef def, Color tint)
{ {
float x = position.x; float x = position.x;
float y = position.y; float y = position.y;
@@ -104,7 +104,7 @@ void DrawCubeBlock(Texture2D texture, Vector3 position, float width, float heigh
UVCorners right = GetUVTex(def.textureSide); UVCorners right = GetUVTex(def.textureSide);
rlSetTexture(texture.id); rlSetTexture(texture.id);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255); rlColor4ub(tint.r, tint.g, tint.b, 255);
// Front Face // Front Face
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlTexCoord2f(front.corner0.x, front.corner0.y); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad rlTexCoord2f(front.corner0.x, front.corner0.y); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
@@ -253,4 +253,57 @@ void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, f
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
} }
} }
#endif #endif
RenderTexture2D LoadRenderTextureDepthTex(int width, int height)
{
RenderTexture2D target = { 0 };
target.id = rlLoadFramebuffer(); // Load an empty framebuffer
if (target.id > 0)
{
rlEnableFramebuffer(target.id);
// Create color texture (default to RGBA)
target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
target.texture.width = width;
target.texture.height = height;
target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
target.texture.mipmaps = 1;
// Create depth texture buffer (instead of raylib default renderbuffer)
target.depth.id = rlLoadTextureDepth(width, height, false);
target.depth.width = width;
target.depth.height = height;
target.depth.format = 19; // DEPTH_COMPONENT_24BIT: Not defined in raylib
target.depth.mipmaps = 1;
// Attach color texture and depth texture to FBO
rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0);
// Check if fbo is complete with attachments (valid)
if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
rlDisableFramebuffer();
}
else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
return target;
}
// Unload render texture from GPU memory (VRAM)
void UnloadRenderTextureDepthTex(RenderTexture2D target)
{
if (target.id > 0)
{
// Color texture attached to FBO is deleted
rlUnloadTexture(target.texture.id);
rlUnloadTexture(target.depth.id);
// NOTE: Depth texture is automatically
// queried and deleted before deleting framebuffer
rlUnloadFramebuffer(target.id);
}
}
+26 -20
View File
@@ -1,10 +1,10 @@
#include <functional>
#if INTERFACE #if INTERFACE
#ifdef Escape #ifdef Escape
#undef Escape #undef Escape
#endif #endif
#include "glfw_keycodes_to_string.h" #include "glfw_keycodes_to_string.h"
#include "../PerlinNoise.hpp"
#ifdef WIN32 #ifdef WIN32
#include "external/fix_win32_compatibility.h" #include "external/fix_win32_compatibility.h"
@@ -79,10 +79,6 @@
#define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS #define NET_ARG_PLRREG 0x07 // Same as ECHOMOVE, used as an answer to REQPLAYERS
#define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw #define NET_ARG_ECHOYAW 0x08 // Byte 1 - ID, byte 2 - yaw
#define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max) #define NET_ARG_MESSAGEE 0x09 // Byte 1 - sender ID, byte 2 - length, rest is message (128b max)
#define NET_ARG_ENTITYSPAWN 0x0A // uint16_t entityWorldID, uint8_t entityTypeID, uint16_t x, uint16_t y, uint16_t z, uint8_t data[8]
#define NET_ARG_ENTITYMOVE 0x0B // uint16_t entityWorldID, uint16_t x, uint16_t y, uint16_t z
#define NET_ARG_PLRSKIN 0x0C // Byte 1 - ID, bytes 2-3 - size, rest is skin
//Client->Server //Client->Server
// Byte 0 // Byte 0
#define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw #define NET_ARG_PLAYERMOVE 0x80 // Byte 1-2 - player X, byte 3-4 - player Y, byte 5-6 - player Z, byte 7 - player yaw
@@ -91,7 +87,6 @@
#define NET_ARG_REQPLAYERS 0x83 // No additional data #define NET_ARG_REQPLAYERS 0x83 // No additional data
#define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw #define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw
#define NET_ARG_MESSAGEC 0x85 // All is message (64b max) #define NET_ARG_MESSAGEC 0x85 // All is message (64b max)
#define NET_ARG_PLRSKINSET 0x86 // Byte 1 - ID, bytes 2-3 - size, rest is skin
// //
//Errors //Errors
#define NET_ERROR_DSCN 0x00 #define NET_ERROR_DSCN 0x00
@@ -103,12 +98,11 @@
#define GAME_VERSION_INT 0 #define GAME_VERSION_INT 0
#define DEFAULT_FONT_SIZE 16 #define DEFAULT_FONT_SIZE 16
#define TPS 30.0 #define TPS 30
#define TPS_DIV 1.0 / TPS #define TPS_DIV 1.0 / TPS
//Rendering //Rendering
#define RENDER_DISTANCE 16 #define RENDER_DISTANCE 16
#define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE #define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE
#define PIXUNIT 1.0f / 16.0f
//Game stuff //Game stuff
#define MAX_HP 100 #define MAX_HP 100
@@ -120,6 +114,8 @@
#define INVENTORY_HEIGHT 6 #define INVENTORY_HEIGHT 6
#define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT #define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT
#define WORLD_TIME_SECONDS (24*60)
#define WORLD_TIME_TICKS WORLD_TIME_SECONDS*TPS
enum BlockType { enum BlockType {
B_Wood, B_Wood,
B_Stone, B_Stone,
@@ -185,7 +181,7 @@ struct Chunk {
uint16_t opaqueMask[CHUNK_DATA_SIZE/16]; uint16_t opaqueMask[CHUNK_DATA_SIZE/16];
uint16_t airMask[CHUNK_DATA_SIZE/16]; uint16_t airMask[CHUNK_DATA_SIZE/16];
uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE]; uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE];
uint16_t light[CHUNK_DATA_SIZE];
}; };
#ifndef SERVER #ifndef SERVER
struct ChunkRenderData { struct ChunkRenderData {
@@ -226,23 +222,32 @@ struct Quad2D {
}; };
#endif #endif
struct Vector3I { struct Vector3I {
int x; int x, y, z;
int y; bool operator==(const Vector3I& other) const {
int z; return (x == other.x && y == other.y && z == other.z);
};
}; };
struct Vector3IHash {
size_t operator()(const Vector3I& p) const noexcept {
size_t h1 = std::hash<int>{}(p.x);
size_t h2 = std::hash<int>{}(p.y);
size_t h3 = std::hash<int>{}(p.z);
return h1 ^ (h2 << 1) ^ (h3 << 2);
}
};
struct Entity { struct Entity {
uint16_t id;
uint8_t type; uint8_t type;
uint8_t id;
uint8_t damage_flash; uint8_t damage_flash;
uint8_t data[4]; uint8_t data[16];
uint8_t data_sv[8];
bool free;
float smoothing; float smoothing;
float health; float health;
float lifetime; float lifetime;
Vector3 position; Vector3 position;
Vector3 velocity; Vector3 velocity;
unsigned short yaw; unsigned short yaw;
bool free;
}; };
struct NetPlayer struct NetPlayer
@@ -255,9 +260,6 @@ struct NetPlayer
float x; float x;
float y; float y;
float z; float z;
std::string nickname;
Texture2D texture;
std::vector<uint8_t> skin;
}; };
struct MemInfo { struct MemInfo {
@@ -316,4 +318,8 @@ struct Particle {
Texture2D texture; Texture2D texture;
int lifetime; int lifetime;
int data[8]; int data[8];
}; };
struct World
{
Chunk chunks[MAX_WORLD_AREA];
};
+327 -286
View File
@@ -15,11 +15,7 @@
#include <list> #include <list>
#include <climits> #include <climits>
#include <queue> #include <queue>
#include <atomic>
#include <thread>
#include <set>
#include <map> #include <map>
#include <fstream>
#define MAX_RAY_DISTANCE 8.0f #define MAX_RAY_DISTANCE 8.0f
struct MessageData { struct MessageData {
std::string message; std::string message;
@@ -35,14 +31,11 @@ Vector2 cameraMovementSmooth;
static float camYaw = 0.0f; static float camYaw = 0.0f;
static float camPitch = -45.0f; static float camPitch = -45.0f;
static const float acceleration = 48.0f; static const float acceleration = 48.0f;
static const float drag = 6.0f; static const float drag = 6.0f; // tuned for feel
static bool singleplayerServer;
Camera camera; Camera camera;
Texture2D playerTex;
bool online = false; bool online = false;
bool flying = false; bool flying = false;
void DrawEntities(std::list<Entity> entities, float dt);
unsigned long long worldTime; unsigned long long worldTime;
static float entUpdateCounter; static float entUpdateCounter;
@@ -59,21 +52,27 @@ Font fnt;
Texture2D terrain; Texture2D terrain;
Texture2D water; Texture2D water;
Texture2D white_pixel; Texture2D white_pixel;
Entity* ent;
const bool ROTATE_PLAYER_WITH_CAMERA = true; const bool ROTATE_PLAYER_WITH_CAMERA = true;
static Sound wood_place; static Sound wood_place;
static Sound stone_place; static Sound stone_place;
static Sound dirt_place; static Sound dirt_place;
static Sound grass_place; static Sound grass_place;
bool tick_entities; static Texture2D sun;
static Texture2D moon;
static Texture2D stars;
bool tick_entities = true;
const std::string LocaleGet(std::string loc); const std::string LocaleGet(std::string loc);
bool InputGetKeyDown(const std::string name); bool InputGetKeyDown(const std::string name);
bool InputGetKeyPressed(const std::string name); bool InputGetKeyPressed(const std::string name);
extern std::list<Entity> entities;
std::bitset<WORLD_SIZE_BLOCKS*WORLD_SIZE_BLOCKS/8/8> clouds; std::bitset<WORLD_SIZE_BLOCKS*WORLD_SIZE_BLOCKS/8/8> clouds;
std::queue<Vector3I> tickedBlocks; std::queue<Vector3I> tickedBlocks;
static std::list<Entity> entities;
static std::map<int, NetPlayer> players;
struct MeshUnit { struct MeshUnit {
Model model; Model model;
Model modelTransparent;
Model modelWater;
int vertices; int vertices;
}; };
struct ProfilerPart { struct ProfilerPart {
@@ -97,100 +96,19 @@ static Vector3 CameraForwardFromYawPitch(float yaw, float pitch)
f.z = cosf(pitch) * sinf(yaw); f.z = cosf(pitch) * sinf(yaw);
return Vector3Normalize(f); return Vector3Normalize(f);
} }
static const char* GetPlayerTexturePath() { World world;
if(FileExists(PathifyUser("player.png"))) {
return PathifyUser("player.png");
}
else {
return Pathify("nekit.png");
}
}
static void DrawPlayer(Texture2D texture, NetPlayer netPlayer) {
Color color = WHITE;
float x = netPlayer.x;
float y = netPlayer.y;
float z = netPlayer.z;
int _yaw = netPlayer.yaw;
Vector3 posLerp = Vector3Add((Vector3){x, y, z}, {-0.5f, -0.1f, -0.5f});
float time = GetTime() * 4.0f;
float armWave0 = sinf(time * PI);
float armWave1 = -abs(cosf(time * PI));
float headWave = cosf(time * PI);
posLerp = Vector3Add(posLerp, {0, abs(sinf(time * PI)) * 0.1f, 0});
Vector3 headPivot = Vector3Add(posLerp, (Vector3){0, 16*PIXUNIT, 0});
float yaw = -yaw / 65535.0f * 360.0f - 90;
Texture2D tex = netPlayer.texture;
rlPushMatrix();
rlTranslatef(posLerp.x, posLerp.y, posLerp.z);
rlRotatef(yaw, 0, 1, 0);
rlTranslatef(-posLerp.x, -posLerp.y, -posLerp.z);
//
rlPushMatrix();
rlTranslatef(headPivot.x, headPivot.y, headPivot.z);
rlRotatef(25.0f * armWave0, 1, 0, 0);
rlRotatef(25.0f * headWave, 0, 0, 1);
// Head
DrawCubeTexture(tex, {0, 4*PIXUNIT, 0}, 8*PIXUNIT, 8*PIXUNIT, 8*PIXUNIT, WHITE, 8, 8, 8, 8);
rlPopMatrix();
Vector3 leftPivot = Vector3Add(posLerp, (Vector3){-6*PIXUNIT, 1.25f - 5*PIXUNIT, 0});
Vector3 rightPivot = Vector3Add(posLerp, (Vector3){6*PIXUNIT, 1.25f - 5*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z);
rlRotatef(45.0f * armWave0, 1, 0, 0);
rlRotatef(45.0f * armWave1, 0, 0, 1);
DrawCubeTexture(tex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4);
rlPopMatrix();
rlPushMatrix();
rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z);
rlRotatef(-45.0f * armWave0, 1, 0, 0);
rlRotatef(-45.0f * armWave1, 0, 0, 1);
DrawCubeTexture(tex, (Vector3){0, -6*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 44,20,4,4);
rlPopMatrix();
Vector3 body = Vector3Add(posLerp, {0, 1.25f - 10*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(body.x, body.y, body.z);
DrawCubeTexture(tex, Vector3Zero(), 8*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 20, 20, 8, 4);
rlPopMatrix();
leftPivot = Vector3Add(posLerp, (Vector3){-2*PIXUNIT, 1.25f - 14*PIXUNIT, 0});
rightPivot = Vector3Add(posLerp, (Vector3){2*PIXUNIT, 1.25f - 14*PIXUNIT, 0});
rlPushMatrix();
rlTranslatef(leftPivot.x, leftPivot.y, leftPivot.z);
rlRotatef(-45.0f * armWave0, 1, 0, 0);
DrawCubeTexture(tex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4);
rlPopMatrix();
rlPushMatrix();
rlTranslatef(rightPivot.x, rightPivot.y, rightPivot.z);
rlRotatef(45.0f * armWave0, 1, 0, 0);
DrawCubeTexture(tex, {0*PIXUNIT, -8*PIXUNIT, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 4, 20, 4, 4);
rlPopMatrix();
rlPopMatrix();
Vector3 dir = Vector3Subtract(camera.position, (Vector3){x, y, z});
rlPushMatrix();
rlTranslatef(x, y + 1.5f, z);
rlRotatef(atan2f(dir.x, dir.z) * RAD2DEG, 0.0f, 1.0f, 0.0f);
rlRotatef(90.0f, 1.0f, 0.0f, 0.0f);
const char* name = netPlayer.nickname.c_str();
DrawText3D(fnt, name, {-MeasureTextEx(fnt, name, PIXUNIT * 4, 0).x * 1.5f, 0, 0}, PIXUNIT * 4, PIXUNIT, 1, true, WHITE);
rlPopMatrix();
}
Chunk world[MAX_WORLD_AREA];
static MeshUnit rendering[MAX_WORLD_AREA]; static MeshUnit rendering[MAX_WORLD_AREA];
static MeshUnit renderingT[MAX_WORLD_AREA];
std::map<std::string, Shader> loadedShaders;
static void LoadNewShader(std::string name) {
Shader temp = LoadShader(
TextFormat("%s/shaders/%s.vs", PATH_APPEND, name.c_str()),
TextFormat("%s/shaders/%s.fs", PATH_APPEND, name.c_str())
);
temp.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(temp, "matModel");
temp.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(temp, "viewPos");
loadedShaders[name] = temp;
}
GameState state = GAME_STATE_MAINMENU; GameState state = GAME_STATE_MAINMENU;
bool loaderParam_remeshOnly = false; bool loaderParam_remeshOnly = false;
int worldCreationProgress = 0; int worldCreationProgress = 0;
@@ -330,14 +248,17 @@ static void ResolveCollisions(float dt)
if (ix > 0 && iy > 0 && iz > 0) if (ix > 0 && iy > 0 && iz > 0)
{ {
// find smallest penetration axis and push out along it
if (ix < iy && ix < iz) if (ix < iy && ix < iz)
{ {
// push on X
if (player_position.x < bx0) player_position.x -= ix; if (player_position.x < bx0) player_position.x -= ix;
else player_position.x += ix; else player_position.x += ix;
player_velocity.x = 0; player_velocity.x = 0;
} }
else if (iy < ix && iy < iz) else if (iy < ix && iy < iz)
{ {
// push on Y
if (player_position.y < by0) player_position.y -= iy; if (player_position.y < by0) player_position.y -= iy;
else player_position.y += iy; else player_position.y += iy;
if (player_velocity.y > 0) player_velocity.y = 0; if (player_velocity.y > 0) player_velocity.y = 0;
@@ -345,6 +266,7 @@ static void ResolveCollisions(float dt)
} }
else else
{ {
// push on Z
if (player_position.z < bz0) player_position.z -= iz; if (player_position.z < bz0) player_position.z -= iz;
else player_position.z += iz; else player_position.z += iz;
player_velocity.z = 0; player_velocity.z = 0;
@@ -357,35 +279,48 @@ static void ResolveCollisions(float dt)
bool loadedChunks[MAX_WORLD_AREA] = { false }; bool loadedChunks[MAX_WORLD_AREA] = { false };
bool dirtyChunks[MAX_WORLD_AREA] = { false }; bool dirtyChunks[MAX_WORLD_AREA] = { false };
const Vector3I dirs2d[4] = {
(Vector3I){ 1, 0, 0},
(Vector3I){ 0, 0, 1},
(Vector3I){-1, 0, 0},
(Vector3I){ 0, 0, -1},
};
void Debug_EndMeasure(const std::string &stuff); void Debug_EndMeasure(const std::string &stuff);
void Debug_EndMeasureLoops(const std::string &stuff, int loops); void Debug_EndMeasureLoops(const std::string &stuff, int loops);
static void RemeshChunk(int x, int y) { static void RemeshChunk(int x, int y) {
int idx = x + y * MAX_WORLD_SIZE; int idx = GetIndexWorld(x, y);
if(loadedChunks[idx]) { if(loadedChunks[idx]) {
UnloadModel(renderingT[idx].model);
UnloadModel(rendering[idx].model); UnloadModel(rendering[idx].model);
UnloadModel(rendering[idx].modelTransparent);
UnloadModel(rendering[idx].modelWater);
} }
Chunk chunk = world[idx]; Chunk &chunk = world.chunks[idx];
RebuildOpaqueMask(&chunk); RebuildOpaqueMask(chunk);
RebuildLighting(world, chunk.x, chunk.z);
MeshData renderDataOpq = GenerateChunkMesh(GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF);
MeshData renderDataTsl = GenerateChunkMesh(GenerateCRDTranslucent(chunk, world), chunk, x, y, 0xFF);
MeshData renderDataOpq = GenerateChunkMesh(world, GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF);
Model model = LoadModelFromMesh(GenChunkMesh(renderDataOpq)); Model model0 = LoadModelFromMesh(GenChunkMesh(renderDataOpq));
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain; model0.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
model0.materials[0].shader = loadedShaders["terrain"];
MeshUnit munit0; MeshUnit munit0;
munit0.model = model; munit0.model = model0;
munit0.vertices += renderDataOpq.vertexCount; munit0.vertices += renderDataOpq.vertexCount;
rendering[idx] = munit0;
model = LoadModelFromMesh(GenChunkMesh(renderDataTsl));
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
MeshUnit munit1;
munit1.model = model;
munit1.vertices += renderDataTsl.vertexCount;
renderingT[idx] = munit1;
loadedChunks[idx] = true;
MeshData renderDataTsl = GenerateChunkMesh(world, GenerateCRDTranslucent(chunk, world), chunk, x, y, 0xFF);
Model model1 = LoadModelFromMesh(GenChunkMesh(renderDataTsl));
model1.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
model1.materials[0].shader = loadedShaders["terrain"];
munit0.modelTransparent = model1;
MeshData renderDataWtr = GenerateChunkMesh(world, GenerateCRDWater(chunk, world), chunk, x, y, 0xFF);
Model model2 = LoadModelFromMesh(GenChunkMesh(renderDataWtr));
model2.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
model2.materials[0].shader = loadedShaders["water"];
munit0.modelWater = model2;
loadedChunks[idx] = true;
rendering[idx] = munit0;
} }
static bool RaycastBlock(Vector3 origin, Vector3 dir, float maxDist, Vector3 *outBlock, Vector3 *outPrev) static bool RaycastBlock(Vector3 origin, Vector3 dir, float maxDist, Vector3 *outBlock, Vector3 *outPrev)
@@ -449,12 +384,21 @@ static inline void RemeshChunkForBlock(int bx, int by, int bz)
if (cx >= 0 && cx < MAX_WORLD_SIZE && cz >= 0 && cz < MAX_WORLD_SIZE) RemeshChunk(cx, cz); if (cx >= 0 && cx < MAX_WORLD_SIZE && cz >= 0 && cz < MAX_WORLD_SIZE) RemeshChunk(cx, cz);
} }
static void AddNekit() {
Entity temp = NewEntity();
temp.type = 2;
temp.health = 50;
temp.velocity = {0, 0, 0};
temp.position = player_position + (Vector3){0, 10, 0};
AddEntity(temp);
}
ENetPeer *peer; ENetPeer *peer;
ENetHost* client; ENetHost* client;
static std::stack<std::vector<uint8_t>> worldPacketStack; static std::stack<std::vector<uint8_t>> worldPacketStack;
static int fetchedChunks; static int fetchedChunks;
int plrId = 0; int plrId = -1;
static bool pauseMenuActive; static bool pauseMenuActive;
void _LoadWorld(const char* path) { void _LoadWorld(const char* path) {
@@ -470,7 +414,7 @@ void PlayRandomMusic() {
PlayMusicStream(currentMusic); PlayMusicStream(currentMusic);
} }
static int _blockPlacedC = 0; static int _blockPlacedC = 0;
void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t) { void SetBlockNetwork(World &world, int bx, int by, int bz, int t) {
float pitch = GetRandomValue(-100, 100) / 100.0f * 0.25f + 1.0f; float pitch = GetRandomValue(-100, 100) / 100.0f * 0.25f + 1.0f;
int sound = B_Stone; int sound = B_Stone;
tickedBlocks.push({bx, by, bz}); tickedBlocks.push({bx, by, bz});
@@ -481,11 +425,11 @@ void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t) {
tickedBlocks.push({bx, by, bz-1}); tickedBlocks.push({bx, by, bz-1});
tickedBlocks.push({bx, by, bz+1}); tickedBlocks.push({bx, by, bz+1});
if(t != 0) { if(t != 0) {
sound = BLOCKS[t].type; sound = GetBlockDefinition(t).type;
} }
else { else {
int id = GetBlock(world, bx, by, bz); int id = GetBlock(world, bx, by, bz);
BlockDef block = BLOCKS[id]; BlockDef block = GetBlockDefinition(id);
if(id != 0) { if(id != 0) {
sound = block.type; sound = block.type;
for (int x = 0; x < 4; x++) for (int x = 0; x < 4; x++)
@@ -565,9 +509,9 @@ static void TickAvailableBlocks() {
} }
} }
} }
std::atomic_bool serverStarted;
int TryConnect(const char* hostname) { int TryConnect(const char* hostname) {
client = StartClient(); /*client = StartClient();
if(client == NULL) if(client == NULL)
{ {
@@ -582,7 +526,7 @@ int TryConnect(const char* hostname) {
int s = enet_address_set_host (& address, hostname); int s = enet_address_set_host (& address, hostname);
address.port = PORT; address.port = PORT;
peer = enet_host_connect(client, &address, 1, 0); peer = enet_host_connect(client, &address, 1);
if (peer == NULL) if (peer == NULL)
{ {
@@ -590,12 +534,10 @@ int TryConnect(const char* hostname) {
"No available peers for initiating an ENet connection.\n"); "No available peers for initiating an ENet connection.\n");
return NET_ERROR_NOTFOUND; return NET_ERROR_NOTFOUND;
} }
printf("Found a host\n");
while (!serverStarted) if (enet_host_service (client, & event, 5000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{ {
if(!online) serverStarted = true;
}
if (enet_host_service (client, & event, 10000) && event.type == ENET_EVENT_TYPE_CONNECT){
puts ("Connection succeeded."); puts ("Connection succeeded.");
char data[1]; char data[1];
data[0] = NET_ARG_REQWORLD; data[0] = NET_ARG_REQWORLD;
@@ -609,41 +551,9 @@ int TryConnect(const char* hostname) {
enet_peer_reset (peer); enet_peer_reset (peer);
return NET_ERROR_FAILED; return NET_ERROR_FAILED;
} }*/
return -1; return -1;
} }
std::thread serverThread;
std::atomic_bool stop_server = false;
void StartInternalServer(std::atomic_bool& started);
void ServerThread(std::atomic_bool& started) {
StartInternalServer(started);
stop_server = false;
while(true) {
if (stop_server) {
serverStarted = false;
StopInternalServer();
return;
}
ServerNetworkUpdate();
}
}
void InitSingleplayer() {
online = true;
serverThread = std::thread(ServerThread, std::ref(serverStarted));
int result = TryConnect("localhost");
if(result == NET_ERROR_FAILED) {
state = GAME_STATE_MAINMENU;
return;
}
singleplayerServer = true;
}
void ExitSingleplayer() {
GameModeCleanup();
}
std::vector<MessageData> messages; std::vector<MessageData> messages;
bool survival = false; bool survival = false;
bool chatOpen = false; bool chatOpen = false;
@@ -655,6 +565,54 @@ void TakeDamage(float amount) {
int currentlyTickedChunk = 0; int currentlyTickedChunk = 0;
Vector3 highlightBlock = {-1, -1, -1}; Vector3 highlightBlock = {-1, -1, -1};
float GetDayProgression() {
return (float)(worldTime % (unsigned long long)(WORLD_TIME_TICKS)) / (float)(WORLD_TIME_TICKS);
}
Color GetSkyColor() {
float progression = GetDayProgression();
Color night = ColorBrightness(BLUE, -0.9f);
Color sunrise = ColorBrightness(ORANGE, -0.25f);
Color noon = BLUE;
if(progression > 0.5f) {
progression = 1 - progression;
}
if(progression < 0.20f) {
return night;
}
if(progression>=0.20f&&progression<0.30f) {
return ColorLerp(night, sunrise, (progression - 0.2f) / 0.1f);
}
if(progression>=0.30f&&progression<0.35f) {
return ColorLerp(sunrise, noon, (progression - 0.3f) / 0.05f);
}
return noon;
}
Color GetSunlightColor() {
float progression = GetDayProgression();
Color night = ColorBrightness(BLUE, -0.9f);
Color sunrise = ColorBrightness(ORANGE, -0.25f);
Color noon = WHITE;
if(progression > 0.5f) {
progression = 1 - progression;
}
if(progression < 0.20f) {
return night;
}
if(progression>=0.20f&&progression<0.30f) {
return ColorLerp(night, sunrise, (progression - 0.2f) / 0.1f);
}
if(progression>=0.30f&&progression<0.35f) {
return ColorLerp(sunrise, noon, (progression - 0.3f) / 0.05f);
}
return noon;
}
static Vector3 GetSunDirection() {
float time = GetDayProgression() - 0.25f;
return Vector3Normalize({-sinf(time*PI*2), -sinf(time*PI*2)/2.0f, -cosf(time*PI*2)});
}
static void GameUpdate(Camera camera, float &time) { static void GameUpdate(Camera camera, float &time) {
if (player_position.y < 0 || if (player_position.y < 0 ||
player_position.x < 0 || player_position.x < 0 ||
@@ -791,6 +749,22 @@ static void GameUpdate(Camera camera, float &time) {
Vector3 rayOrigin = (Vector3){ player_position.x, player_position.y + 1.7f, player_position.z};; Vector3 rayOrigin = (Vector3){ player_position.x, player_position.y + 1.7f, player_position.z};;
Vector3 hitBlock, prevBlock; Vector3 hitBlock, prevBlock;
if(IsKeyDown(KEY_N) && !online) {
AddNekit();
}
if(IsKeyPressed(KEY_F10)) {
tick_entities = !tick_entities;
}
if(IsKeyDown(KEY_F11)) {
worldTime+=8;
}
if(IsKeyPressed(KEY_B) && !online) {
Entity temp = NewEntity();
temp.type = 3;
temp.position = camera.position;
temp.velocity = (camera.target - camera.position) * 4.0f;
AddEntity(temp);
}
if (RaycastBlock(rayOrigin, Vector3Normalize(camForward), 5, &hitBlock, &prevBlock)) if (RaycastBlock(rayOrigin, Vector3Normalize(camForward), 5, &hitBlock, &prevBlock))
{ {
if((int)hitBlock.x != (int)highlightBlock.x || (int)hitBlock.y != (int)highlightBlock.y || (int)hitBlock.z != (int)highlightBlock.z) if((int)hitBlock.x != (int)highlightBlock.x || (int)hitBlock.y != (int)highlightBlock.y || (int)hitBlock.z != (int)highlightBlock.z)
@@ -823,7 +797,7 @@ static void GameUpdate(Camera camera, float &time) {
tier = selected_item->tier; tier = selected_item->tier;
} }
} }
BlockDef block = BLOCKS[GetBlock(world, bx, by, bz)]; BlockDef block = GetBlockDefinition(GetBlock(world, bx, by, bz));
float hardnessMultiplier = block.hardness / 4.0f; float hardnessMultiplier = block.hardness / 4.0f;
if(player_break_parts_time >= 0.05f) { if(player_break_parts_time >= 0.05f) {
Vector3 v = {0, 1, 0}; Vector3 v = {0, 1, 0};
@@ -970,13 +944,30 @@ static void GameUpdate(Camera camera, float &time) {
} }
double PROFCOUNT = GetTime(); double PROFCOUNT = GetTime();
if (bestIdx != -1) { if (bestIdx != -1) {
RebuildOpaqueMask(&world[bestIdx]); RebuildOpaqueMask(world.chunks[bestIdx]);
int bx, by; int bx, by;
GetXZFromIndex(bestIdx, &bx, &by); GetXZFromIndex(bestIdx, &bx, &by);
RemeshChunk(bx, by); RemeshChunk(bx, by);
dirtyChunks[bestIdx] = false; dirtyChunks[bestIdx] = false;
} }
AddProfilerPart("rebuild", GetTime()-PROFCOUNT, BLUE); AddProfilerPart("rebuild", GetTime()-PROFCOUNT, BLUE);
PROFCOUNT = GetTime();
if(tick_entities) {
entUpdateCounter += dt / 2.0f;
if(entUpdateCounter > TPS_DIV) {
while (entUpdateCounter > 0)
{
UpdateEntities(world, TPS_DIV / 2.0f);
entUpdateCounter-= TPS_DIV;
worldTime++;
}
TickAvailableBlocks();
entUpdateCounter = 0.0f;
}
}
AddProfilerPart("entities", GetTime()-PROFCOUNT, MAGENTA);
PROFCOUNT = GetTime(); PROFCOUNT = GetTime();
ParticlesUpdate(dt, world); ParticlesUpdate(dt, world);
@@ -994,12 +985,56 @@ static void GameUpdate(Camera camera, float &time) {
UpdateCamera(&camera, CAMERA_CUSTOM); UpdateCamera(&camera, CAMERA_CUSTOM);
unsigned int debug_verts_opaque = 0; unsigned int debug_verts_opaque = 0;
unsigned int debug_verts_transparent = 0;
UpdateHotbar(); UpdateHotbar();
Frustum frustum = ExtractFrustumPlanes(camera, (float)GetScreenWidth() / (float)GetScreenHeight()); Frustum frustum = ExtractFrustumPlanes(camera, (float)GetScreenWidth() / (float)GetScreenHeight());
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); UpdateCamera(&camera, CAMERA_CUSTOM);
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), {120, 167, 255});
ClearBackground(GetSkyColor());
BeginMode3D(camera);
float time = GetDayProgression() - 0.25f;
Vector3 sunOffset = Vector3Negate(GetSunDirection());
Vector3 _forward = Vector3Subtract(camera.target, camera.position);
Vector3 up = { 0.0f, 1.0f, 0.0f };
Vector3 _right = Vector3CrossProduct(up, _forward);
up = Vector3CrossProduct(_forward, _right);
up = Vector3Normalize(up);
SetRandomSeed(1337);
time += 0.25f;
if(time > 0.5f) {
time = 1-time;
}
float starAlpha = 0.0f;
if(time > 0.2f && time <= 0.3f) {
starAlpha = 1-(time - 0.2f) / 0.1f;
}
if(time <= 0.2f) {
starAlpha = 1;
}
rlSetBlendMode(BLEND_ADDITIVE);
DrawBillboardPro(camera, sun, {0, 0, 64, 64}, player_position+sunOffset*1000, up, {150, 150}, {0.5f, 0.5f}, 0, WHITE);
DrawBillboardPro(camera, moon, {0, 0, 64, 64}, player_position-sunOffset*1000, up, {150, 150}, {0.5f, 0.5f}, 0, WHITE);
for (int i = 0; i < 120; i++)
{
float u = GetRandomValue(0, 100) / 100.0f;
float v = GetRandomValue(0, 100) / 100.0f;
double theta = 2.0 * M_PI * u;
double z = v;
double r = std::sqrt(1.0 - z*z);
Vector3 starOffset = {
r * std::cos(theta),
z,
r * std::sin(theta)
};
Vector3 tgt = starOffset*1000;
float alphaModMoon = fmax(0, fmin(1, Vector3Distance(starOffset, (Vector3Negate(sunOffset)))/0.25f-1));
float alphaModSun = fmax(0, fmin(1, Vector3Distance(starOffset, sunOffset)/0.25f-0.25f));
DrawBillboardPro(camera, stars, {(float)GetRandomValue(0, stars.width/8)*8, 0, 8, 8}, player_position+tgt, up, {10, 10}, {0.5f, 0.5f}, GetRandomValue(0, 360), ColorAlpha(WHITE, starAlpha*alphaModMoon*alphaModSun));
}
rlSetBlendMode(BLEND_ALPHA);
EndMode3D();
BeginMode3D(camera); BeginMode3D(camera);
@@ -1013,16 +1048,13 @@ static void GameUpdate(Camera camera, float &time) {
_z *= CHUNK_SIZE; _z *= CHUNK_SIZE;
if(!loadedChunks[x]) continue; if(!loadedChunks[x]) continue;
if(!IsChunkInFrustum(frustum, world[x], _x, _z)) continue; if(!IsChunkInFrustum(frustum, world.chunks[x], _x, _z)) continue;
DrawModel(rendering[x].model, {0, 0, 0}, 1, WHITE); DrawModel(rendering[x].model, {0, 0, 0}, 1, WHITE);
debug_verts_opaque += rendering[x].vertices; debug_verts_opaque += rendering[x].vertices;
} }
AddProfilerPart("chunk render opq", GetTime()-PROFCOUNT, MAROON); AddProfilerPart("chunk render opq", GetTime()-PROFCOUNT, MAROON);
DrawEntities(entities, 0); DrawEntities(dt);
for (const auto& [id, netplayer] : players) {
DrawPlayer(terrain, netplayer);
}
ParticlesDraw(); ParticlesDraw();
//Transparent shit //Transparent shit
rlDisableDepthMask(); rlDisableDepthMask();
@@ -1084,7 +1116,7 @@ static void GameUpdate(Camera camera, float &time) {
if (!loadedChunks[i]) continue; if (!loadedChunks[i]) continue;
int cx, cz; int cx, cz;
GetXZFromIndex(i, &cx, &cz); GetXZFromIndex(i, &cx, &cz);
if (!IsChunkInFrustum(frustum, world[i], cx*CHUNK_SIZE, cz*CHUNK_SIZE)) continue; if (!IsChunkInFrustum(frustum, world.chunks[i], cx*CHUNK_SIZE, cz*CHUNK_SIZE)) continue;
float wx = cx * CHUNK_SIZE + CHUNK_SIZE * 0.5f; float wx = cx * CHUNK_SIZE + CHUNK_SIZE * 0.5f;
float wz = cz * CHUNK_SIZE + CHUNK_SIZE * 0.5f; float wz = cz * CHUNK_SIZE + CHUNK_SIZE * 0.5f;
float dx = wx - camera.position.x; float dx = wx - camera.position.x;
@@ -1097,8 +1129,8 @@ static void GameUpdate(Camera camera, float &time) {
for (auto &p : distances) { for (auto &p : distances) {
int idx = p.second; int idx = p.second;
DrawModel(renderingT[idx].model, {0, 0, 0}, 1.0f, WHITE); DrawModel(rendering[idx].modelTransparent, {0, 0, 0}, 1.0f, WHITE);
debug_verts_transparent += renderingT[idx].vertices; DrawModel(rendering[idx].modelWater, {0, 0, 0}, 1.0f, WHITE);
} }
AddProfilerPart("chunk render tsl", GetTime()-PROFCOUNT, RED); AddProfilerPart("chunk render tsl", GetTime()-PROFCOUNT, RED);
if (highlightValid) if (highlightValid)
@@ -1117,7 +1149,7 @@ static void GameUpdate(Camera camera, float &time) {
BeginMode3D(camera); BeginMode3D(camera);
rlDisableDepthMask(); rlDisableDepthMask();
rlDisableDepthTest(); rlDisableDepthTest();
DrawSelectedItem(); DrawSelectedItem(GetLight(world, (int)player_position.x, (int)player_position.y, (int)player_position.z));
rlEnableDepthTest(); rlEnableDepthTest();
rlEnableDepthMask(); rlEnableDepthMask();
EndMode3D(); EndMode3D();
@@ -1133,7 +1165,7 @@ static void GameUpdate(Camera camera, float &time) {
oxygen += dt * 20.0f; oxygen += dt * 20.0f;
oxygen = Clamp(oxygen, 0, MAX_HP); oxygen = Clamp(oxygen, 0, MAX_HP);
} }
if(!hide_ui && !taking_panorama) { if(!hide_ui && !taking_panorama) { // DEBUG MENU!!!!
char text[128]; char text[128];
sprintf(text, "%s %s", GAME_NAME, GAME_VERSION); sprintf(text, "%s %s", GAME_NAME, GAME_VERSION);
DrawTextB(text, 20, 20, DEFAULT_FONT_SIZE, WHITE); DrawTextB(text, 20, 20, DEFAULT_FONT_SIZE, WHITE);
@@ -1148,8 +1180,21 @@ static void GameUpdate(Camera camera, float &time) {
float virtualmem = m.virtualSize / 1024.0f / 1024.0f; float virtualmem = m.virtualSize / 1024.0f / 1024.0f;
sprintf(text, "Mem %.2fMiB/%.2fMiB", residentmem, virtualmem); sprintf(text, "Mem %.2fMiB/%.2fMiB", residentmem, virtualmem);
DrawTextB(text, 20, 80, DEFAULT_FONT_SIZE, WHITE); DrawTextB(text, 20, 80, DEFAULT_FONT_SIZE, WHITE);
sprintf(text, "Drawing %d verts", debug_verts_opaque+debug_verts_transparent); Vector3I ppos = {floorf(player_position.x), floorf(player_position.y), floorf(player_position.z)};
DrawTextB(text, 120, 40, DEFAULT_FONT_SIZE, WHITE); sprintf(text, "skylight %d | blocklight: r %d g %d b %d",
GetSkyLight(world, ppos.x, ppos.y, ppos.z),
GetRLight(world, ppos.x, ppos.y, ppos.z),
GetGLight(world, ppos.x, ppos.y, ppos.z),
GetBLight(world, ppos.x, ppos.y, ppos.z)
);
DrawTextB(text, 20, 100, DEFAULT_FONT_SIZE, WHITE);
sprintf(text, "world time %dt (%.1fs)", worldTime, worldTime * TPS_DIV);
DrawTextB(text, 20, 120, DEFAULT_FONT_SIZE, WHITE);
float progress = GetDayProgression();
int hours = progress*24;
int minutes = (int)(progress*24*60)%60;
sprintf(text, "%02d:%02d", hours, minutes);
DrawTextB(text, 20, 140, DEFAULT_FONT_SIZE, WHITE);
DrawRectangle(GetScreenWidth()/2-3, GetScreenHeight()/2-3, 6, 6, BLACK); DrawRectangle(GetScreenWidth()/2-3, GetScreenHeight()/2-3, 6, 6, BLACK);
DrawRectangle(GetScreenWidth()/2-2, GetScreenHeight()/2-2, 4, 4, WHITE); DrawRectangle(GetScreenWidth()/2-2, GetScreenHeight()/2-2, 4, 4, WHITE);
@@ -1196,6 +1241,13 @@ static void GameUpdate(Camera camera, float &time) {
DrawTriangle({x3, y3}, {x2, y2}, {x1, y1}, p.color); DrawTriangle({x3, y3}, {x2, y2}, {x1, y1}, p.color);
angleA = angleB; angleA = angleB;
} }
/*float mid = (startAngle + endAngle) * 0.5f;
float lx = cx + cosf(mid) * (radius * 0.6f);
float ly = cy + sinf(mid) * (radius * 0.6f);
char label[128];
sprintf(label, "%s (%.1f ms)", p.id.c_str(), p.time * 1000.0f);
DrawText(label, lx - 20, ly - 6, 10, WHITE);*/
startAngle = endAngle; startAngle = endAngle;
} }
int T = 0; int T = 0;
@@ -1243,6 +1295,7 @@ static void GameUpdate(Camera camera, float &time) {
} }
} }
static void GameStart() { static void GameStart() {
const int cloudMapSize = MAX_WORLD_SIZE*CHUNK_SIZE/8; const int cloudMapSize = MAX_WORLD_SIZE*CHUNK_SIZE/8;
for (int x = 0; x < cloudMapSize; x++) for (int x = 0; x < cloudMapSize; x++)
{ {
@@ -1255,28 +1308,11 @@ static void GameStart() {
if(online) { if(online) {
char data[1]; char data[1];
data[0] = NET_ARG_REQPLAYERS; data[0] = NET_ARG_REQPLAYERS;
SendPacketR(peer, data, 1); SendPacketR(peer, data, 1); // Tell the server to fetch all players
int memory_size = 65535;
char* dynamic_buffer = new char[memory_size];
std::ifstream file;
file.open(GetPlayerTexturePath(), std::ios_base::in | std::ios_base::binary );
file.read(dynamic_buffer, memory_size);
int bytes_read = (int)(file.gcount());
std::cout << bytes_read << std::endl;
file.close();
uint8_t skin_packet[4+bytes_read];
skin_packet[0] = NET_ARG_PLRSKINSET;
skin_packet[1] = plrId;
skin_packet[2] = (bytes_read & 0xFF00) >> 8;
skin_packet[3] = bytes_read & 0xFF;
memcpy(skin_packet+4, dynamic_buffer, bytes_read);
SendPacketR(peer, skin_packet, sizeof(skin_packet)*sizeof(uint8_t));
//free(skin_packet);
//free(dynamic_buffer);
} }
worldTime = (int)(WORLD_TIME_TICKS * 0.3f);
camera = { 0 }; camera = { 0 };
camera.position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 12.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE}; camera.position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 12.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE};
camera.target = (Vector3){camera.position.x, camera.position.y, camera.position.z + 1}; camera.target = (Vector3){camera.position.x, camera.position.y, camera.position.z + 1};
@@ -1286,7 +1322,7 @@ static void GameStart() {
int center = MAX_WORLD_SIZE / 2 * CHUNK_SIZE; int center = MAX_WORLD_SIZE / 2 * CHUNK_SIZE;
player_position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 128.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE}; player_position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 128.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE};
player_position.y = world[GetIndexWorld(center / 16, center / 16)].highestBlock[0] + 2; player_position.y = world.chunks[GetIndexWorld(center / 16, center / 16)].highestBlock[0] + 2;
player_velocity = (Vector3){ 0, 0, 0 }; player_velocity = (Vector3){ 0, 0, 0 };
DisableCursor(); DisableCursor();
@@ -1299,8 +1335,22 @@ static void GameStart() {
grass_place = LoadSound(Pathify("sound/block_grass.wav")); grass_place = LoadSound(Pathify("sound/block_grass.wav"));
} }
static void CreateNetPlayer(int id) {
Entity temp = NewEntity();
temp.type = 1;
temp.position = player_position;
temp.data[0] = id;
temp.data[1] = 0;
AddEntity(temp);
}
static void RemovePlayerEntity(int id) { static void RemovePlayerEntity(int id) {
players.erase(id); auto match = [&](const Entity ent){
return ent.data[0] == id && ent.type == 1;
};
auto it = std::find_if(entities.begin(), entities.end(), match);
if (it != entities.end()) {
entities.erase(it);
}
} }
static void ParseMessagePacket(std::vector<unsigned char> &a_data) { static void ParseMessagePacket(std::vector<unsigned char> &a_data) {
std::string output; std::string output;
@@ -1315,14 +1365,6 @@ static void ParseMessagePacket(std::vector<unsigned char> &a_data) {
msg.message = output; msg.message = output;
messages.push_back(msg); messages.push_back(msg);
} }
static void CreatePlayer(int id) {
if(id != plrId) {
NetPlayer temp = {0};
temp.id = id;
temp.nickname = "testificate";
players[id] = temp;
}
}
static void ParseData(ENetPacket* packet) { static void ParseData(ENetPacket* packet) {
int len = packet->dataLength; int len = packet->dataLength;
std::vector<unsigned char> a_data; std::vector<unsigned char> a_data;
@@ -1332,6 +1374,7 @@ static void ParseData(ENetPacket* packet) {
a_data.push_back(packet->data[i]); a_data.push_back(packet->data[i]);
} }
switch (a_data[0]) switch (a_data[0])
{ {
case NET_ARG_CHUNKF: case NET_ARG_CHUNKF:
@@ -1344,7 +1387,9 @@ static void ParseData(ENetPacket* packet) {
break; break;
case NET_ARG_PLRCON: case NET_ARG_PLRCON:
puts("Player connected"); puts("Player connected");
CreatePlayer(a_data[1]); if(a_data[1] != plrId) {
CreateNetPlayer(a_data[1]);
}
break; break;
case NET_ARG_PLRDCN: case NET_ARG_PLRDCN:
puts("Player disconnected"); puts("Player disconnected");
@@ -1360,37 +1405,49 @@ static void ParseData(ENetPacket* packet) {
player_position.y = y; player_position.y = y;
player_position.z = z; player_position.z = z;
} }
else { for (Entity &plr : entities)
NetPlayer &plr = players[a_data[1]]; {
players[plrId].yaw = a_data[2]; std::cout << (int)(plr.data[0]) << " " << (int)(plr.type) << std::endl;
float x = DeserializeFloat(a_data[2],a_data[3]); if(plr.data[0] == a_data[1] && plr.type == 1) {
float y = DeserializeFloat(a_data[4],a_data[5]); float x = DeserializeFloat(a_data[2],a_data[3]);
float z = DeserializeFloat(a_data[6],a_data[7]); float y = DeserializeFloat(a_data[4],a_data[5]);
plr.x = x; float z = DeserializeFloat(a_data[6],a_data[7]);
plr.y = y; plr.position.x = x;
plr.z = z; plr.position.y = y;
plr.position.z = z;
//plr.yaw = (short)floorf(a_data[8] / 255.0f* 65536);
plr.data[1] = 255;
std::cout << x << " " << y << " " << z << " " << (float)(plr.yaw) << std::endl;
}
} }
break; break;
case NET_ARG_ECHOYAW: case NET_ARG_ECHOYAW:
std::cout << "Server requested to sync yaw " << (int)(a_data[1]) << std::endl; std::cout << "Server requested to sync yaw " << (int)(a_data[1]) << std::endl;
if(a_data[1] != plrId) { for (Entity &plr : entities)
NetPlayer &plr = players[a_data[1]]; {
players[plrId].yaw = a_data[2]; if(plr.data[0] == a_data[1] && plr.type == 1) {
plr.yaw = (short)floorf(a_data[2] / 255.0f * 65536);
}
} }
break; break;
case NET_ARG_PLRREG: case NET_ARG_PLRREG:
puts("Got a connected player"); puts("Got a connected player");
if(a_data[1] != plrId) { if(a_data[1] != plrId) {
CreatePlayer(a_data[1]); CreateNetPlayer(a_data[1]);
NetPlayer &plr = players[a_data[1]];
float x = DeserializeFloat(a_data[2],a_data[3]);
float y = DeserializeFloat(a_data[4],a_data[5]);
float z = DeserializeFloat(a_data[6],a_data[7]);
plr.x = x;
plr.y = y;
plr.z = z;
plr.yaw = (short)floorf(a_data[8] / 255.0f * 65536);
} }
for (Entity &plr : entities)
{
if(plr.data[0] == a_data[1] && plr.type == 1) {
float x = DeserializeFloat(a_data[2],a_data[3]);
float y = DeserializeFloat(a_data[4],a_data[5]);
float z = DeserializeFloat(a_data[6],a_data[7]);
plr.position.x = x;
plr.position.y = y;
plr.position.z = z;
plr.yaw = (short)floorf(a_data[8] / 255.0f * 65536);
}
}
break;
case NET_ARG_BLOCK: case NET_ARG_BLOCK:
SetBlock(world, a_data[2], a_data[3], a_data[4], a_data[5]); SetBlock(world, a_data[2], a_data[3], a_data[4], a_data[5]);
dirtyChunks[GetIndexWorld(a_data[2] / 16, a_data[4] / 16)] = true; dirtyChunks[GetIndexWorld(a_data[2] / 16, a_data[4] / 16)] = true;
@@ -1410,32 +1467,6 @@ static void ParseData(ENetPacket* packet) {
case NET_ARG_MESSAGEE: case NET_ARG_MESSAGEE:
ParseMessagePacket(a_data); ParseMessagePacket(a_data);
break; break;
case NET_ARG_ENTITYSPAWN:
{
Entity ent = {0};
ent.id = a_data[1] << 8 | a_data[2];
ent.type = a_data[3];
float x = DeserializeFloat(a_data[4],a_data[5]);
float y = DeserializeFloat(a_data[6],a_data[7]);
float z = DeserializeFloat(a_data[8],a_data[9]);
memcpy(ent.data_sv, a_data.data()+10, 8);
entities.push_back(ent);
}
break;
case NET_ARG_PLRSKIN:
{
NetPlayer &plr = players[a_data[1]];
int texsize = (a_data[2] << 8) | a_data[3];
uint8_t img[texsize];
std::cout << texsize << std::endl;
memcpy(img, a_data.data()+4, texsize);
Image temp = LoadImageFromMemory(".png", img, texsize);
plr.texture = LoadTextureFromImage(temp);
std::cout << plr.id << std::endl;
UnloadImage(temp);
//free(img);
}
break;
default: default:
puts("Malformed data?"); puts("Malformed data?");
break; break;
@@ -1499,15 +1530,6 @@ void GameModeCleanupFull() {
enet_host_destroy(client); enet_host_destroy(client);
online = false; online = false;
} }
for (int idx = 0; idx < MAX_WORLD_AREA; idx++)
{
if(loadedChunks[idx]) {
//UnloadModel(renderingT[idx]);
//UnloadModel(rendering[idx]);
}
}
stop_server = true;
memset(loadedChunks, 0, sizeof(loadedChunks)); memset(loadedChunks, 0, sizeof(loadedChunks));
memset(dirtyChunks, 0, sizeof(dirtyChunks)); memset(dirtyChunks, 0, sizeof(dirtyChunks));
entities.clear(); entities.clear();
@@ -1520,6 +1542,7 @@ void GameModeCleanup() {
pauseMenuActive = false; pauseMenuActive = false;
EnableCursor(); EnableCursor();
GameModeCleanupFull(); GameModeCleanupFull();
state = GAME_STATE_MAINMENU;
worldCreationProgress = 0; worldCreationProgress = 0;
worldCreationStep = 0; worldCreationStep = 0;
} }
@@ -1530,6 +1553,13 @@ int main(void)
SetTraceLogLevel(LOG_WARNING); SetTraceLogLevel(LOG_WARNING);
SetConfigFlags(FLAG_WINDOW_RESIZABLE); SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(WIDTH, HEIGHT, GAME_NAME); InitWindow(WIDTH, HEIGHT, GAME_NAME);
if(!DirectoryExists(PathifyUser(""))) {
MakeDirectory(PathifyUser(""));
}
if(!DirectoryExists(PathifyUser("worlds"))) {
MakeDirectory(PathifyUser("worlds"));
}
InitWorldgen(0); InitWorldgen(0);
InitAudioDevice(); InitAudioDevice();
InitMenu(); InitMenu();
@@ -1538,8 +1568,6 @@ int main(void)
LocaleUpdate(); LocaleUpdate();
LoadRecipes(); LoadRecipes();
playerTex = LoadTexture(GetPlayerTexturePath());
camera = { 0 }; camera = { 0 };
camera.position = (Vector3){0, 0, 0}; camera.position = (Vector3){0, 0, 0};
camera.target = (Vector3){camera.position.x, camera.position.y, camera.position.z + 1}; camera.target = (Vector3){camera.position.x, camera.position.y, camera.position.z + 1};
@@ -1549,6 +1577,9 @@ int main(void)
fnt = LoadFontEx(Pathify("font.ttf"), 32, NULL, 1024*8); fnt = LoadFontEx(Pathify("font.ttf"), 32, NULL, 1024*8);
terrain = LoadTexture(Pathify("terrain.png")); terrain = LoadTexture(Pathify("terrain.png"));
sun = LoadTexture(Pathify("sun.png"));
moon = LoadTexture(Pathify("moon.png"));
stars = LoadTexture(Pathify("stars.png"));
GenTextureMipmaps(&terrain); GenTextureMipmaps(&terrain);
Image temp = GenImageColor(1, 1, WHITE); Image temp = GenImageColor(1, 1, WHITE);
white_pixel = LoadTextureFromImage(temp); white_pixel = LoadTextureFromImage(temp);
@@ -1564,14 +1595,32 @@ int main(void)
ImageCrop(&copied, src0); ImageCrop(&copied, src0);
water = LoadTextureFromImage(copied); water = LoadTextureFromImage(copied);
SetTextureWrap(terrain, TEXTURE_WRAP_REPEAT);
SetTextureWrap(water, TEXTURE_WRAP_REPEAT); SetTextureWrap(water, TEXTURE_WRAP_REPEAT);
SetTargetFPS(-1); SetTargetFPS(-1);
float time; float time;
LoadNewShader("terrain");
LoadNewShader("water");
SetExitKey(KEY_NULL); SetExitKey(KEY_NULL);
while (!WindowShouldClose()) while (!WindowShouldClose())
{ {
for (const auto& [key, shader] : loadedShaders) {
Vector4 sunlight = ColorNormalize(GetSunlightColor());
SetShaderValue(shader, GetShaderLocation(shader, "sunlightColor"), &sunlight, SHADER_UNIFORM_VEC4);
Vector4 skyColor = ColorNormalize(GetSkyColor());
SetShaderValue(shader, GetShaderLocation(shader, "skyColor"), &skyColor, SHADER_UNIFORM_VEC4);
Vector3 sunlightDir = Vector3Negate(GetSunDirection());
SetShaderValue(shader, GetShaderLocation(shader, "lightDir"), &sunlightDir, SHADER_UNIFORM_VEC3);
float time = (float)GetTime();
SetShaderValue(shader, GetShaderLocation(shader, "time"), &time, SHADER_UNIFORM_FLOAT);
}
NetworkUpdate(); NetworkUpdate();
InputUpdate(); InputUpdate();
@@ -1594,7 +1643,7 @@ int main(void)
{ {
c.highestBlock[i-CHUNK_DATA_SIZE-2] = data[i]; c.highestBlock[i-CHUNK_DATA_SIZE-2] = data[i];
} }
world[idx] = c; world.chunks[idx] = c;
dirtyChunks[idx] = true; dirtyChunks[idx] = true;
worldPacketStack.pop(); worldPacketStack.pop();
fetchedChunks++; fetchedChunks++;
@@ -1641,7 +1690,7 @@ int main(void)
int idx = x + y * MAX_WORLD_SIZE; int idx = x + y * MAX_WORLD_SIZE;
if(worldCreationStep == 0 && !online) { if(worldCreationStep == 0 && !online) {
Chunk chunk = GenerateChunk(x, y); Chunk chunk = GenerateChunk(x, y);
world[idx] = chunk; world.chunks[idx] = chunk;
} }
if(worldCreationStep == 1 && !online) { if(worldCreationStep == 1 && !online) {
if(worldCreationProgress > 0) { if(worldCreationProgress > 0) {
@@ -1653,7 +1702,7 @@ int main(void)
} }
if (worldCreationStep == 2) if (worldCreationStep == 2)
{ {
RebuildOpaqueMask(&world[idx]); RebuildOpaqueMask(world.chunks[idx]);
} }
if (worldCreationStep == 3) { if (worldCreationStep == 3) {
dirtyChunks[idx] = true; dirtyChunks[idx] = true;
@@ -1686,15 +1735,7 @@ int main(void)
DrawMultiplayer(); DrawMultiplayer();
break; break;
case GAME_STATE_TRANSITION: case GAME_STATE_TRANSITION:
DrawBackground();
DrawLogoCenter(); DrawLogoCenter();
if(!singleplayerServer || !serverStarted) {
state = GAME_STATE_MAINMENU;
}
if (serverThread.joinable()) {
serverThread.join();
singleplayerServer = false;
}
break; break;
case GAME_STATE_OPTIONS: case GAME_STATE_OPTIONS:
DrawControls(); DrawControls();
+14
View File
@@ -0,0 +1,14 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_RC_COMPILER windres)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_C_FLAGS "-static-libgcc -static-libstdc++ ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-static-libgcc -static-libstdc++ ${CMAKE_CXX_FLAGS}")