Compare commits

..

12 Commits

Author SHA1 Message Date
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
39 changed files with 3882 additions and 1790 deletions
+6 -39
View File
@@ -11,13 +11,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install build tools
run: |
# 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 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
run: |
@@ -25,61 +27,26 @@ jobs:
make
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
run: |
chmod +x ${{ 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
uses: actions/upload-artifact@v3
with:
name: release-linux
path: release-linux.zip
path: OUTPUT-Linux
- name: Upload Windows64 Release
uses: actions/upload-artifact@v3
with:
name: release-w64
path: release-w64.zip
path: OUTPUT-w64
- name: Upload Windows32 Release
uses: actions/upload-artifact@v3
with:
name: release-w32
path: release-w32.zip
path: OUTPUT-w32
+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
+2 -4
View File
@@ -1,17 +1,15 @@
#/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
rm tmp.hpp
echo Building x86-64 Linux...
rm -rf build
cmake -B build -DUNIX=ON -DUNIX=true
cmake -B build -DUNIX=ON -DUNIX=true -DCMAKE_BUILD_TYPE=Debug
cd build
make -j12
cd ..
mkdir OUTPUT-Linux
cp build/src/RCRAFT OUTPUT-Linux/CubeGame
cp -r data/resources OUTPUT-Linux
mkdir OUTPUT-Linux/user
mkdir OUTPUT-Linux/user/worlds
-2
View File
@@ -13,5 +13,3 @@ cd ..
mkdir OUTPUT-w32
cp build/src/RCRAFT.exe OUTPUT-w32/CubeGame.exe
cp -r data/resources OUTPUT-w32
mkdir OUTPUT-w32/user
mkdir OUTPUT-w32/user/worlds
-2
View File
@@ -13,5 +13,3 @@ cd ..
mkdir OUTPUT-w64
cp build/src/RCRAFT.exe OUTPUT-w64/CubeGame.exe
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
chat: Open chat
swap_mouse: Swap LMB/RMB
inventory: Open inventory
# Menu
select_level: Singleplayer
multiplayer: Multiplayer
join: Join
exit: Exit
options: Options
create_world: Create world
# Multiplayer errors
error_notfound: Host not found!
error_internal: Internal enet error!
@@ -41,21 +43,17 @@ item.dirt: "Dirt"
item.sand: "Sand"
item.water: "Water"
item.planks: "Wooden Planks"
item.gray_bricks: "Gray Bricks"
item.red_bricks: "Red Bricks"
item.blue_bricks: "Blue Bricks"
item.green_bricks: "Green Bricks"
item.stone_bricks: "Stone Bricks"
item.copper_block: "Copper Block"
item.silver_block: "Silver Block"
item.gold_block: "Gold Block"
item.glass: "Glass"
item.log: "Log"
item.spruce_planks: "Spruce Planks"
item.red_block: "Red Block"
item.green_block: "Green 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.black_block: "Black Block"
item.leaves: "Leaves"
item.copper_ore: "Copper 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

+1 -1
View File
@@ -5,7 +5,7 @@ add_subdirectory(helpers)
set(YAML_BUILD_SHARED_LIBS OFF)
set(YAML_MSVC_SHARED_RT OFF)
set(OPENGL_VERSION 1.1)
set(OPENGL_VERSION 3.3)
add_subdirectory(libraries/raylib)
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
player.cpp
multisound.cpp
svlib.cpp
)
if (WIN32)
@@ -24,6 +23,7 @@ if (WIN32)
target_link_libraries(helpers INTERFACE winmm ws2_32)
endif()
add_compile_options(-Wno-narrowing)
execute_process(COMMAND date +v.%yw%W OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
add_compile_definitions(GAME_VERSION="${BUILD_DATE}")
+520 -108
View File
@@ -1,3 +1,4 @@
#include <unordered_set>
#include <stdint.h>
#include <stdbool.h>
#include "common.hpp"
@@ -6,10 +7,14 @@
#include <fstream>
#include <vector>
#include <iostream>
#include <queue>
#define FNL_IMPL
#include "../FastNoiseLite.h"
#define HUMIDITY_OFFSET 12.3f
#define CAVE_OFFSET 45.6f
#define SCALE 0.01f
#define SCALE 0.1f
#define CAVE_COEFF 0.06
#define EDGES_FADE 64
#define CLOUD_SCALE 0.25f
@@ -17,11 +22,13 @@
#define BIOME_FOREST 0
#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;
const BlockDef BLOCKS[] = {
std::vector<BlockDef> BLOCKS = {
BlockDef{ "air", R_Translucent, B_Stone, 0, 0, 0},
BlockDef{ "stone", R_Normal, B_Stone, 7, 0, 3},
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{ "water", R_Translucent, B_Stone, 0, 0, 14},
BlockDef{ "planks", R_Normal, B_Wood, 3, 0, 11},
BlockDef{ "gray_bricks", R_Normal, B_Stone, 5, 1, 16},
BlockDef{ "red_bricks", R_Normal, B_Stone, 5, 1, 17},
BlockDef{ "blue_bricks", R_Normal, B_Stone, 5, 1, 18},
BlockDef{ "green_bricks", R_Normal, B_Stone, 5, 1, 19},
BlockDef{ "stone_bricks", R_Normal, B_Stone, 5, 1, 16},
BlockDef{ "copper_block", R_Normal, B_Stone, 5, 1, 17},
BlockDef{ "silver_block", R_Normal, B_Stone, 5, 1, 18},
BlockDef{ "gold_block", R_Normal, B_Stone, 5, 1, 19},
BlockDef{ "glass", R_Translucent, B_Stone, 3, 1, 12},
BlockDef{ "log", R_TriSide, B_Wood, 5, 0, 10, 9, 10},
BlockDef{ "spruce_planks", R_Normal, B_Wood, 3, 0, 13},
BlockDef{ "spruce_log", R_TriSide, B_Wood, 5, 0, 21, 20, 21},
BlockDef{ "workbench", R_TranslucentAllSides, B_Stone, 3, 0, 23, 22, 23},
BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 22},
BlockDef{ "yellow_block", R_Normal, B_Stone, 5, 0, 23},
BlockDef{ "cyan_block", R_Normal, B_Stone, 5, 0, 24},
BlockDef{ "magenta_block", R_Normal, B_Stone, 5, 0, 25},
BlockDef{ "white_block", R_Normal, B_Stone, 5, 0, 26},
BlockDef{ "black_block", R_Normal, B_Stone, 5, 0, 27},
BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 22},
BlockDef{ "undefined", R_Normal, B_Stone, 5, 0, 23},
BlockDef{ "red_block", R_Normal, B_Stone, 5, 0, 24},
BlockDef{ "green_block", R_Normal, B_Stone, 5, 0, 25},
BlockDef{ "blue_block", R_Normal, B_Stone, 5, 0, 26},
BlockDef{ "white_block", R_Normal, B_Stone, 5, 0, 27},
BlockDef{ "leaves", R_TranslucentAllSides, B_Grass, 1, 0, 28},
BlockDef{ "copper_ore", R_Normal, B_Stone, 7, 1, 5},
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{ "unobtainium", R_Normal, B_Stone, 7, 999, 3}, // Bedrock?
};
BlockDef &GetBlockDefinition(int id) {
return BLOCKS[id];
}
void LoadBlocks() {
}
int GetNumericIDFromString(std::string s) {
int count = sizeof(BLOCKS) / sizeof(BLOCKS[0]);
for (int i = 0; i < count; ++i) {
for (int i = 0; i < BLOCKS.size(); ++i) {
if (BLOCKS[i].name == s) return i;
}
return -1;
}
static std::bitset<256> marked;
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;
float fade_z = (fmax(EDGES_FADE - z, 0) + fmax(EDGES_FADE - WORLD_SIZE_BLOCKS + z, 0)) / (float)EDGES_FADE;
float fade = 1 - (fade_x + fade_z);
static int GetBlockRegularWorld(int _x, int y, int _z) {
int x = _x + 0;
int z = _z + 0;
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
const int BEACH_DEPTH = 3; // how many blocks below surface become sand
//int height = Lerp(height0, height1, fnlGetNoise2D(&perlinLofi, x, z)) + 26 + 48;
//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;
float mountains = pow((perlin.noise2D((double)x * 0.5f, (double)z * 0.5f * SCALE) + 1.0f ) / 2.0f, 16);
float height1 = (perlin.noise2D((double)x * 4.5f * SCALE, (double)z * 4.5f * SCALE) + 1.0f ) / 2.0f * 24.0f * mountains;
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;
//height = Lerp(32, height, fmin(1.0f, -fmin(0.0f, dist - (MAX_WORLD_SIZE*CHUNK_SIZE/2)-48)/96.0f));
/*if (y <= height) {
//if(caveNoise < 0.02f) return BLOCK_AIR;
if (y == height) {
if (height <= SEA_HEIGHT) {
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) {
return BLOCK_SAND;
}
if(caveNoise < 0.2f || y < 4) return BLOCK_STONE;
//if(caveNoise < 0.2f || y < 4) return BLOCK_STONE;
return BLOCK_DIRT;
}
if (y <= SEA_HEIGHT && height < SEA_HEIGHT) {
return BLOCK_WATERS;
}
}*/
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!
return blockType == BLOCK_SAND;
}
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) {
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) {
return BLOCK_STONE;
}
}*/
return BLOCK_AIR;
}
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 z = 0; z < CHUNK_SIZE; z++)
{
for (int y = WORLD_HEIGHT-1; y >= 0; y--)
{
if(c->blocks[GetIndexChunk(x,y,z)] != 0) {
c->highestBlock[GetIndexChunk2D(x, z)] = y;
if(c.blocks[GetIndexChunk(x,y,z)] != 0) {
c.highestBlock[GetIndexChunk2D(x, z)] = y;
break;
}
}
@@ -195,21 +313,63 @@ int GetBiome(int sx, int sy) {
void SetBlockChunkFast(Chunk *c, int i, int 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; }
int locX = x % CHUNK_SIZE;
int locZ = z % CHUNK_SIZE;
int cx = x / 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) {
const siv::PerlinNoise::seed_type seed = 123456u;
const siv::PerlinNoise perlin{ seed };
perlin = fnlCreateState();
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
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) {
marked.set(i);
}
@@ -224,21 +384,16 @@ Chunk GenerateChunk(int _x, int _y) {
Chunk new_chunk = { 0 };
new_chunk.x = _x;
new_chunk.z = _y;
for (int x = 0; x < CHUNK_SIZE; x++)
{
memset(&new_chunk.light, 0, sizeof(new_chunk.light));
for (int y = 0; y < WORLD_HEIGHT; y++)
{
for (int z = 0; z < CHUNK_SIZE; z++)
{
for (int x = 0; x < CHUNK_SIZE; x++)
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;
}
void GenerateWorldAdditional(Chunk world[]) {
void GenerateWorldAdditional(World &world) {
int biome = GetBiome(0, 0);
SetRandomSeed(0);
switch (world_type)
@@ -247,36 +402,11 @@ void GenerateWorldAdditional(Chunk world[]) {
for (int x = 0; x < WORLD_SIZE_BLOCKS; x++)
{
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 b = fetch_block(c, x % CHUNK_SIZE, highestY, z % CHUNK_SIZE);
for (int _ = 0; _ < GetRandomValue(0, 6); _++)
{
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;
}
}
if(b == BLOCK_DIRT) {
SetBlock(world, x, highestY, z, BLOCK_GRASS);
}
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 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 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);
int maxY = GetRandomValue(5, 7);
for (int y = 1; y < maxY; y++)
@@ -334,7 +464,7 @@ void GenerateWorldAdditional(Chunk world[]) {
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);
int maxY = 8;
for (int y = 1; y < maxY; y++)
@@ -421,62 +551,293 @@ void GenerateWorldAdditional(Chunk world[]) {
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;
int tile = GetBlock(world, wx, wy, wz);
if(tile == BLOCK_SAND) {
if(GetBlock(world, wx, wy-1, wz) == 0) {
SetBlockNetwork(world, wx, wy, wz, 0);
Entity temp = NewEntity(0);
Entity temp = NewEntity();
temp.type = 4;
temp.position = (Vector3){wx, wy, wz};
temp.velocity = {0, 0, 0};
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 x = 0; x < CHUNK_SIZE; x++)
{
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 GROUPS = CHUNK_DATA_SIZE / GROUP;
uint16_t oMask[GROUPS] = { 0 };
uint16_t aMask[GROUPS] = { 0 };
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) {
int g = i / GROUP;
int bit = i % GROUP;
if (chunk->blocks[i] == 0) {
if (chunk.blocks[i] == 0) {
aMask[g] |= 1 << bit;
}
if (!IsTranslucent(chunk->blocks[i])) {
if (!IsTranslucent(chunk.blocks[i])) {
oMask[g] |= 1 << bit;
}
}
memcpy(chunk->opaqueMask, oMask, sizeof(oMask));
memcpy(chunk->airMask, aMask, sizeof(aMask));
memcpy(chunk.opaqueMask, oMask, sizeof(oMask));
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
//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 };
uint16_t mask[CHUNK_DATA_SIZE/16];
memcpy(mask, chunk.opaqueMask, sizeof(chunk.opaqueMask));
uint16_t *mask = chunk.opaqueMask;
const int cxw = chunk.x * CHUNK_SIZE;
const int cxz = chunk.z * CHUNK_SIZE;
@@ -492,8 +853,6 @@ ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) {
int _x = bit;
int y = step >> 4;
int _z = step & 0xF;
//int _x, y, _z;
//GetXYZFromIndex(i2, &_x, &y, &_z);
if (!TestMask(mask, i2)) continue; // Skip if this is translucent
int x = _x + cxw;
@@ -519,7 +878,7 @@ ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) {
}
//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 };
uint16_t *mask0= chunk.opaqueMask;
uint16_t *mask = chunk.airMask;
@@ -544,6 +903,55 @@ ChunkRenderData GenerateCRDTranslucent(Chunk chunk, Chunk world[]) {
new_chunk.sides[i2] = 0xFF;
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 z = _z + chunk.z * CHUNK_SIZE;
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
#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);
if (!data) return;
@@ -576,7 +984,7 @@ void SaveWorld(Chunk world[], const char* path) {
data.write(&fmt, 1);
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;
int last_type = -1;
@@ -614,7 +1022,8 @@ void SaveWorld(Chunk world[], const char* path) {
}
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);
if (!data) return false;
@@ -643,19 +1052,22 @@ bool LoadWorld(Chunk world[], const char* path) {
return false;
}
}
Chunk *c = &world[i];
Chunk c = {0};
c.x = i % 16;
c.z = i >> 4;
int outIndex = 0;
for (size_t p = 0; p + 1 < size; p += 2) {
uint8_t count = temp[p];
uint8_t value = temp[p + 1];
for (uint8_t k = 0; k < count; ++k) {
SetBlockChunkFast(c, outIndex++, value);
SetBlockChunkFast(&c, outIndex++, value);
}
}
while (outIndex < CHUNK_DATA_SIZE) {
SetBlockChunkFast(c, outIndex++, 0);
SetBlockChunkFast(&c, outIndex++, 0);
}
RebuildHeightmap(c);
memcpy(&world.chunks[i], &c, sizeof(c));
}
free(temp);
return true;
+100 -73
View File
@@ -9,8 +9,8 @@
#undef PlaySound
#undef Sound
#endif
#include <functional>
#include "glfw_keycodes_to_string.h"
#include "../PerlinNoise.hpp"
#include "raylib.h"
#include "raymath.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_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_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_BLOCKDELTA 0x81 // Block X, block Y, block Z, block type
#define NET_ARG_REQWORLD 0x82 // No additional data
#define NET_ARG_REQPLAYERS 0x83 // No additional data
#define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw
#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_NOTFOUND 0x01
#define NET_ERROR_FAILED 0x02
@@ -79,11 +75,10 @@
#define GAME_NAME "CubeGame"
#define GAME_VERSION_INT 0
#define DEFAULT_FONT_SIZE 16
#define TPS 30.0
#define TPS 30
#define TPS_DIV 1.0 / TPS
#define RENDER_DISTANCE 16
#define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE
#define PIXUNIT 1.0f / 16.0f
#define MAX_HP 100
#define PATH_APPEND "resources/"
#define PATH_APPEND_USER "user/"
@@ -91,6 +86,8 @@
#define INVENTORY_WIDTH 8
#define INVENTORY_HEIGHT 6
#define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT
#define WORLD_TIME_SECONDS (24*60)
#define WORLD_TIME_TICKS WORLD_TIME_SECONDS*TPS
enum BlockType {
B_Wood,
B_Stone,
@@ -157,7 +154,7 @@ struct Chunk {
uint16_t opaqueMask[CHUNK_DATA_SIZE/16];
uint16_t airMask[CHUNK_DATA_SIZE/16];
uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE];
uint16_t light[CHUNK_DATA_SIZE];
};
#if !defined(SERVER)
typedef struct ChunkRenderData ChunkRenderData;
@@ -200,24 +197,33 @@ struct Quad2D {
#endif
typedef struct Vector3I Vector3I;
struct Vector3I {
int x;
int y;
int z;
int x, y, z;
bool operator==(const Vector3I& other) const {
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;
struct Entity {
uint16_t id;
uint8_t type;
uint8_t id;
uint8_t damage_flash;
uint8_t data[4];
uint8_t data_sv[8];
bool free;
uint8_t data[16];
float smoothing;
float health;
float lifetime;
Vector3 position;
Vector3 velocity;
unsigned short yaw;
bool free;
};
typedef struct NetPlayer NetPlayer;
struct NetPlayer {
@@ -229,9 +235,6 @@ struct NetPlayer {
float x;
float y;
float z;
std::string nickname;
Texture2D texture;
std::vector<uint8_t> skin;
};
typedef struct MemInfo MemInfo;
struct MemInfo {
@@ -297,28 +300,46 @@ struct Particle {
int lifetime;
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 GetCloud(int x,int z);
bool IsTranslucent(int blockType);
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);
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);
Vector3 WorldPosition(int cx,int cz,int localX,int y,int localZ);
Chunk GenerateChunk(int _x,int _y);
void GenerateWorldAdditional(Chunk world[]);
void TickBlock(Chunk world[],int wx,int wy,int wz);
void TickChunk(Chunk *chunk,Chunk *world,int wx,int wz);
void RebuildOpaqueMask(Chunk *chunk);
void GenerateWorldAdditional(World&world);
void TickBlock(World&world,int wx,int wy,int wz);
void TickChunk(Chunk *chunk,World&world,int wx,int wz);
void RebuildOpaqueMask(Chunk&chunk);
void RebuildLighting(World&world,int startX,int startZ);
#if !defined(SERVER)
ChunkRenderData GenerateCRDOpaque(const Chunk&chunk,Chunk world[]);
ChunkRenderData GenerateCRDTranslucent(Chunk chunk,Chunk world[]);
ChunkRenderData GenerateCRDOpaque(Chunk&chunk,World&world);
ChunkRenderData GenerateCRDTranslucent(Chunk chunk,World&world);
ChunkRenderData GenerateCRDWater(Chunk chunk,World&world);
#endif
void SaveWorld(Chunk world[],const char *path);
bool LoadWorld(Chunk world[],const char *path);
void SaveWorld(World&world,const char *path);
bool LoadWorld(World&world,const char *path);
extern long nsTotal;
void Debug_StartMeasure();
#if defined(WIN32)
@@ -330,34 +351,49 @@ bool Debug_GetProcessMemory(MemInfo&out);
#if !defined(WIN32)
bool Debug_GetProcessMemory(MemInfo&out);
#endif
#if !defined(SERVER)
extern Camera camera;
#endif
extern Camera3D camera;
#if !defined(SERVER)
extern Camera camera;
#endif
extern Font fnt;
#if !defined(SERVER)
extern Font fnt;
#endif
extern Texture2D terrain;
#endif
extern Texture2D terrain;
#if !defined(SERVER)
extern Texture2D terrain;
extern Texture2D terrain;
#endif
extern Texture2D nekitTex;
extern Texture2D playerTex;
extern Texture2D playerTex;
extern Texture2D bomb;
extern Sound nekit_idle;
void EntitiesInit();
extern bool online;
#if !defined(SERVER)
extern bool online;
#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 SetBlockNetwork(Chunk world[],int bx,int by,int bz,int t);
Entity NewEntity(int id);
void SetBlockNetwork(World&world,int bx,int by,int bz,int t);
#endif
Entity NewEntity();
void AddEntity(Entity ent);
void UpdateEntities(World&world,float dt);
extern float globalCounter;
#if !defined(SERVER)
void DrawEntities(float dt);
extern bool swap_mouse;
bool InputGetLMB();
bool InputGetLMBDown();
@@ -372,7 +408,6 @@ extern int currentlySelected;
extern GameState state;
extern Texture2D cubemap;
int TryConnect(const char *hostname);
void InitSingleplayer();
void GameModeCleanup();
void DrawBackground();
void InitMenu();
@@ -390,14 +425,13 @@ void DrawMainMenu();
void _LoadWorld(const char *path);
void DrawWorldSelect();
void DrawMultiplayer();
void ExitSingleplayer();
void DrawPauseMenu();
extern char bufferChat[MAX_MESSAGE_LENGTH];
char *DrawChat();
void DrawLogoCenter();
#endif
#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 CreateCubeMeshData(const BlockDef&def,float cx,float cy,float cz);
Mesh GenChunkMesh(MeshData meshData);
@@ -414,10 +448,12 @@ const char *Pathify(const char *src);
const char *PathifyUser(const char *src);
#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 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 DrawText3D(Font font,const char *text,Vector3 position,float fontSize,float fontSpacing,float lineSpacing,bool backface,Color tint);
#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){
return (uint8_t)(
((uint8_t)(b0 ? 1 : 0) << 0) |
@@ -437,10 +473,10 @@ inline void unpack6(uint8_t v,bool *b0,bool *b1,bool *b2,bool *b3,bool *b4,bool
*b5 = (v >> 5) & 1;
};
inline void GetXYZFromIndex(int index,int *x,int *y,int *z){
*x = index & 15;
int tmp = index << 4;
*z = tmp & 15;
*y = tmp << 4;
*y = index / (CHUNK_SIZE * CHUNK_SIZE);
int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
*z = rem / CHUNK_SIZE;
*x = rem % CHUNK_SIZE;
};
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;
@@ -450,36 +486,40 @@ inline int GetIndexChunk2D(int x,int z){
if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0;
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){
if(CheckOOBWorld(x << 4, 0, z << 4)) return 0;
return x + MAX_WORLD_SIZE * z;
};
inline void GetXZFromIndex(int index,int *x,int *z){
*z = 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 bit = position & 15;
int maskArrayLen = CHUNK_DATA_SIZE << 4;
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){
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;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->opaqueMask, localIndex);
const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
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;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->airMask, localIndex);
const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c.airMask, localIndex);
};
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;
@@ -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;
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){
if (!ptr) return malloc(newBytes);
return realloc(ptr, newBytes);
@@ -582,7 +614,6 @@ extern InventoryItem inventory[INVENTORY_SIZE];
#endif
extern InventoryItem inventory[INVENTORY_SIZE];
#if !defined(SERVER)
extern Texture2D playerTex;
extern bool inventoryOpen;
extern InventoryItem *movingItem;
void DrawItem(InventoryItem item,int x,int y);
@@ -594,13 +625,13 @@ void HotbarAddItemLots(Item *registry,int damage,int amount);
void InitHotbar();
void DrawHotbar();
InventoryItem HotbarGetSelected();
void DrawSelectedItem();
void DrawSelectedItem(Color tint);
void CloseInventory();
void UpdateHotbar();
void LocaleUpdate();
void LoadRecipes();
#endif
void ParticlesUpdate(float dt,Chunk world[]);
void ParticlesUpdate(float dt,World&world);
void ParticlesDraw();
void AddParticle(Particle part);
Particle NewParticle(Vector3 position);
@@ -609,14 +640,10 @@ extern float player_health;
extern float player_attack_time;
extern float player_place_time;
extern float player_break_parts_time;
extern Vector3 player_position;
extern Vector3 player_velocity;
void SavePlayerData();
bool LoadPlayerData();
void MS_PlaySound(Sound src,float pitch,float volume,Vector3 position);
void MS_Update(float dt,Camera camera);
void ServerNetworkUpdate();
void StopInternalServer();
#define INTERFACE 0
#define EXPORT_INTERFACE 0
#define LOCAL_INTERFACE 0
+148 -12
View File
@@ -9,36 +9,46 @@
#include <vector>
#include <algorithm>
#define PIXUNIT 1.0f / 16.0f
#ifndef SERVER
extern Camera camera;
extern Font fnt;
extern Texture2D terrain;
Texture2D nekitTex;
Texture2D playerTex;
Texture2D bomb;
Sound nekit_idle;
void EntitiesInit() {
nekitTex = LoadTexture(Pathify("nekit.png"));
playerTex = LoadTexture(Pathify("player.png"));
bomb = LoadTexture(Pathify("bomb.png"));
nekit_idle = LoadSound(Pathify("sound/nekit/idle.ogg"));
}
extern bool online;
extern Vector3 player_position;
extern Vector3 player_velocity;
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;
ent.id = id;
ent.id = entities.size();
ent.type = 0;
ent.yaw = 0;
ent.free = false;
return ent;
}
void AddEntity(std::list<Entity> entities, Entity ent) {
void AddEntity(Entity 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 tgt = Vector3Add(ent.position, Vector3Scale(velocityTgt, dt));
Vector3 final = ent.position;
@@ -57,7 +67,7 @@ static void UpdateEntityPhysics(Chunk world[], Entity& ent, float dt) {
ent.velocity = velocityTgt;
ent.position = final;
}
void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
void UpdateEntities(World &world, float dt) {
if(entities.size() > 0) {
int idx = 0;
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));
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);
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;
@@ -97,8 +110,54 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
if(ent.health < 0.1f) {
ent.free = true;
}
if(ent.data[2] < 90)
ent.data[2]++;
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) {
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;
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->yaw = 0;
@@ -144,8 +203,8 @@ void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
}
}
float globalCounter = 0;
void DrawEntities(std::list<Entity> entities, float dt) {
#ifndef SERVER
void DrawEntities(float dt) {
globalCounter += dt;
for(Entity& ent : entities) {
ent.smoothing += dt;
@@ -222,13 +281,90 @@ void DrawEntities(std::list<Entity> entities, float dt) {
rlPopMatrix();
}
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) {
DrawCube(pos_lerped, 1, 1, 1, RED);
}
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
+22 -26
View File
@@ -21,13 +21,14 @@ inline void unpack6(uint8_t v, bool *b0, bool *b1, bool *b2, bool *b3, bool *b4,
}
inline void GetXYZFromIndex(int index, int* x, int* y, int* z) {
*x = index & 15;
int tmp = index << 4;
*z = tmp & 15;
*y = tmp << 4;
*y = index / (CHUNK_SIZE * CHUNK_SIZE);
int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
*z = rem / CHUNK_SIZE;
*x = rem % CHUNK_SIZE;
}
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;
return x + CHUNK_SIZE * (z + CHUNK_SIZE * y);
@@ -36,7 +37,14 @@ inline int GetIndexChunk2D(int x, int z) {
if(x < 0 || z < 0 || x >= CHUNK_SIZE || z >= CHUNK_SIZE) return 0;
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) {
if(CheckOOBWorld(x << 4, 0, z << 4)) return 0;
return x + MAX_WORLD_SIZE * z;
}
@@ -45,32 +53,29 @@ inline void GetXZFromIndex(int index, int *x, int *z) {
*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 bit = position & 15;
int maskArrayLen = CHUNK_DATA_SIZE << 4;
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) {
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;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->opaqueMask, localIndex);
const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
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;
Chunk* c = &world[GetIndexWorld(x >> 4, z >> 4)];
int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c->airMask, localIndex);
const Chunk c = world.chunks[GetIndexWorld(x >> 4, z >> 4)];
const int localIndex = GetIndexChunk((uint8_t)x & 15, y, (uint8_t)z & 15);
return TestMask(c.airMask, localIndex);
}
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)];
}
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) {
if (!ptr) return malloc(newBytes);
return realloc(ptr, newBytes);
+4 -4
View File
@@ -63,7 +63,7 @@ Vector2 InputGetWalkAxis() {
float y = 0;
if(isJoystick) {
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) {
x = 0;
}
@@ -84,8 +84,8 @@ Vector2 InputGetLookAxis() {
float x = 0;
float y = 0;
if(isJoystick) {
x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X);
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y);
x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X)*3.0f;
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*3.0f;
if(abs(x) < 0.1f) {
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_LEFT)) { x = -1; }
}
return {x, y};
}
void InputWriteControls() {
@@ -136,7 +137,6 @@ void InputInit() {
controls[key] = val;
}
swap_mouse = config["Swap mouse buttons"].as<bool>();
}
}
+11 -11
View File
@@ -6,7 +6,7 @@
#include <iostream>
#include <map>
#include <rlgl.h>
#define PIXUNIT 1.0f / 16.0f
InventoryItem hotbar[ITEMS];
InventoryItem inventory[INVENTORY_SIZE];
static uint8_t selected = 0;
@@ -40,7 +40,7 @@ void DrawItem(InventoryItem item, int x, int y) {
if(item.item->type == IType_Block) {
atlas = terrain;
atl_size = ATLAS_SIZE_W;
tex = BLOCKS[item.damage].textureTop;
tex = GetBlockDefinition(item.damage).textureTop;
}
DrawTexturePro(atlas,
{
@@ -198,9 +198,9 @@ static bool GetTaggedItem(std::string tag, InventoryItem* item) {
bool isBlock;
bool found;
for(int blk = 0; blk < MAX_BLOCK_ID; blk++) {
if(IDTagMatch(tag, BLOCKS[blk].name)) {
if(IDTagMatch(tag, GetBlockDefinition(blk).name)) {
isBlock = true;
id = GetNumericIDFromString(BLOCKS[blk].name);
id = GetNumericIDFromString(GetBlockDefinition(blk).name);
found = true;
break;
};
@@ -307,7 +307,7 @@ void DrawHotbar() {
if(item.item != nullptr) {
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 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);
if(blockCond || genericCond || tagBlockCond || tagItemCond) {
items.push_back(i);
@@ -366,7 +366,7 @@ void DrawHotbar() {
if(item.item != nullptr) {
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 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);
if(blockCond || genericCond || tagBlockCond || tagItemCond) {
items[i] = ingredient.quantity;
@@ -432,7 +432,7 @@ void DrawHotbar() {
DrawItem(*movingItem, GetMouseX(), GetMouseY());
std::string name = "item."+movingItem->item->id;
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);
}
@@ -441,7 +441,7 @@ void DrawHotbar() {
InventoryItem HotbarGetSelected() {
return hotbar[selected];
}
void DrawSelectedItem() {
void DrawSelectedItem(Color tint) {
InventoryItem item = hotbar[selected];
Vector3 center = {-0.75f, -0.45f, 0.5f};
rlPushMatrix();
@@ -458,16 +458,16 @@ void DrawSelectedItem() {
rlRotatef(-45, 1, 0, 0);
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->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 {
UVCorners left = GetUVTex(item.item->texture);
rlSetTexture(item_atlas.id);
rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255);
rlColor4ub(tint.r, tint.g, tint.b, 255);
rlNormal3f(1.0f, 0.0f, 0.0f);
const float size = 0.5f;
rlTexCoord2f(left.corner0.x, left.corner0.y); rlVertex3f(0, -12*PIXUNIT - size, 0.25f - size);
+5 -4
View File
@@ -29,7 +29,7 @@ static int MakeUIPOI(int x, int y) {
std::unordered_set<uint32_t> ui_pois;
int TryConnect(const char* hostname);
void InitSingleplayer();
//void InitSingleplayer();
void GameModeCleanup();
static int mouseX = -1;
@@ -503,7 +503,8 @@ void DrawWorldSelect() {
}
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48, 128, 0)) {
UIResetMousePos();
InitSingleplayer();
InitWorldgen(0);
state = GAME_STATE_LOADING;
return;
}
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48-48, 128, 0)) {
@@ -550,12 +551,12 @@ void DrawMultiplayer() {
EndDrawing();
UIHandleControls();
}
void ExitSingleplayer();
void DrawPauseMenu() {
UIBegin();
DrawRectangle(0,0,GetScreenWidth(),GetScreenHeight(),Fade(GRAY,0.5f));
if (Button(LocaleGet("exit").c_str(), GetScreenWidth()/2-64, 48, 128, 0)) {
ExitSingleplayer();
GameModeCleanup();
UIResetMousePos();
return;
}
+21 -20
View File
@@ -10,7 +10,7 @@
#ifndef SERVER
#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};
@@ -23,17 +23,20 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
std::vector<unsigned short> indices;
int face = 0;
for (int x = 0; x < CHUNK_SIZE; ++x)
for (int y = 0; y < WORLD_HEIGHT; ++y)
for (int z = 0; z < CHUNK_SIZE; ++z)
for (int index = 0; index < CHUNK_DATA_SIZE; index++)
{
int index = GetIndexChunk(x,y,z);
uint8_t crdata = chunkRenderData.sides[index];
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);
BlockDef definition = BLOCKS[this_block];
BlockDef definition = GetBlockDefinition(this_block);
UVCorners UVside = GetUVTex(definition.textureSide);
UVCorners UVtop = GetUVTex(definition.textureTop);
@@ -46,9 +49,6 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
Color color = {255, 255, 255, 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)) {
color = ColorLerp(color, colorShaded, 0.5f);
}*/
@@ -72,7 +72,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
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[1]);
@@ -111,7 +112,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
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[1]);
@@ -150,7 +152,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
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[1]);
@@ -189,12 +192,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
normals.push_back(normal);
if(shaded) {
colors.push_back(colorShaded);
}
else {
colors.push_back(color);
}
Color clr = GetLightMesher(world, wx, wy+1, wz);
colors.push_back(clr);
uvs.push_back(corners[0]);
uvs.push_back(corners[1]);
@@ -233,7 +232,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
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[1]);
@@ -272,7 +272,8 @@ MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chu
positions.push_back(verts[3]);
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[1]);
+5 -6
View File
@@ -25,7 +25,7 @@ ENetHost* StartServer() {
/* Bind the server to port 1234. */
address.port = PORT;
server = enet_host_create(&address, 32, 1, 0, 0);
server = enet_host_create(&address, 32, 1, 0);
if (server == NULL)
{
fprintf (stderr,
@@ -41,8 +41,7 @@ ENetHost* StartClient() {
client = enet_host_create (NULL /* create a client host */,
1 /* 1 channel*/,
1 /* only allow 1 outgoing connection */,
0 /* assume any amount of incoming bandwidth */,
0);
0 /* assume any amount of incoming bandwidth */);
if (client == NULL)
{
@@ -87,17 +86,17 @@ void BroadcastPacketR(ENetHost* server, void* data, int len)
void SerializeFloat2Data(float v, void *target, int 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[1] = 0;
return;
}
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);
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 > 255) frac_byte = 255;
buf[0] = (uint8_t)intpart;
+6 -5
View File
@@ -65,11 +65,12 @@ static void DrawParticle(Particle particle, Color color)
rlSetTexture(0);
}
void ParticlesUpdate(float dt, Chunk world[]) {
particles.remove_if([](Particle x) { return x.lifetime > 200; });
for (Particle &part : particles)
void ParticlesUpdate(float dt, World &world) {
//particles.remove_if([](Particle x) { return x.lifetime > 0; });
particles.remove_if([](Particle x) { return true; });
/*for (Particle &part : particles)
{
part.lifetime++;
art.lifetime++;p
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});
@@ -99,7 +100,7 @@ void ParticlesUpdate(float dt, Chunk world[]) {
part.position = final;
part.velocity = velocityTgt;
}
}
}*/
}
void ParticlesDraw() {
for (Particle part : particles)
-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);
}
+55 -2
View File
@@ -87,7 +87,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
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 y = position.y;
@@ -104,7 +104,7 @@ void DrawCubeBlock(Texture2D texture, Vector3 position, float width, float heigh
UVCorners right = GetUVTex(def.textureSide);
rlSetTexture(texture.id);
rlBegin(RL_QUADS);
rlColor4ub(255, 255, 255, 255);
rlColor4ub(tint.r, tint.g, tint.b, 255);
// Front Face
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
@@ -254,3 +254,56 @@ void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, f
}
}
#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);
}
}
+25 -19
View File
@@ -1,10 +1,10 @@
#include <functional>
#if INTERFACE
#ifdef Escape
#undef Escape
#endif
#include "glfw_keycodes_to_string.h"
#include "../PerlinNoise.hpp"
#ifdef WIN32
#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_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_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
// 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
@@ -91,7 +87,6 @@
#define NET_ARG_REQPLAYERS 0x83 // No additional data
#define NET_ARG_PLAYERYAW 0x84 // Byte 1 - yaw
#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
#define NET_ERROR_DSCN 0x00
@@ -103,12 +98,11 @@
#define GAME_VERSION_INT 0
#define DEFAULT_FONT_SIZE 16
#define TPS 30.0
#define TPS 30
#define TPS_DIV 1.0 / TPS
//Rendering
#define RENDER_DISTANCE 16
#define RENDER_DISTANCE_SQUARED RENDER_DISTANCE*RENDER_DISTANCE
#define PIXUNIT 1.0f / 16.0f
//Game stuff
#define MAX_HP 100
@@ -120,6 +114,8 @@
#define INVENTORY_HEIGHT 6
#define INVENTORY_SIZE INVENTORY_WIDTH*INVENTORY_HEIGHT
#define WORLD_TIME_SECONDS (24*60)
#define WORLD_TIME_TICKS WORLD_TIME_SECONDS*TPS
enum BlockType {
B_Wood,
B_Stone,
@@ -185,7 +181,7 @@ struct Chunk {
uint16_t opaqueMask[CHUNK_DATA_SIZE/16];
uint16_t airMask[CHUNK_DATA_SIZE/16];
uint8_t highestBlock[CHUNK_SIZE*CHUNK_SIZE];
uint16_t light[CHUNK_DATA_SIZE];
};
#ifndef SERVER
struct ChunkRenderData {
@@ -226,23 +222,32 @@ struct Quad2D {
};
#endif
struct Vector3I {
int x;
int y;
int z;
int x, y, z;
bool operator==(const Vector3I& other) const {
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 {
uint16_t id;
uint8_t type;
uint8_t id;
uint8_t damage_flash;
uint8_t data[4];
uint8_t data_sv[8];
bool free;
uint8_t data[16];
float smoothing;
float health;
float lifetime;
Vector3 position;
Vector3 velocity;
unsigned short yaw;
bool free;
};
struct NetPlayer
@@ -255,9 +260,6 @@ struct NetPlayer
float x;
float y;
float z;
std::string nickname;
Texture2D texture;
std::vector<uint8_t> skin;
};
struct MemInfo {
@@ -317,3 +319,7 @@ struct Particle {
int lifetime;
int data[8];
};
struct World
{
Chunk chunks[MAX_WORLD_AREA];
};
+317 -276
View File
@@ -15,11 +15,7 @@
#include <list>
#include <climits>
#include <queue>
#include <atomic>
#include <thread>
#include <set>
#include <map>
#include <fstream>
#define MAX_RAY_DISTANCE 8.0f
struct MessageData {
std::string message;
@@ -35,14 +31,11 @@ Vector2 cameraMovementSmooth;
static float camYaw = 0.0f;
static float camPitch = -45.0f;
static const float acceleration = 48.0f;
static const float drag = 6.0f;
static bool singleplayerServer;
static const float drag = 6.0f; // tuned for feel
Camera camera;
Texture2D playerTex;
bool online = false;
bool flying = false;
void DrawEntities(std::list<Entity> entities, float dt);
unsigned long long worldTime;
static float entUpdateCounter;
@@ -59,21 +52,27 @@ Font fnt;
Texture2D terrain;
Texture2D water;
Texture2D white_pixel;
Entity* ent;
const bool ROTATE_PLAYER_WITH_CAMERA = true;
static Sound wood_place;
static Sound stone_place;
static Sound dirt_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);
bool InputGetKeyDown(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::queue<Vector3I> tickedBlocks;
static std::list<Entity> entities;
static std::map<int, NetPlayer> players;
struct MeshUnit {
Model model;
Model modelTransparent;
Model modelWater;
int vertices;
};
struct ProfilerPart {
@@ -97,100 +96,19 @@ static Vector3 CameraForwardFromYawPitch(float yaw, float pitch)
f.z = cosf(pitch) * sinf(yaw);
return Vector3Normalize(f);
}
static const char* GetPlayerTexturePath() {
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];
World world;
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;
bool loaderParam_remeshOnly = false;
int worldCreationProgress = 0;
@@ -330,14 +248,17 @@ static void ResolveCollisions(float dt)
if (ix > 0 && iy > 0 && iz > 0)
{
// find smallest penetration axis and push out along it
if (ix < iy && ix < iz)
{
// push on X
if (player_position.x < bx0) player_position.x -= ix;
else player_position.x += ix;
player_velocity.x = 0;
}
else if (iy < ix && iy < iz)
{
// push on Y
if (player_position.y < by0) player_position.y -= iy;
else player_position.y += iy;
if (player_velocity.y > 0) player_velocity.y = 0;
@@ -345,6 +266,7 @@ static void ResolveCollisions(float dt)
}
else
{
// push on Z
if (player_position.z < bz0) player_position.z -= iz;
else player_position.z += iz;
player_velocity.z = 0;
@@ -357,35 +279,48 @@ static void ResolveCollisions(float dt)
bool loadedChunks[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_EndMeasureLoops(const std::string &stuff, int loops);
static void RemeshChunk(int x, int y) {
int idx = x + y * MAX_WORLD_SIZE;
int idx = GetIndexWorld(x, y);
if(loadedChunks[idx]) {
UnloadModel(renderingT[idx].model);
UnloadModel(rendering[idx].model);
UnloadModel(rendering[idx].modelTransparent);
UnloadModel(rendering[idx].modelWater);
}
Chunk chunk = world[idx];
RebuildOpaqueMask(&chunk);
Chunk &chunk = world.chunks[idx];
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);
Model model = LoadModelFromMesh(GenChunkMesh(renderDataOpq));
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
MeshData renderDataOpq = GenerateChunkMesh(world, GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF);
Model model0 = LoadModelFromMesh(GenChunkMesh(renderDataOpq));
model0.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
model0.materials[0].shader = loadedShaders["terrain"];
MeshUnit munit0;
munit0.model = model;
munit0.model = model0;
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)
@@ -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);
}
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;
ENetHost* client;
static std::stack<std::vector<uint8_t>> worldPacketStack;
static int fetchedChunks;
int plrId = 0;
int plrId = -1;
static bool pauseMenuActive;
void _LoadWorld(const char* path) {
@@ -470,7 +414,7 @@ void PlayRandomMusic() {
PlayMusicStream(currentMusic);
}
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;
int sound = B_Stone;
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});
if(t != 0) {
sound = BLOCKS[t].type;
sound = GetBlockDefinition(t).type;
}
else {
int id = GetBlock(world, bx, by, bz);
BlockDef block = BLOCKS[id];
BlockDef block = GetBlockDefinition(id);
if(id != 0) {
sound = block.type;
for (int x = 0; x < 4; x++)
@@ -565,9 +509,9 @@ static void TickAvailableBlocks() {
}
}
}
std::atomic_bool serverStarted;
int TryConnect(const char* hostname) {
client = StartClient();
/*client = StartClient();
if(client == NULL)
{
@@ -582,7 +526,7 @@ int TryConnect(const char* hostname) {
int s = enet_address_set_host (& address, hostname);
address.port = PORT;
peer = enet_host_connect(client, &address, 1, 0);
peer = enet_host_connect(client, &address, 1);
if (peer == NULL)
{
@@ -590,12 +534,10 @@ int TryConnect(const char* hostname) {
"No available peers for initiating an ENet connection.\n");
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.");
char data[1];
data[0] = NET_ARG_REQWORLD;
@@ -609,41 +551,9 @@ int TryConnect(const char* hostname) {
enet_peer_reset (peer);
return NET_ERROR_FAILED;
}
}*/
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;
bool survival = false;
bool chatOpen = false;
@@ -655,6 +565,54 @@ void TakeDamage(float amount) {
int currentlyTickedChunk = 0;
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) {
if (player_position.y < 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 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((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;
}
}
BlockDef block = BLOCKS[GetBlock(world, bx, by, bz)];
BlockDef block = GetBlockDefinition(GetBlock(world, bx, by, bz));
float hardnessMultiplier = block.hardness / 4.0f;
if(player_break_parts_time >= 0.05f) {
Vector3 v = {0, 1, 0};
@@ -970,7 +944,7 @@ static void GameUpdate(Camera camera, float &time) {
}
double PROFCOUNT = GetTime();
if (bestIdx != -1) {
RebuildOpaqueMask(&world[bestIdx]);
RebuildOpaqueMask(world.chunks[bestIdx]);
int bx, by;
GetXZFromIndex(bestIdx, &bx, &by);
RemeshChunk(bx, by);
@@ -978,6 +952,23 @@ static void GameUpdate(Camera camera, float &time) {
}
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();
ParticlesUpdate(dt, world);
AddProfilerPart("particles", GetTime()-PROFCOUNT, ORANGE);
@@ -994,12 +985,56 @@ static void GameUpdate(Camera camera, float &time) {
UpdateCamera(&camera, CAMERA_CUSTOM);
unsigned int debug_verts_opaque = 0;
unsigned int debug_verts_transparent = 0;
UpdateHotbar();
Frustum frustum = ExtractFrustumPlanes(camera, (float)GetScreenWidth() / (float)GetScreenHeight());
BeginDrawing();
ClearBackground(RAYWHITE);
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), {120, 167, 255});
UpdateCamera(&camera, CAMERA_CUSTOM);
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);
@@ -1013,16 +1048,13 @@ static void GameUpdate(Camera camera, float &time) {
_z *= CHUNK_SIZE;
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);
debug_verts_opaque += rendering[x].vertices;
}
AddProfilerPart("chunk render opq", GetTime()-PROFCOUNT, MAROON);
DrawEntities(entities, 0);
for (const auto& [id, netplayer] : players) {
DrawPlayer(terrain, netplayer);
}
DrawEntities(dt);
ParticlesDraw();
//Transparent shit
rlDisableDepthMask();
@@ -1084,7 +1116,7 @@ static void GameUpdate(Camera camera, float &time) {
if (!loadedChunks[i]) continue;
int 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 wz = cz * CHUNK_SIZE + CHUNK_SIZE * 0.5f;
float dx = wx - camera.position.x;
@@ -1097,8 +1129,8 @@ static void GameUpdate(Camera camera, float &time) {
for (auto &p : distances) {
int idx = p.second;
DrawModel(renderingT[idx].model, {0, 0, 0}, 1.0f, WHITE);
debug_verts_transparent += renderingT[idx].vertices;
DrawModel(rendering[idx].modelTransparent, {0, 0, 0}, 1.0f, WHITE);
DrawModel(rendering[idx].modelWater, {0, 0, 0}, 1.0f, WHITE);
}
AddProfilerPart("chunk render tsl", GetTime()-PROFCOUNT, RED);
if (highlightValid)
@@ -1117,7 +1149,7 @@ static void GameUpdate(Camera camera, float &time) {
BeginMode3D(camera);
rlDisableDepthMask();
rlDisableDepthTest();
DrawSelectedItem();
DrawSelectedItem(GetLight(world, (int)player_position.x, (int)player_position.y, (int)player_position.z));
rlEnableDepthTest();
rlEnableDepthMask();
EndMode3D();
@@ -1133,7 +1165,7 @@ static void GameUpdate(Camera camera, float &time) {
oxygen += dt * 20.0f;
oxygen = Clamp(oxygen, 0, MAX_HP);
}
if(!hide_ui && !taking_panorama) {
if(!hide_ui && !taking_panorama) { // DEBUG MENU!!!!
char text[128];
sprintf(text, "%s %s", GAME_NAME, GAME_VERSION);
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;
sprintf(text, "Mem %.2fMiB/%.2fMiB", residentmem, virtualmem);
DrawTextB(text, 20, 80, DEFAULT_FONT_SIZE, WHITE);
sprintf(text, "Drawing %d verts", debug_verts_opaque+debug_verts_transparent);
DrawTextB(text, 120, 40, DEFAULT_FONT_SIZE, WHITE);
Vector3I ppos = {floorf(player_position.x), floorf(player_position.y), floorf(player_position.z)};
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-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);
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;
}
int T = 0;
@@ -1243,6 +1295,7 @@ static void GameUpdate(Camera camera, float &time) {
}
}
static void GameStart() {
const int cloudMapSize = MAX_WORLD_SIZE*CHUNK_SIZE/8;
for (int x = 0; x < cloudMapSize; x++)
{
@@ -1255,28 +1308,11 @@ static void GameStart() {
if(online) {
char data[1];
data[0] = NET_ARG_REQPLAYERS;
SendPacketR(peer, data, 1);
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);
SendPacketR(peer, data, 1); // Tell the server to fetch all players
}
worldTime = (int)(WORLD_TIME_TICKS * 0.3f);
camera = { 0 };
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};
@@ -1286,7 +1322,7 @@ static void GameStart() {
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.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 };
DisableCursor();
@@ -1299,8 +1335,22 @@ static void GameStart() {
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) {
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) {
std::string output;
@@ -1315,14 +1365,6 @@ static void ParseMessagePacket(std::vector<unsigned char> &a_data) {
msg.message = output;
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) {
int len = packet->dataLength;
std::vector<unsigned char> a_data;
@@ -1332,6 +1374,7 @@ static void ParseData(ENetPacket* packet) {
a_data.push_back(packet->data[i]);
}
switch (a_data[0])
{
case NET_ARG_CHUNKF:
@@ -1344,7 +1387,9 @@ static void ParseData(ENetPacket* packet) {
break;
case NET_ARG_PLRCON:
puts("Player connected");
CreatePlayer(a_data[1]);
if(a_data[1] != plrId) {
CreateNetPlayer(a_data[1]);
}
break;
case NET_ARG_PLRDCN:
puts("Player disconnected");
@@ -1360,37 +1405,49 @@ static void ParseData(ENetPacket* packet) {
player_position.y = y;
player_position.z = z;
}
else {
NetPlayer &plr = players[a_data[1]];
players[plrId].yaw = a_data[2];
for (Entity &plr : entities)
{
std::cout << (int)(plr.data[0]) << " " << (int)(plr.type) << std::endl;
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.x = x;
plr.y = y;
plr.z = z;
plr.position.x = x;
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;
case NET_ARG_ECHOYAW:
std::cout << "Server requested to sync yaw " << (int)(a_data[1]) << std::endl;
if(a_data[1] != plrId) {
NetPlayer &plr = players[a_data[1]];
players[plrId].yaw = a_data[2];
for (Entity &plr : entities)
{
if(plr.data[0] == a_data[1] && plr.type == 1) {
plr.yaw = (short)floorf(a_data[2] / 255.0f * 65536);
}
}
break;
case NET_ARG_PLRREG:
puts("Got a connected player");
if(a_data[1] != plrId) {
CreatePlayer(a_data[1]);
NetPlayer &plr = players[a_data[1]];
CreateNetPlayer(a_data[1]);
}
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.x = x;
plr.y = y;
plr.z = z;
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:
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;
@@ -1410,32 +1467,6 @@ static void ParseData(ENetPacket* packet) {
case NET_ARG_MESSAGEE:
ParseMessagePacket(a_data);
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:
puts("Malformed data?");
break;
@@ -1499,15 +1530,6 @@ void GameModeCleanupFull() {
enet_host_destroy(client);
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(dirtyChunks, 0, sizeof(dirtyChunks));
entities.clear();
@@ -1520,6 +1542,7 @@ void GameModeCleanup() {
pauseMenuActive = false;
EnableCursor();
GameModeCleanupFull();
state = GAME_STATE_MAINMENU;
worldCreationProgress = 0;
worldCreationStep = 0;
}
@@ -1530,6 +1553,13 @@ int main(void)
SetTraceLogLevel(LOG_WARNING);
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(WIDTH, HEIGHT, GAME_NAME);
if(!DirectoryExists(PathifyUser(""))) {
MakeDirectory(PathifyUser(""));
}
if(!DirectoryExists(PathifyUser("worlds"))) {
MakeDirectory(PathifyUser("worlds"));
}
InitWorldgen(0);
InitAudioDevice();
InitMenu();
@@ -1538,8 +1568,6 @@ int main(void)
LocaleUpdate();
LoadRecipes();
playerTex = LoadTexture(GetPlayerTexturePath());
camera = { 0 };
camera.position = (Vector3){0, 0, 0};
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);
terrain = LoadTexture(Pathify("terrain.png"));
sun = LoadTexture(Pathify("sun.png"));
moon = LoadTexture(Pathify("moon.png"));
stars = LoadTexture(Pathify("stars.png"));
GenTextureMipmaps(&terrain);
Image temp = GenImageColor(1, 1, WHITE);
white_pixel = LoadTextureFromImage(temp);
@@ -1564,14 +1595,32 @@ int main(void)
ImageCrop(&copied, src0);
water = LoadTextureFromImage(copied);
SetTextureWrap(terrain, TEXTURE_WRAP_REPEAT);
SetTextureWrap(water, TEXTURE_WRAP_REPEAT);
SetTargetFPS(-1);
float time;
LoadNewShader("terrain");
LoadNewShader("water");
SetExitKey(KEY_NULL);
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();
InputUpdate();
@@ -1594,7 +1643,7 @@ int main(void)
{
c.highestBlock[i-CHUNK_DATA_SIZE-2] = data[i];
}
world[idx] = c;
world.chunks[idx] = c;
dirtyChunks[idx] = true;
worldPacketStack.pop();
fetchedChunks++;
@@ -1641,7 +1690,7 @@ int main(void)
int idx = x + y * MAX_WORLD_SIZE;
if(worldCreationStep == 0 && !online) {
Chunk chunk = GenerateChunk(x, y);
world[idx] = chunk;
world.chunks[idx] = chunk;
}
if(worldCreationStep == 1 && !online) {
if(worldCreationProgress > 0) {
@@ -1653,7 +1702,7 @@ int main(void)
}
if (worldCreationStep == 2)
{
RebuildOpaqueMask(&world[idx]);
RebuildOpaqueMask(world.chunks[idx]);
}
if (worldCreationStep == 3) {
dirtyChunks[idx] = true;
@@ -1686,15 +1735,7 @@ int main(void)
DrawMultiplayer();
break;
case GAME_STATE_TRANSITION:
DrawBackground();
DrawLogoCenter();
if(!singleplayerServer || !serverStarted) {
state = GAME_STATE_MAINMENU;
}
if (serverThread.joinable()) {
serverThread.join();
singleplayerServer = false;
}
break;
case GAME_STATE_OPTIONS:
DrawControls();