Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfc693785d |
@@ -11,15 +11,13 @@ 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 g++-mingw-w64-i686 gcc-mingw-w64-i686 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 libxinerama-dev libxcursor-dev libxi-dev libgl-dev
|
||||
|
||||
- name: Build makeheaders
|
||||
run: |
|
||||
@@ -27,26 +25,61 @@ 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: OUTPUT-Linux
|
||||
path: release-linux.zip
|
||||
|
||||
- name: Upload Windows64 Release
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: release-w64
|
||||
path: OUTPUT-w64
|
||||
path: release-w64.zip
|
||||
|
||||
- name: Upload Windows32 Release
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: release-w32
|
||||
path: OUTPUT-w32
|
||||
path: release-w32.zip
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
[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
|
||||
@@ -1,15 +1,17 @@
|
||||
#/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 -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 src/helpers/svlib.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 -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake -B build -DUNIX=ON -DUNIX=true
|
||||
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
|
||||
@@ -13,3 +13,5 @@ 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
|
||||
@@ -13,3 +13,5 @@ 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
|
||||
@@ -0,0 +1,64 @@
|
||||
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
|
||||
|
After Width: | Height: | Size: 308 B |
@@ -14,14 +14,12 @@ 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!
|
||||
@@ -43,17 +41,21 @@ item.dirt: "Dirt"
|
||||
item.sand: "Sand"
|
||||
item.water: "Water"
|
||||
item.planks: "Wooden Planks"
|
||||
item.stone_bricks: "Stone Bricks"
|
||||
item.copper_block: "Copper Block"
|
||||
item.silver_block: "Silver Block"
|
||||
item.gold_block: "Gold Block"
|
||||
item.gray_bricks: "Gray Bricks"
|
||||
item.red_bricks: "Red Bricks"
|
||||
item.blue_bricks: "Blue Bricks"
|
||||
item.green_bricks: "Green Bricks"
|
||||
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"
|
||||
|
||||
|
Before Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 628 B |
|
Before Width: | Height: | Size: 628 B After Width: | Height: | Size: 2.9 KiB |
@@ -1,37 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#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));
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
@@ -5,7 +5,7 @@ add_subdirectory(helpers)
|
||||
|
||||
set(YAML_BUILD_SHARED_LIBS OFF)
|
||||
set(YAML_MSVC_SHARED_RT OFF)
|
||||
set(OPENGL_VERSION 3.3)
|
||||
set(OPENGL_VERSION 1.1)
|
||||
|
||||
add_subdirectory(libraries/raylib)
|
||||
add_subdirectory(libraries/enet)
|
||||
|
||||
@@ -0,0 +1,659 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
//
|
||||
// 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_
|
||||
@@ -15,6 +15,7 @@ add_library(helpers STATIC
|
||||
particles.cpp
|
||||
player.cpp
|
||||
multisound.cpp
|
||||
svlib.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
@@ -23,7 +24,6 @@ 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}")
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <unordered_set>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "common.hpp"
|
||||
@@ -7,14 +6,10 @@
|
||||
#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.1f
|
||||
#define SCALE 0.01f
|
||||
#define CAVE_COEFF 0.06
|
||||
#define EDGES_FADE 64
|
||||
#define CLOUD_SCALE 0.25f
|
||||
@@ -22,13 +17,11 @@
|
||||
#define BIOME_FOREST 0
|
||||
#define BIOME_TAIGA 1
|
||||
|
||||
static fnl_state perlin;
|
||||
static fnl_state perlin2;
|
||||
static fnl_state perlinLofi;
|
||||
static const siv::PerlinNoise perlin;
|
||||
|
||||
static int world_type = 0;
|
||||
|
||||
std::vector<BlockDef> BLOCKS = {
|
||||
const 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},
|
||||
@@ -36,21 +29,21 @@ std::vector<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{ "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{ "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{ "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{ "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{ "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{ "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},
|
||||
@@ -58,52 +51,33 @@ std::vector<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) {
|
||||
for (int i = 0; i < BLOCKS.size(); ++i) {
|
||||
int count = sizeof(BLOCKS) / sizeof(BLOCKS[0]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (BLOCKS[i].name == s) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static std::bitset<256> marked;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
//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});
|
||||
const int SEA_HEIGHT = 32; // sea surface y
|
||||
const int BEACH_DEPTH = 3; // how many blocks below surface become sand
|
||||
|
||||
//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;
|
||||
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;
|
||||
if (y == height) {
|
||||
if (height <= SEA_HEIGHT) {
|
||||
return BLOCK_SAND;
|
||||
@@ -115,119 +89,27 @@ 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 false;
|
||||
return (perlin.noise2D((x / 8) * 1.5f * CLOUD_SCALE, (z / 8) * 1.5f * CLOUD_SCALE) + 1.0f) / 2.0f > 0.5f;
|
||||
}
|
||||
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)
|
||||
@@ -292,15 +174,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;
|
||||
}
|
||||
}
|
||||
@@ -313,63 +195,21 @@ int GetBiome(int sx, int sy) {
|
||||
void SetBlockChunkFast(Chunk *c, int i, int t) {
|
||||
c->blocks[i] = t;
|
||||
}
|
||||
void SetBlock(World &world, int x, int y, int z, int t) {
|
||||
void SetBlock(Chunk 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.chunks[GetIndexWorld(cx, cz)], locX, y, locZ, t);
|
||||
SetBlockChunk(&world[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) {
|
||||
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;
|
||||
|
||||
const siv::PerlinNoise::seed_type seed = 123456u;
|
||||
const siv::PerlinNoise perlin{ seed };
|
||||
constexpr size_t MAX = 128; // allowed range: 0..MAX-1
|
||||
for (int i = 0; i < BLOCKS.size(); i++)
|
||||
for (int i = 0; i < sizeof(BLOCKS) / sizeof(BlockDef); i++)
|
||||
{
|
||||
BlockDef def = GetBlockDefinition(i);
|
||||
BlockDef def = BLOCKS[i];
|
||||
if(def.render == R_Translucent || def.render == R_TranslucentAllSides || def.render == R_TranslucentTriSide) {
|
||||
marked.set(i);
|
||||
}
|
||||
@@ -384,16 +224,21 @@ Chunk GenerateChunk(int _x, int _y) {
|
||||
Chunk new_chunk = { 0 };
|
||||
new_chunk.x = _x;
|
||||
new_chunk.z = _y;
|
||||
memset(&new_chunk.light, 0, sizeof(new_chunk.light));
|
||||
for (int y = 0; y < WORLD_HEIGHT; y++)
|
||||
|
||||
for (int x = 0; x < CHUNK_SIZE; x++)
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
{
|
||||
for (int y = 0; y < WORLD_HEIGHT; y++)
|
||||
{
|
||||
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(World &world) {
|
||||
void GenerateWorldAdditional(Chunk world[]) {
|
||||
int biome = GetBiome(0, 0);
|
||||
SetRandomSeed(0);
|
||||
switch (world_type)
|
||||
@@ -402,11 +247,36 @@ void GenerateWorldAdditional(World &world) {
|
||||
for (int x = 0; x < WORLD_SIZE_BLOCKS; x++)
|
||||
{
|
||||
for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) {
|
||||
Chunk c = world.chunks[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)];
|
||||
Chunk c = world[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_DIRT) {
|
||||
SetBlock(world, x, highestY, z, BLOCK_GRASS);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int _ = 0; _ < GetRandomValue(8, 24); _++)
|
||||
{
|
||||
@@ -444,10 +314,10 @@ void GenerateWorldAdditional(World &world) {
|
||||
for (int x = 0; x < WORLD_SIZE_BLOCKS; x++)
|
||||
{
|
||||
for (int z = 0; z < WORLD_SIZE_BLOCKS; z++) {
|
||||
Chunk c = world.chunks[GetIndexWorld(x / CHUNK_SIZE, z / CHUNK_SIZE)];
|
||||
Chunk c = world[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) == 0 && biome == BIOME_FOREST) { // Regular trees
|
||||
if(b == BLOCK_GRASS && GetRandomValue(0, 100) < 4 && biome == BIOME_FOREST) { // Regular trees
|
||||
SetBlock(world, x, highestY, z, BLOCK_DIRT);
|
||||
int maxY = GetRandomValue(5, 7);
|
||||
for (int y = 1; y < maxY; y++)
|
||||
@@ -464,7 +334,7 @@ void GenerateWorldAdditional(World &world) {
|
||||
SetBlock(world, x, wy, z, 12); // log
|
||||
}
|
||||
}
|
||||
if(b == BLOCK_GRASS && GetRandomValue(0, 100) == 0 && biome == BIOME_TAIGA) { // Spruce
|
||||
if(b == BLOCK_GRASS && GetRandomValue(0, 100) < 2 && biome == BIOME_TAIGA) { // Spruce
|
||||
SetBlock(world, x, highestY, z, BLOCK_DIRT);
|
||||
int maxY = 8;
|
||||
for (int y = 1; y < maxY; y++)
|
||||
@@ -551,293 +421,62 @@ void GenerateWorldAdditional(World &world) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
void TickBlock(World &world, int wx, int wy, int wz) {
|
||||
void TickBlock(Chunk 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();
|
||||
Entity temp = NewEntity(0);
|
||||
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, World &world, int wx, int wz) {
|
||||
void TickChunk(Chunk *chunk, Chunk *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++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
TickBlock(world, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct LightNode {
|
||||
Vector3I position;
|
||||
int value;
|
||||
};
|
||||
void RebuildOpaqueMask(Chunk &chunk) {
|
||||
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(Chunk &chunk, World &world) {
|
||||
ChunkRenderData GenerateCRDOpaque(const Chunk &chunk, Chunk world[]) {
|
||||
struct ChunkRenderData new_chunk = { 0 };
|
||||
uint16_t *mask = chunk.opaqueMask;
|
||||
uint16_t mask[CHUNK_DATA_SIZE/16];
|
||||
memcpy(mask, chunk.opaqueMask, sizeof(chunk.opaqueMask));
|
||||
|
||||
const int cxw = chunk.x * CHUNK_SIZE;
|
||||
const int cxz = chunk.z * CHUNK_SIZE;
|
||||
@@ -853,6 +492,8 @@ ChunkRenderData GenerateCRDOpaque(Chunk &chunk, World &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;
|
||||
@@ -878,7 +519,7 @@ ChunkRenderData GenerateCRDOpaque(Chunk &chunk, World &world) {
|
||||
}
|
||||
|
||||
//Generates a translucent CRD (ChunkRenderData). Outputs the CRD.
|
||||
ChunkRenderData GenerateCRDTranslucent(Chunk chunk, World &world) {
|
||||
ChunkRenderData GenerateCRDTranslucent(Chunk chunk, Chunk world[]) {
|
||||
struct ChunkRenderData new_chunk = { 0 };
|
||||
uint16_t *mask0= chunk.opaqueMask;
|
||||
uint16_t *mask = chunk.airMask;
|
||||
@@ -903,55 +544,6 @@ ChunkRenderData GenerateCRDTranslucent(Chunk chunk, World &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);
|
||||
@@ -975,7 +567,7 @@ ChunkRenderData GenerateCRDWater(Chunk chunk, World &world) {
|
||||
#endif
|
||||
#define SAVE_FORMAT 0
|
||||
|
||||
void SaveWorld(World &world, const char* path) {
|
||||
void SaveWorld(Chunk world[], const char* path) {
|
||||
std::ofstream data(path, std::ios::binary);
|
||||
if (!data) return;
|
||||
|
||||
@@ -984,7 +576,7 @@ void SaveWorld(World &world, const char* path) {
|
||||
data.write(&fmt, 1);
|
||||
|
||||
for (int i = 0; i < MAX_WORLD_AREA; ++i) {
|
||||
const Chunk &c = world.chunks[i];
|
||||
const Chunk &c = world[i];
|
||||
|
||||
std::vector<uint8_t> temp;
|
||||
int last_type = -1;
|
||||
@@ -1022,8 +614,7 @@ void SaveWorld(World &world, const char* path) {
|
||||
}
|
||||
|
||||
void Debug_Write(const std::string &stuff);
|
||||
|
||||
bool LoadWorld(World &world, const char* path) {
|
||||
bool LoadWorld(Chunk world[], const char* path) {
|
||||
std::ifstream data(path, std::ios::binary);
|
||||
if (!data) return false;
|
||||
|
||||
@@ -1052,22 +643,19 @@ bool LoadWorld(World &world, const char* path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Chunk c = {0};
|
||||
c.x = i % 16;
|
||||
c.z = i >> 4;
|
||||
Chunk *c = &world[i];
|
||||
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;
|
||||
|
||||
@@ -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,12 +62,16 @@
|
||||
#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
|
||||
@@ -75,10 +79,11 @@
|
||||
#define GAME_NAME "CubeGame"
|
||||
#define GAME_VERSION_INT 0
|
||||
#define DEFAULT_FONT_SIZE 16
|
||||
#define TPS 30
|
||||
#define TPS 30.0
|
||||
#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/"
|
||||
@@ -86,8 +91,6 @@
|
||||
#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,
|
||||
@@ -154,7 +157,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;
|
||||
@@ -197,33 +200,24 @@ struct Quad2D {
|
||||
#endif
|
||||
typedef struct Vector3I Vector3I;
|
||||
struct Vector3I {
|
||||
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);
|
||||
}
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
typedef struct Entity Entity;
|
||||
struct Entity {
|
||||
uint16_t id;
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
uint8_t damage_flash;
|
||||
uint8_t data[16];
|
||||
uint8_t data[4];
|
||||
uint8_t data_sv[8];
|
||||
bool free;
|
||||
float smoothing;
|
||||
float health;
|
||||
float lifetime;
|
||||
Vector3 position;
|
||||
Vector3 velocity;
|
||||
unsigned short yaw;
|
||||
bool free;
|
||||
};
|
||||
typedef struct NetPlayer NetPlayer;
|
||||
struct NetPlayer {
|
||||
@@ -235,6 +229,9 @@ struct NetPlayer {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
std::string nickname;
|
||||
Texture2D texture;
|
||||
std::vector<uint8_t> skin;
|
||||
};
|
||||
typedef struct MemInfo MemInfo;
|
||||
struct MemInfo {
|
||||
@@ -300,46 +297,28 @@ struct Particle {
|
||||
int lifetime;
|
||||
int data[8];
|
||||
};
|
||||
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);
|
||||
extern const BlockDef BLOCKS[];
|
||||
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(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 SetBlock(Chunk world[],int x,int y,int z,int t);
|
||||
void InitWorldgen(int worldType);
|
||||
Vector3 WorldPosition(int cx,int cz,int localX,int y,int localZ);
|
||||
Chunk GenerateChunk(int _x,int _y);
|
||||
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);
|
||||
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);
|
||||
#if !defined(SERVER)
|
||||
ChunkRenderData GenerateCRDOpaque(Chunk&chunk,World&world);
|
||||
ChunkRenderData GenerateCRDTranslucent(Chunk chunk,World&world);
|
||||
ChunkRenderData GenerateCRDWater(Chunk chunk,World&world);
|
||||
ChunkRenderData GenerateCRDOpaque(const Chunk&chunk,Chunk world[]);
|
||||
ChunkRenderData GenerateCRDTranslucent(Chunk chunk,Chunk world[]);
|
||||
#endif
|
||||
void SaveWorld(World&world,const char *path);
|
||||
bool LoadWorld(World&world,const char *path);
|
||||
void SaveWorld(Chunk world[],const char *path);
|
||||
bool LoadWorld(Chunk world[],const char *path);
|
||||
extern long nsTotal;
|
||||
void Debug_StartMeasure();
|
||||
#if defined(WIN32)
|
||||
@@ -351,49 +330,34 @@ 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;
|
||||
extern Font fnt;
|
||||
extern Font fnt;
|
||||
extern Texture2D terrain;
|
||||
#endif
|
||||
extern Font fnt;
|
||||
#if !defined(SERVER)
|
||||
extern Font fnt;
|
||||
#endif
|
||||
extern Texture2D terrain;
|
||||
extern Texture2D terrain;
|
||||
#if !defined(SERVER)
|
||||
extern Texture2D terrain;
|
||||
extern Texture2D terrain;
|
||||
extern Texture2D playerTex;
|
||||
extern Texture2D playerTex;
|
||||
#endif
|
||||
extern Texture2D nekitTex;
|
||||
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(World&world,int bx,int by,int bz,int t);
|
||||
#endif
|
||||
Entity NewEntity();
|
||||
void AddEntity(Entity ent);
|
||||
void UpdateEntities(World&world,float dt);
|
||||
void SetBlockNetwork(Chunk world[],int bx,int by,int bz,int t);
|
||||
Entity NewEntity(int id);
|
||||
extern float globalCounter;
|
||||
#if !defined(SERVER)
|
||||
void DrawEntities(float dt);
|
||||
extern bool swap_mouse;
|
||||
bool InputGetLMB();
|
||||
bool InputGetLMBDown();
|
||||
@@ -408,6 +372,7 @@ extern int currentlySelected;
|
||||
extern GameState state;
|
||||
extern Texture2D cubemap;
|
||||
int TryConnect(const char *hostname);
|
||||
void InitSingleplayer();
|
||||
void GameModeCleanup();
|
||||
void DrawBackground();
|
||||
void InitMenu();
|
||||
@@ -425,13 +390,14 @@ 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(World&world,ChunkRenderData chunkRenderData,Chunk chunk,int chunkWorldX,int chunkWorldY,uint8_t sideMask);
|
||||
MeshData GenerateChunkMesh(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);
|
||||
@@ -448,12 +414,10 @@ 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,Color tint);
|
||||
void DrawCubeBlock(Texture2D texture,Vector3 position,float width,float height,float length,BlockDef def);
|
||||
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) |
|
||||
@@ -473,53 +437,49 @@ 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){
|
||||
*y = index / (CHUNK_SIZE * CHUNK_SIZE);
|
||||
int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
|
||||
*z = rem / CHUNK_SIZE;
|
||||
*x = rem % CHUNK_SIZE;
|
||||
*x = index & 15;
|
||||
int tmp = index << 4;
|
||||
*z = tmp & 15;
|
||||
*y = tmp << 4;
|
||||
};
|
||||
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);
|
||||
return x + CHUNK_SIZE * (z + CHUNK_SIZE* y);
|
||||
};
|
||||
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(const uint16_t *maskArray,int position){
|
||||
if (position < 0 || position >= CHUNK_DATA_SIZE) return false;
|
||||
inline bool TestMask(uint16_t *maskArray,int position){
|
||||
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(const World&world,int x,int y,int z){
|
||||
inline bool TestOpaqueMaskWorld(Chunk world[],int x,int y,int z){
|
||||
if(CheckOOBWorld(x, y, z)) return true;
|
||||
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);
|
||||
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);
|
||||
};
|
||||
inline bool TestAirMaskWorld(const World&world,int x,int y,int z){
|
||||
inline bool TestAirMaskWorld(Chunk world[],int x,int y,int z){
|
||||
if(CheckOOBWorld(x, y, z)) return true;
|
||||
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);
|
||||
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);
|
||||
};
|
||||
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;
|
||||
@@ -529,6 +489,14 @@ 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);
|
||||
@@ -614,6 +582,7 @@ 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);
|
||||
@@ -625,13 +594,13 @@ void HotbarAddItemLots(Item *registry,int damage,int amount);
|
||||
void InitHotbar();
|
||||
void DrawHotbar();
|
||||
InventoryItem HotbarGetSelected();
|
||||
void DrawSelectedItem(Color tint);
|
||||
void DrawSelectedItem();
|
||||
void CloseInventory();
|
||||
void UpdateHotbar();
|
||||
void LocaleUpdate();
|
||||
void LoadRecipes();
|
||||
#endif
|
||||
void ParticlesUpdate(float dt,World&world);
|
||||
void ParticlesUpdate(float dt,Chunk world[]);
|
||||
void ParticlesDraw();
|
||||
void AddParticle(Particle part);
|
||||
Particle NewParticle(Vector3 position);
|
||||
@@ -640,10 +609,14 @@ 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
|
||||
|
||||
@@ -9,46 +9,36 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#define PIXUNIT 1.0f / 16.0f
|
||||
|
||||
#ifndef SERVER
|
||||
extern Camera camera;
|
||||
extern Font fnt;
|
||||
extern Texture2D terrain;
|
||||
|
||||
Texture2D playerTex;
|
||||
Texture2D nekitTex;
|
||||
Texture2D bomb;
|
||||
Sound nekit_idle;
|
||||
void EntitiesInit() {
|
||||
playerTex = LoadTexture(Pathify("player.png"));
|
||||
nekitTex = LoadTexture(Pathify("nekit.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(World &world, int bx, int by, int bz, int t);
|
||||
#else
|
||||
bool online = true;
|
||||
#endif
|
||||
void SetBlockNetwork(Chunk world[], int bx, int by, int bz, int t);
|
||||
|
||||
std::list<Entity> entities;
|
||||
|
||||
Entity NewEntity() {
|
||||
Entity NewEntity(int id) {
|
||||
Entity ent;
|
||||
ent.id = entities.size();
|
||||
ent.id = id;
|
||||
ent.type = 0;
|
||||
ent.yaw = 0;
|
||||
ent.free = false;
|
||||
return ent;
|
||||
}
|
||||
|
||||
void AddEntity(Entity ent) {
|
||||
void AddEntity(std::list<Entity> entities, Entity ent) {
|
||||
entities.push_back(ent);
|
||||
}
|
||||
|
||||
static void UpdateEntityPhysics(World &world, Entity& ent, float dt) {
|
||||
static void UpdateEntityPhysics(Chunk 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;
|
||||
@@ -67,7 +57,7 @@ static void UpdateEntityPhysics(World &world, Entity& ent, float dt) {
|
||||
ent.velocity = velocityTgt;
|
||||
ent.position = final;
|
||||
}
|
||||
void UpdateEntities(World &world, float dt) {
|
||||
void UpdateEntities(std::list<Entity> entities, Chunk world[], float dt) {
|
||||
if(entities.size() > 0) {
|
||||
int idx = 0;
|
||||
for(Entity& ent : entities) {
|
||||
@@ -93,9 +83,6 @@ void UpdateEntities(World &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;
|
||||
@@ -110,54 +97,8 @@ void UpdateEntities(World &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});
|
||||
|
||||
@@ -184,7 +125,7 @@ void UpdateEntities(World &world, float dt) {
|
||||
}
|
||||
Entity* entp = &ent;
|
||||
if(hit) {
|
||||
SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data[1]);
|
||||
SetBlockNetwork(world, (int)ent.position.x, (int)ent.position.y, (int)ent.position.z, ent.data_sv[1]);
|
||||
entp->free = true;
|
||||
}
|
||||
entp->yaw = 0;
|
||||
@@ -203,8 +144,8 @@ void UpdateEntities(World &world, float dt) {
|
||||
}
|
||||
}
|
||||
float globalCounter = 0;
|
||||
#ifndef SERVER
|
||||
void DrawEntities(float dt) {
|
||||
|
||||
void DrawEntities(std::list<Entity> entities, float dt) {
|
||||
globalCounter += dt;
|
||||
for(Entity& ent : entities) {
|
||||
ent.smoothing += dt;
|
||||
@@ -281,90 +222,13 @@ void DrawEntities(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, GetBlockDefinition(ent.data[1]), WHITE);
|
||||
DrawCubeBlock(terrain, pos_lerped, 1,1,1, BLOCKS[ent.data[1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -20,31 +20,23 @@ inline void unpack6(uint8_t v, bool *b0, bool *b1, bool *b2, bool *b3, bool *b4,
|
||||
*b5 = (v >> 5) & 1;
|
||||
}
|
||||
|
||||
inline void GetXYZFromIndex(int index, int* x, int* y, int* z) {
|
||||
*y = index / (CHUNK_SIZE * CHUNK_SIZE);
|
||||
int rem = index % (CHUNK_SIZE * CHUNK_SIZE);
|
||||
*z = rem / CHUNK_SIZE;
|
||||
*x = rem % CHUNK_SIZE;
|
||||
inline void GetXYZFromIndex(int index, int *x, int *y, int *z) {
|
||||
*x = index & 15;
|
||||
int tmp = index << 4;
|
||||
*z = tmp & 15;
|
||||
*y = tmp << 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
return x + CHUNK_SIZE * (z + CHUNK_SIZE* y);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -53,29 +45,32 @@ inline void GetXZFromIndex(int index, int *x, int *z) {
|
||||
*x = index % MAX_WORLD_SIZE;
|
||||
}
|
||||
|
||||
inline bool TestMask(const uint16_t *maskArray, int position)
|
||||
inline bool TestMask(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(const World& world, int x, int y, int z) {
|
||||
inline bool TestOpaqueMaskWorld(Chunk world[], int x, int y, int z) {
|
||||
if(CheckOOBWorld(x, y, z)) return true;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool TestAirMaskWorld(const World& world, int x, int y, int z) {
|
||||
inline bool TestAirMaskWorld(Chunk world[], int x, int y, int z) {
|
||||
if(CheckOOBWorld(x, y, z)) return true;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
inline int fetch_block(Chunk chunk, int x, int y, int z) {
|
||||
@@ -88,6 +83,15 @@ 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);
|
||||
|
||||
@@ -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)*3.0f;
|
||||
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y)*3.0f;
|
||||
x = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_X);
|
||||
y = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_Y);
|
||||
if(abs(x) < 0.1f) {
|
||||
x = 0;
|
||||
}
|
||||
@@ -108,7 +108,6 @@ 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() {
|
||||
@@ -137,6 +136,7 @@ void InputInit() {
|
||||
controls[key] = val;
|
||||
}
|
||||
|
||||
|
||||
swap_mouse = config["Swap mouse buttons"].as<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = GetBlockDefinition(item.damage).textureTop;
|
||||
tex = BLOCKS[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, GetBlockDefinition(blk).name)) {
|
||||
if(IDTagMatch(tag, BLOCKS[blk].name)) {
|
||||
isBlock = true;
|
||||
id = GetNumericIDFromString(GetBlockDefinition(blk).name);
|
||||
id = GetNumericIDFromString(BLOCKS[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, GetBlockDefinition(item.damage).name);
|
||||
bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[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, GetBlockDefinition(item.damage).name);
|
||||
bool tagBlockCond = item.item->type == IType_Block && ingredient.type == IType_Special_Tag && IDTagMatch(ingredient.id, BLOCKS[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."+GetBlockDefinition(movingItem->damage).name;
|
||||
name = "item."+BLOCKS[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(Color tint) {
|
||||
void DrawSelectedItem() {
|
||||
InventoryItem item = hotbar[selected];
|
||||
Vector3 center = {-0.75f, -0.45f, 0.5f};
|
||||
rlPushMatrix();
|
||||
@@ -458,16 +458,16 @@ void DrawSelectedItem(Color tint) {
|
||||
|
||||
rlRotatef(-45, 1, 0, 0);
|
||||
rlRotatef(25, 0, 0, 1);
|
||||
DrawCubeTexture(playerTex, {0, -12*PIXUNIT/2, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, tint, 44,20,4,4);
|
||||
DrawCubeTexture(playerTex, {0, -12*PIXUNIT/2, 0}, 4*PIXUNIT, 12*PIXUNIT, 4*PIXUNIT, WHITE, 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, GetBlockDefinition(item.damage), tint);
|
||||
DrawCubeBlock(terrain, {0, -12*PIXUNIT - 0.25f, 0}, 0.5f, 0.5f, 0.5f, BLOCKS[item.damage]);
|
||||
}
|
||||
else {
|
||||
UVCorners left = GetUVTex(item.item->texture);
|
||||
rlSetTexture(item_atlas.id);
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, 255);
|
||||
rlColor4ub(255, 255, 255, 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);
|
||||
|
||||
@@ -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,8 +503,7 @@ void DrawWorldSelect() {
|
||||
}
|
||||
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48, 128, 0)) {
|
||||
UIResetMousePos();
|
||||
InitWorldgen(0);
|
||||
state = GAME_STATE_LOADING;
|
||||
InitSingleplayer();
|
||||
return;
|
||||
}
|
||||
if (Button(LocaleGet("create_world").c_str(), GetScreenWidth()/2+196-128, GetScreenHeight()-48-48, 128, 0)) {
|
||||
@@ -551,12 +550,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)) {
|
||||
GameModeCleanup();
|
||||
ExitSingleplayer();
|
||||
UIResetMousePos();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef SERVER
|
||||
#ifndef LEGACY_GL
|
||||
|
||||
MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask)
|
||||
MeshData GenerateChunkMesh(ChunkRenderData chunkRenderData, Chunk chunk, int chunkWorldX, int chunkWorldY, uint8_t sideMask)
|
||||
{
|
||||
MeshData out = {0};
|
||||
|
||||
@@ -23,20 +23,17 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
std::vector<unsigned short> indices;
|
||||
|
||||
int face = 0;
|
||||
for (int index = 0; index < CHUNK_DATA_SIZE; index++)
|
||||
for (int x = 0; x < CHUNK_SIZE; ++x)
|
||||
for (int y = 0; y < WORLD_HEIGHT; ++y)
|
||||
for (int z = 0; z < CHUNK_SIZE; ++z)
|
||||
{
|
||||
int index = GetIndexChunk(x,y,z);
|
||||
uint8_t crdata = chunkRenderData.sides[index];
|
||||
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 = GetBlockDefinition(this_block);
|
||||
BlockDef definition = BLOCKS[this_block];
|
||||
|
||||
UVCorners UVside = GetUVTex(definition.textureSide);
|
||||
UVCorners UVtop = GetUVTex(definition.textureTop);
|
||||
@@ -49,6 +46,9 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
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,8 +72,7 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx-1, wy, wz);
|
||||
colors.push_back(clr);
|
||||
colors.push_back(colorShaded);
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
@@ -112,8 +111,7 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx+1, wy, wz);
|
||||
colors.push_back(clr);
|
||||
colors.push_back(colorShaded);
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
@@ -152,8 +150,7 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx, wy-1, wz);
|
||||
colors.push_back(clr);
|
||||
colors.push_back(colorShaded);
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
@@ -192,8 +189,12 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx, wy+1, wz);
|
||||
colors.push_back(clr);
|
||||
if(shaded) {
|
||||
colors.push_back(colorShaded);
|
||||
}
|
||||
else {
|
||||
colors.push_back(color);
|
||||
}
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
@@ -232,8 +233,7 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx, wy, wz+1);
|
||||
colors.push_back(clr);
|
||||
colors.push_back(colorShaded);
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
@@ -272,8 +272,7 @@ MeshData GenerateChunkMesh(World &world, ChunkRenderData chunkRenderData, Chunk
|
||||
positions.push_back(verts[3]);
|
||||
|
||||
normals.push_back(normal);
|
||||
Color clr = GetLightMesher(world, wx, wy, wz-1);
|
||||
colors.push_back(clr);
|
||||
colors.push_back(colorShaded);
|
||||
|
||||
uvs.push_back(corners[0]);
|
||||
uvs.push_back(corners[1]);
|
||||
|
||||
@@ -25,7 +25,7 @@ ENetHost* StartServer() {
|
||||
/* Bind the server to port 1234. */
|
||||
address.port = PORT;
|
||||
|
||||
server = enet_host_create(&address, 32, 1, 0);
|
||||
server = enet_host_create(&address, 32, 1, 0, 0);
|
||||
if (server == NULL)
|
||||
{
|
||||
fprintf (stderr,
|
||||
@@ -41,7 +41,8 @@ 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 /* assume any amount of incoming bandwidth */,
|
||||
0);
|
||||
|
||||
if (client == NULL)
|
||||
{
|
||||
@@ -86,17 +87,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)) { // handle NaN/Inf as zero (choose policy)
|
||||
if (!isfinite(v)) {
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
return;
|
||||
}
|
||||
if (v < 0.0f) v = 0.0f;
|
||||
if (v > 255.0f) v = 255.0f; // clamp to representable range
|
||||
if (v > 255.0f) v = 255.0f;
|
||||
|
||||
int intpart = (int)floorf(v);
|
||||
float frac = v - (float)intpart;
|
||||
int frac_byte = (int)floorf(frac * 255.0f + 0.5f); // round to nearest
|
||||
int frac_byte = (int)floorf(frac * 255.0f + 0.5f);
|
||||
if (frac_byte < 0) frac_byte = 0;
|
||||
if (frac_byte > 255) frac_byte = 255;
|
||||
buf[0] = (uint8_t)intpart;
|
||||
|
||||
@@ -65,12 +65,11 @@ static void DrawParticle(Particle particle, Color color)
|
||||
|
||||
rlSetTexture(0);
|
||||
}
|
||||
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)
|
||||
void ParticlesUpdate(float dt, Chunk world[]) {
|
||||
particles.remove_if([](Particle x) { return x.lifetime > 200; });
|
||||
for (Particle &part : particles)
|
||||
{
|
||||
art.lifetime++;p
|
||||
part.lifetime++;
|
||||
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});
|
||||
|
||||
@@ -100,7 +99,7 @@ void ParticlesUpdate(float dt, World &world) {
|
||||
part.position = final;
|
||||
part.velocity = velocityTgt;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
void ParticlesDraw() {
|
||||
for (Particle part : particles)
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
#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);
|
||||
}
|
||||
@@ -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, Color tint)
|
||||
void DrawCubeBlock(Texture2D texture, Vector3 position, float width, float height, float length, BlockDef def)
|
||||
{
|
||||
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(tint.r, tint.g, tint.b, 255);
|
||||
rlColor4ub(255, 255, 255, 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,56 +254,3 @@ 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);
|
||||
}
|
||||
}
|
||||
@@ -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,6 +79,10 @@
|
||||
#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
|
||||
@@ -87,6 +91,7 @@
|
||||
#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
|
||||
@@ -98,11 +103,12 @@
|
||||
#define GAME_VERSION_INT 0
|
||||
|
||||
#define DEFAULT_FONT_SIZE 16
|
||||
#define TPS 30
|
||||
#define TPS 30.0
|
||||
#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
|
||||
@@ -114,8 +120,6 @@
|
||||
#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,
|
||||
@@ -181,7 +185,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 {
|
||||
@@ -222,32 +226,23 @@ struct Quad2D {
|
||||
};
|
||||
#endif
|
||||
struct Vector3I {
|
||||
int x, y, z;
|
||||
bool operator==(const Vector3I& other) const {
|
||||
return (x == other.x && y == other.y && z == other.z);
|
||||
};
|
||||
int x;
|
||||
int y;
|
||||
int 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[16];
|
||||
uint8_t data[4];
|
||||
uint8_t data_sv[8];
|
||||
bool free;
|
||||
float smoothing;
|
||||
float health;
|
||||
float lifetime;
|
||||
Vector3 position;
|
||||
Vector3 velocity;
|
||||
unsigned short yaw;
|
||||
bool free;
|
||||
};
|
||||
|
||||
struct NetPlayer
|
||||
@@ -260,6 +255,9 @@ struct NetPlayer
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
std::string nickname;
|
||||
Texture2D texture;
|
||||
std::vector<uint8_t> skin;
|
||||
};
|
||||
|
||||
struct MemInfo {
|
||||
@@ -319,7 +317,3 @@ struct Particle {
|
||||
int lifetime;
|
||||
int data[8];
|
||||
};
|
||||
struct World
|
||||
{
|
||||
Chunk chunks[MAX_WORLD_AREA];
|
||||
};
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
#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;
|
||||
@@ -31,11 +35,14 @@ Vector2 cameraMovementSmooth;
|
||||
static float camYaw = 0.0f;
|
||||
static float camPitch = -45.0f;
|
||||
static const float acceleration = 48.0f;
|
||||
static const float drag = 6.0f; // tuned for feel
|
||||
static const float drag = 6.0f;
|
||||
static bool singleplayerServer;
|
||||
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;
|
||||
@@ -52,27 +59,21 @@ 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;
|
||||
static Texture2D sun;
|
||||
static Texture2D moon;
|
||||
static Texture2D stars;
|
||||
bool tick_entities = true;
|
||||
bool tick_entities;
|
||||
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 {
|
||||
@@ -96,19 +97,100 @@ static Vector3 CameraForwardFromYawPitch(float yaw, float pitch)
|
||||
f.z = cosf(pitch) * sinf(yaw);
|
||||
return Vector3Normalize(f);
|
||||
}
|
||||
World world;
|
||||
static MeshUnit rendering[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;
|
||||
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];
|
||||
static MeshUnit rendering[MAX_WORLD_AREA];
|
||||
static MeshUnit renderingT[MAX_WORLD_AREA];
|
||||
|
||||
GameState state = GAME_STATE_MAINMENU;
|
||||
bool loaderParam_remeshOnly = false;
|
||||
int worldCreationProgress = 0;
|
||||
@@ -248,17 +330,14 @@ 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;
|
||||
@@ -266,7 +345,6 @@ 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;
|
||||
@@ -279,48 +357,35 @@ 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 = GetIndexWorld(x, y);
|
||||
int idx = x + y * MAX_WORLD_SIZE;
|
||||
if(loadedChunks[idx]) {
|
||||
UnloadModel(renderingT[idx].model);
|
||||
UnloadModel(rendering[idx].model);
|
||||
UnloadModel(rendering[idx].modelTransparent);
|
||||
UnloadModel(rendering[idx].modelWater);
|
||||
}
|
||||
Chunk &chunk = world.chunks[idx];
|
||||
RebuildOpaqueMask(chunk);
|
||||
RebuildLighting(world, chunk.x, chunk.z);
|
||||
Chunk chunk = world[idx];
|
||||
RebuildOpaqueMask(&chunk);
|
||||
|
||||
MeshData renderDataOpq = GenerateChunkMesh(GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF);
|
||||
MeshData renderDataTsl = GenerateChunkMesh(GenerateCRDTranslucent(chunk, world), chunk, x, y, 0xFF);
|
||||
|
||||
MeshData renderDataOpq = GenerateChunkMesh(world, GenerateCRDOpaque(chunk, world), chunk, x, y, 0xFF);
|
||||
Model model0 = LoadModelFromMesh(GenChunkMesh(renderDataOpq));
|
||||
model0.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
|
||||
model0.materials[0].shader = loadedShaders["terrain"];
|
||||
Model model = LoadModelFromMesh(GenChunkMesh(renderDataOpq));
|
||||
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = terrain;
|
||||
MeshUnit munit0;
|
||||
munit0.model = model0;
|
||||
munit0.model = model;
|
||||
munit0.vertices += renderDataOpq.vertexCount;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
static bool RaycastBlock(Vector3 origin, Vector3 dir, float maxDist, Vector3 *outBlock, Vector3 *outPrev)
|
||||
@@ -384,21 +449,12 @@ 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 = -1;
|
||||
int plrId = 0;
|
||||
|
||||
static bool pauseMenuActive;
|
||||
void _LoadWorld(const char* path) {
|
||||
@@ -414,7 +470,7 @@ void PlayRandomMusic() {
|
||||
PlayMusicStream(currentMusic);
|
||||
}
|
||||
static int _blockPlacedC = 0;
|
||||
void SetBlockNetwork(World &world, int bx, int by, int bz, int t) {
|
||||
void SetBlockNetwork(Chunk 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});
|
||||
@@ -425,11 +481,11 @@ void SetBlockNetwork(World &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 = GetBlockDefinition(t).type;
|
||||
sound = BLOCKS[t].type;
|
||||
}
|
||||
else {
|
||||
int id = GetBlock(world, bx, by, bz);
|
||||
BlockDef block = GetBlockDefinition(id);
|
||||
BlockDef block = BLOCKS[id];
|
||||
if(id != 0) {
|
||||
sound = block.type;
|
||||
for (int x = 0; x < 4; x++)
|
||||
@@ -509,9 +565,9 @@ static void TickAvailableBlocks() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic_bool serverStarted;
|
||||
int TryConnect(const char* hostname) {
|
||||
/*client = StartClient();
|
||||
client = StartClient();
|
||||
|
||||
if(client == NULL)
|
||||
{
|
||||
@@ -526,7 +582,7 @@ int TryConnect(const char* hostname) {
|
||||
int s = enet_address_set_host (& address, hostname);
|
||||
address.port = PORT;
|
||||
|
||||
peer = enet_host_connect(client, &address, 1);
|
||||
peer = enet_host_connect(client, &address, 1, 0);
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
@@ -534,10 +590,12 @@ int TryConnect(const char* hostname) {
|
||||
"No available peers for initiating an ENet connection.\n");
|
||||
return NET_ERROR_NOTFOUND;
|
||||
}
|
||||
|
||||
if (enet_host_service (client, & event, 5000) > 0 &&
|
||||
event.type == ENET_EVENT_TYPE_CONNECT)
|
||||
printf("Found a host\n");
|
||||
while (!serverStarted)
|
||||
{
|
||||
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;
|
||||
@@ -551,9 +609,41 @@ 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;
|
||||
@@ -565,54 +655,6 @@ 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 ||
|
||||
@@ -749,22 +791,6 @@ 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)
|
||||
@@ -797,7 +823,7 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
tier = selected_item->tier;
|
||||
}
|
||||
}
|
||||
BlockDef block = GetBlockDefinition(GetBlock(world, bx, by, bz));
|
||||
BlockDef block = BLOCKS[GetBlock(world, bx, by, bz)];
|
||||
float hardnessMultiplier = block.hardness / 4.0f;
|
||||
if(player_break_parts_time >= 0.05f) {
|
||||
Vector3 v = {0, 1, 0};
|
||||
@@ -944,7 +970,7 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
}
|
||||
double PROFCOUNT = GetTime();
|
||||
if (bestIdx != -1) {
|
||||
RebuildOpaqueMask(world.chunks[bestIdx]);
|
||||
RebuildOpaqueMask(&world[bestIdx]);
|
||||
int bx, by;
|
||||
GetXZFromIndex(bestIdx, &bx, &by);
|
||||
RemeshChunk(bx, by);
|
||||
@@ -952,23 +978,6 @@ 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);
|
||||
@@ -985,56 +994,12 @@ 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();
|
||||
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();
|
||||
ClearBackground(RAYWHITE);
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), {120, 167, 255});
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
@@ -1048,13 +1013,16 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
_z *= CHUNK_SIZE;
|
||||
|
||||
if(!loadedChunks[x]) continue;
|
||||
if(!IsChunkInFrustum(frustum, world.chunks[x], _x, _z)) continue;
|
||||
if(!IsChunkInFrustum(frustum, world[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(dt);
|
||||
DrawEntities(entities, 0);
|
||||
for (const auto& [id, netplayer] : players) {
|
||||
DrawPlayer(terrain, netplayer);
|
||||
}
|
||||
ParticlesDraw();
|
||||
//Transparent shit
|
||||
rlDisableDepthMask();
|
||||
@@ -1116,7 +1084,7 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
if (!loadedChunks[i]) continue;
|
||||
int cx, cz;
|
||||
GetXZFromIndex(i, &cx, &cz);
|
||||
if (!IsChunkInFrustum(frustum, world.chunks[i], cx*CHUNK_SIZE, cz*CHUNK_SIZE)) continue;
|
||||
if (!IsChunkInFrustum(frustum, world[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;
|
||||
@@ -1129,8 +1097,8 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
|
||||
for (auto &p : distances) {
|
||||
int idx = p.second;
|
||||
DrawModel(rendering[idx].modelTransparent, {0, 0, 0}, 1.0f, WHITE);
|
||||
DrawModel(rendering[idx].modelWater, {0, 0, 0}, 1.0f, WHITE);
|
||||
DrawModel(renderingT[idx].model, {0, 0, 0}, 1.0f, WHITE);
|
||||
debug_verts_transparent += renderingT[idx].vertices;
|
||||
}
|
||||
AddProfilerPart("chunk render tsl", GetTime()-PROFCOUNT, RED);
|
||||
if (highlightValid)
|
||||
@@ -1149,7 +1117,7 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
BeginMode3D(camera);
|
||||
rlDisableDepthMask();
|
||||
rlDisableDepthTest();
|
||||
DrawSelectedItem(GetLight(world, (int)player_position.x, (int)player_position.y, (int)player_position.z));
|
||||
DrawSelectedItem();
|
||||
rlEnableDepthTest();
|
||||
rlEnableDepthMask();
|
||||
EndMode3D();
|
||||
@@ -1165,7 +1133,7 @@ static void GameUpdate(Camera camera, float &time) {
|
||||
oxygen += dt * 20.0f;
|
||||
oxygen = Clamp(oxygen, 0, MAX_HP);
|
||||
}
|
||||
if(!hide_ui && !taking_panorama) { // DEBUG MENU!!!!
|
||||
if(!hide_ui && !taking_panorama) {
|
||||
char text[128];
|
||||
sprintf(text, "%s %s", GAME_NAME, GAME_VERSION);
|
||||
DrawTextB(text, 20, 20, DEFAULT_FONT_SIZE, WHITE);
|
||||
@@ -1180,21 +1148,8 @@ 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);
|
||||
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);
|
||||
sprintf(text, "Drawing %d verts", debug_verts_opaque+debug_verts_transparent);
|
||||
DrawTextB(text, 120, 40, DEFAULT_FONT_SIZE, WHITE);
|
||||
DrawRectangle(GetScreenWidth()/2-3, GetScreenHeight()/2-3, 6, 6, BLACK);
|
||||
DrawRectangle(GetScreenWidth()/2-2, GetScreenHeight()/2-2, 4, 4, WHITE);
|
||||
|
||||
@@ -1241,13 +1196,6 @@ 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;
|
||||
@@ -1295,7 +1243,6 @@ 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++)
|
||||
{
|
||||
@@ -1308,10 +1255,27 @@ static void GameStart() {
|
||||
if(online) {
|
||||
char data[1];
|
||||
data[0] = NET_ARG_REQPLAYERS;
|
||||
SendPacketR(peer, data, 1); // Tell the server to fetch all players
|
||||
}
|
||||
SendPacketR(peer, data, 1);
|
||||
|
||||
worldTime = (int)(WORLD_TIME_TICKS * 0.3f);
|
||||
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);
|
||||
}
|
||||
|
||||
camera = { 0 };
|
||||
camera.position = (Vector3){ MAX_WORLD_SIZE / 2 * CHUNK_SIZE, 12.0f, MAX_WORLD_SIZE / 2 * CHUNK_SIZE};
|
||||
@@ -1322,7 +1286,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.chunks[GetIndexWorld(center / 16, center / 16)].highestBlock[0] + 2;
|
||||
player_position.y = world[GetIndexWorld(center / 16, center / 16)].highestBlock[0] + 2;
|
||||
player_velocity = (Vector3){ 0, 0, 0 };
|
||||
|
||||
DisableCursor();
|
||||
@@ -1335,22 +1299,8 @@ 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) {
|
||||
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);
|
||||
}
|
||||
players.erase(id);
|
||||
}
|
||||
static void ParseMessagePacket(std::vector<unsigned char> &a_data) {
|
||||
std::string output;
|
||||
@@ -1365,6 +1315,14 @@ 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;
|
||||
@@ -1374,7 +1332,6 @@ static void ParseData(ENetPacket* packet) {
|
||||
a_data.push_back(packet->data[i]);
|
||||
}
|
||||
|
||||
|
||||
switch (a_data[0])
|
||||
{
|
||||
case NET_ARG_CHUNKF:
|
||||
@@ -1387,9 +1344,7 @@ static void ParseData(ENetPacket* packet) {
|
||||
break;
|
||||
case NET_ARG_PLRCON:
|
||||
puts("Player connected");
|
||||
if(a_data[1] != plrId) {
|
||||
CreateNetPlayer(a_data[1]);
|
||||
}
|
||||
CreatePlayer(a_data[1]);
|
||||
break;
|
||||
case NET_ARG_PLRDCN:
|
||||
puts("Player disconnected");
|
||||
@@ -1405,49 +1360,37 @@ static void ParseData(ENetPacket* packet) {
|
||||
player_position.y = y;
|
||||
player_position.z = z;
|
||||
}
|
||||
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) {
|
||||
else {
|
||||
NetPlayer &plr = players[a_data[1]];
|
||||
players[plrId].yaw = a_data[2];
|
||||
float x = DeserializeFloat(a_data[2],a_data[3]);
|
||||
float y = DeserializeFloat(a_data[4],a_data[5]);
|
||||
float z = DeserializeFloat(a_data[6],a_data[7]);
|
||||
plr.position.x = x;
|
||||
plr.position.y = y;
|
||||
plr.position.z = z;
|
||||
//plr.yaw = (short)floorf(a_data[8] / 255.0f* 65536);
|
||||
plr.data[1] = 255;
|
||||
std::cout << x << " " << y << " " << z << " " << (float)(plr.yaw) << std::endl;
|
||||
}
|
||||
plr.x = x;
|
||||
plr.y = y;
|
||||
plr.z = z;
|
||||
}
|
||||
break;
|
||||
case NET_ARG_ECHOYAW:
|
||||
std::cout << "Server requested to sync yaw " << (int)(a_data[1]) << std::endl;
|
||||
for (Entity &plr : entities)
|
||||
{
|
||||
if(plr.data[0] == a_data[1] && plr.type == 1) {
|
||||
plr.yaw = (short)floorf(a_data[2] / 255.0f * 65536);
|
||||
}
|
||||
if(a_data[1] != plrId) {
|
||||
NetPlayer &plr = players[a_data[1]];
|
||||
players[plrId].yaw = a_data[2];
|
||||
}
|
||||
break;
|
||||
case NET_ARG_PLRREG:
|
||||
puts("Got a connected player");
|
||||
if(a_data[1] != plrId) {
|
||||
CreateNetPlayer(a_data[1]);
|
||||
}
|
||||
for (Entity &plr : entities)
|
||||
{
|
||||
if(plr.data[0] == a_data[1] && plr.type == 1) {
|
||||
CreatePlayer(a_data[1]);
|
||||
NetPlayer &plr = players[a_data[1]];
|
||||
float x = DeserializeFloat(a_data[2],a_data[3]);
|
||||
float y = DeserializeFloat(a_data[4],a_data[5]);
|
||||
float z = DeserializeFloat(a_data[6],a_data[7]);
|
||||
plr.position.x = x;
|
||||
plr.position.y = y;
|
||||
plr.position.z = z;
|
||||
plr.x = x;
|
||||
plr.y = y;
|
||||
plr.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;
|
||||
@@ -1467,6 +1410,32 @@ 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;
|
||||
@@ -1530,6 +1499,15 @@ 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();
|
||||
@@ -1542,7 +1520,6 @@ void GameModeCleanup() {
|
||||
pauseMenuActive = false;
|
||||
EnableCursor();
|
||||
GameModeCleanupFull();
|
||||
state = GAME_STATE_MAINMENU;
|
||||
worldCreationProgress = 0;
|
||||
worldCreationStep = 0;
|
||||
}
|
||||
@@ -1553,13 +1530,6 @@ 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();
|
||||
@@ -1568,6 +1538,8 @@ 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};
|
||||
@@ -1577,9 +1549,6 @@ 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);
|
||||
@@ -1595,32 +1564,14 @@ 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();
|
||||
|
||||
@@ -1643,7 +1594,7 @@ int main(void)
|
||||
{
|
||||
c.highestBlock[i-CHUNK_DATA_SIZE-2] = data[i];
|
||||
}
|
||||
world.chunks[idx] = c;
|
||||
world[idx] = c;
|
||||
dirtyChunks[idx] = true;
|
||||
worldPacketStack.pop();
|
||||
fetchedChunks++;
|
||||
@@ -1690,7 +1641,7 @@ int main(void)
|
||||
int idx = x + y * MAX_WORLD_SIZE;
|
||||
if(worldCreationStep == 0 && !online) {
|
||||
Chunk chunk = GenerateChunk(x, y);
|
||||
world.chunks[idx] = chunk;
|
||||
world[idx] = chunk;
|
||||
}
|
||||
if(worldCreationStep == 1 && !online) {
|
||||
if(worldCreationProgress > 0) {
|
||||
@@ -1702,7 +1653,7 @@ int main(void)
|
||||
}
|
||||
if (worldCreationStep == 2)
|
||||
{
|
||||
RebuildOpaqueMask(world.chunks[idx]);
|
||||
RebuildOpaqueMask(&world[idx]);
|
||||
}
|
||||
if (worldCreationStep == 3) {
|
||||
dirtyChunks[idx] = true;
|
||||
@@ -1735,7 +1686,15 @@ 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();
|
||||
|
||||