summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml14
-rw-r--r--CIbuild.sh6
-rw-r--r--CMakeLists.txt11
-rw-r--r--SetFlags.cmake79
-rw-r--r--lib/cmake-coverage/CodeCoverage.cmake160
-rw-r--r--lib/cmake-coverage/LICENSE23
-rw-r--r--lib/polarssl.cmake8
-rw-r--r--src/BiomeDef.h2
-rw-r--r--src/BlockArea.cpp164
-rw-r--r--src/BlockArea.h5
-rw-r--r--src/Chunk.cpp161
-rw-r--r--src/Chunk.h31
-rw-r--r--src/ChunkBuffer.cpp297
-rw-r--r--src/ChunkBuffer.h319
-rw-r--r--src/ChunkDef.h100
-rw-r--r--src/ChunkMap.cpp16
-rw-r--r--src/ChunkSender.h1
-rw-r--r--src/Entities/FallingBlock.cpp5
-rw-r--r--src/LightingThread.cpp11
-rw-r--r--src/MobProximityCounter.cpp4
-rw-r--r--src/MobProximityCounter.h4
-rw-r--r--src/Simulator/FireSimulator.cpp10
-rw-r--r--src/StringUtils.h3
-rw-r--r--src/Vector3.h2
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp3
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h4
-rw-r--r--src/WorldStorage/WSSCompact.cpp10
-rw-r--r--src/WorldStorage/WSSCompact.h3
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/ChunkBuffer/CMakeLists.txt16
-rw-r--r--tests/ChunkBuffer/Coordinates.cpp15
-rw-r--r--tests/ChunkBuffer/creatable.cpp9
-rw-r--r--tests/TestGlobals.h136
-rw-r--r--uploadCoverage.sh5
34 files changed, 1231 insertions, 413 deletions
diff --git a/.travis.yml b/.travis.yml
index 0ab25ae3b..3bf2acc43 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,15 @@ language: cpp
compiler:
- gcc
- clang
+
+before_install:
+ - if [TRAVIS_MCSERVER_BUILD_TYPE == "COVERAGE"] then sudo pip install cpp_coveralls fi
+
# Build MCServer
-script: cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | $MCSERVER_PATH)
+script: CIbuild.sh
+
+after_success:
+ - uploadCoverage.sh
env:
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
@@ -11,6 +18,11 @@ env:
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug
+matrix:
+ include:
+ - compiler: gcc
+ env: TRAVIS_MCSERVER_BUILD_TYPE=COVERAGE MCSERVER_PATH=./MCServer_debug
+
# Notification Settings
notifications:
email:
diff --git a/CIbuild.sh b/CIbuild.sh
new file mode 100644
index 000000000..0c00a351f
--- /dev/null
+++ b/CIbuild.sh
@@ -0,0 +1,6 @@
+ #!/usr/bin/env bash
+
+cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1;
+make -j 2;
+cd MCServer/;
+echo stop | gcov $MCSERVER_PATH;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a860920c..56dea1a34 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.2)
# Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html )
enable_language(CXX C)
@@ -14,6 +14,10 @@ if(DEFINED ENV{TRAVIS_MCSERVER_FORCE32})
set(FORCE32 $ENV{TRAVIS_MCSERVER_FORCE32})
endif()
+if(DEFINED ENV{TRAVIS_BUILD_WITH_COVERAGE})
+ set(BUILD_WITH_COVERAGE $ENV{TRAVIS_BUILD_WITH_COVERAGE})
+endif()
+
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)
@@ -69,3 +73,8 @@ set_exe_flags()
add_subdirectory (src)
+if(${SELF_TEST})
+ enable_testing()
+ add_subdirectory (tests)
+endif()
+
diff --git a/SetFlags.cmake b/SetFlags.cmake
index 4eed529bd..c4713e2d2 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -1,32 +1,41 @@
macro (add_flags_lnk FLAGS)
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE "${CMAKE_MODULE_LINKER_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${FLAGS}")
endmacro()
macro(add_flags_cxx FLAGS)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} ${FLAGS}")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}")
endmacro()
macro(set_flags)
# Add the preprocessor macros used for distinguishing between debug and release builds (CMake does this automatically for MSVC):
if (NOT MSVC)
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/lib/cmake-coverage/")
+ include(CodeCoverage)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -D_DEBUG")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -D_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
endif()
if(MSVC)
@@ -42,9 +51,10 @@ macro(set_flags)
elseif(APPLE)
#on os x clang adds pthread for us but we need to add it for gcc
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
add_flags_cxx("-stdlib=libc++")
add_flags_lnk("-stdlib=libc++")
else()
@@ -57,6 +67,7 @@ macro(set_flags)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
endif()
@@ -97,10 +108,12 @@ macro(set_lib_flags)
string(REPLACE "/W3" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/W3" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
else()
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -w")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -w")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -w")
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -w")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -w")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -w")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -w")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -w")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -w")
+ set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} -w")
endif()
# On Unix we use two dynamic loading libraries dl and ltdl.
@@ -128,7 +141,7 @@ macro(enable_profile)
# Declare the profiling configurations:
SET(CMAKE_CXX_FLAGS_DEBUGPROFILE
- "${CMAKE_CXX_FLAGS_DEBUG} ${PCXX_ROFILING}"
+ "${CMAKE_CXX_FLAGS_DEBUG} ${CXX_PROFILING}"
CACHE STRING "Flags used by the C++ compiler during profile builds."
FORCE )
SET(CMAKE_C_FLAGS_DEBUGPROFILE
@@ -171,7 +184,7 @@ macro(enable_profile)
CMAKE_EXE_LINKER_FLAGS_RELEASEPROFILE
CMAKE_SHARED_LINKER_FLAGS_RELEASEPROFILE )
# The configuration types need to be set after their respective c/cxx/linker flags and before the project directive
- set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile" CACHE STRING "" FORCE)
+ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile;Coverage" CACHE STRING "" FORCE)
endmacro()
macro(set_exe_flags)
@@ -180,10 +193,12 @@ macro(set_exe_flags)
# We do not do that for MSVC since MSVC produces an awful lot of warnings for its own STL headers;
# the important warnings are turned on using #pragma in Globals.h
if (NOT MSVC)
- string(REPLACE "-w" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
- string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
- string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
- string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "-w" "" CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE}")
+ string(REPLACE "-w" "" CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE}")
add_flags_cxx("-Wall -Wextra -Wno-unused-parameter -Wno-error=switch")
# we support non-IEEE 754 fpus so can make no guarentees about error
diff --git a/lib/cmake-coverage/CodeCoverage.cmake b/lib/cmake-coverage/CodeCoverage.cmake
new file mode 100644
index 000000000..edf927fec
--- /dev/null
+++ b/lib/cmake-coverage/CodeCoverage.cmake
@@ -0,0 +1,160 @@
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# USAGE:
+# 1. Copy this file into your cmake modules path.
+#
+# 2. Add the following line to your CMakeLists.txt:
+# INCLUDE(CodeCoverage)
+#
+# 3. Set compiler flags to turn off optimization and enable coverage:
+# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#
+# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
+# which runs your test executable and produces a lcov code coverage report:
+# Example:
+# SETUP_TARGET_FOR_COVERAGE(
+# my_coverage_target # Name for custom target.
+# test_driver # Name of the test driver executable that runs the tests.
+# # NOTE! This should always have a ZERO as exit code
+# # otherwise the coverage generation will not complete.
+# coverage # Name of output directory.
+# )
+#
+# 4. Build a Debug build:
+# cmake -DCMAKE_BUILD_TYPE=Debug ..
+# make
+# make my_coverage_target
+#
+#
+
+# Check prereqs
+FIND_PROGRAM( GCOV_PATH gcov )
+FIND_PROGRAM( LCOV_PATH lcov )
+FIND_PROGRAM( GENHTML_PATH genhtml )
+FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
+
+IF(NOT GCOV_PATH)
+MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
+ENDIF() # NOT GCOV_PATH
+
+IF(NOT CMAKE_COMPILER_IS_GNUCXX)
+# Clang version 3.0.0 and greater now supports gcov as well.
+MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
+
+IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+ENDIF()
+ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX
+
+SET(CMAKE_CXX_FLAGS_COVERAGE
+ "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_COVERAGE
+ "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE )
+SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE )
+SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
+
+IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage"))
+ MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
+ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests.
+# MUST return ZERO always, even on errors.
+# If not, no coverage report will be created!
+# Param _outputname lcov output is generated as _outputname.info
+# HTML report is generated in _outputname/index.html
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
+
+IF(NOT LCOV_PATH)
+MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
+ENDIF() # NOT LCOV_PATH
+
+IF(NOT GENHTML_PATH)
+MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
+ENDIF() # NOT GENHTML_PATH
+
+# Setup target
+ADD_CUSTOM_TARGET(${_targetname}
+
+# Cleanup lcov
+${LCOV_PATH} --directory . --zerocounters
+
+# Run tests
+COMMAND ${_testrunner} ${ARGV3}
+
+# Capturing lcov counters and generating report
+COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
+COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
+COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
+COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+
+WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
+)
+
+# Show info where to find the report
+ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+COMMAND ;
+COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
+)
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
+
+# Param _targetname The name of new the custom make target
+# Param _testrunner The name of the target which runs the tests
+# Param _outputname cobertura output is generated as _outputname.xml
+# Optional fourth parameter is passed as arguments to _testrunner
+# Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
+
+IF(NOT PYTHON_EXECUTABLE)
+MESSAGE(FATAL_ERROR "Python not found! Aborting...")
+ENDIF() # NOT PYTHON_EXECUTABLE
+
+IF(NOT GCOVR_PATH)
+MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
+ENDIF() # NOT GCOVR_PATH
+
+ADD_CUSTOM_TARGET(${_targetname}
+
+# Run tests
+${_testrunner} ${ARGV3}
+
+# Running gcovr
+COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
+WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+COMMENT "Running gcovr to produce Cobertura code coverage report."
+)
+
+# Show info where to find the report
+ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+COMMAND ;
+COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
+)
+
+ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
diff --git a/lib/cmake-coverage/LICENSE b/lib/cmake-coverage/LICENSE
new file mode 100644
index 000000000..36b7cd93c
--- /dev/null
+++ b/lib/cmake-coverage/LICENSE
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/lib/polarssl.cmake b/lib/polarssl.cmake
index d57cc9220..91f0fa145 100644
--- a/lib/polarssl.cmake
+++ b/lib/polarssl.cmake
@@ -1,5 +1,11 @@
if(NOT TARGET polarssl)
message("including polarssl")
- add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl EXCLUDE_FROM_ALL )
+ if (SELF_TEST)
+ set(ENABLE_TESTING OFF CACHE BOOL "Disable tests")
+ set(ENABLE_PROGRAMS OFF CACHE BOOL "Disable programs")
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl)
+ else()
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/polarssl/ ${CMAKE_CURRENT_BINARY_DIR}/lib/polarssl EXCLUDE_FROM_ALL)
+ endif()
endif()
diff --git a/src/BiomeDef.h b/src/BiomeDef.h
index 67916890d..f929596e9 100644
--- a/src/BiomeDef.h
+++ b/src/BiomeDef.h
@@ -10,7 +10,7 @@
#pragma once
-
+#include "StringUtils.h"
// tolua_begin
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index 9e20a0983..fd2f3c9b4 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -9,7 +9,7 @@
#include "OSSupport/GZipFile.h"
#include "Blocks/BlockHandler.h"
#include "Cuboid.h"
-
+#include "ChunkBuffer.h"
@@ -1835,116 +1835,88 @@ bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ)
-void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
+void cBlockArea::cChunkReader::ChunkBuffer(const cChunkBuffer & a_BlockBuffer)
{
- if (m_Area.m_BlockTypes == NULL)
{
- // Don't want BlockTypes
- return;
- }
-
- int SizeY = m_Area.m_Size.y;
- int MinY = m_Origin.y;
-
- // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
- // OffX, OffZ are the offsets of the current chunk data from the area origin
- // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
- int SizeX = cChunkDef::Width;
- int SizeZ = cChunkDef::Width;
- int OffX, OffZ;
- int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
- if (OffX < 0)
- {
- BaseX = -OffX;
- SizeX += OffX; // SizeX is decreased, OffX is negative
- OffX = 0;
- }
- else
- {
- BaseX = 0;
- }
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
- if (OffZ < 0)
- {
- BaseZ = -OffZ;
- SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
- OffZ = 0;
- }
- else
- {
- BaseZ = 0;
- }
- // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
- {
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
- }
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
- {
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
- }
-
- for (int y = 0; y < SizeY; y++)
- {
- int ChunkY = MinY + y;
- int AreaY = y;
- for (int z = 0; z < SizeZ; z++)
+ if (!(m_Area.m_BlockTypes == NULL))
{
- int ChunkZ = BaseZ + z;
- int AreaZ = OffZ + z;
- for (int x = 0; x < SizeX; x++)
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
+
+ // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
+ // OffX, OffZ are the offsets of the current chunk data from the area origin
+ // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders
+ int SizeX = cChunkDef::Width;
+ int SizeZ = cChunkDef::Width;
+ int OffX, OffZ;
+ int BaseX, BaseZ;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
+ if (OffX < 0)
{
- int ChunkX = BaseX + x;
- int AreaX = OffX + x;
- m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ);
- } // for x
- } // for z
- } // for y
-}
-
-
-
+ BaseX = -OffX;
+ SizeX += OffX; // SizeX is decreased, OffX is negative
+ OffX = 0;
+ }
+ else
+ {
+ BaseX = 0;
+ }
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
+ if (OffZ < 0)
+ {
+ BaseZ = -OffZ;
+ SizeZ += OffZ; // SizeZ is decreased, OffZ is negative
+ OffZ = 0;
+ }
+ else
+ {
+ BaseZ = 0;
+ }
+ // If the chunk extends beyond the area in the X or Z axis, cut off the Size:
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
+ {
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
+ }
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
+ {
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
+ }
+ for (int y = 0; y < SizeY; y++)
+ {
+ int ChunkY = MinY + y;
+ int AreaY = y;
+ for (int z = 0; z < SizeZ; z++)
+ {
+ int ChunkZ = BaseZ + z;
+ int AreaZ = OffZ + z;
+ for (int x = 0; x < SizeX; x++)
+ {
+ int ChunkX = BaseX + x;
+ int AreaX = OffX + x;
+ m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockBuffer.GetBlock(ChunkX, ChunkY, ChunkZ);
+ } // for x
+ } // for z
+ } // for y
+ }
+ }
-void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas)
-{
- if (m_Area.m_BlockMetas == NULL)
+ if (m_Area.m_BlockMetas)
{
- // Don't want metas
- return;
+ a_BlockBuffer.CopyMeta(m_Area.m_BlockMetas);
}
- CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight)
-{
- if (m_Area.m_BlockLight == NULL)
+ if (m_Area.m_BlockLight)
{
- // Don't want light
- return;
+ a_BlockBuffer.CopyLight(m_Area.m_BlockLight);
}
- CopyNibbles(m_Area.m_BlockLight, a_BlockLight);
-}
-
-
-
-
-void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight)
-{
- if (m_Area.m_BlockSkyLight == NULL)
+ if (m_Area.m_BlockSkyLight)
{
- // Don't want skylight
- return;
+ a_BlockBuffer.CopySkyLight(m_Area.m_BlockSkyLight);
}
- CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight);
-}
+}
diff --git a/src/BlockArea.h b/src/BlockArea.h
index 6dba0f12e..50c28aaf2 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -317,10 +317,7 @@ protected:
// cChunkDataCallback overrides:
virtual bool Coords (int a_ChunkX, int a_ChunkZ) override;
- virtual void BlockTypes (const BLOCKTYPE * a_BlockTypes) override;
- virtual void BlockMeta (const NIBBLETYPE * a_BlockMetas) override;
- virtual void BlockLight (const NIBBLETYPE * a_BlockLight) override;
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override;
+ virtual void ChunkBuffer (const cChunkBuffer & a_BlockTypes) override;
} ;
typedef NIBBLETYPE * NIBBLEARRAY;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index ca536e89a..0303e1502 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -241,23 +241,9 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
a_Callback.HeightMap (&m_HeightMap);
a_Callback.BiomeData (&m_BiomeMap);
- COMPRESSED_BLOCKTYPE Blocks = m_BlockTypes;
- Blocks.resize(NumBlocks);
- a_Callback.BlockTypes (&Blocks[0]);
-
- COMPRESSED_NIBBLETYPE Metas = m_BlockMeta;
- Metas.resize(NumBlocks / 2);
- a_Callback.BlockMeta (&Metas[0]);
-
a_Callback.LightIsValid (m_IsLightValid);
- COMPRESSED_NIBBLETYPE BlockLights = m_BlockLight;
- BlockLights.resize(NumBlocks / 2);
- a_Callback.BlockLight (&BlockLights[0]);
-
- COMPRESSED_NIBBLETYPE BlockSkyLights = m_BlockSkyLight;
- BlockSkyLights.resize(NumBlocks / 2, 0xff);
- a_Callback.BlockSkyLight(&BlockSkyLights[0]);
+ a_Callback.ChunkBuffer (m_ChunkBuffer);
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{
@@ -296,48 +282,10 @@ void cChunk::SetAllData(
CalculateHeightmap(a_BlockTypes);
}
- int IdxWhereNonEmptyStarts = 0;
- { // Blocktype compression
- unsigned char Highest = 0;
- int X = 0, Z = 0;
- m_BlockTypes.clear();
-
- for (int x = 0; x < Width; x++)
- {
- for (int z = 0; z < Width; z++)
- {
- unsigned char Height = m_HeightMap[x + z * Width];
- if (Height > Highest)
- {
- Highest = Height;
- X = x; Z = z;
- }
- }
- }
-
- IdxWhereNonEmptyStarts = MakeIndexNoCheck(X, Highest + 1, Z);
-
- m_BlockTypes.insert(m_BlockTypes.end(), &a_BlockTypes[0], &a_BlockTypes[IdxWhereNonEmptyStarts]);
- }
-
- { // Blockmeta compression
- m_BlockMeta.clear();
- m_BlockMeta.insert(m_BlockMeta.end(), &a_BlockMeta[0], &a_BlockMeta[IdxWhereNonEmptyStarts / 2]);
- }
-
- if (a_BlockLight != NULL)
- {
- // Compress blocklight
- m_BlockLight.clear();
- m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts / 2]);
- }
-
- if (a_BlockSkyLight != NULL)
- {
- // Compress skylight
- m_BlockSkyLight.clear();
- m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_BlockSkyLight[0], &a_BlockSkyLight[IdxWhereNonEmptyStarts / 2]);
- }
+ m_ChunkBuffer.SetBlocks (a_BlockTypes);
+ m_ChunkBuffer.SetMeta (a_BlockMeta);
+ m_ChunkBuffer.SetLight (a_BlockLight);
+ m_ChunkBuffer.SetSkyLight (a_BlockSkyLight);
m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL);
@@ -378,15 +326,9 @@ void cChunk::SetLight(
// TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation.
// Postponing until we see how bad it is :)
- { // Compress blocklight
- m_BlockLight.clear();
- m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size() / 2]);
- }
+ m_ChunkBuffer.SetLight (a_BlockLight);
- { // Compress skylight
- m_BlockSkyLight.clear();
- m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size() / 2]);
- }
+ m_ChunkBuffer.SetSkyLight (a_SkyLight);
m_IsLightValid = true;
}
@@ -397,8 +339,7 @@ void cChunk::SetLight(
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
{
- std::copy(m_BlockTypes.begin(), m_BlockTypes.end(), a_BlockTypes);
- std::fill_n(&a_BlockTypes[m_BlockTypes.size()], NumBlocks - m_BlockTypes.size(), E_BLOCK_AIR);
+ m_ChunkBuffer.CopyBlocks(a_BlockTypes);
}
@@ -684,8 +625,7 @@ void cChunk::Tick(float a_Dt)
void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ)
{
- unsigned Index = MakeIndex(a_RelX, a_RelY, a_RelZ);
- cBlockHandler * Handler = BlockHandler(GetBlock(Index));
+ cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*this->GetWorld());
@@ -810,19 +750,18 @@ void cChunk::CheckBlocks()
{
return;
}
- std::vector<unsigned int> ToTickBlocks;
+ std::vector<Vector3i> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks);
cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World);
- for (std::vector<unsigned int>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
+ for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
{
- unsigned int index = (*itr);
- Vector3i BlockPos = IndexToCoordinate(index);
+ Vector3i Pos = (*itr);
- cBlockHandler * Handler = BlockHandler(GetBlock(index));
- Handler->Check(ChunkInterface, PluginInterface, BlockPos.x, BlockPos.y, BlockPos.z, *this);
+ cBlockHandler * Handler = BlockHandler(GetBlock(Pos));
+ Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this);
} // for itr - ToTickBlocks[]
}
@@ -865,8 +804,7 @@ void cChunk::TickBlocks(void)
continue; // It's all air up here
}
- unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
- cBlockHandler * Handler = BlockHandler(GetBlock(Index));
+ cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ));
ASSERT(Handler != NULL); // Happenned on server restart, FS #243
Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ);
} // for i - tickblocks
@@ -1258,9 +1196,8 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB
// The chunk is not available, bail out
return false;
}
- int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ);
- a_BlockLight = Chunk->GetBlockLight(idx);
- a_SkyLight = Chunk->GetSkyLight(idx);
+ a_BlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
return true;
}
@@ -1465,11 +1402,9 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes)
void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
-
- const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
// Tick this block and its neighbors:
- m_ToTickBlocks.push_back(index);
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
// If there was a block entity, remove it:
@@ -1533,7 +1468,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
return;
}
- m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ));
+ m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
}
@@ -1571,9 +1506,8 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
ASSERT(IsValid());
- const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- const BLOCKTYPE OldBlockType = GetBlock(index);
- const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index);
+ const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ const BLOCKTYPE OldBlockMeta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta))
{
return;
@@ -1581,11 +1515,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
MarkDirty();
- if ((size_t)index >= m_BlockTypes.size())
- {
- m_BlockTypes.resize(index + 1);
- }
- m_BlockTypes[index] = a_BlockType;
+ m_ChunkBuffer.SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType);
// The client doesn't need to distinguish between stationary and nonstationary fluids:
if (
@@ -1601,7 +1531,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta));
}
- SetNibble(m_BlockMeta, index, a_BlockMeta);
+ m_ChunkBuffer.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta);
// ONLY recalculate lighting if it's necessary!
if (
@@ -1624,7 +1554,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
{
for (int y = a_RelY - 1; y > 0; --y)
{
- if (GetBlock(MakeIndexNoCheck(a_RelX, y, a_RelZ)) != E_BLOCK_AIR)
+ if (GetBlock(a_RelX, y, a_RelZ) != E_BLOCK_AIR)
{
m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y;
break;
@@ -1658,19 +1588,16 @@ void cChunk::SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta)
void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client)
{
- // The coords must be valid, because the upper level already does chunk lookup. No need to check them again.
- // There's an debug-time assert in MakeIndexNoCheck anyway
- unsigned int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
if (a_Client == NULL)
{
// Queue the block for all clients in the chunk (will be sent in Tick())
- m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(index), GetMeta(index)));
+ m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)));
return;
}
Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ);
- a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(index), GetMeta(index));
+ a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ));
// FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
@@ -2529,27 +2456,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
return 0; // Clip
}
- return GetBlock(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ));
-}
-
-
-
-
-
-BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
-{
- if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks))
- {
- ASSERT(!"GetBlock(idx) out of bounds!");
- return 0;
- }
-
- if ((size_t)a_BlockIdx >= m_BlockTypes.size())
- {
- return E_BLOCK_AIR;
- }
-
- return m_BlockTypes[a_BlockIdx];
+ return m_ChunkBuffer.GetBlock(a_RelX, a_RelY, a_RelZ);
}
@@ -2558,9 +2465,8 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const
void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = GetBlock(Idx);
- a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_BlockMeta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
}
@@ -2569,11 +2475,10 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_
void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight)
{
- int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
- a_BlockType = GetBlock(Idx);
- a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx);
- a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx);
- a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx);
+ a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
+ a_Meta = m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
+ a_SkyLight = m_ChunkBuffer.GetSkyLight(a_RelX, a_RelY, a_RelZ);
+ a_BlockLight = m_ChunkBuffer.GetBlockLight(a_RelX, a_RelY, a_RelZ);
}
diff --git a/src/Chunk.h b/src/Chunk.h
index 84ec35496..d2328971f 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -3,6 +3,7 @@
#include "Entities/Entity.h"
#include "ChunkDef.h"
+#include "ChunkBuffer.h"
#include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h"
@@ -66,6 +67,7 @@ public:
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks
);
+ cChunk(cChunk& other);
~cChunk();
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated)
@@ -154,7 +156,7 @@ public:
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const;
- BLOCKTYPE GetBlock(int a_BlockIdx) const;
+ BLOCKTYPE GetBlock(Vector3i a_cords) const { return GetBlock(a_cords.x,a_cords.y,a_cords.z);}
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
@@ -320,15 +322,17 @@ public:
m_BlockTickZ = a_RelZ;
}
- inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const { return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
- inline NIBBLETYPE GetMeta(int a_BlockIdx) const { return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
- inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { SetMeta(MakeIndex(a_RelX, a_RelY, a_RelZ), a_Meta); }
- void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta);
+ inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ return m_ChunkBuffer.GetMeta(a_RelX, a_RelY, a_RelZ);
+ }
+ inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
+ {
+ m_ChunkBuffer.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta);
+ }
- inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
- inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ, true); }
- inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); }
- inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx, true); }
+ inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkBuffer.GetBlockLight(a_RelX, a_RelY, a_RelZ); }
+ inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkBuffer.GetSkyLight(a_RelX, a_RelY, a_RelZ); }
/** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
@@ -403,8 +407,8 @@ private:
bool m_IsSaving; // True if the chunk is being saved
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
- std::vector<unsigned int> m_ToTickBlocks;
- sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
+ std::vector<Vector3i> m_ToTickBlocks;
+ sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick
@@ -420,10 +424,7 @@ private:
cWorld * m_World;
cChunkMap * m_ChunkMap;
- COMPRESSED_BLOCKTYPE m_BlockTypes;
- COMPRESSED_NIBBLETYPE m_BlockMeta;
- COMPRESSED_NIBBLETYPE m_BlockLight;
- COMPRESSED_NIBBLETYPE m_BlockSkyLight;
+ cChunkBuffer m_ChunkBuffer;
cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_BiomeMap;
diff --git a/src/ChunkBuffer.cpp b/src/ChunkBuffer.cpp
new file mode 100644
index 000000000..a41b8f61a
--- /dev/null
+++ b/src/ChunkBuffer.cpp
@@ -0,0 +1,297 @@
+
+#include "Globals.h"
+#include "ChunkBuffer.h"
+
+cChunkBuffer cChunkBuffer::Copy() const
+{
+ cChunkBuffer copy;
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ if(m_Sections[i])
+ {
+ copy.m_Sections[i] = Allocate();
+ *copy.m_Sections[i] = *m_Sections[i];
+ }
+ }
+ return copy;
+}
+
+
+
+
+
+void cChunkBuffer::CopyBlocks (BLOCKTYPE * a_dest, size_t a_Idx, size_t length) const
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16;
+ if (a_Idx > 0) a_Idx = a_Idx > length ? a_Idx - length : 0;
+ if (a_Idx == 0)
+ {
+ size_t tocopy = length > segment_length ? segment_length : length;
+ length -= tocopy;
+ if(m_Sections[i])
+ {
+ memcpy(
+ &a_dest[i * segment_length],
+ &m_Sections[i]->m_BlockTypes,
+ sizeof(BLOCKTYPE) * length
+ );
+ }
+ else
+ {
+ memset(
+ &a_dest[i * segment_length],
+ 0,
+ sizeof(BLOCKTYPE) * length
+ );
+ }
+ }
+ }
+}
+
+
+
+
+
+void cChunkBuffer::CopyMeta(NIBBLETYPE * a_dest) const
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if(m_Sections[i])
+ {
+ memcpy(
+ &a_dest[i * segment_length],
+ &m_Sections[i]->m_BlockMeta,
+ sizeof(NIBBLETYPE) * segment_length);
+ }
+ else
+ {
+ memset(
+ &a_dest[i * segment_length],
+ 0,
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ }
+}
+
+
+
+
+
+void cChunkBuffer::CopyLight(NIBBLETYPE * a_dest) const
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if(m_Sections[i])
+ {
+ memcpy(
+ &a_dest[i * segment_length],
+ &m_Sections[i]->m_BlockLight,
+ sizeof(NIBBLETYPE) * segment_length
+ );
+ }
+ else
+ {
+ memset(
+ &a_dest[i * segment_length],
+ 0,
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ }
+}
+
+
+
+
+
+void cChunkBuffer::CopySkyLight(NIBBLETYPE * a_dest) const
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if(m_Sections[i])
+ {
+ memcpy(
+ &a_dest[i * segment_length],
+ &m_Sections[i]->m_BlockSkyLight,
+ sizeof(NIBBLETYPE) * segment_length
+ );
+ }
+ else
+ {
+ memset(
+ &a_dest[i * segment_length],
+ 0xFF,
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ }
+}
+
+
+
+
+
+void cChunkBuffer::SetBlocks(const BLOCKTYPE * a_src)
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if (m_Sections[i])
+ {
+ memcpy(&m_Sections[i]->m_BlockTypes, &a_src[i * segment_length], sizeof(BLOCKTYPE) * segment_length);
+ }
+ else
+ {
+ size_t j = 0;
+ // do nothing whilst 0
+ for (; j < segment_length && a_src[i * segment_length + j] == 0; j++);
+ if (j != segment_length)
+ {
+ m_Sections[i] = Allocate();
+ memcpy(
+ &m_Sections[i]->m_BlockTypes,
+ &a_src[i * segment_length],
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ else
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = 0;
+ }
+ }
+ }
+}
+
+
+
+
+void cChunkBuffer::SetMeta(const NIBBLETYPE * a_src)
+{
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if (m_Sections[i])
+ {
+ memcpy(&m_Sections[i]->m_BlockMeta, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
+ }
+ else
+ {
+ size_t j = 0;
+ // do nothing whilst 0
+ for (; j < segment_length && a_src[i * segment_length + j] == 0; j++);
+ if (j != segment_length)
+ {
+ m_Sections[i] = Allocate();
+ memcpy(
+ &m_Sections[i]->m_BlockMeta,
+ &a_src[i * segment_length],
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ else
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = 0;
+ }
+ }
+ }
+}
+
+
+
+
+void cChunkBuffer::SetLight(const NIBBLETYPE * a_src)
+{
+ if (!a_src) return;
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if (m_Sections[i])
+ {
+ memcpy(&m_Sections[i]->m_BlockLight, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
+ }
+ else
+ {
+ size_t j = 0;
+ // do nothing whilst 0
+ for (; j < segment_length && a_src[i * segment_length + j] == 0; j++);
+ if (j != segment_length)
+ {
+ m_Sections[i] = Allocate();
+ memcpy(
+ &m_Sections[i]->m_BlockLight,
+ &a_src[i * segment_length],
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ else
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = 0;
+ }
+ }
+ }
+}
+
+
+
+
+void cChunkBuffer::SetSkyLight (const NIBBLETYPE * a_src)
+{
+ if (!a_src) return;
+ for (size_t i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ const size_t segment_length = CHUNK_SECTION_HEIGHT * 16 * 16 / 2;
+ if (m_Sections[i])
+ {
+ memcpy(&m_Sections[i]->m_BlockSkyLight, &a_src[i * segment_length], sizeof(NIBBLETYPE) * segment_length);
+ }
+ else
+ {
+ size_t j = 0;
+ // do nothing whilst 0
+ for (; j < segment_length && a_src[i * segment_length + j] == 0xFF; j++);
+ if (j != segment_length)
+ {
+ m_Sections[i] = Allocate();
+ memcpy(
+ &m_Sections[i]->m_BlockSkyLight,
+ &a_src[i * segment_length],
+ sizeof(BLOCKTYPE) * segment_length
+ );
+ }
+ else
+ {
+ Free(m_Sections[i]);
+ m_Sections[i] = 0;
+ }
+ }
+ }
+}
+
+
+
+
+
+cChunkBuffer::sChunkSection * cChunkBuffer::Allocate() const
+{
+ // TODO: use a allocation pool
+ return new cChunkBuffer::sChunkSection;
+}
+
+
+
+void cChunkBuffer::Free(cChunkBuffer::sChunkSection * ptr) const
+{
+ delete ptr;
+}
+
+
+
diff --git a/src/ChunkBuffer.h b/src/ChunkBuffer.h
new file mode 100644
index 000000000..410532232
--- /dev/null
+++ b/src/ChunkBuffer.h
@@ -0,0 +1,319 @@
+
+#pragma once
+
+
+#include <cstring>
+
+
+#include "ChunkDef.h"
+
+
+#define CHUNK_SECTION_HEIGHT 16
+#define CHUNK_SECTION_NUM (256 / CHUNK_SECTION_HEIGHT)
+
+#if __cplusplus < 201103L
+// auto_ptr style interface for memory management
+#else
+// unique_ptr style interface for memory management
+#endif
+
+class cChunkBuffer
+{
+public:
+
+ cChunkBuffer()
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ : IsOwner(true)
+ #endif
+ {
+ memset(m_Sections, 0, sizeof(m_Sections));
+ }
+ ~cChunkBuffer()
+ {
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ if(!IsOwner) return;
+ #endif
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ if(m_Sections[i]) Free(m_Sections[i]);;
+ }
+ }
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ cChunkBuffer(const cChunkBuffer& other) :
+ IsOwner(true)
+ {
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ m_Sections[i] = other.m_Sections[i];
+ }
+ other.IsOwner = false;
+ }
+
+ void operator=(const cChunkBuffer& other)
+ {
+ if(IsOwner)
+ {
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ if(m_Sections[i]) Free(m_Sections[i]);;
+ }
+ }
+ IsOwner = true;
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ m_Sections[i] = other.m_Sections[i];
+ }
+ other.IsOwner = false;
+ }
+ #else
+ // unique_ptr style interface for memory management
+ cChunkBuffer(const cChunkBuffer&& other)
+ {
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ m_Sections[i] = other.m_Sections[i];
+ }
+ }
+
+ void operator=(const cChunkBuffer&& other)
+ {
+ for (int i = 0; i < CHUNK_SECTION_NUM; i++)
+ {
+ if(m_Sections[i]) Free(m_Sections[i]);;
+ m_Sections[i] = other.m_Sections[i];
+ }
+ }
+ #endif
+
+ BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const
+ {
+ ASSERT((a_X >= 0) && (a_X < cChunkDef::Width));
+ ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height));
+ ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width));
+ int Section = a_Y / CHUNK_SECTION_HEIGHT;
+ if(m_Sections[Section])
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * CHUNK_SECTION_HEIGHT), a_Z);
+ return m_Sections[Section]->m_BlockTypes[Index];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block)
+ {
+ if (
+ (a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
+ (a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
+ (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
+ )
+ {
+ ASSERT(!"cChunkBuffer::SetMeta(): index out of range!");
+ return;
+ }
+
+ int Section = a_RelY / CHUNK_SECTION_HEIGHT;
+ if(!m_Sections[Section])
+ {
+ m_Sections[Section] = Allocate();
+ if(!m_Sections[Section])
+ {
+ ASSERT("Failed to allocate a new section in Chunkbuffer");
+ return;
+ }
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
+ m_Sections[Section]->m_BlockTypes[Index] = a_Block;
+ }
+
+ NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
+ {
+ int Section = a_RelY / CHUNK_SECTION_HEIGHT;
+ if(m_Sections[Section])
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
+ return (m_Sections[Section]->m_BlockMeta[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
+ return 0;
+ }
+
+ void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble)
+ {
+ if (
+ (a_RelX >= cChunkDef::Width) || (a_RelX < 0) ||
+ (a_RelY >= cChunkDef::Height) || (a_RelY < 0) ||
+ (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0)
+ )
+ {
+ ASSERT(!"cChunkBuffer::SetMeta(): index out of range!");
+ return;
+ }
+
+ int Section = a_RelY / CHUNK_SECTION_HEIGHT;
+ if(!m_Sections[Section])
+ {
+ m_Sections[Section] = Allocate();
+ if(!m_Sections[Section])
+ {
+ ASSERT("Failed to allocate a new section in Chunkbuffer");
+ return;
+ }
+ }
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
+ m_Sections[Section]->m_BlockMeta[Index / 2] = static_cast<NIBBLETYPE>(
+ (m_Sections[Section]->m_BlockMeta[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
+ ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
+ );
+ }
+
+ NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
+ {
+ int Section = a_RelY / CHUNK_SECTION_HEIGHT;
+ if(m_Sections[Section])
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
+ return 0;
+ }
+
+ NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const
+ {
+ if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1))
+ {
+ int Section = a_RelY / CHUNK_SECTION_HEIGHT;
+ if(m_Sections[Section])
+ {
+ int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * CHUNK_SECTION_HEIGHT), a_RelZ);
+ return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
+ }
+ else
+ {
+ return 0xFF;
+ }
+ }
+ ASSERT(!"cChunkBuffer::GetMeta(): coords out of chunk range!");
+ return 0;
+ }
+
+ cChunkBuffer Copy() const;
+ void CopyBlocks (BLOCKTYPE * a_dest, size_t a_Idx = 0, size_t length = cChunkDef::NumBlocks) const;
+ void CopyMeta (NIBBLETYPE * a_dest) const;
+ void CopyLight (NIBBLETYPE * a_dest) const;
+ void CopySkyLight (NIBBLETYPE * a_dest) const;
+
+ void SetBlocks (const BLOCKTYPE * a_src);
+ void SetMeta (const NIBBLETYPE * a_src);
+ void SetLight (const NIBBLETYPE * a_src);
+ void SetSkyLight (const NIBBLETYPE * a_src);
+
+private:
+
+ #if __cplusplus < 201103L
+ // auto_ptr style interface for memory management
+ mutable bool IsOwner;
+ #endif
+
+ struct sChunkSection {
+ BLOCKTYPE m_BlockTypes [CHUNK_SECTION_HEIGHT * 16 * 16] ;
+ NIBBLETYPE m_BlockMeta [CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
+ NIBBLETYPE m_BlockLight [CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
+ NIBBLETYPE m_BlockSkyLight[CHUNK_SECTION_HEIGHT * 16 * 16 / 2];
+ };
+
+ sChunkSection *m_Sections[CHUNK_SECTION_NUM];
+
+ sChunkSection * Allocate() const;
+ void Free(sChunkSection * ptr) const;
+};
+
+
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer
+*/
+class cChunkBufferCollector :
+ public cChunkDataCallback
+{
+public:
+
+ cChunkBuffer m_BlockData;
+
+protected:
+
+ virtual void ChunkBuffer(const cChunkBuffer & a_BlockData) override
+ {
+ m_BlockData = a_BlockData.Copy();
+ }
+};
+
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
+*/
+class cChunkDataCollector :
+public cChunkDataCallback
+{
+public:
+
+ // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
+ unsigned char m_BlockData[cChunkDef::BlockDataSize];
+
+protected:
+
+ virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlocks(m_BlockData);
+ a_ChunkBuffer.CopyMeta(m_BlockData + cChunkDef::NumBlocks);
+ a_ChunkBuffer.CopyLight(m_BlockData + 3 * cChunkDef::NumBlocks / 2);
+ a_ChunkBuffer.CopySkyLight(m_BlockData + 2 * cChunkDef::NumBlocks);
+ }
+};
+
+/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers
+*/
+class cChunkDataSeparateCollector :
+public cChunkDataCallback
+{
+public:
+
+ cChunkDef::BlockTypes m_BlockTypes;
+ cChunkDef::BlockNibbles m_BlockMetas;
+ cChunkDef::BlockNibbles m_BlockLight;
+ cChunkDef::BlockNibbles m_BlockSkyLight;
+
+protected:
+
+ virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
+ {
+ a_ChunkBuffer.CopyBlocks(m_BlockTypes);
+ a_ChunkBuffer.CopyMeta(m_BlockMetas);
+ a_ChunkBuffer.CopyLight(m_BlockLight);
+ a_ChunkBuffer.CopySkyLight(m_BlockSkyLight);
+ }
+} ;
+
+
+
+
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 83f3c8f5f..d79f4b92b 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -328,6 +328,7 @@ private:
+class cChunkBuffer;
/** Interface class used for getting data out of a chunk using the GetAllData() function.
@@ -352,20 +353,11 @@ public:
/// Called once to provide biome data
virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); };
- /// Called once to export block types
- virtual void BlockTypes (const BLOCKTYPE * a_Type) {UNUSED(a_Type); };
+ /// Called once to let know if the chunk lighting is valid. Return value is ignored
+ virtual void LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); };
- /// Called once to export block meta
- virtual void BlockMeta (const NIBBLETYPE * a_Meta) {UNUSED(a_Meta); };
-
- /// Called once to let know if the chunk lighting is valid. Return value is used to control if BlockLight() and BlockSkyLight() are called next (if true)
- virtual bool LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); return true; };
-
- /// Called once to export block light
- virtual void BlockLight (const NIBBLETYPE * a_BlockLight) {UNUSED(a_BlockLight); };
-
- /// Called once to export sky light
- virtual void BlockSkyLight(const NIBBLETYPE * a_SkyLight) {UNUSED(a_SkyLight); };
+ /// Called once to export block info
+ virtual void ChunkBuffer (const cChunkBuffer & a_Buffer) {UNUSED(a_Buffer); };
/// Called for each entity in the chunk
virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); };
@@ -378,88 +370,6 @@ public:
-/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer
-*/
-class cChunkDataCollector :
- public cChunkDataCallback
-{
-public:
-
- // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
- unsigned char m_BlockData[cChunkDef::BlockDataSize];
-
-protected:
-
- virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
- {
- memcpy(m_BlockData, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
- }
-
-
- virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
- {
- memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2);
- }
-
-
- virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
- {
- memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2);
- }
-
-
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
- {
- memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2);
- }
-} ;
-
-
-
-
-
-/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers
-*/
-class cChunkDataSeparateCollector :
- public cChunkDataCallback
-{
-public:
-
- cChunkDef::BlockTypes m_BlockTypes;
- cChunkDef::BlockNibbles m_BlockMetas;
- cChunkDef::BlockNibbles m_BlockLight;
- cChunkDef::BlockNibbles m_BlockSkyLight;
-
-protected:
-
- virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
- {
- memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
- }
-
-
- virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
- {
- memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas));
- }
-
-
- virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
- {
- memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
- }
-
-
- virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
- {
- memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
- }
-} ;
-
-
-
-
-
/** Interface class used for comparing clients of two chunks.
Used primarily for entity moving while both chunks are locked.
*/
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index d7164a6a5..d3f44bef8 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -219,9 +219,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -242,8 +241,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockType = Chunk->GetBlock(Index);
+ a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -264,8 +262,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB
return false;
}
- int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ);
- a_BlockMeta = Chunk->GetMeta(Index);
+ a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
return true;
}
@@ -1484,9 +1481,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
res = false;
continue;
}
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- itr->BlockType = Chunk->GetBlock(idx);
- itr->BlockMeta = Chunk->GetMeta(idx);
+ itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z);
+ itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z);
}
return res;
}
diff --git a/src/ChunkSender.h b/src/ChunkSender.h
index a26f764a7..81b298a55 100644
--- a/src/ChunkSender.h
+++ b/src/ChunkSender.h
@@ -27,6 +27,7 @@ Note that it may be called by world's BroadcastToChunk() if the client is still
#include "OSSupport/IsThread.h"
#include "ChunkDef.h"
+#include "ChunkBuffer.h"
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index beb58f207..111c5fa84 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -55,9 +55,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx);
- NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
+ BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
+ NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
{
// Fallen onto a block that breaks this into pickups (e. g. half-slab)
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 5459644af..f961e35c6 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -18,20 +18,17 @@
class cReader :
public cChunkDataCallback
{
- virtual void BlockTypes(const BLOCKTYPE * a_Type) override
+ virtual void ChunkBuffer(const cChunkBuffer & a_ChunkBuffer) override
{
- // ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
- // C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
- typedef struct {BLOCKTYPE m_Row[16]; } ROW;
- ROW * InputRows = (ROW *)a_Type;
- ROW * OutputRows = (ROW *)m_BlockTypes;
+ BLOCKTYPE * OutputRows = m_BlockTypes;
int InputIdx = 0;
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
for (int y = 0; y < cChunkDef::Height; y++)
{
for (int z = 0; z < cChunkDef::Width; z++)
{
- OutputRows[OutputIdx] = InputRows[InputIdx++];
+ a_ChunkBuffer.CopyBlocks(OutputRows + OutputIdx * 16, InputIdx * 16, 16);
+ InputIdx++;
OutputIdx += 3;
} // for z
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
diff --git a/src/MobProximityCounter.cpp b/src/MobProximityCounter.cpp
index 519757c2c..ce20bf56b 100644
--- a/src/MobProximityCounter.cpp
+++ b/src/MobProximityCounter.cpp
@@ -24,7 +24,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl
if (a_Distance < it->second.m_Distance)
{
it->second.m_Distance = a_Distance;
- it->second.m_Chunk = a_Chunk;
+ it->second.m_Chunk = &a_Chunk;
}
}
@@ -36,7 +36,7 @@ void cMobProximityCounter::convertMaps()
{
for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); ++itr)
{
- m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk)));
+ m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,*itr->second.m_Chunk)));
}
}
diff --git a/src/MobProximityCounter.h b/src/MobProximityCounter.h
index 8a67139aa..79429eb60 100644
--- a/src/MobProximityCounter.h
+++ b/src/MobProximityCounter.h
@@ -16,9 +16,9 @@ protected :
// structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster)
struct sDistanceAndChunk
{
- sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {}
+ sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(&a_Chunk) {}
double m_Distance;
- cChunk& m_Chunk;
+ cChunk* m_Chunk;
};
struct sMonsterAndChunk
{
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 4fbfffd43..311f8b4c4 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -95,8 +95,10 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
int NumMSecs = (int)a_Dt;
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
{
- int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
- BLOCKTYPE BlockType = a_Chunk->GetBlock(idx);
+ int x = itr->x;
+ int y = itr->y;
+ int z = itr->z;
+ BLOCKTYPE BlockType = a_Chunk->GetBlock(x,y,z);
if (!IsAllowedBlock(BlockType))
{
@@ -125,7 +127,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
);
*/
- NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx);
+ NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z);
if (BlockMeta == 0x0f)
{
// The fire burnt out completely
@@ -140,7 +142,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun
if((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z))))
{
- a_Chunk->SetMeta(idx, BlockMeta + 1);
+ a_Chunk->SetMeta(x, y, z, BlockMeta + 1);
}
itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this
} // for itr - Data[]
diff --git a/src/StringUtils.h b/src/StringUtils.h
index caad85aef..87b574a34 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -11,6 +11,9 @@
+#include <string>
+
+
typedef std::string AString;
diff --git a/src/Vector3.h b/src/Vector3.h
index fed776018..5faac1457 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -5,6 +5,8 @@
#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
#include <math.h>
+#include <list>
+#include <vector>
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 2ac1d7962..c087ca8ef 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -717,10 +717,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca
-bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
{
m_IsLightValid = a_IsLightValid;
- return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
}
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 51d104970..6da2bc6dd 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../ChunkDef.h"
+#include "../ChunkBuffer.h"
@@ -121,7 +121,7 @@ protected:
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
// cChunkDataSeparateCollector overrides:
- virtual bool LightIsValid(bool a_IsLightValid) override;
+ virtual void LightIsValid(bool a_IsLightValid) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index 6d06b8fe3..7a113849a 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -107,15 +107,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
-bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
{
- if (!a_IsLightValid)
+ if (a_IsLightValid)
{
- return false;
+ m_Root["IsLightValid"] = true;
+ m_HasJsonData = true;
}
- m_Root["IsLightValid"] = true;
- m_HasJsonData = true;
- return true;
}
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 97e3b82f9..606853a16 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -14,6 +14,7 @@
#include "WorldStorage.h"
#include "../Vector3.h"
#include "json/json.h"
+#include "ChunkBuffer.h"
@@ -42,7 +43,7 @@ protected:
// cChunkDataCollector overrides:
virtual void Entity (cEntity * a_Entity) override;
virtual void BlockEntity (cBlockEntity * a_Entity) override;
- virtual bool LightIsValid (bool a_IsLightValid) override;
+ virtual void LightIsValid (bool a_IsLightValid) override;
} ;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 000000000..1e3a01dc8
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.6)
+
+enable_testing()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+add_subdirectory(ChunkBuffer)
diff --git a/tests/ChunkBuffer/CMakeLists.txt b/tests/ChunkBuffer/CMakeLists.txt
new file mode 100644
index 000000000..08d01d1a0
--- /dev/null
+++ b/tests/ChunkBuffer/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required (VERSION 2.6)
+
+enable_testing()
+
+include_directories(${CMAKE_SOURCE_DIR}/src/)
+
+add_library(ChunkBuffer ${CMAKE_SOURCE_DIR}/src/ChunkBuffer.cpp)
+
+
+add_executable(creatable-exe creatable.cpp)
+target_link_libraries(creatable-exe ChunkBuffer)
+add_test(NAME creatable-test COMMAND creatable-exe)
+
+add_executable(coordinates-exe Coordinates.cpp)
+target_link_libraries(coordinates-exe ChunkBuffer)
+add_test(NAME coordinates-test COMMAND coordinates-exe)
diff --git a/tests/ChunkBuffer/Coordinates.cpp b/tests/ChunkBuffer/Coordinates.cpp
new file mode 100644
index 000000000..d61eda7ad
--- /dev/null
+++ b/tests/ChunkBuffer/Coordinates.cpp
@@ -0,0 +1,15 @@
+
+#include "TestGlobals.h"
+#include "ChunkBuffer.h"
+
+
+
+int main(int argc, char** argv)
+{
+ cChunkBuffer buffer;
+ buffer.SetBlock(0,0,0, 0xAB);
+ assert(buffer.GetBlock(0,0,0) == 0xAB);
+ buffer.SetMeta(0,16,0, 0xC);
+ assert(buffer.GetMeta(0,16,0) == 0xC);
+ return 0;
+}
diff --git a/tests/ChunkBuffer/creatable.cpp b/tests/ChunkBuffer/creatable.cpp
new file mode 100644
index 000000000..49204c879
--- /dev/null
+++ b/tests/ChunkBuffer/creatable.cpp
@@ -0,0 +1,9 @@
+
+#include "TestGlobals.h"
+#include "ChunkBuffer.h"
+
+int main(int argc, char** argv)
+{
+ cChunkBuffer buffer;
+ return 0;
+}
diff --git a/tests/TestGlobals.h b/tests/TestGlobals.h
new file mode 100644
index 000000000..cb8fc9376
--- /dev/null
+++ b/tests/TestGlobals.h
@@ -0,0 +1,136 @@
+
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+
+
+// Compiler-dependent stuff:
+#if defined(_MSC_VER)
+ // MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether
+ #pragma warning(disable:4481)
+
+ // Disable some warnings that we don't care about:
+ #pragma warning(disable:4100) // Unreferenced formal parameter
+
+ // Useful warnings from warning level 4:
+ #pragma warning(3 : 4127) // Conditional expression is constant
+ #pragma warning(3 : 4189) // Local variable is initialized but not referenced
+ #pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch
+ #pragma warning(3 : 4310) // Cast truncates constant value
+ #pragma warning(3 : 4389) // Signed/unsigned mismatch
+ #pragma warning(3 : 4505) // Unreferenced local function has been removed
+ #pragma warning(3 : 4701) // Potentially unitialized local variable used
+ #pragma warning(3 : 4702) // Unreachable code
+ #pragma warning(3 : 4706) // Assignment within conditional expression
+
+ // Disabling this warning, because we know what we're doing when we're doing this:
+ #pragma warning(disable: 4355) // 'this' used in initializer list
+
+ // Disabled because it's useless:
+ #pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member
+
+ // 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places
+ // #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data
+
+ #define OBSOLETE __declspec(deprecated)
+
+ // No alignment needed in MSVC
+ #define ALIGN_8
+ #define ALIGN_16
+
+ #define FORMATSTRING(formatIndex, va_argsIndex)
+
+ // MSVC has its own custom version of zu format
+ #define SIZE_T_FMT "%Iu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
+ #define SIZE_T_FMT_HEX "%Ix"
+
+ #define NORETURN __declspec(noreturn)
+
+#elif defined(__GNUC__)
+
+ // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
+ #define abstract
+
+ // override is part of c++11
+ #if __cplusplus < 201103L
+ #define override
+ #endif
+
+ #define OBSOLETE __attribute__((deprecated))
+
+ #define ALIGN_8 __attribute__((aligned(8)))
+ #define ALIGN_16 __attribute__((aligned(16)))
+
+ // Some portability macros :)
+ #define stricmp strcasecmp
+
+ #define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
+
+ #define SIZE_T_FMT "%zu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
+ #define SIZE_T_FMT_HEX "%zx"
+
+ #define NORETURN __attribute((__noreturn__))
+
+#else
+
+ #error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
+
+ /*
+ // Copy and uncomment this into another #elif section based on your compiler identification
+
+ // Explicitly mark classes as abstract (no instances can be created)
+ #define abstract
+
+ // Mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class)
+ #define override
+
+ // Mark functions as obsolete, so that their usage results in a compile-time warning
+ #define OBSOLETE
+
+ // Mark types / variables for alignment. Do the platforms need it?
+ #define ALIGN_8
+ #define ALIGN_16
+ */
+
+#endif
+
+
+
+// Integral types with predefined sizes:
+typedef long long Int64;
+typedef int Int32;
+typedef short Int16;
+
+typedef unsigned long long UInt64;
+typedef unsigned int UInt32;
+typedef unsigned short UInt16;
+
+typedef unsigned char Byte;
+
+
+
+#define ASSERT(x) assert(x)
+
+
+#ifndef TOLUA_TEMPLATE_BIND
+#define TOLUA_TEMPLATE_BIND(x)
+#endif
+
+// A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc
+#define UNUSED(X) (void)(X)
+
+// Logging functions
+void LOGERROR(const char* a_Format, ...) FORMATSTRING(1,2);
+
+void LOGERROR(const char* a_Format, ...)
+{
+ va_list argList;
+ va_start(argList, a_Format);
+ vprintf(a_Format, argList);
+ va_end(argList);
+}
+
+
diff --git a/uploadCoverage.sh b/uploadCoverage.sh
new file mode 100644
index 000000000..0897479ae
--- /dev/null
+++ b/uploadCoverage.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+if [TRAVIS_MCSERVER_BUILD_TYPE == "COVERAGE"] then
+ coveralls --exclude lib --exclude tests
+fi