diff options
36 files changed, 1395 insertions, 431 deletions
diff --git a/.travis.yml b/.travis.yml index 0ab25ae3b..73d7eb557 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 100755 index 000000000..20785a488 --- /dev/null +++ b/CIbuild.sh @@ -0,0 +1,9 @@ + #!/usr/bin/env bash + +set -e + +cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1; +make -j 2; +make -j 2 test; +cd MCServer/; +echo stop | $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/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject 5c8557d4fdfa580c100510cde07a1a778ea2e24 +Subproject 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be5 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..a986ac076 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; @@ -1638,39 +1568,18 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT -void cChunk::SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) -{ - if (GetNibble(m_BlockMeta, a_BlockIdx) == a_Meta) - { - return; - } - - MarkDirty(); - SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); - Vector3i Coords(IndexToCoordinate(a_BlockIdx)); - - m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, Coords.x, Coords.y, Coords.z, GetBlock(a_BlockIdx), 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 +2438,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 +2447,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 +2457,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..26f1e9d10 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,23 @@ 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) + { + if (!GetMeta(a_RelX, a_RelY, a_RelZ) == a_Meta) + { + MarkDirty(); + m_ChunkBuffer.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta); + + m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(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 +413,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 +430,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..baeeff890 --- /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) * tocopy + ); + } + else + { + memset( + &a_dest[i * segment_length], + 0, + sizeof(BLOCKTYPE) * tocopy + ); + } + } + } +} + + + + + +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; + 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..b1bd024d5 --- /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..73dc79e25 --- /dev/null +++ b/tests/ChunkBuffer/CMakeLists.txt @@ -0,0 +1,20 @@ +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) + +add_executable(copies-exe Copies.cpp) +target_link_libraries(copies-exe ChunkBuffer) +add_test(NAME copies-test COMMAND copies-exe) diff --git a/tests/ChunkBuffer/Coordinates.cpp b/tests/ChunkBuffer/Coordinates.cpp new file mode 100644 index 000000000..a6a8aa18f --- /dev/null +++ b/tests/ChunkBuffer/Coordinates.cpp @@ -0,0 +1,106 @@ + +#include "TestGlobals.h" +#include "ChunkBuffer.h" + + + +int main(int argc, char** argv) +{ + cChunkBuffer buffer; + + // Empty chunks + buffer.SetBlock(0,0,0, 0xAB); + testassert(buffer.GetBlock(0,0,0) == 0xAB); + buffer.SetMeta(0,16,0, 0xC); + testassert(buffer.GetMeta(0,16,0) == 0xC); + + // loaded but not written segments + testassert(buffer.GetBlock(1,0,0) == 0x0); + testassert(buffer.GetMeta(1,16,0) == 0x0); + + // Notloaded segments + testassert(buffer.GetBlock(0,32,0) == 0x0); + testassert(buffer.GetMeta(0,48,0) == 0x0); + + // Out of Range + CheckAsserts( + buffer.SetBlock(-1, 0, 0, 0); + ); + CheckAsserts( + buffer.SetBlock(0, -1, 0, 0); + ); + CheckAsserts( + buffer.SetBlock(0, 0, -1, 0); + ); + CheckAsserts( + buffer.SetBlock(256, 0, 0, 0); + ); + CheckAsserts( + buffer.SetBlock(0, 256, 0, 0); + ); + CheckAsserts( + buffer.SetBlock(0, 0, 256, 0); + ); + + // Out of Range + CheckAsserts( + buffer.GetBlock(-1, 0, 0); + ); + CheckAsserts( + buffer.GetBlock(0, -1, 0); + ); + CheckAsserts( + buffer.GetBlock(0, 0, -1); + ); + CheckAsserts( + buffer.GetBlock(256, 0, 0); + ); + CheckAsserts( + buffer.GetBlock(0, 256, 0); + ); + CheckAsserts( + buffer.GetBlock(0, 0, 256); + ); + + // Out of Range + CheckAsserts( + buffer.SetMeta(-1, 0, 0, 0); + ); + CheckAsserts( + buffer.SetMeta(0, -1, 0, 0); + ); + CheckAsserts( + buffer.SetMeta(0, 0, -1, 0); + ); + CheckAsserts( + buffer.SetMeta(256, 0, 0, 0); + ); + CheckAsserts( + buffer.SetMeta(0, 256, 0, 0); + ); + CheckAsserts( + buffer.SetMeta(0, 0, 256, 0); + ); + + // Out of Range + CheckAsserts( + buffer.GetMeta(-1, 0, 0); + ); + CheckAsserts( + buffer.GetMeta(0, -1, 0); + ); + CheckAsserts( + buffer.GetMeta(0, 0, -1); + ); + CheckAsserts( + buffer.GetMeta(256, 0, 0); + ); + CheckAsserts( + buffer.GetMeta(0, 256, 0); + ); + CheckAsserts( + buffer.GetMeta(0, 0, 256); + ); + + return 0; +} diff --git a/tests/ChunkBuffer/Copies.cpp b/tests/ChunkBuffer/Copies.cpp new file mode 100644 index 000000000..6bdf80268 --- /dev/null +++ b/tests/ChunkBuffer/Copies.cpp @@ -0,0 +1,53 @@ + +#include "TestGlobals.h" +#include "ChunkBuffer.h" + + + +int main(int argc, char** argv) +{ + cChunkBuffer buffer; + + buffer.SetBlock(3,1,4,0xDE); + buffer.SetMeta(3,1,4,0xA); + + cChunkBuffer copy = buffer.Copy(); + testassert(copy.GetBlock(3,1,4) == 0xDE); + testassert(copy.GetMeta(3,1,4) == 0xA); + + BLOCKTYPE * SrcBlockBuffer = new BLOCKTYPE[16 * 16 * 256]; + for (int i = 0; i < 16 * 16 * 256; i += 4) + { + SrcBlockBuffer[i+0] = 0xDE; + SrcBlockBuffer[i+1] = 0xAD; + SrcBlockBuffer[i+2] = 0xBE; + SrcBlockBuffer[i+3] = 0xEF; + } + + buffer.SetBlocks(SrcBlockBuffer); + BLOCKTYPE * DstBlockBuffer = new BLOCKTYPE[16 * 16 * 256]; + buffer.CopyBlocks(DstBlockBuffer); + testassert(memcmp(SrcBlockBuffer, DstBlockBuffer, (16 * 16 * 256) -1) == 0); + delete SrcBlockBuffer; + delete DstBlockBuffer; + SrcBlockBuffer = NULL; + DstBlockBuffer = NULL; + + NIBBLETYPE * SrcNibbleBuffer = new NIBBLETYPE[16 * 16 * 256/2]; + for (int i = 0; i < 16 * 16 * 256 / 2; i += 4) + { + SrcNibbleBuffer[i+0] = 0xEF; + SrcNibbleBuffer[i+1] = 0xDE; + SrcNibbleBuffer[i+2] = 0xAD; + SrcNibbleBuffer[i+3] = 0xBE; + } + + buffer.SetMeta(SrcNibbleBuffer); + NIBBLETYPE * DstNibbleBuffer = new NIBBLETYPE[16 * 16 * 256/ 2]; + buffer.CopyMeta(DstNibbleBuffer); + testassert(memcmp(SrcNibbleBuffer, DstNibbleBuffer, (16 * 16 * 256 /2) -1) == 0); + delete SrcNibbleBuffer; + delete DstNibbleBuffer; + SrcNibbleBuffer = NULL; + DstNibbleBuffer = NULL; +} 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..bb25bd20a --- /dev/null +++ b/tests/TestGlobals.h @@ -0,0 +1,139 @@ + + +#include <cstdarg> +#include <cstdio> +#include <cstdlib> + + +// 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; + +class cAssertFailure +{ +}; + +#define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0) +#define testassert(x) do { if(!(x)) { exit(1); } } while (0) +#define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } exit(1); } while (0) + +#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 100755 index 000000000..fc17ddc2c --- /dev/null +++ b/uploadCoverage.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ] + then + find tests -type f -name '*.gcda' -exec sh -c 'cp {} $(dirname {})/../$(basename {})' \; + coveralls --exclude lib --exclude Android >/dev/null +fi + + |